-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathTF_VectorWindow.js
1749 lines (1579 loc) · 59.3 KB
/
TF_VectorWindow.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//=================================================
// TF_VectorWindow.js
// Version :1.6.0.0
// For : RPGツクールMZ (RPG Maker MZ)
// ----------------------------------------------
// Copyright : Tobishima-Factory 2020-2025
// Website : http://tonbi.jp
//
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
//=================================================
// #region annotation
/*:ja
* @target MZ
* @plugindesc ウィンドウの表示をベクトル描画
* @author とんび﹫鳶嶋工房(tonbi.jp)
* @url https://github.com/tonbijp/RPGMakerMZ/blob/master/TF_VectorWindow.js
* @base PluginCommonBase
* @orderAfter PluginCommonBase
*
* @================= parameter ====================
* @param preset @text ウィンドウ設定
* @desc ウィンドウ設定のプリセット
* (1:UI用、2:メッセージ用、3〜 : メッセージ変更用)
* @type struct<WindowParam>[]
* @default ["{\"name\":\"UI\",\"shape\":\"roundrect\",\"margin\":\"3\",\"borderWidth\":\"6\",\"borderColor\":\"#fff\",\"decorSize\":\"20\",\"padding\":\"12\",\"bgColor\":\"[\\\"#0008\\\"]\"}","{\"name\":\"talk\",\"shape\":\"roundrect\",\"margin\":\"3\",\"borderWidth\":\"6\",\"borderColor\":\"#0ee\",\"decorSize\":\"20\",\"padding\":\"14\",\"bgColor\":\"[\\\"#0008\\\",\\\"#000C\\\"]\"}","{\"name\":\"thought\",\"shape\":\"roundrect\",\"margin\":\"6\",\"borderWidth\":\"2\",\"borderColor\":\"#666\",\"decorSize\":\"100\",\"padding\":\"16\",\"bgColor\":\"[\\\"#000a\\\"]\"}","{\"name\":\"shout\",\"shape\":\"spike\",\"margin\":\"60\",\"borderWidth\":\"6\",\"borderColor\":\"#fff\",\"decorSize\":\"80\",\"padding\":\"74\",\"bgColor\":\"[\\\"#0006\\\"]\"}"]
*
* @================================================
* @param dropShadow @text ウィンドウの影
* @type boolean @default true
* @on 影あり(規定値) @off 影なし
*
* @================================================
* @param lineHeightRatio @text 行高さ
* @desc 標準文字サイズを100%とした比率
* 規定値:140
* @type number @default 140
* @min 100
*
* @================================================
* @param itemHeightRatio @text 項目高さ
* @desc 標準文字サイズを100%とした比率
* 規定値:160
* @type number @default 160
*
* @================================================
* @param messageFontSize @text メッセージフォントサイズ
* @desc
* 規定値:30
* @type number @default 30
* @min 8
*
* @================================================
* @param nameFontSize @text 名前フォントサイズ
* @desc
* 規定値:20
* @type number @default 20
* @min 8
*
* @================================================
* @param nameWithFace @text 顔に名前表示
* @type boolean @default true
* @on 顔の下に表示(規定) @off 標準
*
* @================================================
* @param messageLines @text メッセージに表示する行数
* @desc
* 規定値:3
* @type number @default 3
* @min 1
*
* @================================================
* @param messageView @text メッセージウィンドウ表示範囲
* @desc 画面全体に対する x,y,幅,高さ の順の数値(ピクセル数)
* 規定値:4,4,808,616
* @type string @default 4,4,808,616
*
* @================================================
* @param pointerLength @text シッポの長さ
* @desc フキダシのシッポの長さ(ピクセル数)
* 規定値:36
* @type string @default 36
*
* @================================================
* @param pointerWidth @text シッポの幅
* @desc フキダシのシッポの幅(ピクセル数)
* 規定値:20
* @type string @default 20
*
*
* @================== command =====================
* @command setWindow @text ウィンドウの準備
* @desc [文章の表示]コマンドの前に実行すること。
* 一回表示されるとウィンドウタイプは規定値に戻る。
*
* @arg windowType @text ウィンドウタイプ
* @desc プラグインパラメータで設定した番号か名前
* あらかじめ UI, talk, thought, shout がある
* @type combo @default shout
* @option UI @option talk @option thought @option shout
*
* @arg faceAlign @text 顔位置
* @desc
* 規定値:left
* @type select @default left
* @option 左外 @value beyondLeft
* @option 左 @value left
* @option 右 @value right
* @option 右外 @value beyondRight
*
* @arg pos @text ウィンドウ位置
* @desc 画面左上から x,y の座標
* command は[文章の表示]に従う
* @type combo @default command
* @option command
*
* @arg continuousPos @text 表示位置継続
* @desc [ウィンドウ位置]で指定した座標を
* 継続した[文章の表示]に適用する。
* @type boolean @default true
* @on 継続(規定値) @off 単体
*
* @================================================
* @command setSpeachBalloon @text フキダシの準備
* @desc [文章の表示]コマンドの前に実行すること。
* 一回表示されるとウィンドウタイプは規定値に戻る。
*
* @arg windowType @text ウィンドウタイプ
* @desc プラグインパラメータで設定した番号か名前
* あらかじめ UI, talk, thought, shout がある
* @type combo @default talk
* @option UI @option talk @option thought @option shout
*
* @arg pointerAlign @text シッポ位置
* @desc autoは[文章の表示]の指定と[顔位置]指定から決定されます
* 規定値:auto
* @type select @default auto
* @option 自動配置 @value auto
* @option 上の左側 @value NW
* @option 上の中央 @value NC
* @option 上の右側 @value NE
* @option 下の左側 @value SW
* @option 下の中央 @value SC
* @option 下の右側 @value SE
* @option -------- @value none
* @option 左の上側 @value WN
* @option 左の中央 @value WC
* @option 左の下側 @value WS
* @option 右の上側 @value EN
* @option 右の中央 @value EC
* @option 右の下側 @value ES
*
* @arg faceAlign @text 顔位置
* @desc
* 規定値:left
* @type select @default left
* @option 左外 @value beyondLeft
* @option 左 @value left
* @option 右 @value right
* @option 右外 @value beyondRight
*
* @arg pos @text フキダシ位置
* @desc 画面左上から x,y の座標(例:"200,100")
* 規定値の command は[文章の表示]に従う
* @type combo @default command
* @option command
*
* @arg continuousPos @text 表示位置継続
* @desc [ウィンドウ位置]で指定した座標を
* 継続した[文章の表示]に適用する。
* @type boolean @default true
* @on 継続(規定値) @off 単体
*
* @================================================
* @command setSpeachBalloonToEvent @text イベントフキダシの準備
* @desc [文章の表示]コマンドの前に実行すること。
* 一回表示されるとウィンドウタイプは規定値に戻る。
*
* @arg eventId @text イベントID
* @desc
* イベントID(数値)かイベントの名前
* @type combo @default this
* @option this @option player @option follower0 @option follower1 @option follower2
* @option boat @option ship @option airship
*
* @arg windowType @text ウィンドウタイプ
* @desc プラグインパラメータで設定した番号か名前
* あらかじめ UI, talk, thought, shout がある
* @type combo @default talk
* @option UI @option talk @option thought @option shout
*
* @arg pointerAlign @text シッポ位置
* @desc autoは[文章の表示]の指定と[顔位置]指定から決定されます
* 規定値:auto
* @type select @default auto
* @option 自動配置 @value auto
* @option 上の左側 @value NW
* @option 上の中央 @value NC
* @option 上の右側 @value NE
* @option 下の左側 @value SW
* @option 下の中央 @value SC
* @option 下の右側 @value SE
* @option -------- @value none
* @option 左の上側 @value WN
* @option 左の中央 @value WC
* @option 左の下側 @value WS
* @option 右の上側 @value EN
* @option 右の中央 @value EC
* @option 右の下側 @value ES
*
* @arg faceAlign @text 顔位置
* @desc
* 規定値:left
* @type select @default left
* @option 左外 @value beyondLeft
* @option 左 @value left
* @option 右 @value right
* @option 右外 @value beyondRight
*
* @arg continuousPos @text 表示位置継続
* @desc [ウィンドウ位置]で指定した座標を
* 継続した[文章の表示]に適用する。
* @type boolean @default true
* @on 継続(規定値) @off 単体
*
* @============ この長さに合わせるとヘルプではみ出ない =============
* @help
* ウィンドウをPNG画像を使わずに描画する。
* 背景のグラデーションや枠線の太さや形など指定が可能。
*
* 標準の[文章の表示]コマンドを使う前に
* プラグインコマンド[ウィンドウの準備]を実行し、
* ウィンドウタイプや顔グラフィックの左右位置を指定する。
*
* [イベントフキダシの準備]で上にフキダシを出す場合に、
* パラメータの[イベント画像の高さ]を基準にします。
*
* パラメータとは別に個々のキャラに設定にしたい場合は、
* プレイヤーと隊列メンバーはデータベースの[アクター]のメモ欄、
* また[イベント]のメモ欄に次のタグを書ける。
*
* <TF_EVENTHEIGHT:高さ>
*
* 高さはピクセル数(画面の拡大率を考慮する必要はない)
*
* 以下のタグだと、96pxの高さがあるキャラ(イベント)と判断します。
* <TF_EVENTHEIGHT:96>
*
* ※ PluginCommonBase 定義によりパラメータや引数に \V[n] を使えます。
*/
/*~struct~WindowParam:ja
*
* @param name @text ウィンドウ名
* @type string
*
* @================================================
* @param shape @text ウィンドウの形
* @desc
* 規定値:roundrect
* @type select @default roundrect
* @option 角丸(decorSize:0 で長方形) @value roundrect
* @option 破裂型(叫び) @value spike
* @option 8角形 @value octagon
* @option なし @value none
*
* @================================================
* @param margin @text 端から枠までの間隔
* @desc
* 規定値:8
* @type number @default 8
* @min 0
*
* @================================================
* @param borderWidth @text 枠の幅
* @desc
* 規定値:6
* @type number @default 6
* @min 0
*
* @================================================
* @param borderColor @text 枠の色(CSS形式)
* @desc
* 規定値:#FFF
* @type string @default #FFF
*
* @================================================
* @param decorSize @text 装飾の大きさ
* @desc 角丸・角・トゲのサイズ
* 規定値:10
* @type number @default 10
* @min 0
*
* @================================================
* @param padding @text 枠から内容までの間隔
* @desc
* 規定値:18
* @type number @default 18
* @min 0
*
* @================================================
* @param bgColor @text 背景色(CSS形式)
* @desc 複数指定すると縦のグラデーションとして描画
* 規定値:["#0086"]
* @type string[] @default ["#0086"]
*/
// #endregion
( () => {
"use strict";
// エラー表示用にプラグイン名を取得
const PLUGIN_NAME = PluginManagerEx.findPluginName( document.currentScript );
const TF_EVENTHEIGHT = "TF_EVENTHEIGHT";// イベント高さ設定タグ名
// ウィンドウ描画関連
const ERROR_NUMBER = -1;
const WINDOW_TYPE_UI = 0; // UIタイプの規定値
const WINDOW_TYPE_TALK = 1; // [文章の表示]ウィンドウタイプの規定値
const WINDOW_TYPE_THOUGHT = 2;
const WINDOW_TYPE_SHOUT = 3;
const SHAPE_ROUNDRECT = "roundrect";
const SHAPE_SPIKE = "spike";
const SHAPE_OCTAGON = "octagon";
const SHAPE_NONE = "none";
const workBitmap = new Bitmap( 1, 1 ); // 前処理用に使うビットマップ
const wCtx = workBitmap.context;
const BOX_MARGIN = 4; // boxWidth,boxHeight の外にある余白
// $gameMessage.positionType()
const ALIGN_UP = 0;
const ALIGN_MIDDLE = 1;
const ALIGN_DOWN = 2;
const POSITION_FREE = 20; // 座標指定
const COMMAND_ALIGN = "command"; // [文章の表示]-[ウィンドウ位置]
// 顔位置
const ALIGN_BEYONDLEFT = "beyondLeft";
const ALIGN_LEFT = "left";
const ALIGN_INNERLEFT = "innerLeft";
const ALIGN_CENTER = "center";
const ALIGN_INNERRIGHT = "innerRight";
const ALIGN_RIGHT = "right";
const ALIGN_BEYONDRIGHT = "beyondRight";
const PARAM_TRUE = "true";
const PARAM_FALSE = "false";
const PARAM_ON = "on";
const TYPE_BOOLEAN = "boolean";
const TYPE_NUMBER = "number";
const TYPE_STRING = "string";
/**
* パラメータを受け取る
*/
const pluginParams = PluginManagerEx.createParameter( document.currentScript );
// メッセージ設定
const messageFontSize = pluginParams.messageFontSize;
const lineHeightRatio = pluginParams.lineHeightRatio / 100;
const messageLines = pluginParams.messageLines;
// フキダシ(メッセージ)ウィンドウ設定
const pointerLength = pluginParams.pointerLength;// シッポの長さ
const pointerWidth = Math.floor( pluginParams.pointerWidth / 2 );// シッポの幅(半分)
// 名前表示設定
const nameFontSize = pluginParams.nameFontSize;
const nameWithFace = pluginParams.nameWithFace;
// 選択項目設定
const itemHeightRatio = pluginParams.itemHeightRatio / 100;
// const dropShadow = pluginParams.dropShadow;
let messageView;
// #region Scene_Boot
/**
* 全体での大きさを_windowLayer からのサイズに変換
* Graphics のサイズがここで決まるので、その直後に処理
*/
const _Scene_Boot_start = Scene_Boot.prototype.start;
Scene_Boot.prototype.start = function() {
_Scene_Boot_start.call( this );
messageView = ( rect => {
rect.x = rect.x - Math.floor( ( Graphics.width - Graphics.boxWidth ) / 2 );
rect.y = rect.y - Math.floor( ( Graphics.height - Graphics.boxHeight ) / 2 );
return rect;
} )( stringToRectangle( pluginParams.messageView ) );
};
// #endregion
// #region registerCommand
/**
* プラグインコマンドの登録
*/
const COM_SET_WINDOW = "setWindow";
const COM_SET_SPEACHBALLOON = "setSpeachBalloon";
const COM_SET_SPEACHBALLOON2EVENT = "setSpeachBalloonToEvent";
const PLUGIN_PARAM = 657;// プラグインコマンドのエディタでの引数の表示用
const SHOW_TEXT = 101;// 文章の表示…
const TEXT_DATA = 401;// 文章の表示のメッセージ
// [メッセージウィンドウの準備]
PluginManagerEx.registerCommand( document.currentScript, COM_SET_WINDOW, function( args ) {
$gameMessage.TF_pointerAlign = POINTER_NONE;
setWindowType( args );
setWindowAreaToCommand( this, args.pos, args.continuousPos );
} );
// [フキダシウィンドウの準備]
PluginManagerEx.registerCommand( document.currentScript, COM_SET_SPEACHBALLOON, function( args ) {
$gameMessage.TF_pointerAlign = args.pointerAlign;
setWindowType( args );
setWindowAreaToCommand( this, args.pos, args.continuousPos );
} );
// [イベントフキダシウィンドウの準備]
PluginManagerEx.registerCommand( document.currentScript, COM_SET_SPEACHBALLOON2EVENT, function( args ) {
setWindowType( args );
$gameMessage.setPositionType( POSITION_FREE );
setFreeWindowPosition( this, args.continuousPos );
// [文章の表示]の際に参照できるように、メッセージウィンドウを設定
$gameMessage.TF_pointerAlign = args.pointerAlign;
const id = stringToEventId( args.eventId );
// [このイベント]が指定されていた場合、ここでイベントIDを設定しておく
$gameMessage.TF_targetEventId = ( id === 0 ) ? this._eventId : id;
} );
// #endregion
// #region Game_CharacterBase
const _Game_CharacterBase_initMembers = Game_CharacterBase.prototype.initMembers;
Game_CharacterBase.prototype.initMembers = function() {
_Game_CharacterBase_initMembers.apply( this, arguments );
this.TF_setImageSize( 0, 0 );
};
Game_CharacterBase.prototype.TF_setImageSize = function( width, height ) {
this._size = { width: width, height: height };
};
// #endregion
// #region window command
/**
* メッセージウィンドウの設定
* @param {Array} args プラグインコマンドのパラメータリスト
*/
function setWindowType( args ) {
const windowType = getWindowType( args.windowType );
if( windowType === ERROR_NUMBER ) throw `"${args.windowType}" is wrong window type.`;
$gameMessage.TF_windowType = windowType;
$gameMessage.TF_faceAlign = args.faceAlign;
}
/**
* メッセージウィンドウの位置をコマンドに設定
* @param {Game_Interpreter} interpreter コマンドインタプリタ
* @param {String} posText ウィンドウの位置・大きさの文字列
* @param {Boolean} continuousPos 表示位置継続か
*/
function setWindowAreaToCommand( interpreter, posText, continuousPos ) {
if( posText === COMMAND_ALIGN ) return;
$gameMessage.setPositionType( POSITION_FREE );
setFreeWindowPosition( interpreter, continuousPos );
if( isPointString( posText ) ) {
setWindowPosition( stringToPoint( posText ) );
} else {
setWindowReactangle( stringToRectangle( posText ) );
}
}
/**
* メッセージウィンドウの位置を設定
* @param {Point} point ウィンドウの位置
*/
function setWindowPosition( point ) {
const mw = Graphics.app.stage._messageWindow;
[ mw.x, mw.y ] = [ point.x, point.y ];
}
/**
* メッセージウィンドウの矩形を設定
* @param {Rectangle} rectangle ウィンドウの位置・大きさ
*/
function setWindowReactangle( rectangle ) {
const mw = Graphics.app.stage._messageWindow;
// _width、_height に代入するのは、_refreshAllParts を発生させないため
[ mw.x, mw.y, mw._width, mw._height ] = [ rectangle.x, rectangle.y, rectangle.width, rectangle.height ];
}
/**
* フキダシ位置に座標(x,y)が書かれている場合の処理
* @param {Game_Interpreter} interpreter コマンドインタプリタ
* @param {Boolean} continuousPos 表示位置継続か
*/
function setFreeWindowPosition( interpreter, continuousPos ) {
const mw = Graphics.app.stage._messageWindow;
mw._positionType = POSITION_FREE;
let eventIndex = getNextCommandIndex( interpreter._list, interpreter._index + 1, PLUGIN_PARAM );
// ウィンドウ位置 : parameters[ 3 ]
if( continuousPos ) {
// [文章を表示]コマンドが続く限り、ウィンドウ位置を自由位置指定にする
while( interpreter._list[ eventIndex ].code === SHOW_TEXT ) {
interpreter._list[ eventIndex ].parameters[ 3 ] = POSITION_FREE;
eventIndex = getNextCommandIndex( interpreter._list, eventIndex + 1, TEXT_DATA );
}
} else if( interpreter._list[ eventIndex ].code === SHOW_TEXT ) {
// 次の[文章を表示]コマンドのウィンドウ位置を自由位置指定にする
interpreter._list[ eventIndex ].parameters[ 3 ] = POSITION_FREE;
}
}
/**
* 指定のインデックスの次のコマンドのインデックスを返す
* コマンドが複数行に複数行にわたる事があるので、次のコマンドまで不要な行を飛ばす処理が入っている
* @param {Array.<RPG.EventCommand>} list イベントコマンドのリスト
* @param {Number} index 現在のコマンドのインデックス
* @param {Number} ignoredCommand 飛ばすコマンド
* @returns {Number} 次のコマンドのインデックス
*/
const getNextCommandIndex = ( list, index, ignoredCommand ) => {
while( list[ index ] && list[ index ].code === ignoredCommand ) index++;
return index;
};
/**
* ウィンドウタイプ番号を返す
* @param {String|Number} windowType ウィンドウタイプの番号か名前の文字列
* @returns {Number} ウィンドウタイプ番号
*/
function getWindowType( windowType ) {
if( typeof windowType === TYPE_STRING ) {
return pluginParams.preset.findIndex( ( e ) => e.name === windowType ); // 名前から数値を得る
} else if( 0 < windowType && windowType <= pluginParams.preset.length ) {
return windowType - 1;
} else {
return ERROR_NUMBER;
}
};
// #endregion
// #region Game_Screen
/**
* 画面座標をズームを考慮した座標に変換します。
* @param {Number} x 画面座標
* @returns {Number} ズームを考慮したxf座標
*/
Game_Screen.prototype.convertRealX = function( x ) {
const scale = this.zoomScale();
return scale * x - ( scale - 1.0 ) * this.zoomX();
};
/**
* 画面座標をズームを考慮した座標に変換します。
* @param {Number} y 画面座標
* @returns {Number} ズームを考慮したy座標
*/
Game_Screen.prototype.convertRealY = function( y ) {
const scale = this.zoomScale();
return scale * y - ( scale - 1.0 ) * this.zoomY();
};
// #endregion
// #region Game_Interpreter
/**
* [文章の表示]イベントコマンドの実行時に、Game_Interpreterが必要な処理をしておく
*/
const _Game_Interpreter_command101 = Game_Interpreter.prototype.command101;
Game_Interpreter.prototype.command101 = function( params ) {
const result = _Game_Interpreter_command101.call( this, params );
if( !result ) return false;
// 次のコマンドも[文章の表示]か
$gameMessage.TF_continuous = ( this.nextEventCode() === SHOW_TEXT );
return true;
};
// #endregion
// #region Window
const _Window_initialize = Window.prototype.initialize;
Window.prototype.initialize = function() {
_Window_initialize.call( this );
// SceneCustomMenu.js のスキンの設定があれば、TF_VectorWindowの設定はしない
if( this._data && this._data.WindowSkin ) return;
// TF_windowTypeが設定されていないなら、規定値を設定
if( !this.TF_windowType ) {
this.TF_windowType = WINDOW_TYPE_UI;
setWindowParam( this );
}
};
const _Window__refreshAllParts = Window.prototype._refreshAllParts;
Window.prototype._refreshAllParts = function() {
// SceneCustomMenu.js のスキンの設定がなければ、パスを先読みしておく
if( !this._data || !this._data.WindowSkin ) {
this.TF_path2d = setWindowPath( this );
}
_Window__refreshAllParts.call( this );
};
const _Window__refreshBack = Window.prototype._refreshBack;
Window.prototype._refreshBack = function() {
// SceneCustomMenu.js のスキンの設定があれば、通常の描画に渡す
if( this._data && this._data.WindowSkin ) return _Window__refreshBack.call( this );
if( !this.TF_path2d || this.TF_shape === SHAPE_NONE ) return;
const sprite = this._backSprite;
setupBitmap( sprite, this.width, this.height );
sprite.setFrame( 0, 0, this.width, this.height );
drawWindowBack( this );
};
/**
* ウィンドウ背景描画
* @param {Window} tw 対象ウィンドウ
*/
function drawWindowBack( tw ) {
const ctx = tw._backSprite.bitmap.context;
setFillColor( tw, ctx );
// if( dropShadow ) setShadowParam( ctx );
ctx.fill( tw.TF_path2d );
//if( !dropShadow ) setShadowParam( ctx );
}
/**
* ウィンドウの描画色を設定
* @param {Window_Base} tw 対象ウィンドウ
* @param {CanvasRenderingContext2D} ctx 対象コンテキスト
*/
function setFillColor( tw, ctx ) {
const bgColor = pluginParams.preset[ tw.TF_windowType ].bgColor;
if( bgColor.length === 1 ) {
ctx.fillStyle = tintColor( bgColor[ 0 ], tw._colorTone );
return;
}
const grad = ctx.createLinearGradient( 0, 0, 0, tw._height );
const l = bgColor.length;
const interval = 1.0 / ( l - 1 );
bgColor.forEach( ( e, i ) => {
grad.addColorStop( i * interval, tintColor( e, tw._colorTone ) );
} );
ctx.fillStyle = grad;
}
const _Window__refreshFrame = Window.prototype._refreshFrame;
Window.prototype._refreshFrame = function() {
// SceneCustomMenu.js のスキンの設定があれば、通常の描画に渡す
if( this._data && this._data.WindowSkin ) return _Window__refreshFrame.call( this );
if( !this.TF_path2d || this.TF_shape === SHAPE_NONE ) return;
setupBitmap( this._frameSprite, this.width, this.height );
this._frameSprite.setFrame( 0, 0, this.width, this.height );
drawWindowFrame( this );
};
// #endregion
// #region Window method
/**
* ウィンドウ枠描画
* @param {Window} tw 対象ウィンドウ
*/
function drawWindowFrame( tw ) {
const path2d = tw.TF_path2d;
const ctx = tw._frameSprite.bitmap.context;
setBorderParam( ctx, tw.TF_windowType );
ctx.stroke( path2d );
}
/**
* 枠の設定をする
* @param {CanvasRenderingContext2D} ctx コンテキスト
* @param {String} type ウィンドウのタイプ
*/
function setBorderParam( ctx, type ) {
if( !pluginParams.preset[ type ].borderWidth ) return;
ctx.lineWidth = pluginParams.preset[ type ].borderWidth;
ctx.strokeStyle = pluginParams.preset[ type ].borderColor;
ctx.shadowBlur = 3;
ctx.shadowOffsetY = 0;
}
/**
* スプライトに指定サイズのビットマップを設定する
* @param {Sprite} sprite スプライト
* @param {Number} width 幅
* @param {Number} height 高さ
*/
function setupBitmap( sprite, width, height ) {
if( sprite.bitmap ) {
sprite.bitmap.clear();
} else {
sprite.bitmap = new Bitmap( 1, 1 );
}
sprite.bitmap.resize( width, height );
}
/**
* ウィンドウのパスを得る
* @param {Window} tw 対象ウィンドウ
* @returns {Path2D} 描画するパス
*/
function setWindowPath( tw ) {
const m = tw.margin;
const r = pluginParams.preset[ tw.TF_windowType ].decorSize;
const w = tw.width;
const h = tw.height;
switch( tw.TF_shape ) {
case SHAPE_ROUNDRECT: return drawRoundrect( m, w, h, r );
case SHAPE_OCTAGON: return drawOctagon( m, w, h, r );
case SHAPE_SPIKE: return drawSpike( m, w, h, r, pluginParams.preset[ tw.TF_windowType ].borderWidth );
}
}
/**
* ウィンドウの数値設定
* @param {Window} tw 対象ウィンドウ
*/
function setWindowParam( tw ) {
const preset = pluginParams.preset[ tw.TF_windowType ];
tw.TF_shape = preset.shape;
const p = preset.padding;
tw._padding = p;
tw._margin = preset.margin;
tw._clientArea.move( p, p );
}
// #endregion
// #region Window_Base
Window_Base.prototype.lineHeight = () => Math.ceil( $dataSystem.advanced.fontSize * lineHeightRatio );
Window_Base.prototype.textPadding = function() {
return Math.ceil( this.lineHeight() - $dataSystem.advanced.fontSize ) + 0.5;
};
// なぜかここで padding を上書きして設定した値が戻っているので無視
const _Window_Base_updatePadding = Window_Base.prototype.updatePadding;
Window_Base.prototype.updatePadding = function() {
if( this._data && this._data.WindowSkin ) {
_Window_Base_updatePadding.call( this );
}
};
// #endregion
// #region Window_Message
const _Window_Message_initialize = Window_Message.prototype.initialize;
Window_Message.prototype.initialize = function() {
_Window_Message_initialize.apply( this, arguments );
// MessageAlignCenter.js が Window_MessageDummy を作った時の対策で
// TF_initialize を通さないパターンを用意しておく
// [メッセージを表示]コマンドが継続しているなら値を維持
if( $gameMessage.TF_continuous ) return;
// 次回は規定値を予約
this.TF_initialize();
};
Window_Message.prototype.TF_initialize = function() {
$gameMessage.TF_windowType = WINDOW_TYPE_TALK;
$gameMessage.TF_faceAlign = ALIGN_LEFT;
$gameMessage.TF_continuous = false;
$gameMessage.TF_pointerAlign = POINTER_NONE;
$gameMessage.TF_targetEventId = null;
this.TF_windowType = WINDOW_TYPE_TALK;
this.TF_pointerAlign = POINTER_NONE;
this.TF_targetEvent = null;
this.TF_eventX = null;
this.TF_eventY = null;
this.TF_eventHeight = null;
this.TF_eventWidth = null;
this.TF_path2d = null;
this.TF_facePicture = null;
this.TF_shape = null;
};
const BG_WINDOW = 0;
const BG_DIMMER = 1;
const BG_TRANSPARENT = 2;
const _Window_Message_startMessage = Window_Message.prototype.startMessage;
Window_Message.prototype.startMessage = function() {
if( $gameMessage.TF_targetEventId ) {
// イベントの情報をあらかじめ、取り出しておく
const te = getEventById( $gameMessage.TF_targetEventId );
this.TF_targetEvent = te;
this.TF_eventX = $gameScreen.convertRealX( te.screenX() );
this.TF_eventY = $gameScreen.convertRealY( te.screenY() );
this.TF_eventHeight = getEventHeight( te ) * $gameScreen.zoomScale();
this.TF_eventWidth = te._size.width * $gameScreen.zoomScale();
if( $gameMessage.TF_pointerAlign === DIRECTION_AUTO ) {
$gameMessage.TF_pointerAlign = this.TF_getAutoPointerDirection();
}
$gameMessage.TF_targetEventId = null;
}
if( typeof $gameMessage.TF_windowType === TYPE_NUMBER ) {
this.TF_windowType = $gameMessage.TF_windowType;
}
setWindowParam( this );
if( this.TF_targetEvent ) {
this.TF_resetLayoutByEvent();
} else if( $gameMessage.background() !== BG_TRANSPARENT ) {
this.TF_setMessageParam();
}
this._refreshAllParts();
_Window_Message_startMessage.apply( this, arguments );
};
/**
* 自動配置の場合、フキダシのトゲの向きを自動設定する
*
* @returns 設定するトゲの向き
*/
const AUTO_BALLOON_NS_THRESHOLD = 0.35;// 南北の際の閾値
const AUTO_BALLOON_WE_THRESHOLD = 0.2;// 東西の際の閾値
Window_Message.prototype.TF_getAutoPointerDirection = function() {
const sw = $dataSystem.advanced.screenWidth;
const sh = $dataSystem.advanced.screenHeight;
const flagW = this.TF_eventX < sw * AUTO_BALLOON_WE_THRESHOLD;// 西際
const flagE = sw - sw * AUTO_BALLOON_WE_THRESHOLD < this.TF_eventX;// 東際
const flagN = this.TF_eventY < sh * AUTO_BALLOON_NS_THRESHOLD; // 北際
const flagS = sh - sh * AUTO_BALLOON_NS_THRESHOLD < this.TF_eventY; //南際
if( flagW ) {
if( flagN ) return DIRECTION_NW;
return DIRECTION_SW;
} else if( flagE ) {
if( flagN ) return DIRECTION_NE;
return DIRECTION_SE;
}
if( flagN ) return DIRECTION_NC;
if( flagS ) return DIRECTION_SC;
// 中央付近の場合、対象のキャラ配置によって上下に分ける
if( this.TF_targetEvent instanceof Game_Player ) {
if( this.TF_targetEvent.direction() === 8 ) return DIRECTION_NC;
} else {
if( $gamePlayer.y < this.TF_targetEvent.y ) return DIRECTION_NC;
}
return DIRECTION_SC;
};
/**
* メッセージウィンドウの数値設定
*/
Window_Message.prototype.TF_setMessageParam = function() {
this.width = messageView.width;
this.height = this.lineHeight() * messageLines + this._padding * 2;
};
/**
* イベントとメッセージに合わせてフキダシの位置・大きさを決める
*/
Window_Message.prototype.TF_resetLayoutByEvent = function() {
const textSize = this.textSizeEx( $gameMessage.allText() );
// 謎の数字18(うち4に関しては本体の newLineX で追加してある謎の数値)
const messageWidth = textSize.width + this._padding * 2 + 18;
const messageHeight = textSize.height + this._padding * 2;
const pl = ( this.TF_windowType === WINDOW_TYPE_SHOUT ) ? 0 : pointerLength;// シッポの長さ
let x = this.TF_eventX;
let y = this.TF_eventY;
switch( $gameMessage.TF_pointerAlign ) {
case DIRECTION_NW:
case DIRECTION_NC:
case DIRECTION_NE:
y += pl;
break;
case DIRECTION_SW:
case DIRECTION_SC:
case DIRECTION_SE:
y -= messageHeight + this.TF_eventHeight + pl;
break;
case DIRECTION_WN:
case DIRECTION_EN:
break;
case DIRECTION_WC:
case DIRECTION_EC:
y -= Math.round( messageHeight / 2 ) + this.TF_eventHeight - pl;
break;
case DIRECTION_WS:
case DIRECTION_ES:
y -= messageHeight + this.TF_eventHeight;
}
switch( $gameMessage.TF_pointerAlign ) {
case DIRECTION_NW:
case DIRECTION_SW:
break;
case DIRECTION_NE:
case DIRECTION_SE:
x -= messageWidth;
break;
case DIRECTION_WN:
case DIRECTION_WC:
case DIRECTION_WS:
x += Math.round( this.TF_eventWidth / 2 ) + pl;
break;
case DIRECTION_EN:
case DIRECTION_EC:
case DIRECTION_ES:
x -= messageWidth + Math.round( this.TF_eventWidth / 2 ) + pl;
break;
default:
// 中央
x -= Math.ceil( messageWidth / 2 );
break;
}
this.x = x;
this.y = y;
this._width = messageWidth;
this._height = messageHeight;
};
/**
* メッセージウィンドウの位置設定
*/
const _Window_Message_updatePlacement = Window_Message.prototype.updatePlacement;
Window_Message.prototype.updatePlacement = function() {
// _Window_Message_updatePlacement.call(this);
this._positionType = $gameMessage.positionType();
if( this._positionType !== POSITION_FREE ) {
this.x = messageView.x;
switch( this._positionType ) {
case ALIGN_UP:
this.y = messageView.y; break;
case ALIGN_MIDDLE:
this.y = messageView.y + Math.ceil( ( messageView.height - this.height ) / 2 ); break;
case ALIGN_DOWN:
this.y = messageView.y + ( messageView.height - this.height ); break;
}
}
const goldWindow = this._goldWindow;
if( goldWindow ) {
goldWindow.y = 0 < this.y ? 0 : Graphics.boxHeight - goldWindow.height;
}
};
// フォントサイズが異なるので、オーバーライドして別計算
const _Window_Message_calcTextHeight = Window_Message.prototype.calcTextHeight;
Window_Message.prototype.calcTextHeight = function( textState ) {
const textPadding = this.textPadding();
const lines = textState.text.slice( textState.index ).split( "\n" );
const lastFontSize = this.contents.fontSize;
const textHeight = this.maxFontSizeInLine( lines[ 0 ] ) + textPadding;
this.contents.fontSize = lastFontSize;
return textHeight;
};
// $gameMessage.positionType() で上下位置は決まる
Window_Message.prototype.numVisibleRows = () => messageLines;
Window_Message.prototype.lineHeight = () => Math.ceil( messageFontSize * lineHeightRatio );
Window_Message.prototype.textPadding = function() {
return this.lineHeight() - messageFontSize;
};
Window_Message.prototype.resetFontSettings = function() {
Window_Base.prototype.resetFontSettings.call( this );
this.contents.fontSize = messageFontSize;
};
// 顔描画を新規のクラスに任せる
// const _Window_Message_drawMessageFace = Window_Message.prototype.drawMessageFace;
Window_Message.prototype.drawMessageFace = function() {
const facePicture = Graphics.app.stage.TF_facePicture;
facePicture.moveOnMessageWindow( this );
facePicture.drawFace( this._faceBitmap, $gameMessage.faceIndex() );
};
// TODO: ここで顔画像を閉じているがチラつくので対処したい
const _Window_Message_newPage = Window_Message.prototype.newPage;
Window_Message.prototype.newPage = function() {
_Window_Message_newPage.apply( this, arguments );
closeFacePicture();
};
// 閉じるときに顔を非表示に
const _Window_Message_close = Window_Message.prototype.close;
Window_Message.prototype.close = function() {
_Window_Message_close.call( this );
closeFacePicture();
};
function closeFacePicture() {
Graphics.app.stage.TF_facePicture.bitmap.clear();