/
ESAS简易事件ARPG扩展.rb
2085 lines (2064 loc) · 78.1 KB
/
ESAS简易事件ARPG扩展.rb
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
#==============================================================================
# ■ 简易事件ARPG扩展 by 老鹰(https://github.com/OneEyedEagle/EAGLE-RGSS3)
# ※ 本插件需要放置在【组件-通用方法汇总 by老鹰】之下
#==============================================================================
$imported ||= {}
$imported["EAGLE-ESAS"] = "1.1.7"
#==============================================================================
# - 2023.3.18.23 优化pop的动态
#==============================================================================
# - 本插件新增一系列方便事件脚本调用的方法,用于创作简易ARPG
#--------------------------------------------------------------------------
# ○ 前言
#--------------------------------------------------------------------------
# - 使用本插件需要一部分脚本知识,比如需要知道最基础的字符串、数组是什么
# - 还需要一些RGSS的基础认识,如知道地图上的事件,其数据存储在Game_Event对象中
# 同时可以通过 $game_map.events[id] 获取指定id序号的事件
# - 本插件核心在于各个时机增加对指定事件页的(并行)调用
#--------------------------------------------------------------------------
# 【注意】
# - 对于本插件的新增脚本
# 标注了【全局】的可以在任意地方使用
# 标注了【地图】的可以在地图上时使用(即开启菜单时就不可以用了)
# 标注了【事件】的必须在事件脚本中使用
#--------------------------------------------------------------------------
#
#=============================================================================
# ○ 核心 - 事件页执行扩展
#=============================================================================
# - 本插件的核心思想是增加在各个时机执行指定事件页的方式
# - 由于事件自身机制优秀,可视化的编辑也更加方便,
# 因此本插件尽量保证结合事件指令来达成目的,
# 而对于事件脚本,也新增了报错捕捉,确保能快速DEBUG
#--------------------------------------------------------------------------
# @esas
#
# 【事件】当事件页是在ESAS相关功能中(具体的,就是下述注释中出现的功能)被调用时,
# 事件指令-脚本中才会存在的变量
# (具体见 Process_Event_Data 类)
#
# 在ESAS事件脚本中,新增了下列可读取的数据:
# event 获取当前解释器绑定的事件Game_Event实例
# @esas.mid 获取当前执行事件页所在的地图ID
# @esas.eid 获取当前执行事件页所在的事件ID
# @esas.pid 获取当前执行事件页的页码ID
# @esas.chara 获取当前事件页的调用来源角色
# 比如:由玩家绑定的按键触发的当前事件页,该变量值为 $game_player
# 比如:由 $game_map.events[1].run_event() 调用的当前事件页,
# 该变量值为 $game_map.events[1]
# 比如:由动画播放时调用的当前事件页,该变量值为动画的调用来源
# @esas.x
# @esas.y 获取来源角色位于地图上的坐标
# 比如:由动画播放时调用的当前事件页,则为动画所在的地图坐标
#
#--------------------------------------------------------------------------
# chara.run_event(params)
#
# 【地图】以事件/角色为【本事件】,执行指定事件页(并行处理)
#
# 注意:通过该方法,每个角色同时只会执行一个事件页,
# 若旧的事件页还未执行完,再次调用时将尝试强制终止,并开始执行新事件页
#
# chara → Game_Character类及其子类的对象
# 可以用 chara = ESAS.get_chara(chara_id) 获取
# 其中 chara_id 为 -1 时代表玩家,正数时代表对应ID事件的对象
#
# params → 存储一系列执行信息的哈希表
# :mid → 所要执行的事件页的地图ID(若不传入或传入0,则为当前地图)
# (若传入 -1,则为公共事件,且 :pid 无效)
# :eid → 所要执行的事件页的事件ID
# :pid → 所要执行的事件页的页号(若不传入或传入0,则取符合出现条件的最大页)
# :abort → 是否可以强制终止,默认 true
# 若设置为 false ,则会保证必定执行完,中途的其余事件页调用都被取消
#
# 若使用了【事件互动扩展 by老鹰】,新增如下设置:
# :sym → 仅调用事件页中的对应名称的互动,而不执行整页
#
# 此外,可以传入【事件互动扩展 by老鹰】的tags格式字符串来进行params设置:
# 如 chara.run_event("mid=1 abort=false")
#
# - 示例:
# 事件脚本:chara = ESAS.get_chara(1) # 获取1号事件对象
# ps = { :mid => 2, :eid => 2 } # 设置调用2号地图2号事件第1页
# ps[:abort] = false # 设置不允许强制终止
# chara.run_event(ps) # 并行调用事件页(当前事件继续执行之后的指令)
#
# - 高级:
# chara.esas_running? → 角色是否存在正在执行run_event调用的事件页
# chara.esas_abort(n) → 打断角色正在执行的run_event事件页,
# 若成功,给角色增加n帧硬直
# (硬直期间角色无法移动、无法利用 chara.run_event 触发esas事件)
#
#--------------------------------------------------------------------------
# chara.freeze(n)
#
# 【地图】给角色设置持续 n 帧的硬直,
# 期间角色无法行动,无法触发它的 chara.run_event() 方法,
# 在 n 帧后将会自动解除该硬直状态
#
# n → 若不传入或传入 0,则不限制持续时间
#
# chara.unfreeze
#
# 【地图】解除角色硬直
#
# - 高级:
# chara.freeze? → 角色正处于硬直?
#
#--------------------------------------------------------------------------
# chara.no_esas(n)
#
# 【地图】给角色设置持续 n 帧的无敌,期间角色不可被 esas_iter 响应事件指令,
# 即事件中通过事件脚本 esas_iter(ids) 迭代事件时,该chara事件将被跳过,
# 在 n 帧后将会自动解除该无敌状态
#
# n → 若不传入或传入 0,则不限制持续时间
#
# chara.re_esas
#
# 【地图】解除角色无敌
#
# - 高级:
# chara.no_esas? → 角色正处于无敌?
#
#--------------------------------------------------------------------------
# - 玩家按键触发事件页
#
# $game_player.set_key(key, params)
#
# 【全局】给玩家绑定按键触发的事件页
#
# key → 设置绑定按键,当按下对应按键时,自动执行一次事件页
# 与 Input 模块中所响应的键值Symbol保持一致
# params → 要调用的事件页的信息,同 chara.run_event 中的params
#
# $game_player.call_key(key)
#
# 【全局】直接调用一次按键所绑定的事件页
#
# - 高级:
# $game_player.esas_running? → 角色是否存在正在执行的事件页(含按键触发的)
# $game_player.esas_abort(n) → 打断角色正在执行的事件页(含按键触发的),
# 若有任意一个打断成功,给角色增加n帧硬直
#
# - 示例:
# 事件脚本:$game_player.set_key(:A, {:mid => 0, :eid => 1, :pid => 2})
# → 当玩家按下Shift键时,调用当前地图1号事件的第2页,将并行执行
# 请在事件页中设置玩家的禁止移动等
#
#--------------------------------------------------------------------------
# - 绑定事件页并行
#
# 在事件页的开头第一个指令为注释的情况下,在注释中编写
#
# <esas mid eid pid>
#
# 可以指定该事件页符合条件并显示时,同步开始并行执行的事件页,
# 其中的【本事件】全部被替换为当前事件。
#
# 也可以编写tags字符串,并新增sym设置:
# <esas mid=1 eid=2 pid=0 sym=互动>
# 来便捷编写所绑定的事件页,或者具体设置所触发的事件页中的互动。
#
# 当本事件被按键/接触触发时,绑定的事件页也暂停执行。
#
# - 示例:
# 1号事件的第2页开头注释中填写了 <esas 0 2 1>
# 当事件的第2页符合出现条件并显示时,同步开始并行执行当前地图2号事件的第1页
# 并且执行过程中的【本事件】均为 1号事件
#
#--------------------------------------------------------------------------
#
#=============================================================================
# ○ 模块 - 动画
#=============================================================================
# - 动画播放是非常常用的一项功能,在动画播放中途,也应该能够并行执行事件页
# 本插件扩展了动画播放相关方式
#--------------------------------------------------------------------------
# ESAS.anim_map(anim_id, x, y, params)
#
# 【地图】在地图上指定位置播放动画
#
# anim_id → 数据库中对应动画的ID
# 请提前设置动画的x坐标偏移值 16,y坐标偏移值0,以对齐格子底部中心播放
# x, y → 地图上的坐标(与编辑器中一致)
# params → 设置具体帧播放时,需要调用的事件页 {帧序号 => 事件页params}
# 同时可以传入 :chara_id => id 来存储动画的来源角色id
# 比如 { 5 => {:mid=>1,:eid=>2,:pid=>1}, :chara_id => -1 }
# 代表当前动画第 5 帧时执行1号地图2号事件第1页,且来源为玩家
#
# (若使用了【像素级移动 by老鹰】)
# ESAS.anim_map_pixel(anim_id, px, py, params)
#
# 【地图】在地图上指定位置播放动画
#
# x, y → 地图上的移动单位坐标
#
#
# ESAS.anim_event(anim_id, chara_id, params)
#
# 【地图】在指定事件上指定位置播放动画
#
# chara_id → -1时代表玩家,正数代表对应事件
#
#
# - 示例:
# 事件脚本:ps = { 2 => {:mid => -1, :eid => 2} } # 设置第2帧时调用2号公共事件
# ps[:chara_id] = 1 # 设置调用来源为1号事件
# ESAS.anim_map(112, 6, 9, ps) # 并行显示112号动画
#
#--------------------------------------------------------------------------
#
#=============================================================================
# ○ 模块 - 目标获取
#=============================================================================
# - 对于ARPG,能够获取角色面前指定范围内的全部目标是非常关键的一件事
# 本插件引入了一个完整的模块用于处理目标的获取
#--------------------------------------------------------------------------
# - 范围数组
# 本插件使用最基础的一维数组[x,y]来表示坐标,使用坐标的数组来保存范围
#
# - 范围数组的约定:
# 范围设置时,角色朝向右,且角色位于(0,0)处,向右为x正方向,向下为y正方向
#
# - 示例:(黑色方块为角色,空心方块为范围)
# □
# ■□□ → 该范围数组为 arr = [ [1,0], [2,0], [1,-1], [1,1] ]
# □
#
# - 示例:
# □□■□□ → 该范围数组为 arr = [ [-2,0], [-1,0], [1,0], [2,0], [0,1] ]
# □
#--------------------------------------------------------------------------
# - 兼容
#
# 如果使用了【像素级移动 by 老鹰】,则需要注意,此处传入的依然为RGSS中的坐标,
# 但 $game_player.x 获取的是 移动单位坐标!
#
#--------------------------------------------------------------------------
# xys = ESAS.range_xys(chara_id, arr)
#
# 【全局】传入角色ID和范围数组,返回实际在地图上的坐标的数组
#
# chara_id → -1 代表玩家,正数代表事件ID
# arr → 范围数组
#
# - 示例:
# 玩家位于地图的(5,3)处,朝向右
# xys = ESAS.range_xys(-1, [[1,0], [2,0]])
# 则 xys = [ [6,3], [7,3] ]
#
#--------------------------------------------------------------------------
# xys = ESAS.range_xys(x, y, direction, arr)
#
# 【全局】传入地图位置(x,y)和朝向和范围数组,返回实际在地图上的坐标的数组
#
# x,y → 地图上的坐标,和编辑器中显示的保持一致
# direction → 朝向(2朝下,4朝左,6朝右,8朝上)
# arr → 范围数组
#
# - 示例:
# 在地图的(5,3)处,朝向右
# xys = ESAS.range_xys(5,3, 6, [[1,0], [2,0]])
# 则 xys = [ [6,3], [7,3] ]
#
#--------------------------------------------------------------------------
# ids = ESAS.range_ids(xys, type)
#
# 【全局】传入地图坐标数组和索引范围,返回位于这些坐标内的角色的ID数组
#
# xys → 地图上实际坐标的数组
# type → :party 代表只检索我方角色,:enemy 代表只检索敌方角色
# :all 代表全部角色都会检索,若不传入,则检索敌方角色
# ids → 被检索到的角色的ID的数组(其中-1代表玩家,正数代表对应ID的事件)
# 注意:无图像 且 当前激活的事件页无任何指令 的事件将会被跳过
#
# - 示例:
# 承上,在地图的(6,3)处存在3号事件,在(7,3)处存在5号事件,在(8,3)处存在2号事件
# ids = ESAS.range_ids(xys)
# 则 ids = [ 3, 5 ]
#
#--------------------------------------------------------------------------
# ids = ESAS.select_ids(ids, sym)
#
# 【全局】传入角色ID数组和筛选条件,返回符合条件的ID数组
#
# sym →
# 若 sym 为符号,则事件/角色名字需含有该字符串
# 比如 ESAS.select_ids(ids, :<NPC>) ,就筛选出名称含有 <NPC> 的事件
# 若 sym 为字符串,则事件当前页第一个指令为注释,注释中需含有该字符串,
# 或角色数据库备注栏中需含有该字符串
# 若 sym 为数组,则每一项为字符串,且事件/角色需要在eval后全部返回 true
# 可用 s 代表开关组,v 代表变量组,e代表当前判定的事件/角色对象
# es 代表当前地图的事件组, pl 代表玩家
# 比如 ESAS.select_ids(ids,
# ["(pl.x - e.x).abs < 2", "(pl.y - e.y).abs < 2"] )
# 会筛选出和玩家x、y距离均小于2格的事件,并返回它们的ID的数组
#
# - 示例:
# 承上,3号事件名称为 "事件<npc>", 5号事件名称为 "事件<enemy>"
# ids = ESAS.select_ids(ids, :<enemy>)
# 则 ids = [ 5 ]
#
#--------------------------------------------------------------------------
#
#=============================================================================
# ○ 模块 - 事件迭代
#=============================================================================
# - 在目标获取中,我们获得了在指定范围内的事件ID的数组,
# 但是在事件中并不好对这些事件进行处理
# 因此本插件对默认的事件编辑器进行了扩展,使其能够在一个事件页中对其他事件进行处理
#--------------------------------------------------------------------------
# esas_iter(ids)
#
# 【事件】开始对角色ID数组中的事件迭代,事件指令的【本事件】将替换为被迭代事件
#
# esas_iter_end
#
# 【事件】结束事件的迭代区域,若未迭代完,则回到迭代开头继续
#
# - 示例:当前事件为 2 号事件
# | 事件脚本:esas_iter( [1,3] )
# | 独立开关:A开启
# | 显示动画:本事件,1号动画
# | 事件脚本:esas_iter_end
# | 独立开关:A开启
#
# 则 依次对1号事件和3号事件进行处理:
# 先开启1号事件的独立开关A,在1号事件上面显示1号动画,
# 再开启3号事件的独立开关A,在3号事件上面显示1号动画,
# 最后开启当前事件(2号事件)的独立开关A
#
#--------------------------------------------------------------------------
#
#=============================================================================
# ○ 模块 - POP
#=============================================================================
# - 为了让ARPG能更加生动,伤害数字等信息文本的显示也不可或缺
# 本插件新增了扩展性较强的气泡文本显示模块,能够轻松增加任意弹出文本
#--------------------------------------------------------------------------
# ESAS.new_pop(params)
#
# 【全局】生成一个立即显示,然后消失的气泡文本,
#
# params → 各种参数的Hash
# :text => 需要绘制的文本(单行,不可含转义符)
# :cid => 绑定显示的角色ID(-1为玩家,正数为事件)
# :type => 显示模式
# :float 浮起并逐渐透明
# :zoom1 由放大状态,动态缩小并透明
# :zoom2 动态放大上浮,再动态缩小下降
# :bounce 从事件图像中心向上弹出落地后跳起,并逐渐透明
# :w / :h => 精灵宽度、高度
# :size => 字体大小
# :c => 字体颜色的索引号
# :shadow => 字体启用阴影?(true 或 1 代表启用,false 或 0 代表关闭,默认true)
# :outline => 字体启用描边?(true 或 1 代表启用,false 或 0 代表关闭,默认false)
# :screen => 传入 1 时代表绑定到屏幕上,否则默认绑定到地图上
#
# - 示例:
# 在玩家行走图上显示 10 的文本
# ESAS.new_pop( {:cid => -1, :text => "10"} )
#
# - 也可以编写tags字符串进行设置:
#
# ESAS.new_pop( "text=miss cid=-1 c=17" )
#
#--------------------------------------------------------------------------
#
#=============================================================================
# ○ 模块 - 扩展
#=============================================================================
# - 此处放一些稀奇古怪的扩展功能
# 全部是基于给 Game_Character 类新增的 tmp 变量(Hash结构)
# 你也可以通过调用 chara.tmp 获取这个哈希变量,并且任意对其中的值进行修改
#--------------------------------------------------------------------------
# - 显示HP
# 为地图上的事件绑定了一个非常简单的HP血条精灵
#
# 利用 chara.hp = v 初始化事件的HP,同时将会在事件底部显示一个血条
# 对 chara.hp 进行操作的同时,将会直观反映到血条图像的增减上
# (注意,并不包含POP,请自己增加POP的事件脚本)
#
# - 示例:
# 事件脚本: event.hp = 10 # 初始化HP为 10
# 事件脚本: event.hp -= 5 # 减少 5 点HP
#
# - 高级:
# chara.tmp[:hp_max] 存储了初始化时的HP值,并且将被作为HP上限进行绘制
# (但并不会对hp值的更改进行限制)
# chara.tmp[:hp_draw] 存储了当前被绘制的HP值
#
#=============================================================================
#=============================================================================
# ○ 设置
#=============================================================================
module ESAS
#=============================================================================
# ○【设置】常量
#=============================================================================
# 当开关开启时,禁止事件的自主移动(移动路线指令不受影响)
S_ID_NO_EVENT_MOVE = 0
# 当开关开启时,禁止玩家的按键移动
S_ID_NO_PLAYER_MOVE = 0
end
#=============================================================================
# ○ 通用
#=============================================================================
module ESAS
#--------------------------------------------------------------------------
# ● 执行eval
#--------------------------------------------------------------------------
def self.eval(str, params = {})
s = $game_switches; v = $game_variables
e = params[:event]; es = $game_map.events
pl = $game_player
begin
eval(str)
rescue
p "在执行ESAS中的eval时发生错误!"
p " - 报错信息:#{$!}"
p " - 扩展信息:" + params[:log] if params[:log]
return false
end
end
#--------------------------------------------------------------------------
# ● 获取指定行走图角色的对象
#--------------------------------------------------------------------------
def self.get_chara(id = -1)
if id == -1
return $game_player
elsif id > 0
return $game_map.events[id]
elsif id < 0
return $game_player.followers[id.abs - 2]
end
end
#--------------------------------------------------------------------------
# ● 获取指定行走图角色的精灵
#--------------------------------------------------------------------------
def self.get_chara_sprite(id = -1)
if SceneManager.scene_is?(Scene_Map)
charas_s = SceneManager.scene.spriteset.character_sprites
chara = get_chara(id)
charas_s.each { |s| return s if s.character == chara }
end
return nil
end
#--------------------------------------------------------------------------
# ● 获取指定事件页的指令列表
# (参数均与编辑器中显示的数字保持一致)
#--------------------------------------------------------------------------
def self.get_event_list(map_id, event_id, page_id = nil)
event = nil
map_id = $game_map.map_id if map_id.nil? || map_id == 0
# 公共事件
if map_id < 0
event = $data_common_events[event_id]
return event.list
end
# 地图上的事件
if map_id != $game_map.map_id
map = ESAS.get_map_data(map_id)
event_data = map.events[event_id] rescue return
return if event_data == nil
event = Game_Event.new(map_id, event_data)
else
event = $game_map.events[event_id] rescue return
end
page = nil
if page_id == nil || page_id == 0
page = event.find_proper_page
else
page = event.event.pages[page_id-1] rescue return
end
return page.list
end
#--------------------------------------------------------------------------
# ● 获取地图数据
#--------------------------------------------------------------------------
def self.get_map_data(map_id)
EAGLE_COMMON.cache_load_map(map_id)
end
end
#=============================================================================
# ○ 更新
#=============================================================================
module ESAS
#--------------------------------------------------------------------------
# ● 每帧更新
#--------------------------------------------------------------------------
def self.update
update_anims
update_pops
end
end
class Scene_Base
#--------------------------------------------------------------------------
# ● 绑定每帧更新
#--------------------------------------------------------------------------
alias eagle_esas_scenebase_update_basic update_basic
def update_basic
eagle_esas_scenebase_update_basic
ESAS.update
end
end
#=============================================================================
# ○ 核心设置 - 执行指定事件页
#=============================================================================
module ESAS
#--------------------------------------------------------------------------
# ● 管理事件页执行的类
#--------------------------------------------------------------------------
class Process_Event
attr_reader :params, :data
#--------------------------------------------------------------------------
# ● 初始化
#--------------------------------------------------------------------------
def initialize(params = {}, params_data = {})
reset(params)
reset_data(params_data)
@interpreter = Game_Interpreter.new(1)
end
#--------------------------------------------------------------------------
# ● 重置
#--------------------------------------------------------------------------
def reset(params)
@params = params
#@params[:mid] ||= nil # 设置指定事件页的位置 - 地图ID
#@params[:eid] ||= nil # 事件ID
#@params[:pid] ||= nil # 事件页ID(与编辑器中一致)
@params[:abort] ||= true # 是否可以被强制中止
#@params[:key] ||= nil # 按键呼叫(玩家用)
@params[:enable] ||= true # 是否可以按键
@params[:active] = false # 是否已经在执行
@params[:repeat] ||= false #是否自动循环执行(在执行run后,自动循环)
end
#--------------------------------------------------------------------------
# ● 重置数据
#--------------------------------------------------------------------------
def reset_data(params)
@data = Process_Event_Data.new
@params.each do |k, v|
@data.method("#{k}=").call(v) rescue nil
end
params.each do |k, v|
@data.method("#{k}=").call(v) rescue nil
end
end
#--------------------------------------------------------------------------
# ● 开始执行
#--------------------------------------------------------------------------
def run
list = ESAS.get_event_list(@params[:mid], @params[:eid], @params[:pid])
return if list.nil?
@params[:active] = true
@interpreter.bind_esas(@data)
event_id = 0
event_id = @data.chara.id if @data.chara
@interpreter.setup(list, event_id)
if $imported["EAGLE-EventInteractEX"]
@interpreter.event_interact_search(@params[:sym]) if @params[:sym]
end
end
#--------------------------------------------------------------------------
# ● 在更新?
#--------------------------------------------------------------------------
def running?
@interpreter.running?
end
#--------------------------------------------------------------------------
# ● 终止事件
#--------------------------------------------------------------------------
def abort
return false if !@params[:abort]
@interpreter.clear
return true
end
#--------------------------------------------------------------------------
# ● 每帧更新
#--------------------------------------------------------------------------
def update
@interpreter.update
f = running?
run if @params[:repeat] && @params[:active] && !f
@params[:active] = f
update_key if @params[:key]
end
#--------------------------------------------------------------------------
# ● 更新按键判定
#--------------------------------------------------------------------------
def update_key
return if @params[:active]
run if @params[:enable] && Input.trigger?(@params[:key])
end
end
#--------------------------------------------------------------------------
# ● 存储事件页执行环境等信息的类
# 用于传递给 Game_Interpreter类中使用
#--------------------------------------------------------------------------
class Process_Event_Data
attr_accessor :mid, :eid, :pid, :chara, :x, :y
def initialize
@mid = @eid = @pid = nil
@chara = nil # 如果来源为 行走图角色 就存储Game_Character对象
@x = @y = nil # 当前处理所在的地图位置,当来源为动画时,需要靠其获得显示位置
end
end
end
class Game_Interpreter
attr_reader :esas, :event_id
#--------------------------------------------------------------------------
# ● 绑定的事件
#--------------------------------------------------------------------------
def event
$game_map.events[@event_id]
end
#--------------------------------------------------------------------------
# ● 绑定信息类
#--------------------------------------------------------------------------
def bind_esas(data)
@esas = data
end
#--------------------------------------------------------------------------
# ● 脚本
#--------------------------------------------------------------------------
alias eagle_esas_command_355 command_355
def command_355
event = $game_map.events[self.event_id]
begin
eagle_esas_command_355
rescue
p "#{@map_id}号地图#{@event_id}号事件第#{@index+1}行指令eval出错!"
p " - 报错信息:#{$!}"
if @esas_iter_ids
p " - 出错指令位于 esas_iter 与 esas_iter_end 的范围内!"
end
if @esas
p " - 当前出错事件是 ESAS 所执行的事件页!"
p " - 谁造成了这次调用:#{@esas.chara.id}(-1为玩家,正数为对应事件)" if @esas.chara
p " - 谁实际进行这次调用:#{self.event_id}(-1为玩家,正数为对应事件)"
p " - 被调用的事件页:#{@esas.mid}号地图#{@esas.eid}号事件第#{@esas.pid}页"
p " - 报错的指令行数:#{@index+1}"
end
return false
end
end
end
class Game_CharacterBase
attr_reader :tmp
#--------------------------------------------------------------------------
# ● 初始化公有成员变量
#--------------------------------------------------------------------------
alias eagle_esas_charabase_init_public_members init_public_members
def init_public_members
eagle_esas_charabase_init_public_members
init_esas_members
end
#--------------------------------------------------------------------------
# ● 初始化ESAS变量
#--------------------------------------------------------------------------
def init_esas_members
@tmp = {}
@freeze = false
@freeze_count = 0
@no_esas = false
@no_esas_count = 0
end
#--------------------------------------------------------------------------
# ● 冻结/硬直/阻止自身发起的ESAS处理
#--------------------------------------------------------------------------
def freeze(count = 0)
@freeze = true
@freeze_count = count if count > 0
end
#--------------------------------------------------------------------------
# ● 冻结/硬直?
#--------------------------------------------------------------------------
def freeze?
@freeze
end
#--------------------------------------------------------------------------
# ● 解冻
#--------------------------------------------------------------------------
def unfreeze
@freeze = false
end
#--------------------------------------------------------------------------
# ● 开始无敌帧/阻止受到的ESAS处理
#--------------------------------------------------------------------------
def no_esas(count = 0)
@no_esas = true
@no_esas_count = count if count > 0
end
#--------------------------------------------------------------------------
# ● 无敌帧中?
#--------------------------------------------------------------------------
def no_esas?
@no_esas
end
#--------------------------------------------------------------------------
# ● 无敌帧结束
#--------------------------------------------------------------------------
def re_esas
@no_esas = false
end
#--------------------------------------------------------------------------
# ● 每帧更新
#--------------------------------------------------------------------------
alias eagle_esas_charabase_update update
def update
update_freeze_count
update_no_esas_count
eagle_esas_charabase_update
end
#--------------------------------------------------------------------------
# ● 更新冻结倒计时
#--------------------------------------------------------------------------
def update_freeze_count
return if @freeze_count <= 0
@freeze_count -= 1
unfreeze if freeze? && @freeze_count == 0
end
#--------------------------------------------------------------------------
# ● 更新无敌帧倒计时
#--------------------------------------------------------------------------
def update_no_esas_count
return if @no_esas_count <= 0
@no_esas_count -= 1
re_esas if no_esas? && @no_esas_count == 0
end
end
class Game_Character < Game_CharacterBase
attr_reader :esas_event
#--------------------------------------------------------------------------
# ● 获取名称
#--------------------------------------------------------------------------
def name
""
end
#--------------------------------------------------------------------------
# ● 获取注释
#--------------------------------------------------------------------------
def note
""
end
#--------------------------------------------------------------------------
# ● 初始化ESAS变量
#--------------------------------------------------------------------------
def init_esas_members
super
data = { :chara => self, :x => self.x, :y => self.y }
@esas_event = ESAS::Process_Event.new({}, data)
end
#--------------------------------------------------------------------------
# ● 执行ESAS的事件
#--------------------------------------------------------------------------
def run_event(params)
return if freeze?
if @esas_event.running?
return if !@esas_event.abort # 不可以强制中止,就取消当前事件的执行
end
if params.is_a?(String) && $imported["EAGLE-EventInteractEX"]
params = EAGLE_COMMON.parse_tags(params)
params[:mid] = params[:mid].to_i if params[:mid]
params[:eid] = params[:eid].to_i
params[:pid] = params[:pid].to_i if params[:pid]
params[:abort] = false if params[:abort] == "false"
end
@esas_event.reset(params)
@esas_event.run
end
#--------------------------------------------------------------------------
# ● 存在ESAS的事件更新?
#--------------------------------------------------------------------------
def esas_running?
@esas_event.running?
end
#--------------------------------------------------------------------------
# ● 终止ESAS的事件更新
#--------------------------------------------------------------------------
def esas_abort(count = 0)
if @esas_event.abort
freeze(count)
return true
end
return false
end
#--------------------------------------------------------------------------
# ● 每帧更新
#--------------------------------------------------------------------------
def update
super
@esas_event.update
end
#--------------------------------------------------------------------------
# ● 冻结
#--------------------------------------------------------------------------
def freeze(count = 0)
super
# 停止移动
@move_route_forcing = false
restore_move_route
end
#--------------------------------------------------------------------------
# ● 空事件?
#--------------------------------------------------------------------------
def empty?
return false
end
end
class Game_Player < Game_Character
attr_reader :id, :esas_keys
#--------------------------------------------------------------------------
# ● 初始化
#--------------------------------------------------------------------------
alias eagle_esas_player_init initialize
def initialize
eagle_esas_player_init
@id = -1
end
#--------------------------------------------------------------------------
# ● 初始化ESAS变量
#--------------------------------------------------------------------------
def init_esas_members
super
@esas_keys = {}
#~ set_key(:A, {:mid => 1, :eid => 9}) # TEST
end
#--------------------------------------------------------------------------
# ● 获取名称
#--------------------------------------------------------------------------
def name
actor.name
end
#--------------------------------------------------------------------------
# ● 获取注释
#--------------------------------------------------------------------------
def note
actor.note
end
#--------------------------------------------------------------------------
# ● 由方向键移动
#--------------------------------------------------------------------------
alias eagle_esas_player_move_by_input move_by_input
def move_by_input
return if freeze? || $game_switches[ESAS::S_ID_NO_PLAYER_MOVE]
eagle_esas_player_move_by_input
end
#--------------------------------------------------------------------------
# ● 每帧更新
#--------------------------------------------------------------------------
alias eagle_esas_player_update update
def update
eagle_esas_player_update
update_keys
end
#--------------------------------------------------------------------------
# ● 每帧更新
#--------------------------------------------------------------------------
def update_keys
@esas_keys.each { |key, process| process.update }
end
#--------------------------------------------------------------------------
# ● 玩家存在按键事件执行?
#--------------------------------------------------------------------------
def esas_running?
super || @esas_keys.any? { |key, process| process.running? }
end
#--------------------------------------------------------------------------
# ● 终止玩家的全部按键事件
# count 为若打断成功可产生的硬直时间
#--------------------------------------------------------------------------
def esas_abort(count = 0)
f = super(count)
flag = false
@esas_keys.each { |key, process|
flag = true if process.abort
}
freeze(count) if flag
return f || flag
end
#--------------------------------------------------------------------------
# ● 绑定按键对应的事件
#--------------------------------------------------------------------------
def set_key(key, params)
if params.is_a?(String) && $imported["EAGLE-EventInteractEX"]
params = EAGLE_COMMON.parse_tags(params)
params[:mid] = params[:mid].to_i if params[:mid]
params[:eid] = params[:eid].to_i
params[:pid] = params[:pid].to_i if params[:pid]
params[:abort] = false if params[:abort] == "false"
end
params[:key] = key
data = { :chara => self, :x => self.x, :y => self.y }
@esas_keys[key] = ESAS::Process_Event.new(params, data)
end
#--------------------------------------------------------------------------
# ● 呼叫按键对应的事件
#--------------------------------------------------------------------------
def call_key(key)
data = @esas_keys[key]
data.run if data
end
end
class Game_Follower < Game_Character
attr_reader :id
#--------------------------------------------------------------------------
# ● 初始化
#--------------------------------------------------------------------------
alias eagle_esas_follower_init initialize
def initialize(member_index, preceding_character)
eagle_esas_follower_init(member_index, preceding_character)
@id = -member_index
end
#--------------------------------------------------------------------------
# ● 获取名称
#--------------------------------------------------------------------------
def name
actor.name
end
#--------------------------------------------------------------------------
# ● 获取注释
#--------------------------------------------------------------------------
def note
actor.note
end
end
class Game_Event < Game_Character
#--------------------------------------------------------------------------
# ● 初始化ESAS变量
#--------------------------------------------------------------------------
def init_esas_members
super
data = { :chara => self, :x => self.x, :y => self.y }
@esas_ai_event = ESAS::Process_Event.new({}, data)
end
#--------------------------------------------------------------------------
# ● 获取名称
#--------------------------------------------------------------------------
def name
@event.name
end
#--------------------------------------------------------------------------
# ● 获取当前事件页的头部注释
#--------------------------------------------------------------------------
def note
EAGLE_COMMON.event_comment_head(@list)
end
#--------------------------------------------------------------------------
# ● 冻结
#--------------------------------------------------------------------------
def freeze(count = 0)
super
# 停止事件触发
@locked = true
end
#--------------------------------------------------------------------------
# ● 解冻
#--------------------------------------------------------------------------
def unfreeze
super
@locked = false
end
#--------------------------------------------------------------------------
# ● 自动移动的更新
#--------------------------------------------------------------------------
alias eagle_esas_event_update_self_movement update_self_movement
def update_self_movement
return if esas_running?
return if freeze? || $game_switches[ESAS::S_ID_NO_EVENT_MOVE]
eagle_esas_event_update_self_movement
end
#--------------------------------------------------------------------------
# ● 事件启动
#--------------------------------------------------------------------------
alias eagle_esas_event_start start
def start
return if freeze? || esas_running?
eagle_esas_event_start
end
#--------------------------------------------------------------------------
# ● 当前位于空事件页?
# 事件指令列表为空 且 事件图像为空
#--------------------------------------------------------------------------
def esas_empty?
return true if @erased
if @page.nil? || (@page.list.size == 1 && @page.graphic.character_name == "")
return true
end