| 赞 | 31 |
| VIP | |
| 好人卡 | |
| 积分 | 58 |
| 经验 | |
| 最后登录 | 2026-8-16 |
| 在线时间 | 971 小时 |
- 梦石
- 0
- 星屑
- 5816
- 在线时间
- 971 小时
- 注册时间
- 2015-2-6
- 回帖
- 123

|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有账号?注册会员
×
本帖最后由 戏蹑群星斗 于 2024-2-25 18:25 编辑
发现一个敌人行动预测插件,支持回合制和即时制,给大家分享下
使用请遵守MIT协议 https://kekeelabo.com/?i=42
[fold=敵キャラの次の行動とターゲットを表示するシステム
ターン制&タイムプログレス両対応][pre lang="javascript" file="Keke_PredictionSystem.js"]//=============================================================================
// Keke_PredictionSystem - 行動予測システム
// バージョン: 1.1.9
//=============================================================================
// Copyright (c) 2023 ケケー
// Released under the MIT license
// http://opensource.org/licenses/mit-license.php
//=============================================================================
/*:
* @target MZ
* @plugindesc 敵の行動&ターゲット先行表示システム
* @author ケケー
* @url https://kekeelabo.com
*
* @help
* 【ver.1.1.9】
* 敵キャラの次の行動とターゲットを表示するシステム
* ターン制&タイムプログレス両対応
*
* ● 使い方 ●
*
* ■【最初にやること】ターゲットラインの調整
* バトルのレイアウトに応じてターゲットラインの位置と方向を調整する
* ◎ターゲットラインとは行動者からターゲットに向けて伸び、
* 誰がターゲットなのか示すラインのこと
* ◎調整はプラグインパラメータで行う
* ◎一例として、左が敵、右が味方のサイドビュー画面向けに調整してみる
* そのままやってみてほしい
* [1]プラグインパラメータ → 『ライン-進行方向』 を「右」にする
* ラインは敵から味方に向けて伸びるもの
* そして敵が左側、味方が右側なので「右」に向かって伸ばす
* [2]プラグインパラメータ → 『ライン-終点』
* 『終点-方向(味方)』を「左」にする
* ラインが味方グラの左側に向かって伸びるようになる
* [3]以上。バトルを「サイドビュー」にしてテストしてみる
*
*
* ■【設定1】行動予測を手動で発動するようにする
* [1]プラグインパラメータ → 『常に行動予測』 を「false」にする
* 行動予測が自動で発動しないようになる
* [2]データベースのメモ欄orスイッチを使って行動予測をオンにする。詳細は後述
*
*
* ■【設定2】行動ビュー/ターゲットラインを無効化
* デフォルトでは行動とターゲットの両方が表示されるが、
* どちらか片方だけにしたい場合に
* ◎行動表示を無効化
* プラグインパラメータ → 『行動表示』 を「false」
* ◎ターゲット表示を無効化
* プラグインパラメータ → 『ターゲット表示』 を「false」
*
*
* ■【設定3】行動ビューの見た目をカスタマイズ
* プラグインパラメータ → 『行動ビュー』
* ◎色々と設定項目が並んでいるが、好きにいじってよい
*
*
* ■【設定4】ターゲットラインの見た目をカスタマイズ
* プラグインパラメータ → 『ターゲットライン』
* ◎色々と設定項目が並んでいるが、好きにいじってよい
*
*
* ■【機能1】データベースのメモ欄で行動予測の設定変更
* 行動予測の設定を動的に変更できる
* ・敵毎に行動ビューの位置をずらす
* ・行動ビューに表示される名前を指定
* ・行動予測を動的にオンオフ
* といった機能がある
* ◎アクター、職業、スキル、アイテム、武器、防具、敵キャラ、ステートのメモ欄に
* <行動予測: x: y: dire: name: icon: redoAct redoTarget on off>
* ★例)
* <行動予測: x:100>
* 行動ビューの位置を右に 100 ピクセル ずらす。-100 なら左
* <行動予測: y:100>
* 行動ビューの位置を下に 100 ピクセル ずらす。-100 なら上
* <行動予測: dire:上>
* 行動ビューの表示方向を 上 にする
* 方向は「中央」「上」「下」「左」「右」を入れられる
* <行動予測: text:謎の攻撃>
* 行動ビューに表示されるテキストを『謎の攻撃』にする。制御文字も使用可能
* \n で改行。指定がなければスキル名が表示される
* <行動予測: icon:11>
* 行動ビューに表示されるアイコンを ID 11 のアイコンにする
* 指定がなければスキルのアイコンが表示される
* <行動予測: redoAct>
* 敵キャラの行動を再決定する。ターゲットも同時に再決定される
* <行動予測: redoTarget>
* 敵キャラのターゲットを再決定する。行動はそのまま
* <行動予測: on>
* 行動予測を オン(有効) にする
* <行動予測: off>
* 行動予測を オフ(無効) にする
* オンとオフが両方ある場合はオフが優先される
* <行動予測: showLine>
* ターゲットラインを表示する
* <行動予測: hideLine>
* ターゲットラインを表示しない
* <行動予測: x:100 y:100 dire:上 icon:11 name:謎の攻撃 on>
* とまとめて設定することも可能
*
*
* ■【機能2】スイッチで行動予測を有効/無効
* [1]プラグインパラメータ →
* 『行動予測"有効"スイッチ』/『行動予測"無効"スイッチ』 に、
* それぞれ好きなスイッチを割り当てる
* [2]有効スイッチをオンにすると行動予測有効、
* 無効スイッチをオンにすると無効になる
* 両方ともオンの場合は無効が優先され無効
*
*
* ● 利用規約 ●
* MITライセンスのもと、自由に使ってくれて大丈夫です
*
*
*
* A system that displays the next action and target of the enemy character
* Supports both turn-based and time-progress
*
* ● How to use ●
*
* ■【First thing to do】 Adjust the target line
* Adjust the position and direction of the target line
* according to the battle layout
* ◎ The target line extends from the actor toward the target,
* A line that indicates who is the target
* ◎ Adjustments are made with plug-in parameters
* ◎ As an example, try adjusting for the side view screen
* with enemies on the left and allies on the right.
* I want you to try it as it is
* [1] Plug-in parameter → Set "ライン-進行方向" to "right"
* Lines extend from enemies to allies
* And since the enemy is on the left and the ally is on the right,
* stretch toward "right"
* [2] Plugin parameter → "ライン-進行方向"
* Set "終点-方向(味方)" to "left"
* The line will extend toward the left side of the allied graphic
* [3] and above. Test the battle in "side view"
*
*
* ■ [Setting 1] Manually activate action prediction
* [1] Plugin parameter → Set "常に行動予測r" to "false"
* Action prediction will not be activated automatically
* [2] Turn on action prediction using the memo field in the database
* or switch. Details later
*
*
* ■ [Setting 2] Disable action view/target line
* By default, both actions and targets are displayed,
* If you want to use only one of them
* ◎ Disable action display
* Plugin parameter → "行動表示" to "false"
* ◎ Disable target display
* Plugin parameter → "ターゲット表示" to "false"
*
*
* ■ [Setting 3] Customize the action view appearance
* Plugin parameter → "行動ビュー"
* ◎ Various setting items are lined up, but you can tweak them as you like.
*
*
* ■ [Setting 4] Customize the appearance of the target line
* Plug-in parameter → "ターゲットライン"
* ◎ Various setting items are lined up, but you can tweak them as you like.
*
*
* ■ [Function 1] Change action prediction settings
* in the memo field of the database
* You can dynamically change action prediction settings
* ・Shift the position of the action view for each enemy
* ・Specify the name displayed in the action view
* ・ Dynamically turn on/off action prediction
* There are functions such as
* ◎ Actor, class, skill, item, weapon, armor, enemy character,
* state memo column
* <prediction: x: y: dire: name: icon: redoAct redoTarget on off>
* ★example)
* <prediction: x:100>
* Shift the position of the action view by 100 pixels to the right.
* -100 is left
* <prediction: y:100>
* Shift the position of the action view downward by 100 pixels. -100 is up
* <prediction: dire:up>
* Set the display direction of the action view to up
* Direction can be "Center", "Top", "Bottom", "Left", and "Right"
* <prediction: text: Mysterious attack>
* Change the text displayed in the action view to "Mysterious Attack".
* Control characters are allowed
* Newline with \n. If not specified, the skill name will be displayed
* <prediction: icon:11>
* Set the icon displayed in the action view to the icon with ID 11
* If not specified, the skill icon will be displayed
* <prediction: redoAct>
* Redetermine the actions of the enemy characters.
* The target is also re-determined at the same time
* <prediction: redoTarget>
* Redetermine the enemy character's target. action as it is
* <prediction: on>
* Action prediction he turned on (enabled)
* <prediction: off>
* He turns off (disables) action prediction
* If there are both on and off, off takes precedence
* <prediction: showLine>
* display target line
* <prediction: hideLine>
* Do not display target line
* <prediction: x:100 y:100 dire:up icon:11 name:mysterious attack on>
* It is also possible to set together with
*
*
* ■ [Function 2] Activate/deactivate action prediction with a switch
* [1] Plugin parameters →
* In the "行動予測"有効"スイッチ" / "行動予測"無効"スイッチ",
* Allocate your favorite switch to each
* [2] Action prediction is enabled when the enable switch is turned on,
* Disabled when the disabled switch is turned on
* If both are on, disable takes precedence over disable
*
*
* ● Terms of Use ●
* Feel free to use it under the MIT license.
*
*
*
* @param 常に行動予測
* @desc predictionAlways 常に有効予測を有効にする。有効にしない場合はデータベースのメモ欄で適宜有効にする
* @type boolean
* @default true
*
* @param 行動予測"有効"スイッチ
* @desc prediction"valid"switch 行動予測を有効にするスイッチ
* @type switch
* @default
*
* @param 行動予測"無効"スイッチ
* @desc prediction"unValid"switch 行動予測を無効にするスイッチ
* @type switch
* @default
*
* @param 行動ビュー
*
* @param 行動-表示
* @parent 行動ビュー
* @desc act-show 味方キャラの行動ビューを表示する(場合によっては味方キャラも)
* @type boolean
* @default true
*
* @param 行動-入力中のみ表示
* @parent 行動ビュー
* @desc act-showOnlyInput 行動入力中のみ行動ビューを表示する
* @type boolean
* @default true
*
* @param 行動-詠唱中の味方も表示
* @parent 行動ビュー
* @desc act-showCastActor 詠唱中の味方キャラも行動ビューを表示する
* @type boolean
* @default false
*
* @param 行動-自動中の味方も表示
* @parent 行動ビュー
* @desc act-showAutoActor 自動戦闘中の味方キャラも行動ビューを表示する
* @type boolean
* @default false
*
* @param 行動-フォント
* @parent 行動ビュー
* @desc act-font 行動ビューの使用フォント。Keke_CommonDataでフォント登録しそのフォント名を書く。空欄ならメインフォント
* @default
*
* @param 行動-文字サイズ
* @parent 行動ビュー
* @desc act-fontSize 行動ビューの文字サイズ。基本 20
* @default 20
*
* @param 行動-文字色
* @parent 行動ビュー
* @desc act-fontColor 行動ビューの文字色。赤、緑、青、濃度。色0~255、濃度0~1。基本 255, 255, 0
* @default 255, 255, 0
*
* @param 行動-文字色(詠唱中)
* @parent 行動ビュー
* @desc act-fonColorCast 詠唱中の行動ビューの文字色。赤、緑、青、濃度。色0~255、濃度0~1。基本 255, 192, 255
* @default 255, 192, 255
*
* @param 行動-縁取り幅
* @parent 行動ビュー
* @desc act-outWidth 行動ビューの文字縁取り幅。5 なら 5ピクセル。基本 7
* @default 7
*
* @param 行動-横幅
* @parent 行動ビュー
* @desc act-width 行動ビューの横幅。100 なら 100ピクセル。基本 200
* @default 200
*
* @param 行動-背景色
* @parent 行動ビュー
* @desc act-backColor 行動ビューの背景の色。(赤, 緑, 青, 濃度)。色0~255、濃度0~1。基本 0, 0, 0, 0.25
* @default 0, 0, 0, 0.25
*
* @param 行動-アイコン表示
* @parent 行動ビュー
* @desc act-showicon 行動のアイコンを表示する。基本 true
* @type boolean
* @default true
*
* @param …アイコン間隔
* @parent 行動ビュー
* @desc act-interval 行動名とアイコンの間の間隔。5 なら 5ピクセル。基本 0
* @default 0
*
* @param …アイコンサイズ
* @parent 行動ビュー
* @desc act-iconSize アイコンの大きさ。150 なら 150%、50 なら 50% の大きさになる。基本 100
* @default 100
*
* @param 行動-行間
* @parent 行動ビュー
* @desc act-lineSpace 行動を複数行にわたって表示する時の行間。5 なら 5ピクセル。基本 2
* @default 2
*
* @param 行動-表示位置/味方
* @parent 行動ビュー
* @desc act-showPos/actor 味方の行動ビューの表示位置
* @type struct<viewPos>
* @default {"表示方向":"上","ずらしX":"","ずらしY":""}
*
* @param 行動-表示位置/敵
* @parent 行動ビュー
* @desc act-showPos/enemy 敵の行動ビューの表示位置
* @type struct<viewPos>
* @default {"表示方向":"上","ずらしX":"","ずらしY":""}
*
* @param 行動-非表示範囲
* @parent 行動ビュー
* @desc act-noShowScope 行動ビューを表示しない範囲。下50 なら、画面下端から 50ピクセル の範囲には表示しない
* @type struct<noShowScope>
* @default {"上":"0","下":"0","左":"0","右":"0"}
*
* @param 行動-表示レイヤー
* @parent 行動ビュー
* @desc act-showLayer 行動ビューの表示レイヤー。基本 ウインドウより下
* @type select
* @option ウインドウより上
* @option ウインドウより下
* @default ウインドウより下
*
* @param 行動-不発エフェクト
* @parent 行動ビュー
* @desc act-misfireEffect 行動がMP不足等で不発に終わった時のエフェクト
* @type struct<effect>
* @default {"アニメーション":"64","効果音":"[\"{\\\"ファイル\\\":\\\"Monster4\\\",\\\"音量\\\":\\\"100\\\",\\\"ピッチ\\\":\\\"70\\\",\\\"位相\\\":\\\"0\\\"}\"]","画面フラッシュ":"true","…フラッシュ色":"255, 255, 255, 170","…フラッシュ遅延":"","…フラッシュ時間":"30","ヒットストップ":"0, 0","フリーアニメ":""}
*
* @param ターゲットライン
*
* @param ライン-表示
* @parent ターゲットライン
* @desc line-show 敵キャラのターゲットラインを表示する
* @type boolean
* @default true
*
* @param ライン-入力中のみ表示
* @parent ターゲットライン
* @desc line-showOnlyInput 行動入力中のみターゲットラインを表示する
* @type boolean
* @default true
*
* @param ライン-進行方向
* @parent ターゲットライン
* @desc line-vector ターゲットラインの向かう方向
* @type select
* @option 上
* @option 下
* @option 左
* @option 右
* @default 下
*
* @param ライン-始点
* @parent ターゲットライン
* @desc line-startPoint ライン始点の位置設定。始点は敵キャラにのみ発生(ターゲットを表示するのは敵のみであるため)
* @type struct<lineStart>
* @default {"始点-方向":"右","始点-ずらしX":"","始点-ずらしY":""}
*
* @param ライン-終点
* @parent ターゲットライン
* @desc line-endPoint ライン終点の位置設定。終点は味方と敵キャラ両方ある(回復行動など、敵が敵をターゲットすることがあるため)
* @type struct<lineEnd>
* @default {"味方へのライン":"","終点-方向(味方)":"上","終点-ずらしX(味方)":"","終点-ずらしY(味方)":"","敵同士のライン":"","終点-方向(敵)":"中央","終点-ずらしX(敵)":"","終点-ずらしY(敵)":""}
*
* @param ライン-太さ
* @parent ターゲットライン
* @desc line-width ターゲットラインの太さ。5 なら 5ピクセル。基本 4
* @default 4
*
* @param ライン-縁取り幅
* @parent ターゲットライン
* @desc line-outWidth ターゲットラインの縁取りの幅。1 なら 1ピクセル。基本 1.5
* @default 1.5
*
* @param ライン-色リスト
* @parent ターゲットライン
* @desc line-colorList ターゲットラインの色。赤, 緑, 青。各0~255。1行目は一番目の敵、2行目は二番目の敵といった感じで適用
* @type string[]
* @default ["255, 255, 0","255, 0, 255","0, 255, 255","255, 128, 0","128, 255, 0","0, 128, 255","255, 255, 255","255, 0, 0"]
*
* @param ライン-始点大きさ
* @parent ターゲットライン
* @desc line-startPointSize ターゲットラインの始点の円部分の大きさ。5 なら 5ピクセル。基本 3
* @default 3
*
* @param ライン-矢印大きさ
* @parent ターゲットライン
* @desc line-arrowSize ターゲットラインの矢印部分の大きさ。5 なら 5ピクセル。基本 4
* @default 4
*
* @param ライン-重なりずらし
* @parent ターゲットライン
* @desc line-pileOffset ターゲットラインが重なった時にずらす幅。5 なら 5ピクセル。基本 12
* @default 12
*
* @param ライン-最低長さ
* @parent ターゲットライン
* @desc line-minLength ターゲットラインが短すぎる場合の最低長さ。この長さは下回らない。50 なら 50ピクセル。基本 50
* @default 50
*
* @param ライン-全体時はワード
* @parent ターゲットライン
* @desc line-wordOnAll 全体対象の時はラインではなく指定の文字列を表示する
* @type boolean
* @default true
*
* @param …全体ワード設定
* @parent ターゲットライン
* @desc line-allWordCfg 全体対象の時に表示する文字列の設定
* @type struct<allWordCfg>
* @default {"ワード":"ALL","フォント":"","文字サイズ":"22","文字色":"96, 255, 255","縁取り幅":"7","ずらしX":"","ずらしY":""}
*/
//==================================================
/*~struct~viewPos:
//==================================================
* @param 表示方向
* @desc showDire 行動ビューの表示方向。基本 上
* @type select
* @option 中央
* @option 上
* @option 下
* @option 左
* @option 右
* @default 上
*
* @param ずらしX
* @desc offsetX 行動ビューのX位置ずらし。5 なら 5ピクセル 右へ。基本 0
* @default
*
* @param ずらしY
* @desc offsetY 行動ビューのY位置ずらし。5 なら 5ピクセル 下へ。基本 0
* @default
*/
//==================================================
/*~struct~noShowScope:
//==================================================
* @param 上
* @desc up 上側の非表示範囲。50 なら 画面上端から 50ピクセル の範囲には表示しない。基本 0
*
* @param 下
* @desc down 下側の非表示範囲。50 なら 画面下端から 50ピクセル の範囲には表示しない。基本 0
*
* @param 左
* @desc left 左側の非表示範囲。50 なら 画面左端から 50ピクセル の範囲には表示しない。基本 0
*
* @param 右
* @desc right 右側の非表示範囲。50 なら 画面右端から 50ピクセル の範囲には表示しない。基本 0
*/
//==================================================
/*~struct~allWordCfg:
//==================================================
* @param ワード
* @desc word 全体ワードとして表示する文字列
* @default ALL
*
* @param フォント
* @parent 行動ビュー
* @desc font 全体ワードの使用フォント。Keke_CommonDataでフォント登録したフォント名を書く。空欄ならメインフォント
* @default
*
* @param 文字サイズ
* @desc fontSize 全体ワードの文字サイズ。基本 22
* @default 22
*
* @param 文字色
* @desc fontColor 全体ワードの文字色。赤、緑、青、濃度。各0〜255。基本 96, 255, 255
* @default 96, 255, 255
*
* @param 縁取り幅
* @desc outWidth 全体ワードの文字縁取り幅。5 なら 5ピクセル。基本 7
* @default 7
*
* @param ずらしX
* @desc offsetX 全体ワードのX位置ずらし。5 なら 5ピクセル 右へ。基本 0
* @default
*
* @param ずらしY
* @desc offsetY 全体ワードのY位置ずらし。5 なら 5ピクセル 下へ。基本 0
* @default
*/
//==================================================
/*~struct~lineStart:
//==================================================
* @param 始点-方向
* @desc startPoint-dire ライン始点の位置方向。基本 右
* @type select
* @option 中央
* @option 上
* @option 下
* @option 左
* @option 右
* @default 右
*
* @param 始点-ずらしX
* @desc startPoint-offsetX ライン始点のXずらし。5 なら 5ピクセル 右へ。基本 0
* @default
*
* @param 始点-ずらしY
* @desc startPoint-offsetY ライン始点のYずらし。5 なら 5ピクセル 下へ。基本 0
* @default
*/
//==================================================
/*~struct~lineEnd:
//==================================================
* @param 味方へのライン
*
* @param 終点-方向(味方)
* @parent 味方へのライン
* @desc endPoint-dire(actor) 味方のライン終点の位置方向。基本 上
* @type select
* @option 中央
* @option 上
* @option 下
* @option 左
* @option 右
* @default 上
*
* @param 終点-ずらしX(味方)
* @parent 味方へのライン
* @desc endPoint-offsetX(actor) 味方のライン終点のXずらし。5 なら 5ピクセル 右へ。基本 0
* @default
*
* @param 終点-ずらしY(味方)
* @parent 味方へのライン
* @desc endPoint-offsetY(actor) 味方のライン終点のYずらし。5 なら 5ピクセル 下へ。基本 0
* @default
*
* @param 敵同士のライン
*
* @param 終点-方向(敵)
* @parent 敵同士のライン
* @desc endPoint-dire(enemy) 敵のライン終点の位置方向。基本 中央
* @type select
* @option 中央
* @option 上
* @option 下
* @option 左
* @option 右
* @default 中央
*
* @param 終点-ずらしX(敵)
* @parent 敵同士のライン
* @desc endPoint-offsetX(enemy) 敵のライン終点のXずらし。5 なら 5ピクセル 右へ。基本 0
* @default
*
* @param 終点-ずらしY(敵)
* @parent 敵同士のライン
* @desc endPoint-offsetY(enemy) 敵のライン終点のYずらし。5 なら 5ピクセル 下へ。基本 0
* @default
*/
//==================================================
/*~struct~effect:
//==================================================
*
* @param アニメーション
* @desc animation 表示するアニメーション
* @type animation
*
* @param 効果音
* @desc SE 鳴らす効果音
* @type struct<se>[]
* @default []
*
* @param 画面フラッシュ
* @desc screenFlash 画面フラッシュを実行する
* @type boolean
* @default false
*
* @param …フラッシュ色
* @desc flashColor 画面フラッシュの色。赤, 緑, 青, 強さ。各0~255。基本 255, 255, 255, 170
* @default 255, 255, 255, 170
*
* @param …フラッシュ遅延
* @desc flashDelay フラッシュのディレイ。5 なら 5フレーム 待ってからフラッシュ。基本 0
* @default
*
* @param …フラッシュ時間
* @desc flashTime フラッシュの所要時間。5 なら 5フレーム。基本 30
* @default 30
*
* @param ヒットストップ
* @desc hitStope 画面を止める演出。5, 7 なら 5フレーム 待ってから 7フレーム 止める。Keke_HitStopが必要。基本 0, 0
* @default 0, 0
*
* @param フリーアニメ
* @desc freeAnime フリーアニメを再生する。メモ欄同様に記述。Keke_FreeAnimeが必要
* @type multiline_string
*/
//==================================================
/*~struct~se:
//==================================================
* @param ファイル
* @desc file 効果音ファイル
* @type file
* @dir audio/se
*
* @param 音量
* @desc volime 効果音の音量
* @default 100
*
* @param ピッチ
* @desc pitch 効果音のピッチ
* @default 100
*
* @param 位相
* @desc pan 効果音の位相
* @default 0
*/
(() => {
//- プラグイン名
const pluginName = document.currentScript.src.match(/^.*\/(.*).js$/)[1];
//==================================================
//-- 公開
//==================================================
//- 行動予測の開始(公開)
Game_Temp.prototype.startPredictionKe = function(subject, force) {
// 行動予測の開始
startPrediction(subject, force);
};
//==================================================
//-- スプライト追加 /ベーシック
//==================================================
//- 破棄付きスプライト
function SpriteKePrds() {
this.initialize(...arguments);
}
SpriteKePrds.prototype = Object.create(Sprite.prototype);
SpriteKePrds.prototype.constructor = SpriteKePrds;
SpriteKePrds.prototype.destroy = function() {
if (this.bitmap && !this.bitmap._url) { this.bitmap.destroy(); }
if (this._texture) { Sprite.prototype.destroy.apply(this); }
};
//==================================================
//-- 文字列オート変換 /ベーシック
//==================================================
//- 文字列のハッシュ化
function strToHash(str) {
if (!str || !str.length) { return {}; }
let hash = {};
const strs = JSON.parse(str);
let val = null;
let val2 = null;
for (const key in strs) {
val = strs[key];
if (!key || !val) { continue; }
val2 = strToAuto(val, key);
hash[key] = val2;
}
return hash;
};
//- 文字列のリスト化
function strToList(str) {
if (!str || !str.length) { return []; }
let array = JSON.parse(str);
return array.map((val, i) => {
return strToAuto(val);
});
};
//- 文字列の自動処理
function strToAuto(val, key = "") {
let val2 = null;
let match = null;
let end = false;
if (!end) {
if (val[0] == "{") {
val2 = strToHash(val);
end = true;
}
}
if (!end) {
if (val[0] == "[") {
val2 = strToList(val);
end = true;
}
}
if (!end) { val = val + ","; }
if (!end) {
match = val.match(/^\s*(-?\d+,\s*-?\d+,\s*-?\d+,?\s*-?\d*\.?\d*)\s*,$/);
if (match && !val.match(/[^\d\.\-,\s]/)) {
if (key.match(/(カラー|色|塗り)/) && !key.includes("トーン") && !key.includes("ブレンド") && !key.includes("配色") && !key.includes("着色") && !key.includes("フラッシュ") && !key.includes("チェンジ") && !key.includes("選択")) {
val2 = "rgba(" + match[1] + ")";
} else {
val2 = JSON.parse("[" + match[1] + "]");
}
end = true;
}
}
if (!end) {
match = val.match(/(-?\d+\.?\d*),\s*/g);
if (match && match.length >= 2 && !val.match(/[^\d\.\-,\s]/)) {
val2 = JSON.parse("[" + match.reduce((r, s) => r + s).replace(/,$/, "") + "]");
end = true;
}
}
if (!end) {
match = val.match(/^(true|false)\s*,/);
if (match) {
val2 = match[1] == "true" ? true : false;
end = true;
}
}
if (!end) {
match = val.match(/^(-?\d+\.?\d*)\s*,/);
if (match && !val.match(/[a-z]/)) {
val2 = Number(match[1]); end = true;
end = true;
}
}
if (!end) {
if (val[0] == "\"") { val = val.slice(1); }
val2 = val.slice(0, -1);
}
return val2;
};
//==================================================
//-- パラメータ受け取り
//==================================================
//- 真偽化
function toBoolean(str) {
if (!str) { return false; }
const str2 = str.toString().toLowerCase();
if (str2 == "true" || str2 == "on") { return true; }
if (str2 == "false" || str2 == "off") { return false; }
return Number(str);
};
let parameters = PluginManager.parameters(pluginName);
const keke_predictionAlways = toBoolean(parameters["常に行動予測"]);
const keke_predictionOnSwitch = Number(parameters["行動予測\"有効\"スイッチ"]);
const keke_predictionOffSwitch = Number(parameters["行動予測\"無効\"スイッチ"]);
//- 行動ビュー
const keke_actShow = toBoolean(parameters["行動-表示"]);
const keke_actOnlyInput = toBoolean(parameters["行動-入力中のみ表示"]);
const keke_actShowCastActor = toBoolean(parameters["行動-詠唱中の味方も表示"]);
const keke_actShowAutoActor = toBoolean(parameters["行動-自動中の味方も表示"]);
const keke_actFontFace = parameters["行動-フォント"];
const keke_actFontSize = Number(parameters["行動-文字サイズ"]);
const keke_actFontColor = "rgba(" + parameters["行動-文字色"] + ")";
const keke_actFontColorCast = "rgba(" + parameters["行動-文字色(詠唱中)"] + ")";
const keke_actOutW = Number(parameters["行動-縁取り幅"]);
const keke_actW = Number(parameters["行動-横幅"]);
const keke_actBackColor = parameters["行動-背景色"] ? `rgba(${parameters["行動-背景色"]})` : "";
const keke_actShowIcon = toBoolean(parameters["行動-アイコン表示"]);
const keke_actIconSpace = Number(parameters["…アイコン間隔"]);
const keke_actIconSize = Number(parameters["…アイコンサイズ"]) || 100;
const keke_actLineSpace = Number(parameters["行動-行間"]);
const keke_actPosActor = strToHash(parameters["行動-表示位置/味方"]);
const keke_actPosEnemy = strToHash(parameters["行動-表示位置/敵"]);
const keke_actNoShowScope = strToHash(parameters["行動-非表示範囲"]);
const keke_actLayer = parameters["行動-表示レイヤー"];
const keke_actMisfireEffect = strToHash(parameters["行動-不発エフェクト"]);
//- ターゲットライン
const keke_lineShow = toBoolean(parameters["ライン-表示"]);
const keke_lineOnlyInput = toBoolean(parameters["ライン-入力中のみ表示"]);
const keke_lineDire = parameters["ライン-進行方向"];
const keke_lineStart = strToHash(parameters["ライン-始点"]);
const keke_lineEnd = strToHash(parameters["ライン-終点"]);
const keke_lineW = Number(parameters["ライン-太さ"]);
const keke_lineOutW = Number(parameters["ライン-縁取り幅"]);
const keke_lineColorList = makeColorList(parameters["ライン-色リスト"]);
const keke_linePileOffset = Number(parameters["ライン-重なりずらし"]);
const keke_lineStartSize = Number(parameters["ライン-始点大きさ"]);
const keke_lineArrowSize = Number(parameters["ライン-矢印大きさ"]);
const keke_lineMinLength = Number(parameters["ライン-最低長さ"]);
const keke_lineWordIfAll = toBoolean(parameters["ライン-全体時はワード"]);
const keke_allWordCfg = strToHash(parameters["…全体ワード設定"]);
parameters = null;
//- カラーリストの作成
function makeColorList(str) {
const list = strToList(str);
return list.map(s => `rgba(${s})`);
};
//==================================================
//-- プラグインコマンド
//==================================================
PluginManager.registerCommand(pluginName, "", args => {
const a = Number(args.a);
});
//==================================================
//-- 他プラグイン連携
//==================================================
//- フルアニメステータスASIの取得
function getFullAnimeStatusAsi(battler) {
// サイドビュー時はバトグラに表示
if ($gameSystem.isSideView()) { return null; }
if (!$gameTemp._fullAnimeStatusKe) { return null; }
const asi = $gameTemp.getFullAnimeStatusAsiKe(battler);
// 顔アイコンがなければバトグラに表示
if (!asi || !asi.faceBaseSprite || !asi.faceBaseSprite.visible) { return null; }
return asi;
};
//- 文字サイズ率の取得
function getFontSizeRate(fontName) {
if (!fontName || !$gameTemp._fontListKe) { return { width:1, half:1 }; }
let widthSize = 1;
let halfSize = 1;
// フォントリスト展開
for (const data of $gameTemp._fontListKe) {
// 名前が適合したら取得
if (data["フォント名"] == fontName) {
widthSize = data["横幅サイズ"] || 1;
halfSize = data["半角サイズ"] || 1;
break;
}
}
return { width:widthSize, half:halfSize };
};
//==================================================
//-- 共通開始
//==================================================
//- ゲームバトラー/TPB初期化(コア追加)
const _Game_Battler_initTpbChargeTime = Game_Battler.prototype.initTpbChargeTime;
Game_Battler.prototype.initTpbChargeTime = function(advantageous) {
_Game_Battler_initTpbChargeTime.apply(this, arguments);
// 行動予測の開始(TPB)
if (BattleManager.isTpb()) {
setTimeout(startPrediction, 0, this);
}
};
//- バトルマネージャー/入力の開始(コア追加)
const _BattleManager_startInput = BattleManager.startInput;
BattleManager.startInput = function() {
_BattleManager_startInput.apply(this);
// 行動予測の開始-全員(ターン)
if (!BattleManager.isTpb()) {
startPredictionAll();
}
};
//==================================================
//-- 共通更新
//==================================================
//- スプライトエネミー/更新(コア追加)
const _Sprite_Enemy_update = Sprite_Enemy.prototype.update;
Sprite_Enemy.prototype.update = function() {
_Sprite_Enemy_update.apply(this);
// ターゲットラインの更新
updateTargetLine(this);
};
//- スプライトセット・バトル/更新(コア追加)
const _Spriteset_Battle_updateBattleback = Spriteset_Battle.prototype.updateBattleback;
Spriteset_Battle.prototype.updateBattleback = function() {
// ターゲットライン周期の更新
updateTargetLineCycle();
_Spriteset_Battle_updateBattleback.apply(this);
};
//==================================================
//-- 共通終了
//==================================================
//- バトル終了時の処理(コア追加)
const _BattleManager_endBattle = BattleManager.endBattle;
BattleManager.endBattle = function(result) {
_BattleManager_endBattle.apply(this, arguments);
// 先行ターゲットの消去-全員
delTargetFastAll();
// 受容ラインの初期化
initReceptLine();
};
//- スプライトセット・バトル(コア追加)
const _Spriteset_Battle_destroy = Spriteset_Battle.prototype.destroy
Spriteset_Battle.prototype.destroy = function(options) {
// スプライトの全破棄
destroySpriteAll(this);
_Spriteset_Battle_destroy.apply(this, arguments);
};
//- スプライトの全破棄
function destroySpriteAll(spriteset) {
const layers = spriteset._predictionLayersKe;
if (!layers) { return; }
// 全てのレイヤーに対して処理
Object.keys(layers).forEach(key => {
// スプライトの破棄
destroySprite(layers[key]);
});
spriteset._predictionLayersKe = null;
};
//- スプライトの破棄
function destroySprite(sprite) {
if (!sprite) { return; }
sprite.children.forEach(s => destroySprite(s));
if (sprite.bitmap && !sprite.bitmap._url) { sprite.bitmap.destroy(); }
if (sprite._texture) { sprite.destroy(); }
};
//- バトルマネージャー/ターンの更新(コア追加)
const _BattleManager_updateTurn = BattleManager.updateTurn;
BattleManager.updateTurn = function(timeActive) {
// 再決定の実行
executeRedo();
_BattleManager_updateTurn.apply(this, arguments);
};
//==================================================
//-- 共通処理
//==================================================
//- 全アクションの終了時の処理(コア追加)
const _BattleManager_endBattlerActions = BattleManager.endBattlerActions;
BattleManager.endBattlerActions = function(battler) {
_BattleManager_endBattlerActions.apply(this, arguments);
// 行動予測の開始
startPrediction(battler);
};
//- ターン終了時の処理(コア追加)
const _Game_Battler_onTurnEnd = Game_Battler.prototype.onTurnEnd;
Game_Battler.prototype.onTurnEnd = function() {
_Game_Battler_onTurnEnd.apply(this);
// 行動予測の開始
startPrediction(this);
};
//- 行動直前の処理(コア追加)
const _Game_Action_prepare = Game_Action.prototype.prepare;
Game_Action.prototype.prepare = function() {
_Game_Action_prepare.apply(this);
// 先行ターゲットの適用
applyTargetFast(this.subject());
// 不発だったら不発エフェクト
if (!this.isValid()) {
misfireEffect(this.subject());
}
};
//- 詠唱開始時の処理
const _Game_Battler_startTpbCasting = Game_Battler.prototype.startTpbCasting;
Game_Battler.prototype.startTpbCasting = function() {
_Game_Battler_startTpbCasting.apply(this);
// 行動ビューのリフレッシュフラグをオン
this._refreshsActViewKe = true;
};
//- アクション開始時の処理(コア追加)
const _BattleManager_startAction = BattleManager.startAction;
BattleManager.startAction = function() {
_BattleManager_startAction.apply(this);
// 再決定の処理
processRedo(this._subject, this._targets, this._action);
};
//- 行動不能時の処理(コア追加)
const _Game_Battler_onRestrict = Game_Battler.prototype.onRestrict;
Game_Battler.prototype.onRestrict = function() {
_Game_Battler_onRestrict.apply(this);
// 行動予約の消去
delPrediction(this);
};
//==================================================
//-- レイヤー
//==================================================
//- ウインドウレイヤー作成時に行動予測レイヤーも作成
const _Scene_Battle_createWindowLayer = Scene_Battle.prototype.createWindowLayer;
Scene_Battle.prototype.createWindowLayer = function() {
_Scene_Battle_createWindowLayer.apply(this);
// レイヤーの形成
createLayer(this);
};
//- レイヤーの形成
function createLayer(scene) {
const spriteset = scene._spriteset;
const layers = {};
// Aレイヤー
const layerA = new SpriteKePrds();
spriteset.addChild(layerA);
layers["A"] = layerA;
// Bレイヤー
const layerB = new SpriteKePrds();
spriteset.addChild(layerB);
layers["B"] = layerB;
// Cレイヤー
const layerC = new SpriteKePrds();
scene.addChild(layerC);
layers["C"] = layerC;
// Dレイヤー
const layerD = new SpriteKePrds();
scene.addChild(layerD);
layers["D"] = layerD;
// 変数セット
spriteset._predictionLayersKe = layers;
};
//- レイヤーチルド
function childLayer(sprite, id) {
SceneManager._scene._spriteset._predictionLayersKe[id].addChild(sprite);
};
//==================================================
//-- メモ欄からの取得
//==================================================
//- 行動予測設定の取得
function getPredictionCfg(battler, tage, calc = "*", action = null, radioIndex) {
const metas = totalAllMetaArray(battler, ["行動予測", "prediction"], action, true, radioIndex);
if (!metas || !metas.length) { return null; }
const array = [];
for (const str of metas.reverse()) {
if (!str) { continue; }
// ずらしX
if (tage == "ずらしX") {
const match = str.match(/(^|[,\s\n])(x|offsetX|posX|ずらしX|位置X):\s*(\-*\d+\.*\d*)/i);
if (match && match[3]) {
return Number(match[3]);
}
continue;
}
// ずらしY
if (tage == "ずらしY") {
const match = str.match(/(^|[,\s\n])(y|offsetY|posY|ずらしY|位置Y):\s*(\-*\d+\.*\d*)/i);
if (match && match[3]) {
return Number(match[3]);
}
continue;
}
// 表示方向
if (tage == "表示方向") {
const match = str.match(/(^|[,\s\n])(dire|direction|showDire|表示方向|方向):\s*(中央|左|右|上|下|center|left|right|up|down|c|l|r|u|d)/i);
if (match && match[3]) {
return convertDirection(match[3]);
}
continue;
}
// テキスト
if (tage == "テキスト") {
const match = str.match(/(^|[,\s\n])(text|name|テキスト|文章|名前):\s*([^\s,]+)/i);
if (match && match[3]) {
return match[3];
}
continue;
}
// アイコン
if (tage == "アイコン") {
const match = str.match(/(^|[,\s\n])(icon|showIcon|アイコン|表示アイコン):\s*(\d*),*\s*(\-*\d*\.*\d*)/i);
if (match && (match[3] || match[4])) {
return { index:Number(match[3]), size:Number(match[4]) };
}
continue;
}
// 行動再決定
if (tage == "行動再決定") {
const match = str.match(/(^|[,\s\n])(actRedo|redoAct|行動再決定|再行動)/i);
if (match && match[2]) {
return true
}
continue;
}
// ターゲット再決定
if (tage == "ターゲット再決定") {
const match = str.match(/(^|[,\s\n])(targetRedo|redoAct|ターゲット再決定|再ターゲット)/i);
if (match && match[2]) {
return true
}
continue;
}
// ラインあり
if (tage == "ラインあり") {
const match = str.match(/(^|[,\s\n])(showLine|showTarget|ラインあり|ターゲットあり|ライン表示|ターゲット表示)/i);
if (match && match[2]) {
return true
}
continue;
}
// ラインなし
if (tage == "ラインなし") {
const match = str.match(/(^|[,\s\n])(hideLine|hideTarget|ラインなし|ターゲットなし|ライン非表示|ターゲット非表示)/i);
if (match && match[2]) {
return true
}
continue;
}
// 無効
if (tage == "無効") {
const match = str.match(/(^|[,\s\n])(no|off|none|無効|オフ)/i);
if (match && match[2]) {
return true
}
continue;
}
// 有効
if (tage == "有効") {
const match = str.match(/(^|[,\s\n])(ok|on|valid|有効|オン)/i);
if (match && match[2]) {
return true
}
continue;
}
}
return null;
};
//- 方向の変換
function convertDirection(d) {
if (d.match(/center|c/i)) {
return "中央";
} else if (d.match(/left|l/i)) {
return "左";
} else if (d.match(/right|r/i)) {
return "右";
} else if (d.match(/up|u/i)) {
return "上";
} else if (d.match(/down|d/i)) {
return "下";
}
return d;
};
//- メモ欄からのフラグの取得
function getValidByMemo(subject) {
const members = [subject, ...$gameParty.aliveMembers()];
// メモ欄に無効フラグがあったら無効
if (members.some(battler => getPredictionCfg(battler, "無効"))) { return false; };
// メモ欄に有効フラグがあったら有効
if (members.some(battler => getPredictionCfg(battler, "有効"))) { return true; };
return null;
}
//==================================================
//-- 行動予測システム
//==================================================
// 再決定予約
let redoReserve = null;
// 行動予測の開始
function startPrediction(subject, force) {
// 対象は敵キャラ & 自動キャラのみ
if (subject._actorId && !subject.isAutoBattle()) { return; }
// 行動の先行作成
makeActionFast(subject, force);
// ターゲットの先行作成
makeTargetFast(subject);
};
// 行動の先行作成
function makeActionFast(subject, force) {
if (!subject) { return; }
// 行動作成(TPB時のみ)
if (BattleManager.isTpb()) {
if (!subject._actions.length || force) {
// アクションのクリア
subject.clearActions();
const preActionState = subject._actionState;
// 行動予約がなければアクション作成
subject.makeActions();
subject.setActionState(preActionState);
// 先行アクションフラグをオン
subject._actionMakedFastKe = true;
}
}
// 行動ビューのリフレッシュフラグをオン
subject._refreshsActViewKe = true;
};
// 行動ビューを表示するか
function isActShow() {
return keke_actShow;
};
// ターゲットラインを表示するか
function isTargetLineShow(subject) {
if (getPredictionCfg(subject, "ラインあり")) { return true; };
if (getPredictionCfg(subject, "ラインなし")) { return false; };
return keke_lineShow;
};
//- 行動予測有効か
function isValidPrediction(subject) {
// 無効スイッチがオンなら無効
if ($gameSwitches.value(keke_predictionOffSwitch)) { return false; };
//メモ欄に無効フラグがあったら無効
const memoValid = getValidByMemo(subject);
if (memoValid == false) { return false; }
// 常に行動予測/有効スイッチ/有効フラグのいずれかがオンなら有効
return keke_predictionAlways || memoValid == true || $gameSwitches.value(keke_predictionOnSwitch);
};
// 行動予測の開始-全員
function startPredictionAll() {
// 全てのキャラに対して処理
const members = [...$gameTroop.aliveMembers(), ...$gameParty.aliveMembers()];
members.forEach(subject => {
// 行動予測の開始
startPrediction(subject);
});
};
//- 行動入力時に先行アクションを適用(TPB)(コア追加)
const _Game_Battler_startTpbTurn = Game_Battler.prototype.startTpbTurn;
Game_Battler.prototype.startTpbTurn = function() {
// 先行アクションしていたら
if (this._actionMakedFastKe) {
// フラグオフ
this._actionMakedFastKe = false;
// 使用できないアクションは不発にさせる
const preActionNum = this._actions.filter(action => action.item()).length;
this._actions = this._actions.filter(action => action.isValid());
// 不発エフェクト
if (preActionNum >= 1 && this._actions.length < preActionNum) {
misfireEffect(this);
}
// 行動作成済みフラグをオン
this._isActionMakedKe = true;
}
_Game_Battler_startTpbTurn.apply(this);
// 行動作成済みフラグをオフ
this._isActionMakedKe = false;
// 先行ターゲットを消去
targetFast = null;
// 被キャンセルフラグをオフ
this._isCanceledKe = true;
};
//- 不発エフェクト
function misfireEffect(battler) {
// エフェクトの実行
doEffect(keke_actMisfireEffect, battler);
//不発ポップアップ
misfirePopup(battler);
};
//- 不発ポップアップ
function misfirePopup(battler) {
if (!PluginManager._scripts.some(n => n == "Keke_StatePopup")) { return; }
// 不発ポップの表示
battler.showMisfirePopKeStpp();
};
//- 行動作成時、行動作成済みなら作成スキップしてそれを採用(コア追加)
const _Game_Battler_makeActions = Game_Battler.prototype.makeActions;
Game_Battler.prototype.makeActions = function() {
if (this._isActionMakedKe) { return; }
_Game_Battler_makeActions.apply(this);
};
const _Game_Battler_numActions = Game_Battler.prototype.numActions;
Game_Battler.prototype.numActions = function() {
if (this._isActionMakedKe) { return 0; }
return _Game_Battler_numActions.apply(this);
};
//- 先行アクション済みのキャラをチャージ完了まで行動させない
/*const _BattleManager_getNextSubject = BattleManager.getNextSubject;
BattleManager.getNextSubject = function() {
const battler = this._actionBattlers[0];
if (battler && battler._actionMakedFastKe) {
this._actionBattlers.shift();
return null;
}
return _BattleManager_getNextSubject.apply(this);
};*/
//- 行動予約の消去
function delPrediction(subject) {
// アクションを消去
subject._actions = [];
// 先行アクションフラグをオフ
subject._actionMakedFastKe = false;
// 行動作成済みフラグをオフ
subject._isActionMakedKe = false;
// 先行ターゲットの消去
delTargetFast(subject);
};
//- 行動予測時はTPBターン初期値を 1 に(コア追加)
const _Game_Battler_initTpbTurn = Game_Battler.prototype.initTpbTurn;
Game_Battler.prototype.initTpbTurn = function() {
_Game_Battler_initTpbTurn.apply(this);
this._tpbTurnCount = 1;
};
//==================================================
//-- 行動の再決定
//==================================================
//- 再決定の処理
function processRedo(subject, targets, action) {
// ターゲットの重複を削除、敵キャラのみに限定
targets = Array.from(new Set(targets)).filter(target => target._enemyId);
// 行動再決定
if (getPredictionCfg(subject, "行動再決定", "", action)) {
// 行動再決定を予約
redoReserve = { targets:getRedoTarget(targets), type:"act" };
return;
}
// ターゲット再決定
if (getPredictionCfg(subject, "ターゲット再決定", "", action)) {
// ターゲット再決定を予約
redoReserve = { targets:getRedoTarget(targets), type:"target" };
return;
}
};
//- 再決定ターゲットの取得
function getRedoTarget(targets) {
// ターゲットの敵キャラが入っていたらそのまま返す
if (targets.length && targets.some(battler => battler._enemyId)) {
return targets;
}
// そうでなければ敵キャラ全てを返す
return $gameTroop.aliveMembers();
};
//- 再決定の実行
function executeRedo() {
if (!redoReserve) { return; }
const targets = redoReserve.targets;
if (!targets || !targets.length) { return; }
// 行動再決定の実行
if (redoReserve.type == "act") {
targets.forEach(target => {
// 行動の先行作成
makeActionFast(target, true);
// ターゲットの先行作成
makeTargetFast(target, true);
});
// ターゲット再決定の実行
} else {
targets.forEach(target => {
// ターゲットの先行作成
makeTargetFast(target, true);
});
}
// 予約を消去
redoReserve = null;
};
//==================================================
//-- 行動ビューウインドウ
//==================================================
//- 行動ビューウインドウ
function Window_ActViewKe() {
this.initialize(...arguments);
}
Window_ActViewKe.prototype = Object.create(Window_Base.prototype);
Window_ActViewKe.prototype.constructor = Window_ActViewKe;
//- 初期化(コア追加)
Window_ActViewKe.prototype.initialize = function(rect) {
Window_Base.prototype.initialize.call(this, rect);
this.frameVisible = false;
this._backSprite.visible = false;
};
//- 独自背景スプライトを形成(コア追加)
Window_ActViewKe.prototype._createBackSprite = function() {
Window_Base.prototype._createBackSprite.call(this);
// スプライト形成 & チルド
this._backSpriteKe = new SpriteKePrds();
this._container.addChild(this._backSpriteKe);
};
//- 背景の描画
Window_ActViewKe.prototype.drawBackKe = function(width, height, color) {
// 背景を描画
const bitmap = new Bitmap(this._width, this._height);
const padding = this._padding;
/*const backW = this._width// - padding * 2;
const backH = this._height// - padding * 2;*/
bitmap.fillRect(padding, padding, width, height, color);
// ビットマップを挿入
const backSprite = this._backSpriteKe;
if (backSprite.bitmap) { backSprite.bitmap.destroy(); }
backSprite.bitmap = bitmap;
};
//- フォント基本設定(コア追加)
Window_ActViewKe.prototype.resetFontSettings = function() {
const contents = this.contents;
contents.fontFace = keke_actFontFace || $gameSystem.mainFontFace();
contents.fontSize = keke_actFontSize;
this.changeTextColor(isCasting(this._battlerKe) ? keke_actFontColorCast : keke_actFontColor);
this.changeOutlineColor(ColorManager.outlineColor());
contents.outlineWidth = keke_actOutW;
};
//- テキストの高さの計算(コア追加)
Window_ActViewKe.prototype.calcTextHeight = function(textState) {
const lastFontSize = this.contents.fontSize;
const lines = textState.text.slice(textState.index).split("\n");
const textHeight = this.maxFontSizeInLine(lines[0]) + keke_actLineSpace;
this.contents.fontSize = lastFontSize;
return textHeight;
};
//- テキストステート作成処理(コア追加)
Window_ActViewKe.prototype.createTextState = function(text, x, y, width) {
const textState = Window_Base.prototype.createTextState.call(this, text, x, y, width);
// テキストステートを保存
this._textState = textState;
// 各行のフレームを記録する変数を作成
textState.lineFrames = [];
// 1行目のフレームを保存
textState.lineFrames.push(this.getLineFrame(textState));
return textState;
};
//- 行替えの処理(コア追加)
Window_ActViewKe.prototype.processNewLine = function(textState) {
Window_Base.prototype.processNewLine.call(this, textState);
// 新しい行のフレームを保存
textState.lineFrames.push(this.getLineFrame(textState));
};
//- テキスト書き出しの処理(コア追加)
Window_ActViewKe.prototype.flushTextState = function(textState) {
const preOutputHeight = textState.outputHeight;
// テキスト横幅を取得
const text = textState.buffer;
const fontSize = this.contents.fontSize;
const fontSizeRate = getFontSizeRate(this.contents.fontFace);
const textW = Math.max(strWidth(text, fontSize, fontSizeRate));
Window_Base.prototype.flushTextState.call(this, textState);
// 行フレームの横幅を更新
const lineFrames = textState.lineFrames;
lineFrames[lineFrames.length - 1].width += textW;
// 書き出しがなかったらアウトプットヘイトの更新を無効
if (!text) {
textState.outputHeight = preOutputHeight;
}
};
//- 行フレームの取得
Window_ActViewKe.prototype.getLineFrame = function(textState) {
const x = textState.x;
const y = textState.y;
const width = 0;
const height = textState.height;
const heightEx = textState.height - keke_actLineSpace;
const text = textState.text.slice(textState.index);
// 行頭か判定(改行文字による行でないか)
let isTop = false;
if (text.match(/^topke/)) {
isTop = true;
textState.index += 5;
}
return { x:x, y:y, width:width, height:height, heightEx:heightEx, isTop:isTop };
};
//==================================================
//-- 行動ビュー
//==================================================
//- スプライトバトラー/更新(コア追加)
const _Sprite_Battler_update = Sprite_Battler.prototype.update;
Sprite_Battler.prototype.update = function() {
_Sprite_Battler_update.apply(this);
// 行動ビューの更新
updateActView(this, this._battler);
};
//- 行動ビューの更新
function updateActView(battlerSprite, battler) {
if (!battler) { return; }
if (BattleManager._phase == "start" && !$gameTroop.isEventRunning()) { return; }
// 行動ビューリフレッシュの更新
updateActViewRefresh(battler);
// 行動ビュースプライトを更新
const actWindow = battlerSprite._actWindowKe;
if (actWindow) {
// 行動ビューの可視更新
updateViewVisibleAct(actWindow, battler);
}
};
//- 行動ビューリフレッシュの更新
function updateActViewRefresh(subject) {
if (!subject._refreshsActViewKe) { return; }
const asi = getFullAnimeStatusAsi(subject);
const faceSprite = asi ? asi.faceBaseSprite : null;
if (faceSprite) {
if (asi.startNear) { return; }
// 行動ビューのリフレッシュ
refreshActView(subject);
} else {
const subjectSprite = searchSpriteBattler(subject);
if (!subjectSprite || !subjectSprite._frame.width) { return;}
// 行動ビューのリフレッシュ
refreshActView(subject, subjectSprite);
}
};
//- 行動ビューのリフレッシュ
function refreshActView(battler, battlerSprite) {
battlerSprite = battlerSprite || searchSpriteBattler(battler);
if (!battlerSprite) { return; }
const actions = battler._actions.filter(action => action && action.item());
const skillNames = actions.map(action => getSkillName(action)).filter(a => a);
// 行動テキストの作成
const text = makeActText(skillNames);
// 行動ビューの形成
createActView(battlerSprite, battler, actions.length, text);
const actWindow = battlerSprite._actWindowKe;
// テキストを描画
const outW = keke_actOutW;
actWindow.drawTextEx(text, outW / 2, outW / 2, Graphics.width);
// 描画したテキストステートからフレームを取得
const textState = actWindow._textState;
const frames = textState.lineFrames;
// 行動アイコンの作成
const iconW = makeActIcon(actWindow, battler, actions, frames);
// 行動ビューの可視更新
updateViewVisibleAct(actWindow, battler);
// メモ欄からの位置設定を取得
actWindow._memoXKe = getPredictionCfg(battler, "ずらしX", "", actions[0]) || 0;
actWindow._memoYKe = getPredictionCfg(battler, "ずらしY", "", actions[0]) || 0;
actWindow._showDireKe = getPredictionCfg(battler, "表示方向", "", actions[0]);
// 最大横幅を保存
let widthMax = null;
frames.forEach(frame => {
// アイコン幅をフレームに保存
frame.iconW = iconW;
if (widthMax == null || frame.width > widthMax) {
widthMax = frame.width;
}
});
// 背景の描画
actWindow.drawBackKe(widthMax + keke_actOutW, textState.outputHeight + keke_actOutW, keke_actBackColor);
if (widthMax != null) { actWindow._widthKe = widthMax; }
// 行動ビューの位置更新
updateViewPosAct(actWindow, battlerSprite, battler);
// フレームを保存
battlerSprite._actFramesKe = frames;
// リフレッシュフラグをオフ
battler._refreshsActViewKe = null;
};
//- スキル名の取得
function getSkillName(action) {
const item = action.item();
// スキル名を取得
const skillName = item.name;
// メモ欄から表示名を取得
const showName = getPredictionCfg(null, "テキスト", "", action);
return showName || skillName;
};
//- 行動テキストの作成
function makeActText(skillNames) {
let text = "";
skillNames.forEach(name => {
name = name.replace(/\\n/g, "\n");
text += "topke" + name +"\n";
});
return text;
};
//- 行動ビューの形成
function createActView(battlerSprite, battler, actionNum, text) {
const preSprite = battlerSprite._actWindowKe;
if (preSprite && preSprite._actionNum == actionNum) { return; }
// 前のがあったら破棄
if (preSprite) {
destroyActView(preSprite);
}
// 仮ウインドウを作成
const tempWindow = new Window_ActViewKe({ x:0, y:0, width:Graphics.width, height:Graphics.height });
// テキストのサイズを取得
const outW = keke_actOutW;
const sizes = tempWindow.textSizeEx(text, 0, 0, Graphics.width);
sizes.width += outW;
sizes.height += outW;
// ウインドウ形成
const padding = tempWindow._padding;
const windowWidth = keke_actW + padding * 2;
const windowHeight = sizes.height + padding * 2;
const windo = new Window_ActViewKe({ x:0, y:0, width:windowWidth, height:windowHeight });
tempWindow.destroy();
// チルド
const scene = SceneManager._scene;
const layerId = keke_actLayer == "ウインドウより上" ? "D" : "B";
childLayer(windo, layerId);
// 原点
const pos = battler._enemyId ? keke_actPosEnemy : keke_actPosActor;
// 変数セット
battlerSprite._actWindowKe = windo;
// スプライトにサイズを保存
windo._widthKe = sizes.width;
windo._heightKe = sizes.height + keke_actLineSpace;
// ウインドウを中心に配置するために位置補正
windo._centerXKe = -windo._width / 2 - windo._padding + (windowWidth - sizes.width) / 2;
windo._centerYKe = -windo._height + windo._padding
// バトラーを保存
windo._battlerKe = battler;
// アクション数を保存
windo._actionNumKe = actionNum;
// 表示方向を保存
windo._direKe = pos["表示方向"];
};
//- 行動アイコンの作成
function makeActIcon(actWindow, battler, actions, frames) {
if (!keke_actShowIcon) { return; }
let iconWMax = 0;
// 全てのアクションに対して処理
actions.forEach((action, i) => {
// アイコンデータの取得
const iconData = getIconData(action);
// 行フレームの取得
const frame = getLineFrame(frames, i);
// アイコンスプライトの形成
const iconSprite = createIconSprite(iconData.index);
// サイズを設定
const iconW = frame.height * iconData.size;
iconSprite.scale.x = iconW / ImageManager.iconWidth;
iconSprite.scale.y = iconW / ImageManager.iconHeight;
iconWMax = Math.max(iconW, iconWMax) + keke_actIconSpace;
// 位置を設定
const padding = actWindow._padding;
iconSprite.x = padding - iconW / 2 - keke_actIconSpace;
iconSprite.y = padding + frame.y + frame.height / 2;
// レイヤーチルド
actWindow.addChild(iconSprite);
// 変数セット
if (!actWindow._iconSpritesKe) { actWindow._iconSpritesKe = []; }
actWindow._iconSpritesKe.push(iconSprite);
// 烈の中心をアイコン分だけ左にずらす
frame.x -= iconWMax / 2;
});
// 行動ビューをアイコンの分、右にずらす
actWindow._iconXKe = iconWMax / 2;
return iconWMax;
};
//- 行フレームの取得
function getLineFrame(frames, tage_i) {
let i = -1;
let true_i = 0;
for (const frame of frames) {
i++;
if (!frame.isTop) { continue; }
if (true_i == tage_i) { break; }
true_i++;
};
return frames;
};
//- アイコンデータの取得
function getIconData(action) {
const item = action.item();
// スキルのアイコンを取得
const iconIndex = item.iconIndex;
// メモ欄から表示アイコンを取得
const d = getPredictionCfg(null, "アイコン", "", action) || {};
return { index:d.index || iconIndex, size:(d.size || keke_actIconSize) / 100 };
};
//- 行動ビューの位置更新
function updateViewPosAct(sprite, battlerSprite, battler) {
const pos = battler._enemyId ? keke_actPosEnemy : keke_actPosActor;
const dire = sprite._showDireKe || pos["表示方向"];
const asi = getFullAnimeStatusAsi(battler);
// フルアニメ
if (asi && asi.visible) {
const frame = asi.frame;
const faceFrame = asi.faceFrame;
sprite.x = frame.x;
sprite.y = frame.y;
if (faceFrame.width) {
const direX = dire == "左" ? -faceFrame.width / 2 : dire == "右" ? faceFrame.width / 2 : 0;
const direY = dire == "上" ? -faceFrame.height / 2 : dire == "下" ? faceFrame.height / 2 : 0;
sprite.x += faceFrame.x + direX;
sprite.y += faceFrame.y + direY;
} else {
const direX = dire == "左" ? -frame.width / 2 : dire == "右" ? frame.width / 2 : 0;
const direY = dire == "上" ? -frame.height / 2 : dire == "下" ? frame.height / 2 : 0;
sprite.y += direY;
sprite.x += direX;
}
// 通常
} else {
const frame = battlerSprite._frame;
const battlerW = frame.width * battlerSprite.scale.x;
const battlerH = frame.height * battlerSprite.scale.y;
const direX = dire == "左" ? -battlerW / 2 : dire == "右" ? battlerW / 2 : 0;
const direY = dire == "下" ? 0 : dire == "中央" ? -battlerH / 2 : -battlerH * 1.1;
sprite.x = battlerSprite._homeX + direX;
sprite.y = battlerSprite._homeY + direY;
}
// 共通の位置
sprite.x += (pos["ずらしX"] || 0) + (sprite._iconXKe || 0) + sprite._memoXKe + sprite._centerXKe;
sprite.y += (pos["ずらしY"] || 0) + sprite._memoYKe + sprite._centerYKe;
// 鋼体ビューがあるなら上にずらす
/*if (existSteelView(battlerSprite, dire)) {
sprite.y -= battlerSprite._steelSpriteKe._heightKe || 0;
}*/
// 行動ビューとの合計高さを取得
const isSteelView = existSteelView(battlerSprite, dire);
const steelH = isSteelView ? battlerSprite._steelSpriteKe._heightKe : 0;
// 画面外に出さない
noOutScreen(sprite, sprite._widthKe, sprite._widthKe, sprite._padding, steelH);
};
//- 鋼体ビューがあるか
function existSteelView(battlerSprite, dire) {
const steelSprite = battlerSprite._steelSpriteKe;
if (!steelSprite) { return false; }
if (steelSprite._direKe != dire) { return false;}
return true;
};
//- 画面外に出さない
function noOutScreen(sprite, width, height, padding, upPlus) {
// 非表示範囲を取得
noShowScope = keke_actNoShowScope || {};
// 上下左右の端の位置を取得
const leftEdge = sprite.x + padding;
const rightEdge = sprite.x + width - padding;
const upEdge = sprite.y + padding - upPlus;
const downEdge = sprite.y + height - padding;
// 上下左右の超過分を取得
const leftOver = leftEdge - (noShowScope["左"] || 0);
const rightOver = rightEdge - (Graphics.width - (noShowScope["右"] || 0));
const upOver = upEdge - (noShowScope["上"] || 0);
const downOver = downEdge - (Graphics.height - (noShowScope["下"] || 0));
// 超過分だけ位置をずらす
if (leftOver < 0) {
sprite.x -= leftOver;
} else if (rightOver > 0) {
sprite.x -= rightOver;
}
if (upOver < 0) {
sprite.y -= upOver;
} else if (downOver > 0) {
sprite.y -= downOver;
}
};
//- 行動ビューの破棄
function destroyActView(actWindow) {
actWindow.destroy();
const iconSprites = actWindow._iconSpritesKe;
if (iconSprites && iconSprites.length) {
iconSprites.forEach(sprite => sprite.destroy());
}
actWindow._iconSpritesKe = [];
};
//- 行動ビューの可視更新
function updateViewVisibleAct(sprite, battler) {
if (isVisibleAct(battler)) {
sprite.visible = true;
} else {
sprite.visible = false;
}
};
//- 見えるか-行動
function isVisibleAct(battler) {
if (BattleManager._phase == "battleEnd") { return false;}
if (!isActShow() || !isValidPrediction(battler)) { return false; }
if (isActing(battler) || battler.isRestricted()) { return false; }
if (keke_actOnlyInput && !BattleManager.isInputting()) { return false; }
if (battler._actorId) {
let valid = false;
if (keke_actShowCastActor && isCasting(battler)) { valid = true; }
if (keke_actShowAutoActor && isAutoBattle(battler)) { valid = true; }
if (!valid) { return false; }
}
return true;
};
//- 行動中か
function isActing(battler) {
return battler.isActing() || isActingSpeedStar(battler);
};
//- 行動中か(スピードスター)
function isActingSpeedStar(battler) {
const isSpeedStar = PluginManager._scripts.some(n => n == "Keke_SpeedStarBattle");
const subject = BattleManager._action ? BattleManager._action.subject() : null;
return isSpeedStar && BattleManager._battleWaitKe && subject && subject == battler;
};
//- 詠唱中か
function isCasting(battler, isStart) {
if (!battler) { return false; }
const state = battler._tpbState;
const isActive = battler.isAlive() && !battler.isRestricted() && BattleManager._phase != "battleEnd";
return state.match(/casting/) && isActive && (isStart ? true : battler._tpbCastTime);
};
//- 自動戦闘中か
function isAutoBattle(battler) {
if (!battler) { return false; }
return battler.isAutoBattle();
};
//==================================================
//-- ターゲット予測
//==================================================
// 先行ターゲット
let targetFast = null;
//- ターゲットの先行作成
function makeTargetFast(subject, redo) {
// 対象は敵キャラのみ
if (subject._actorId) { return; }
// アクションを取得
const actions = subject._actions;
if (!actions.length) { return; }
// ターゲットを作成
let targets = [];
let targetsForLine = [];
actions.forEach((action, i) => {
// 再決定時は強制ターゲットを消去
if (redo) { action._targetIndex = -1; }
// アクションのターゲットを取得
const t = getActionTargets(action);
if (t.list) { targets = t.list; }
if (t.listForLine) { targetsForLine = t.listForLine; }
});
// ターゲットを保存
if (targets.length) {
subject._targetsFastKe = { lists:targets, listsForLine:targetsForLine };
// ターゲットラインのリフレッシュ
refreshTargetLine(subject);
}
};
//- アクションのターゲットを取得
function getActionTargets(action) {
if (!action.item()) { return {}; }
// ターゲットの作成
const tages = action.makeTargets();
if (!tages.length) { return {}; }
// 実際のターゲット用
let list = tages.map(target => battlerToId(target));
// ターゲットライン用
let listForLine = [];
// 対全体か
const isAll = isForAllAction(action);
// 全体ワードの時は全体ワードフラグを挿入
if (isAll && keke_lineWordIfAll) {
listForLine.push({ isAll:true, isAllWord:true });
// それ以外はターゲットが重複しないように挿入
} else {
const line = [];
tages.forEach(target => {
if (!line.includes(target)) { line.push(target); }
});
listForLine = line.map(target => battlerToId(target));
listForLine[0].isAll = isAll;
}
return { list:list, listForLine:listForLine };
};
//- 対全体アクションか
function isForAllAction(action) {
if (!action || !action.item()) { return false; }
return action.isForAll() || action.isForEveryone();
};
//- 先行ターゲットの適用
function applyTargetFast(subject) {
if (!subject._targetsFastKe || !subject._targetsFastKe.lists.length) { return; }
// ターゲットラインの消去
delTargetLine(subject);
// 先行ターゲットリストを取得
const targets = subject._targetsFastKe.lists.shift();
if (!targets || !targets.length) { return; }
// 先行ターゲットをセット
targetFast = targets.map(id => idToBattler(id)).filter(target => target.isAlive());
};
//- 先行ターゲット済みならそれを適用(コア追加)
const _Game_Action_makeTargets = Game_Action.prototype.makeTargets;
Game_Action.prototype.makeTargets = function() {
if (targetFast) { return targetFast; }
return _Game_Action_makeTargets.apply(this);
};
//- アクション消去時に先行ターゲットも消去(コア追加)
const _Game_Battler_removeCurrentAction = Game_Battler.prototype.removeCurrentAction;
Game_Battler.prototype.removeCurrentAction = function() {
_Game_Battler_removeCurrentAction.apply(this);
targetFast = null;
};
//- 先行ターゲットの消去
function delTargetFast(subject) {
if (subject._actorId) { return; }
if (!subject._targetsFastKe || !subject._targetsFastKe.lists.length) { return; }
subject._targetsFastKe = null;
// ターゲットラインの消去
delTargetLine(subject);
};
//- 先行ターゲットの消去-全員
function delTargetFastAll() {
$gameTroop.members().forEach(subject => {
// 先行ターゲットの消去
delTargetFast(subject);
});
};
//==================================================
//-- ターゲットの再決定
//==================================================
//- 被ターゲットが戦闘不能になったらターゲットの修正(コア追加)
const _Game_Battler_die = Game_Battler.prototype.die;
Game_Battler.prototype.die = function() {
_Game_Battler_die.apply(this);
// 個別ターゲットの修正
setTimeout(restoreEachTarget, 0, this);
// 全体ターゲットの修正
setTimeout(restoreAllTarget, 0, this);
};
//- 被ターゲット側が復活したら全体ターゲットの修正(コア追加)
const _Game_Battler_revive = Game_Battler.prototype.revive;
Game_Battler.prototype.revive = function() {
_Game_Battler_revive.apply(this);
// 全体ターゲットの修正
setTimeout(restoreAllTarget, 0, this);
};
//- メンバーが加わった時に全体ターゲットの修正(コア追加)
const _Game_Party_addActor = Game_Party.prototype.addActor;
Game_Party.prototype.addActor = function(actorId) {
_Game_Party_addActor.apply(this, arguments);
if (inBattle()) {
// 加わったアクターを取得
const actor = $gameParty.members().find(a => a._actorId == actorId);
if (actor) {
// 全体ターゲットの修正
setTimeout(restoreAllTarget, 300, actor);
}
}
};
//- メンバーが外れた時にターゲットの修正(コア追加)
const _Game_Party_removeActor = Game_Party.prototype.removeActor;
Game_Party.prototype.removeActor = function(actorId) {
// 外れたアクターを取得
let actor = null;
if (inBattle()) {
actor = $gameParty.members().find(a => a._actorId == actorId);
}
_Game_Party_removeActor.apply(this, arguments);
if (actor) {
// 個別ターゲットの修正
setTimeout(restoreEachTarget, 300, actor);
// 全体ターゲットの修正
setTimeout(restoreAllTarget, 300, actor);
}
};
//- 戦闘中か
function inBattle() {
// 戦闘中以外はリターン
if (!$gameParty.inBattle) { return false; }
// 戦闘開始時はリターン
if (!BattleManager._phase || BattleManager._phase == "start") { return false; }
return true;
};
//- 個別ターゲットの修正
function restoreEachTarget(delTarget) {
if (!delTarget) { return; }
// 全ての敵キャラに対して処理
$gameTroop.aliveMembers().forEach(subject => {
const targets = subject._targetsFastKe;
if (!targets || !targets.listsForLine.length) { return; }
// 全ての行動に対して判定
targets.listsForLine.forEach((tages, i) => {
// 対全体はリターン
if (tages[0].isAll) { return; }
// 消去ターゲットがターゲットに含まれてなければリターン
if (!tages.some(target => idToBattler(target) == delTarget)) { return; }
// アクションを取得
const action = subject._actions;
if (!action) { return; }
// アクションのターゲットを取得
const t = getActionTargets(action);
// ターゲットを修正
if (t.list) { targets.lists = t.list; };
if (t.listForLine) { targets.listsForLine = t.listForLine; };
// ターゲットラインのリフレッシュ
refreshTargetLine(subject);
});
});
};
//- 全体ターゲットの修正
function restoreAllTarget(target) {
if (!target) { return; }
// 全ての敵キャラに対して処理
$gameTroop.aliveMembers().forEach(subject => {
const targets = subject._targetsFastKe;
if (!targets || !targets.listsForLine.length) { return; }
// 全ての行動に対して判定
targets.listsForLine.forEach((tages, i) => {
// 対全体以外はリターン
if (!tages[0].isAll) { return; }
// アクションを取得
const action = subject._actions;
if (!action) { return; }
// アクションのターゲットを取得
const t = getActionTargets(action);
// ターゲットを修正
if (t.list) { targets.lists = t.list; };
if (t.listForLine) { targets.listsForLine = t.listForLine; };
// ターゲットラインのリフレッシュ
refreshTargetLine(subject);
});
});
};
//- 先行ターゲットの更新判定
/*function judgeTargetFastUpdate(target) {
// 全ての敵キャラに対して処理
$gameTroop.aliveMembers().forEach(subject => {
const targets = subject._targetsFastKe;
if (!targets || !targets.lists.length) { return; }
// ターゲットに戦闘不能になったキャラが含まれているか判定
if (targets.lists.some(list => list.some(id => idToBattler(id) == target))) {
// 含まれていたらターゲットの先行作成
makeTargetFast(subject);
}
});
};*/
//- 先行ターゲットの更新判定-全体
/*function judgeTargetFastUpdateForAll(target) {
// 全ての敵キャラに対して処理
$gameTroop.aliveMembers().forEach(subject => {
const targets = subject._targetsFastKe;
if (!targets || !targets.lists.length) { return; }
// 全体攻撃か判定
if (!targets.isAll) { return; }
// 全体攻撃ならターゲットの先行作成
makeTargetFast(subject);
});
};*/
//==================================================
//-- ターゲットライン
//==================================================
//- ターゲットラインのリフレッシュ
function refreshTargetLine(subject) {
subject._makesTargetLineKe = true;
};
//- ターゲットラインのリフレッシュ-全員
function refreshTargetLineAll() {
$gameTroop.members().forEach(subject => {
subject._makesTargetLineKe = true;
});
};
//- ステータスウインドウが移動したらターゲットラインをリフレッシュ
const _Scene_Battle_updateStatusWindowPosition = Scene_Battle.prototype.updateStatusWindowPosition;
Scene_Battle.prototype.updateStatusWindowPosition = function() {
const statusWindow = this._statusWindow;
const targetX = this.statusWindowX();
const preSame = statusWindow.x == targetX;
_Scene_Battle_updateStatusWindowPosition.apply(this);
if (statusWindow.visible) {
const same = statusWindow.x == targetX;;
if (!preSame && same) {
// ターゲットラインのリフレッシュ-全員
refreshTargetLineAll();
}
}
};
//- アクター移動終了時にターゲットラインをリフレッシュ
const _Sprite_Actor_onMoveEnd = Sprite_Actor.prototype.onMoveEnd;
Sprite_Actor.prototype.onMoveEnd = function() {
_Sprite_Actor_onMoveEnd.apply(this);
// ターゲットラインのリフレッシュ-全員
refreshTargetLineAll();
};
//- ターゲットラインの更新
function updateTargetLine(sprite) {
if (BattleManager._phase == "start" && !$gameTroop.isEventRunning()) { return; }
const subject = sprite._battler;
// ターゲットライン作成の更新
updateTargetLineMake(subject);
// ターゲットライン明滅の更新
updataTargetLineFlicker(subject, sprite);
// ターゲットラインの可視更新
updateTargetLineVisible(subject, sprite);
};
//- ターゲットライン作成の更新
function updateTargetLineMake(subject) {
if (!subject._makesTargetLineKe) { return; }
const asi = getFullAnimeStatusAsi(subject);
const faceSprite = asi ? asi.faceBaseSprite : null;
if (faceSprite) {
if (asi.startNear) { return; }
// ターゲットラインの作成
makeTargetLine(subject);
} else {
const subjectSprite = searchSpriteBattler(subject);
if (!subjectSprite || !subjectSprite._frame.width) { return;}
// ターゲットラインの作成
makeTargetLine(subject);
}
};
//- ターゲットラインの作成
function makeTargetLine(subject) {
// ターゲットラインの消去
delTargetLine(subject);
// アクションがない場合はリターン
if (!subject._actions.filter(action => action.item()).length) {
subject._makesTargetLineKe = null;
return;
}
const targets = subject._targetsFastKe;
if (!targets || !targets.listsForLine.length) { return; }
// 全てのターゲットに対して処理
targets.listsForLine.forEach((tages, i) => {
tages.forEach(targetId => {
if (!targetId) { return; }
// 全体ワードの作成
if (targetId.isAllWord) {
makeAllWord(subject, i);
// ワイヤーの形成
} else {
const target = idToBattler(targetId);
createWire(subject, target, i);
}
})
});
// 作成開始フラグをオフ
subject._makesTargetLineKe = null;
// ターゲットラインのリチルド
rechildTargetLine();
};
//- 全体ワードの作成
function makeAllWord(subject, i) {
subjectSprite = searchSpriteBattler(subject);
const allCfg = keke_allWordCfg;
//if (!subjectSprite) { return }
// 全体ワードの形成
const allSprite = createAllWord(subjectSprite, subject, i);
// ワードの描画
const cfg = {};
cfg.word = allCfg["ワード"];
cfg.fontFace = allCfg["フォント"];
cfg.fontSize = allCfg["文字サイズ"] || keke_actFontSize;
cfg.fontSizeRate = getFontSizeRate(cfg.fontFace);
cfg.fontColor = allCfg["文字色"] || keke_lineColorList[subject.index() % 8] || "rgba(255, 255, 255)";
cfg.outW = allCfg["縁取り幅"] || keke_actOutW;
const frame = drawWard(allSprite, subject, cfg);
// ライン始点の取得
const point = getLineStart(subject, subjectSprite, i, frame);
// 位置をセット
allSprite.x = point.x + (allCfg["ずらしX"] || 0);
allSprite.y = point.y + (allCfg["ずらしY"] || 0);
};
//- 全体ワードの形成
function createAllWord(subjectSprite, subject, i) {
const allCfg = keke_allWordCfg;
// サイズを取得
const outW = allCfg["縁取り幅"] || keke_actOutW;
const width = keke_actW + outW;
const height = keke_actFontSize + outW;
// スプライト & ビットマップ形成
const bitmap = new Bitmap(width, height);
const sprite = new SpriteKePrds(bitmap);
// チルド
const layerId = keke_actLayer == "ウインドウより上" ? "D" : "B";
childLayer(sprite, layerId);
// 原点
sprite.anchor.x = 0.5;
sprite.anchor.y = 0.5;
// 変数セット
if (!subjectSprite._targetLinesKe) { subjectSprite._targetLinesKe = { list:[] }; }
subjectSprite._targetLinesKe.list.push(sprite);
// スプライトにサイズを保存
sprite._widthKe = width;
sprite._heightKe = height;
// 表示方向を保存
const pos = subject._enemyId ? keke_actPosEnemy : keke_actPosActor;
sprite._direKe = pos["表示方向"];
// 全体ワードフラグをセット
sprite._isAllWordKe = true;
return sprite;
};
//- ワードの描画
function drawWard(sprite, subject, cfg) {
const fontSize = cfg.fontSize;
const word = cfg.word;
const outW = cfg.outW;
// フォント設定
const bitmap = sprite.bitmap;
bitmap.fontFace = cfg.fontFace || $gameSystem.mainFontFace();;
bitmap.fontSize = fontSize;
bitmap.textColor = cfg.fontColor;
bitmap.outlineWidth = cfg.outW;
// サイズを取得
const width = strWidth(word, fontSize, cfg.fontSizeRate);
const height = fontSize + outW;
// 描画
bitmap.drawText(word, 0, 0, bitmap.width, height, "center");
// フレームを保存
const frame = { x:0, y:0, width:width, height:height, outW:outW }
return frame;
};
//- ワイヤーの形成
function createWire(subject, target, i) {
// バトラースプライト取得
const subjectSprite = searchSpriteBattler(subject);
if (!subjectSprite) { return; }
const targetSprite = searchSpriteBattler(target);
if (!isFrontViewActor(target) && !targetSprite ) { return; }
// ライン始点の取得
const subjectPoint = getLineStart(subject, subjectSprite, i);
// ワイヤー始点Yの補正
subjectPoint.y += keke_lineW / 2 + keke_lineOutW;
// ライン終点の取得
const targetPoint = getLineEnd(target, targetSprite);
// 受容ラインの選択
const receptIndex = saveReceptLine(target, subject);
// ワイヤーの描画
const wireBitmap = new Bitmap(Graphics.width, Graphics.height);
const wireSprite = new SpriteKePrds(wireBitmap);
drawWire(subject, target, wireBitmap, subjectPoint.x, subjectPoint.y, targetPoint.x, targetPoint.y, receptIndex);
wireSprite._isWireKe = true;
// 矢印の描画
const arrowBitmap = new Bitmap(Graphics.width, Graphics.height);
const arrowSprite = new SpriteKePrds(arrowBitmap);
drawWire(subject, target, arrowBitmap, subjectPoint.x, subjectPoint.y, targetPoint.x, targetPoint.y, receptIndex, true);
arrowSprite._isArrowKe = true;
// スプライト内にターゲットIDを保存
wireSprite._targetIdKe = battlerToId(target);
arrowSprite._targetIdKe = wireSprite._targetIdKe;
// チルド
const layerId = keke_actLayer == "ウインドウより上" ? "C" : "A";
childLayer(wireSprite, layerId);
childLayer(arrowSprite, layerId);
// 変数セット
if (!subjectSprite._targetLinesKe) { subjectSprite._targetLinesKe = { list:[] }; }
subjectSprite._targetLinesKe.list.push(wireSprite);
subjectSprite._targetLinesKe.list.push(arrowSprite);
// ワイヤーの長さを保存
const length = pointDistance(subjectPoint.x, subjectPoint.y, targetPoint.x, targetPoint.y);
const preLength = subjectSprite._targetLinesKe.length || 0;
subjectSprite._targetLinesKe.length = Math.max(length, preLength);
};
//- フロントビューアクターか
function isFrontViewActor(battler) {
return !$gameSystem.isSideView() && battler._actorId;
};
//- ライン始点の取得
function getLineStart(battler, battlerSprite, i, allData) {
// 行動ビューからのポイント取得
const point = getPointFromActView(battler, battlerSprite, i, allData);
if (point) { return point; }
// 取得できなければバトグラから始点を取得
const asi = getFullAnimeStatusAsi(battler);
const faceSprite = asi ? asi.faceBaseSprite : null;
const startCfg = keke_lineStart;
const dire = startCfg["始点-方向"];
const offsetX = startCfg["始点-ずらしX"] || 0;
const offsetY = startCfg["始点-ずらしY"] || 0;
// ラインポイントの取得
return getLinePoint(battler, battlerSprite, asi, faceSprite, dire, offsetX, offsetY);
};
//- 行動ビューからのポイント取得
function getPointFromActView(battler, battlerSprite, i, allData) {
// 行動ビュースプライトを取得
const actWindow = battlerSprite._actWindowKe;
if (!actWindow) { return; }
// 行動ビューのフレームを取得
const actFrames = battlerSprite._actFramesKe;
if (!actFrames || !actFrames.length) { return; }
const frame = getLineFrame(actFrames, i);
if (!frame) { return; }
// 始点の設定を取得
const startCfg = keke_lineStart;
const dire = startCfg["始点-方向"];
const offsetX = startCfg["始点-ずらしX"] || 0;
const offsetY = startCfg["始点-ずらしY"] || 0;
// ポイント位置を取得
const point = {};
const padding = actWindow._padding;
point.x = actWindow.x + padding + offsetX;
point.y = actWindow.y + padding + offsetY + frame.y + frame.height / 2;
const actOutW = keke_actOutW;
// 全体ワードの方向補正
if (allData) {
const outWs = actOutW + allData.outW;
point.x += dire == "左" ? -frame.iconW - allData.width / 2 - outWs : frame.width + allData.width / 2 + outWs;
// 画面外に出さない-全体ワード
noOutScreenAllWord(point, frame.width, allData.width, frame.iconW);
// 始点ポイントの方向補正
} else {
const startSize = keke_lineStartSize + actOutW;
point.x += dire == "左" ? -frame.iconW - startSize : dire == "右" ? frame.width + startSize : frame.width / 2;
point.y += dire == "上" ? -frame.height / 2 - startSize : dire == "下" ? frame.height / 2 + startSize : 0;
}
return point;
};
//- 画面外に出さない全体ワード
function noOutScreenAllWord(point, frameW, allW, iconW) {
// 非表示範囲を取得
noShowScope = keke_actNoShowScope || {};
// 左右の端の位置を取得
const leftEdge = point.x - allW / 2;
const rightEdge = point.x + allW / 2;
// 左右の超過分を取得
const leftOver = leftEdge - (noShowScope["左"] || 0);
const rightOver = rightEdge - (Graphics.width - (noShowScope["右"] || 0));
// 超過分だけ位置をずらす
if (leftOver < 0) {
sprite.x -= leftOver;
} else if (rightOver > 0) {
sprite.x -= rightOver;
}
// 左に超過したら右に移動
/*if (leftOver < 0) {
point.x += frameW + allW + iconW / 2;
}
// 右に超過したら右に移動
if (rightOver > 0) {
point.x -= frameW + allW + iconW / 2;
}*/
};
//- ライン終点の取得
function getLineEnd(battler, battlerSprite) {
const asi = getFullAnimeStatusAsi(battler);
const faceSprite = asi ? asi.faceBaseSprite : null;
const endCfg = keke_lineEnd;
const word = battler._actorId ? "(味方)" : "(敵)";
const dire = endCfg["終点-方向" + word];
const offsetX = endCfg["終点-ずらしX" + word] || 0;
const offsetY = endCfg["終点-ずらしY" + word] || 0;
// ラインポイントの取得
return getLinePoint(battler, battlerSprite, asi, faceSprite, dire, offsetX, offsetY);
};
//- ラインポイントの取得
function getLinePoint(battler, battlerSprite, asi, faceSprite, dire, offsetX, offsetY) {
const point = {}
let frame = null;
let x = 0;
let y = 0;
let inX = 0;
let inY = 0;
// 顔アイコンの位置情報
if (faceSprite) {
frame = asi.faceFrame;
x = asi.faceHomeX;
y = asi.faceHomeY;
// バトグラの位置情報
} else {
// フロントビュー時のアクターはステータス位置を取得
if (isFrontViewActor(battler)) {
const statusWindow = SceneManager._scene._statusWindow;
const i = $gameParty.allMembers().indexOf(battler);
frame = copyHash(statusWindow.faceRect(i));
frame.height = 0;
x = statusWindow.x + frame.x + frame.width / 2;
y = statusWindow.y + frame.y;
// その他はバトグラ位置
} else {
frame = copyHash(battlerSprite._frame);
frame.width *= battlerSprite.scale.x;
frame.height *= battlerSprite.scale.y;
x = battlerSprite.x;
y = battlerSprite.y - frame.height / 4;
// 原点による補正
inX += (0.5 - battlerSprite.anchor.x) * frame.width;
inY += (0.5 - battlerSprite.anchor.y) * frame.height;
}
}
// ポイントの位置
inX += dire == "左" ? -frame.width / 2 : dire == "右" ? frame.width / 2 : 0;
inY += dire == "上" ? -frame.height / 2 : dire == "下" ? frame.height / 2 : 0;
// 座標
point.x = x + inX + offsetX;
point.y = y + inY + offsetY;
// 画面外に出さない-ポイント
noOutScreenPoint(point);
return point;
};
//- 画面外に出さない-ポイント
function noOutScreenPoint(point) {
// 非表示範囲を取得
noShowScope = keke_actNoShowScope || {};
// 上下左右の限界位置を取得
const leftMax = noShowScope["左"] || 0;
const rightMax = Graphics.width - (noShowScope["右"] || 0);
const upMax = noShowScope["上"] || 0;
const downMax = Graphics.height - (noShowScope["下"] || 0);
// 限界位置を超えた分だけずらす
if (point.x < leftMax) { point.x += leftMax - point.x; } else
if (point.x > rightMax) { point.x += rightMax - point.x; }
if (point.y < upMax) { point.y += upMax - point.y; } else
if (point.y > downMax) { point.y += downMax - point.y; }
};
//- ポイント間の距離
function pointDistance(ax, ay, bx, by) {
return Math.sqrt(Math.pow(ax - bx, 2) + Math.pow(ay - by, 2));
};
//- ワイヤーの描画
function drawWire(subject, target, bitmap, ax, ay, bx, by, receptIndex, isArrow) {
const context = bitmap.context;
// 矢印の方向を取得
let dire = keke_lineDire;
// 敵キャラ同志をつなぐ場合は反転
if (target._enemyId) {
dire = dire == "左" ? "右" : dire == "右" ? "左" : dire == "上" ? "下" : "上";
}
const lineW = keke_lineW;
const ow = keke_lineOutW;
// ラインが複数ある時のずらしを取得
const pileOffset = keke_linePileOffset;
let offsetX = 0;
let offsetY = 0;
// 横ラインの時
if (dire.match(/左|右/)) {
offsetY = pileOffset * receptIndex;
// 縦ラインの時
} else {
offsetX = -pileOffset * receptIndex;
}
// アウトラインを描画
context.strokeStyle = "rgba(0, 0, 0)";
context.lineWidth = ow;
const radius = keke_lineStartSize || lineW;
context.beginPath();
context.arc(ax, ay, radius, 0, Math.PI * 2, false);
context.stroke();
context.lineWidth = lineW + ow * 2;
if (isArrow) { strokeArrow(context, ax, ay, bx, by, dire, offsetX, offsetY, lineW, ow, true); } else
{ strokeWire(context, ax, ay, bx, by, dire, offsetX, offsetY, lineW, ow, true); }
// 本線を描画
context.strokeStyle = keke_lineColorList[subject.index() % 8] || "rgba(255, 255, 255)";
context.fillStyle = context.strokeStyle;
context.beginPath();
context.arc(ax, ay, radius, 0, Math.PI * 2, false);
context.fill();
context.lineWidth = lineW;
if (isArrow) { strokeArrow(context, ax, ay, bx, by, dire, offsetX, offsetY, lineW, ow); } else
{ strokeWire(context, ax, ay, bx, by, dire, offsetX, offsetY, lineW, ow); }
// 終了
context.restore();
bitmap._baseTexture.update();
};
//- ワイヤーの線描画
function strokeWire(context, ax, ay, bx, by, dire, offsetX, offsetY, lineW, ow, isOutLine) {
const arrowW = keke_lineArrowSize + ow;
const minLength = keke_lineMinLength;
const xLength = Math.abs(bx - ax);
const yLength = Math.abs(by - ay);
const w = dire.match(/左|右/i) ? bx - ax : by - ay;
context.beginPath();
// 上
if (dire == "上") {
by += arrowW;
bx += offsetX;
if (ax == bx) { ax -= keke_linePileOffset; }
const middleY= by > ay || yLength < minLength ? by + minLength : ay + w * 0.5;
context.moveTo(ax, ay);
context.lineTo(bx, middleY);
// 下
} else if (dire == "下") {
by += -arrowW;
bx += offsetX;
if (ax == bx) { ax -= keke_linePileOffset; }
const middleY= by < ay || yLength < minLength ? by - minLength : ay + w * 0.5;
context.moveTo(ax, ay);
context.lineTo(bx, middleY);
// 左
} else if (dire == "左") {
bx += arrowW;
by += offsetY;
if (ay == by) { ay += keke_linePileOffset; }
const middleX= bx > ax || xLength < minLength ? bx + minLength : ax + w * 0.5;
context.moveTo(ax, ay);
context.lineTo(middleX, by);
// 右
} else if (dire == "右") {
bx += -arrowW;
by += offsetY;
if (ay == by) { ay += keke_linePileOffset; }
const middleX= bx < ax || xLength < minLength ? bx - minLength : ax + w * 0.5;
context.moveTo(ax, ay);
context.lineTo(middleX, by);
}
context.lineTo(bx, by);
context.stroke();
};
//- 矢印の線描画
function strokeArrow(context, ax, ay, bx, by, dire, offsetX, offsetY, lineW, ow, isOutLine) {
const arrowW = keke_lineArrowSize;
const middleW = Math.max((arrowW * 2 - lineW - ow * 2) / 2, 1);
const sharp = arrowW / 20;
context.beginPath();
// 上
if (dire == "上") {
bx += offsetX;
if (ax == bx) { ax -= keke_linePileOffset; }
context.beginPath();
context.moveTo(bx, by);
context.lineTo(bx - arrowW, by + arrowW);
context.lineTo(bx, by);
context.lineTo(bx + arrowW, by + arrowW);
if (isOutLine) {
context.lineTo(bx + arrowW - middleW, by + arrowW - sharp);
context.moveTo(bx - arrowW + middleW, by + arrowW - sharp);
}
context.lineTo(bx - arrowW, by + arrowW);
// 下
} else if (dire == "下") {
bx += offsetX;
if (ax == bx) { ax -= keke_linePileOffset; }
context.beginPath();
context.moveTo(bx, by);
context.lineTo(bx - arrowW, by - arrowW);
context.lineTo(bx, by);
context.lineTo(bx + arrowW, by - arrowW);
if (isOutLine) {
context.lineTo(bx + arrowW - middleW, by - arrowW + sharp);
context.moveTo(bx - arrowW + middleW, by - arrowW + sharp);
}
context.lineTo(bx - arrowW, by - arrowW);
// 左
} else if (dire == "左") {
by += offsetY;
if (ay == by) { ay += keke_linePileOffset; }
context.beginPath();
context.moveTo(bx, by);
context.lineTo(bx + arrowW, by - arrowW);
context.lineTo(bx, by);
context.lineTo(bx + arrowW, by + arrowW);
if (isOutLine) {
context.lineTo(bx + arrowW - sharp, by + arrowW - middleW);
context.moveTo(bx + arrowW - sharp, by - arrowW + middleW);
}
context.lineTo(bx + arrowW, by - arrowW);
// 右
} else if (dire == "右") {
by += offsetY;
if (ay == by) { ay += keke_linePileOffset; }
context.beginPath();
context.moveTo(bx, by);
context.lineTo(bx - arrowW, by - arrowW);
context.lineTo(bx, by);
context.lineTo(bx - arrowW, by + arrowW);
if (isOutLine) {
context.lineTo(bx - arrowW + sharp, by + arrowW - middleW);
context.moveTo(bx - arrowW + sharp, by - arrowW + middleW);
}
context.lineTo(bx - arrowW, by - arrowW)
}
context.lineTo(bx, by);
context.stroke();
context.fill();
};
//- ターゲットラインの消去
function delTargetLine(subject) {
// ターゲットライン作成フラグを消去
subject._makesTargetLineKe = null;
if (!subject) { return; }
// ラインを取得
const sprite = searchSpriteBattler(subject);
if (!sprite) { return; }
const lines = sprite._targetLinesKe;
if (!lines || !lines.list.length) { return; }
// 全てのラインに対して処理
lines.list.forEach(sprite => {
// スプライト破棄
sprite.parent.removeChild(sprite);
sprite.destroy();
// 受容ラインの消去
delReceptLine(idToBattler(sprite._targetIdKe), subject)
});
sprite._targetLinesKe = null;
};
//- 受容ラインの選択
function saveReceptLine(target, subject) {
if (!target._receptLinesKe) { target._receptLinesKe = []; }
const recepts = target._receptLinesKe;
let receptIndex = 0;
// 攻撃者ID
const subjectId = battlerToId(subject);
// 空きがあったらそこを選択
let saved = false;
recepts.forEach((slot, i) => {
if (!slot && !saved) {
recepts = subjectId;
receptIndex = i;
saved = true;
}
});
// 空きがなかったら末尾を選択
if (!saved) {
recepts.push(subjectId);
receptIndex = recepts.length - 1;
}
return receptIndex;
};
//- 受容ラインの消去
function delReceptLine(target, subject) {
if (!target || !target._receptLinesKe) { return; }
const recepts = target._receptLinesKe;
// 行動者のスロットがあったら消去
recepts.forEach((slot, i) => {
if (idToBattler(slot) == subject) {
recepts = null;
}
});
};
//- 受容ラインの初期化
function initReceptLine() {
$gameParty.allMembers().forEach(target => {
target._receptLinesKe = null;
});
};
//- ターゲットラインのリチルド
function rechildTargetLine() {
const layerId = keke_actLayer == "ウインドウより上" ? "C" : "A";
// ラインを全て取得
const allLines = [];
$gameTroop.aliveMembers().forEach(enemy => {
const sprite = searchSpriteBattler(enemy);
if (!sprite) { return false; }
const lines = sprite._targetLinesKe;
if (!lines || !lines.list.length) { return false; }
allLines.push(lines);
});
if (!allLines.length) { return; }
// ラインを長さが長い順にソート
allLines.sort((a, b) => b.length - a.length);
// ワイヤーを再チルド
allLines.forEach(lines => {
lines.list.forEach(sprite => {
// ワイヤーでなければ除外
if (!sprite._isWireKe) { return; }
childLayer(sprite, layerId);
});
});
// 矢印を再チルド
allLines.forEach(lines => {
lines.list.forEach(sprite => {
// 矢印でなければ除外
if (!sprite._isArrowKe) { return; }
childLayer(sprite, layerId);
});
});
};
//- ターゲットラインの可視更新
function updateTargetLineVisible(subject, subjectSprite) {
if (!subjectSprite._targetLinesKe || !subjectSprite._targetLinesKe.list.length) { return; }
let valid = true;
while (true) {
if (BattleManager._phase == "battleEnd") { valid = false; break; }
if (isActing(subject) || subject.isRestricted()) { valid = false; break; }
if (keke_lineOnlyInput && !BattleManager.isInputting()) { valid = false; break; }
if (!isTargetLineShow(subject) || !isValidPrediction(subject)) { valid = false; break; }
break;
}
subjectSprite._targetLinesKe.list.forEach(line => {
line.visible = valid;
})
};
//==================================================
//-- ターゲットライン-アニメ
//==================================================
//- ターゲットライン周期の更新
function updateTargetLineCycle() {
const gt = $gameTemp;
if (gt._tlFlickerDurationKe == null) { gt._tlFlickerDurationKe = 45; }
gt._tlFlickerDurationKe--;
if (gt._tlFlickerDurationKe <= 0) {
gt._tlFlickerDurationKe = 45;
}
};
//- ターゲットライン明滅の更新
function updataTargetLineFlicker(subject, sprite) {
const lines = sprite._targetLinesKe;
if (!lines || !lines.list.length) { return; }
// 全てのラインに対して処理
lines.list.forEach(sprite => {
// 明滅の更新
updataFlicker(sprite);
});
};
//- 明滅の更新
function updataFlicker(sprite) {
// 明滅の開始
startFlicker(sprite);
// 明滅の処理
processFlicker(sprite);
};
//- 明滅の開始
function startFlicker(sprite) {
if (sprite._flickerKe) { return; }
const d = {};
d.start = 64;
d.target = 255;
d.timeMax = 45;
d.easing = "eo";
d.duration = $gameTemp._tlFlickerDurationKe || d.timeMax;
d.current = d.start;
sprite._flickerKe = d;
};
//- 明滅の処理
function processFlicker(sprite) {
if (!sprite._flickerKe) { return; }
const d = sprite._flickerKe;
// カウントを減らす
d.duration--;
// ターンの処理
//d.current = processTurn(d.current, d.start, d.target, d.duration + 1, d.timeMax);
d.current = processEasing(d.current, d.target, d.duration + 1, d.timeMax, d.easing);
sprite.opacity = d.current;
// ループ
if (d.duration <= 0) {
d.duration = d.timeMax;
d.current = d.start;
}
};
//==================================================
//-- フォント基本 /ベーシック
//==================================================
//- 文字列幅
function strWidth(str, fontSize, sizeRate = {}) {
return strBytes(str, 0.5, sizeRate.half || 1) * fontSize * (sizeRate.width || 1);
};
//- 文字列バイト数
function strBytes(str, rate = 1, halfSize = 1) {
let byte = 0;
for (let i = 0; i < str.length; i++) {
var c = str.charCodeAt(i);
if ((c >= 0x0 && c < 0x81) || (c === 0xf8f0) || (c >= 0xff61 && c < 0xffa0) || (c >= 0xf8f1 && c < 0xf8f4)) {
byte += 1 * (rate * halfSize);
} else {
byte += 2 * rate;
}
}
return byte;
};
//==================================================
//-- 配列基本 /ベーシック
//==================================================
//- ハッシュのディープコピー
function copyHash(hash) {
const copy = {};
Object.keys(hash).forEach(k => {
if (!hash[k]) { copy[k] = hash[k]; return; }
if (hash[k].constructor.name == "Object") {
copy[k] = copyHash(hash[k]);
} else if (hash[k].constructor.name == "Array") {
copy[k] = copyArray(hash[k]);
} else {
copy[k] = hash[k];
}
});
return copy;
};
//- 配列のディープコピー
function copyArray(array) {
const copy = [];
array.forEach((v, i) => {
if (v.constructor.name == "Object") {
copy = copyHash(v);
} else if (v.constructor.name == "Array") {
copy = copyArray(v);
} else {
copy = v;
}
});
return copy;
};
//==================================================
//-- バトラー基本 /ベーシック
//==================================================
//- バトラーをIDに
function battlerToId(battler) {
if (battler._actorId) {
return { type:"actor", id:battler._actorId};
} else {
return { type:"enemy", id:battler.index()};
}
};
//- IDをバトラーに
function idToBattler(id) {
if (!id) { return; }
if (id.type == "actor") {
return $gameParty.members().find(actor => actor._actorId == id.id);
} else {
return $gameTroop.members()[id.id];
}
};
//==================================================
//-- メタ取得 /ベーシック
//==================================================
//- 全てのメタ配列を合算
function totalAllMetaArray(battler, words, action, noDelSpace, ratioIndex) {
let data = null
let array = [];
// バトラー値
if (battler) {
data = battler._actorId ? battler.actor() : battler.enemy();
if (data) { metaAll(data.note, words, ratioIndex).forEach(e => array.push(e)); }
if (battler._actorId) {
// 職業値
data = battler.currentClass();
if (data) { metaAll(data.note, words, ratioIndex).forEach(e => array.push(e)); }
// 装備値
battler._equips.forEach(equip => {
data = equip.object();
if (data) { metaAll(data.note, words, ratioIndex).forEach(e => array.push(e)); }
});
}
// ステート値
battler._states.forEach(stateId => {
data = $dataStates[stateId];
if (data) { metaAll(data.note, words, ratioIndex).forEach(e => array.push(e)); }
});
}
// アクション値
if (action) {
data = action.item();
if (data) { metaAll(data.note, words, ratioIndex).forEach(e => array.push(e)); }
}
// スペース削除
if (!noDelSpace) { array = array.map(e => e.replace(/\s/g, "")); }
// 空の要素は削除
array = array.filter(e => e);
return array;
};
//- 全取得メタ
function metaAll(note, words, ratioIndex) {
var result = [];
words.forEach(word => {
var regText = '\<' + word + ':([^\>]*)\>';
var regExp_g = new RegExp(regText, 'g');
var regExp = new RegExp(regText);
var matches = note.match(regExp_g);
if (matches) {
matches.forEach(function(line) {
const match = line.match(regExp);
const vals = match[1].replace(/\s/g, "").split(",");
ratioIndexEx = ratioIndex - 1;
if (ratioIndex && vals[ratioIndexEx] && Math.randomInt(100) >= Number(vals[ratioIndexEx])) {
return;
}
result.push(match[1]);
});
}
});
return result;
};
//==================================================
//-- スプライト基本 /ベーシック
//==================================================
//- スプライトの検索-バトラー
function searchSpriteBattler(battler) {
const spriteset = SceneManager._scene._spriteset;
let result = null;
const sprites = battler._enemyId ? spriteset._enemySprites : spriteset._actorSprites;
for (const sprite of sprites) {
if(!sprite._battler) { continue; }
if ((battler._actorId && sprite._battler._actorId == battler._actorId) || (battler._enemyId && sprite._battler.index() == battler.index())) {
result = sprite;
break;
}
}
return result;
};
//==================================================
//-- イージング /ベーシック
//==================================================
//- ターンの処理
function processTurn(current, start, target, duration, timeMax, easingRate = 1) {
let result = 0;
const d1 = Math.round(timeMax / 2);
const d2 = timeMax - d1;
if (duration > d2) {
result = processEasing(current, target, duration - d2, d1, "e", easingRate);
} else {
result = processEasing(current, start, duration, d2, "e", easingRate);
}
return result;
};
//- イージングの処理
function processEasing(current, target, duration, timeMax, easing, easingRate = 1) {
const lt = calcEasing((timeMax - duration) / timeMax, easing, easingRate);
const t = calcEasing((timeMax - duration + 1) / timeMax, easing, easingRate);
const start = (current - target * lt) / (1 - lt);
return start + (target - start) * t;
};
//- イージングの計算
function calcEasing(t, easing, easingRate = 1) {
const exponent = 2 * easingRate;
switch (easing.toUpperCase()) {
case "EI":
return easeIn(t, exponent);
case "EO":
return easeOut(t, exponent);
case "E":
return easeInOut(t, exponent);
default:
return t;
}
};
//- 各イージング処理
function easeIn(t, exponent) {
return Math.pow(t, exponent) || 0.001;
};
function easeOut(t, exponent) {;
return 1 - (Math.pow(1 - t, exponent) || 0.001);
};
function easeInOut(t, exponent) {
if (t < 0.5) {
return easeIn(t * 2, exponent) / 2;
} else {
return easeOut(t * 2 - 1, exponent) / 2 + 0.5;
}
};
//==================================================
//-- アイコンスプライト /ベーシック
//==================================================
//- アイコンスプライトの形成
function createIconSprite(iconIndex, anchorX = 0.5, anchorY = 0.5) {
const sprite = new SpriteKePrds();
sprite.anchor.x = anchorX;
sprite.anchor.y = anchorY;
const bitmap = ImageManager.loadSystem("IconSet");
sprite.bitmap = bitmap;
const pw = ImageManager.iconWidth;
const ph = ImageManager.iconHeight;
const sx = (iconIndex % 16) * pw;
const sy = Math.floor(iconIndex / 16) * ph;
sprite.setFrame(sx, sy, pw, ph);
return sprite;
};
//==================================================
//-- エフェクト /ベーシック
//==================================================
//- エフェクトの実行
function doEffect(effect, subject, target) {
target = target || subject;
// アニメの表示
showAnime(subject, target, effect["アニメーション"]);
// 効果音の再生
playSe(effect["効果音"]);
// 画面フラッシュの表示
showScreenFlash(effect);
// 画面ストップの開始
startScreenStop(effect["ヒットストップ"]);
// フリーアニメ・スキルの実行
doFreeAnimeSkill(subject, target, effect["フリーアニメ"]);
};
//- アニメの表示
function showAnime(subject, target, animeId) {
if (!animeId) { return; }
Window_BattleLog.prototype.showAnimation(subject, [target], animeId);
};
//- 効果音の再生
function playSe(ses) {
if (!ses || !ses.length) { return; }
ses.forEach(se => {
if (!se) { return; }
AudioManager.playSe({ name:se["ファイル"], volume:se["音量"], pitch:se["ピッチ"], pan:se["位相"] });
});
};
//- 画面フラッシュの表示
function showScreenFlash(d) {
if (!d["画面フラッシュ"] || !d["…フラッシュ色" || !d["…フラッシュ時間"]]) { return; }
const delay = d["…フラッシュ遅延"] || 0;
if (delay) {
setTimeout(screenFlash, delay * 1000 / 60, d);
} else {
screenFlash(d);
}
};
//- 画面フラッシュ
function screenFlash(d) {
$gameScreen.startFlash(d["…フラッシュ色"], d["…フラッシュ時間"]);
};
//- 画面ストップの開始
function startScreenStop(str) {
if (!PluginManager._scripts.some(n => n == "Keke_HitStop")) { return; }
// 画面ストップ
$gameTemp.screenStopKe(str);
};
//- フリーアニメ・スキルの実行
function doFreeAnimeSkill(subject, target, note) {
if (!isFreeAnime() || !note) { return; }
// アニメファイルとコモンを取得
const metaList = metaAll(note, ["フリーアニメ", "freeAnime"]);
if (!metaList || !metaList.length) { return; }
metaList.forEach(meta => {
//-フリーアニメ・スキルの実行-個別
BattleManager.doFreeAnimeSkillKe(meta, subject, [target]);
});
};
//- フリーアニメフラグ
function isFreeAnime() {
return PluginManager._scripts.some(n => n == "Keke_FreeAnime");
};
})();[/pre][/fold]
|
-
|