R3EXS 1.0.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/R3EXS/utils.rb CHANGED
@@ -1,971 +1,1081 @@
1
- # frozen_string_literal: true
2
-
3
- require 'oj'
4
- require_relative 'RGSS3_R3EXS'
5
-
6
- module R3EXS
7
-
8
- # 工具模块
9
- # 主要用来提供一些读取,写入,转换等功能
10
- module Utils
11
-
12
- # 用来匹配读取的 rvdata2 文件名
13
- RVDATA2_FILE_NAME =
14
- [
15
- /\AActors\.rvdata2\z/,
16
- /\AAnimations\.rvdata2\z/,
17
- /\AArmors\.rvdata2\z/,
18
- /\AClasses\.rvdata2\z/,
19
- /\ACommonEvents\.rvdata2\z/,
20
- /\AEnemies\.rvdata2\z/,
21
- /\AItems\.rvdata2\z/,
22
- /\AMap\d{3}\.rvdata2\z/,
23
- /\AMapInfos\.rvdata2\z/,
24
- /\AScripts\.rvdata2\z/,
25
- /\ASkills\.rvdata2\z/,
26
- /\AStates\.rvdata2\z/,
27
- /\ASystem\.rvdata2\z/,
28
- /\ATilesets\.rvdata2\z/,
29
- /\ATroops\.rvdata2\z/,
30
- /\AWeapons\.rvdata2\z/
31
- ]
32
-
33
- # 用来匹配读取的 JSON 文件名
34
- JSON_FILE_NAME =
35
- [
36
- /\AActors\.json\z/,
37
- /\AAnimations\.json\z/,
38
- /\AArmors\.json\z/,
39
- /\AClasses\.json\z/,
40
- /\ACommonEvents\.json\z/,
41
- /\AEnemies\.json\z/,
42
- /\AItems\.json\z/,
43
- /\AMap\d{3}\.json\z/,
44
- /\AMapInfos\.json\z/,
45
- /\ASkills\.json\z/,
46
- /\AStates\.json\z/,
47
- /\ASystem\.json\z/,
48
- /\ATilesets\.json\z/,
49
- /\ATroops\.json\z/,
50
- /\AWeapons\.json\z/
51
- ]
52
-
53
- # 用来匹配读取的文件名到对应的R3EXS的类
54
- FILE_BASENAME_TO_CLASS_R3EXS = {
55
- /\AActors\z/ => R3EXS::Actor,
56
- /\AAnimations\z/ => R3EXS::Animation,
57
- /\AArmors\z/ => R3EXS::Armor,
58
- /\AClasses\z/ => R3EXS::Class,
59
- /\ACommonEvents\z/ => R3EXS::CommonEvent,
60
- /\AEnemies\z/ => R3EXS::Enemy,
61
- /\AItems\z/ => R3EXS::Item,
62
- /\AMap\d{3}\z/ => R3EXS::Map,
63
- /\AMapInfos\z/ => R3EXS::MapInfo,
64
- /\ASkills\z/ => R3EXS::Skill,
65
- /\AStates\z/ => R3EXS::State,
66
- /\ASystem\z/ => R3EXS::System,
67
- /\ATilesets\z/ => R3EXS::Tileset,
68
- /\ATroops\z/ => R3EXS::Troop,
69
- /\AWeapons\z/ => R3EXS::Weapon
70
- }
71
-
72
- # 用来匹配读取的文件名到对应的RPG的类
73
- FILE_BASENAME_TO_CLASS_RPG = {
74
- /\AActors\z/ => RPG::Actor,
75
- /\AAnimations\z/ => RPG::Animation,
76
- /\AArmors\z/ => RPG::Armor,
77
- /\AClasses\z/ => RPG::Class,
78
- /\ACommonEvents\z/ => RPG::CommonEvent,
79
- /\AEnemies\z/ => RPG::Enemy,
80
- /\AItems\z/ => RPG::Item,
81
- /\AMap\d{3}\z/ => RPG::Map,
82
- /\AMapInfos\z/ => RPG::MapInfo,
83
- /\ASkills\z/ => RPG::Skill,
84
- /\AStates\z/ => RPG::State,
85
- /\ASystem\z/ => RPG::System,
86
- /\ATilesets\z/ => RPG::Tileset,
87
- /\ATroops\z/ => RPG::Troop,
88
- /\AWeapons\z/ => RPG::Weapon
89
- }
90
-
91
- # 事件指令的命令名称
92
- EVENT_COMMANDS = {
93
- 0 => 'Empty',
94
-
95
- =begin
96
- [string(Face Graphic name)]---[int(Face Graphic index)]---[int:{0:Normal Window, 1:Dim Background, 2:Transparent}]---[int:{0:Top, 1:Middle, 2:Bottom}]---END
97
- =end
98
- 101 => 'ShowTextAttributes',
99
-
100
- =begin
101
- [Array<string>(Choices Array)]---[int:{0:Disallow, 1:Choice 1, 2:Choice 2, 3:Choice 3, 4:Choice 4, 5:Branch}(When Cancel)]---END
102
- =end
103
- 102 => 'ShowChoices',
104
-
105
- =begin
106
- [int(Variable for Number)]---[int:{1~8}(Digits)]---END
107
- =end
108
- 103 => 'InputNumber',
109
-
110
- =begin
111
- [int(Variable for Item ID)]---END
112
- =end
113
- 104 => 'SelectKeyItem',
114
-
115
- =begin
116
- [int:{1~8}(Speed)]---[bool(No Fast Forward)]---END
117
- =end
118
- 105 => 'ShowScrollingTextAttributes',
119
-
120
- =begin
121
- [string]---END
122
- =end
123
- 108 => 'Comment',
124
-
125
- =begin
126
- |--[int:0(Switch)]---[int(Switch ID)]---[int{0:ON, 1:OFF}]---END
127
- |
128
- | |--[int:0(Compare to Constant)]---[int(Number)]-------|
129
- |--[int:1(Variable)]---[int(Variable ID)]--| |--[int{0:==, 1:>=, 2:<=, 3:>, 4:<, 5:!=}]---END
130
- | |--[int:1(Compare to Variable)]---[int(Variable ID)]--|
131
- |
132
- |--[int:2(Self Switch)]---[string{'A', 'B', 'C', 'D'}]---[int{0:ON, 1:OFF}]---END
133
- |
134
- |--[int:3(Timer)]---[int:{0~5999}(sec)]---[int{0:>=, 1:<=}]---END
135
- |
136
- | |--[int:0(In the Party)]---END
137
- | |
138
- | |--[int:1(Name)]---[string]---END
139
- | |
140
- | |--[int:2(Class)]---[int(Class ID)]---END
141
- | |
142
- |--[int:4(Actor)]---[int(Actor ID)]--------|--[int:3(Skill)]---[int(Skill ID)]---END
143
- | |
144
- | |--[int:4(Weapon)]---[int(Wwapon ID)]---END
145
- | |
146
- | |--[int:5(Armor)]---[int(Armor ID)]---END
147
- | |
148
- | |--[int:6(State)]---[int(State ID)]---END
149
- |
150
- | |--[int:0(Appeared)---END
151
- |--[int:5(Enemy)]---[int(Enemy ID)]--------|
152
- | |--[int:1(State)]---[int(State ID)]---END
153
- |
154
- |--[int:6(Character)]---[int:{-1:Player, 0:This event, 1:EV001, ...}]---[int:{2:Down, 4:Left, 6:Right, 8:Up}]---END
155
- |
156
- |--[int:7(Gold)]---[int(Money)]---[int{0:>=, 1:<=, 2:<}]---END
157
- |
158
- |--[int:8(Item)]---[int(Item ID)]---END
159
- |
160
- |--[int:9(Weapon)]---[int(Weapon ID)]---[bool(Include Equipments)]---END
161
- |
162
- |--[int:10(Armor)]---[int(Armor ID)]---[bool(Include Equipments)]---END
163
- |
164
- |--[int:11(Button)]---[int:{2:Down, 4:Left, 6:Right, 8:Up, 11:A, 12:B, 13:C, 14:X, 15:Y, 16:Z, 17:L, 18:R}]---END
165
- |
166
- |--[int:12(Script)]---[string]---END
167
- |
168
- |--[int:13(Vehicle)]---[int:{0:Boat, 1:Ship, 2:Airship}]---END
169
- =end
170
- 111 => 'ConditionalBranch',
171
- 112 => 'Loop',
172
- 113 => 'BreakLoop',
173
- 115 => 'ExitEventProcessing',
174
-
175
- =begin
176
- [int(Common Event ID)]---END
177
- =end
178
- 117 => 'CallCommonEvent',
179
-
180
- =begin
181
- [string]---END
182
- =end
183
- 118 => 'Label',
184
-
185
- =begin
186
-
187
- [string]---END
188
- =end
189
- 119 => 'JumpToLabel',
190
-
191
- =begin
192
- [int(Switch Begin ID)]---[int(Switch End ID)]---[int:{0:ON, 1:OFF}]---END
193
- =end
194
- 121 => 'ControlSwitches',
195
-
196
- =begin
197
- |--[int:0(Constant)]---[int(Number)]---END
198
- |
199
- |--[int:1(Variable)]---[int(Variable ID)]---END
200
- |
201
- |--[int:2(Random)]---[int(Min)]---[int(Max)]---END
202
- |
203
- | |--[int:{0:Item, 1:Weapon, 2:Armor}]---[int(Corresponded Item ID)]---[int:0]---END
204
- | |
205
- [int(Variable Begin ID)]---[int(Variable End ID)]---[int:{0:Set, 1:Add, 2:Sub, 3:Mul, 4:Div, 5:Mod}]--| |--[int:3(Actor)]---[int:(Actor ID)]---[int:{0:Level, 1:EXP, 2:HP, 3:MP, 4:MHP, 5:MMP, 6:ATK, 7:DEF, 8:MAT, 9:MDF, 10:AGI, 11:LUK}]---END
206
- | |
207
- | |--[int:4(Enemy)]---[int:(Enemy ID)]---[int:{0:HP, 1:MP, 2:MHP, 3:MMP, 4:ATK, 5:DEF, 6:MAT, 7:MDF, 8:AGI, 9:LUK}]---END
208
- |--[int:3(Game Data)]--|
209
- | |--[int:5(Character)]---[int:{-1:Player, 0:This Event, 1:EV001, ...}]---[int:{0:Map X, 1:Map Y, 2:Direction, 3:Screen X ,4:Screen Y}]---END
210
- | |
211
- | |--[int:6(Party)]---[int:{0~7}(Member ID)]---[int:0]---END('s Actor ID)
212
- | |
213
- | |--[int:7(Other)]---[int:{0(Map ID), 1(Party Members), 2(Gold), 3(Steps), 4(Play Time), 5(Timer), 6(Save Count), 7(Battle Count)}]---[int:0]---END
214
- |
215
- |--[int:4(Scripts)]---[string]---END
216
- =end
217
- 122 => 'ControlVariables',
218
-
219
- =begin
220
- [string:{'A', 'B', 'C', 'D'}(Self Switch Name)]---[int:{0:ON, 1:OFF}]---END
221
- =end
222
- 123 => 'ControlSelfSwitch',
223
-
224
- =begin
225
- [int:{0:Start, 1:Stop}]---[int:{0~5999}(sec)]---END
226
- =end
227
- 124 => 'ControlTimer',
228
-
229
- =begin
230
- |--[int:0(Constant)]---[int:{0~9999999}(Number)]---END
231
- [int:{0:Increase, 1:Decrease}]--|
232
- |--[int:1(Variable)]---[int(Variable ID)]---END
233
- =end
234
- 125 => 'ChangeGold',
235
-
236
- =begin
237
- |--[int:0(Constant)]---[int:{0~9999999}(Number)]---END
238
- [int(Item ID)]---[int:{0:Increase, 1:Decrease}]--|
239
- |--[int:1(Variable)]---[int(Variable ID)]---END
240
- =end
241
- 126 => 'ChangeItems',
242
-
243
- =begin
244
- |--[int:0(Constant)]---[int:{0~9999999}(Number)]--|
245
- |--[int:0(Increase)]--| |--[bool:false(Include Equipment)]---END
246
- | |--[int:1(Variable)]---[int(Variable ID)]---------|
247
- [int(Weapon ID)]--|
248
- | |--[int:0(Constant)]---[int:{0~9999999}(Number)]--|
249
- |--[int:1(Decrease)]--| |--[bool(Include Equipment)]---END
250
- |--[int:1(Variable)]---[int(Variable ID)]---------|
251
- =end
252
- 127 => 'ChangeWeapons',
253
-
254
- =begin
255
- |--[int:0(Constant)]---[int:{0~9999999}(Number)]--|
256
- |--[int:0(Increase)]--| |--[bool:false(Include Equipment)]---END
257
- | |--[int:1(Variable)]---[int(Variable ID)]---------|
258
- [int(Armor ID)]--|
259
- | |--[int:0(Constant)]---[int:{0~9999999}(Number)]--|
260
- |--[int:1(Decrease)]--| |--[bool(Include Equipment)]---END
261
- |--[int:1(Variable)]---[int(Variable ID)]---------|
262
- =end
263
- 128 => 'ChangeArmor',
264
-
265
- =begin
266
- [int(Actor ID)]---[int:{0:Add, 1:Remove}]---[int:{0:NO, 1:YES}(Initialize)]---END
267
- =end
268
- 129 => 'ChangePartyMember',
269
-
270
- =begin
271
- [RPG::BGM]---END
272
- =end
273
- 132 => 'ChangeBattleBGM',
274
-
275
- =begin
276
- [RPG::ME]---END
277
- =end
278
- 133 => 'ChangeBattleEndME',
279
-
280
- =begin
281
- [int:{0:Disable, 1:Enable}]---END
282
- =end
283
- 134 => 'ChangeSaveAccess',
284
-
285
- =begin
286
- [int:{0:Disable, 1:Enable}]---END
287
- =end
288
- 135 => 'ChangeMenuAccess',
289
-
290
- =begin
291
- [int:{0:Disable, 1:Enable}]---END
292
- =end
293
- 136 => 'ChangeEncounter',
294
-
295
- =begin
296
- [int:{0:Disable, 1:Enable}]---END
297
- =end
298
- 137 => 'ChangeFormationAccess',
299
-
300
- =begin
301
- [RPG::Tone]---END
302
- =end
303
- 138 => 'ChangeWindowColor',
304
-
305
- =begin
306
- |--[int:0(Direct Designation)]---[int(Map ID)]---[int(Map X)]---[int(Map Y)]-------------------------------------------------------------------------------------|
307
- | |--[int:{0:Retain, 2:Down, 4:Left, 6:Right, 8:Up}(Direction)]---[int:{0:Normal, 1:White, 2:None}(Fade)]---END
308
- |--[int:1(Designation with Variables)]---[int(Map ID Corresponded Variable ID)]---[int(Map X Corresponded Variable ID)]---[int(Map Y Corresponded Variable ID)]--|
309
- =end
310
- 201 => 'TransferPlayer',
311
-
312
- =begin
313
- |--[int:0(Direct Designation)]---[int(Map ID)]---[int(Map X)]---[int(Map Y)]---END
314
- [int:{0:Boat, 1:Ship, 2:Airship}]--|
315
- |--[int:1(Designation with Variables)]---[int(Map ID Corresponded Variable ID)]---[int(Map X Corresponded Variable ID)]---[int(Map Y Corresponded Variable ID)]---END
316
- =end
317
- 202 => 'SetVehicleLocation',
318
-
319
- =begin
320
- |--[int:0(Direct Designation)]---[int(Map X)]---[int(Map Y)]------------------------------------------------------------|
321
- | |
322
- [int:{0:This Event, 1:EV001, ...}]----------|--[int:1(Designation with Variables)]---[int(Map X Corresponded Variable ID)]---[int(Map Y Corresponded Variable ID)]--|--[int:{0:Retain, 2:Down, 4:Left, 6:Right, 8:Up}(Direction)]---END
323
- | |
324
- |--[int:2(Exchange with Another Event)]---[int(Exchanged Event ID)]---[int:0]----------------------------------------- |
325
- =end
326
- 203 => 'SetEventLocation',
327
-
328
- =begin
329
- [int:{2:Down, 4:Left, 6:Right, 8:Up}]---[int:{0~100}(Distance)]---[int:{1:1/8 Speed, 2:1/4 Speed, 3:1/2 Speed, 4:Normal, 5:2 Speed, 6:4 Speed}]---END
330
- =end
331
- 204 => 'ScrollMap',
332
-
333
- =begin
334
- [int:{-1:Player, 0:This Event, 1:EV001, ...}]---[RPG::MoveRoute(45 is Script)]---END
335
- =end
336
- 205 => 'SetMoveRoute',
337
-
338
- =begin
339
- END
340
- =end
341
- 206 => 'GetSwitchVehicle',
342
-
343
- =begin
344
- [int:{0:ON, 1:OFF}]---END
345
- =end
346
- 211 => 'ChangeTransparency',
347
-
348
- =begin
349
- [int:{-1:Player, 0:This Event, 1:EV001, ...}]---[int(Animation ID)]---[bool(Wait for Completion)]---END
350
- =end
351
- 212 => 'ShowAnimation',
352
-
353
- =begin
354
- [int:{-1:Player, 0:This Event, 1:EV001, ...}]---[int(Ballon Icon ID)]---[bool(Wait for Completion)]---END
355
- =end
356
- 213 => 'ShowBalloonIcon',
357
- 214 => 'EraseEvent',
358
-
359
- =begin
360
- [int:{0:ON, 1:OFF}]---END
361
- =end
362
- 216 => 'ChangePlayerFollowers',
363
- 217 => 'GatherFollowers',
364
- 221 => 'FadeoutScreen',
365
- 222 => 'FadeinScreen',
366
-
367
- =begin
368
- [RPG::Tone]---[int:{0~600}(Time 1/60 sec)]---[bool(Wait for Completion)]---END
369
- =end
370
- 223 => 'TintScreen',
371
-
372
- =begin
373
- [RPG::Color]---[int:{0~600}(Time 1/60 sec)]---[bool(Wait for Completion)]---END
374
- =end
375
- 224 => 'FlashScreen',
376
-
377
- =begin
378
- [int:{1~9}(Power)]---[int:{1~9}(Speed)]---[int:{0~600}(Time 1/60 sec)]---[bool(Wait for Completion)]---END
379
- =end
380
- 225 => 'ShakeScreen',
381
-
382
- =begin
383
- [int:{0~999}(Time 1/60 sec)]---END
384
- =end
385
- 230 => 'Wait',
386
-
387
- =begin
388
- |--[int:0(Constant)]---[int:{-9999~9999}(Map X)]---[int:{-9999~9999}(Map Y)]--------------------------|
389
- [int:{1~100}(Number)]---[string(Picture Graphic Name)]---[int:{0:Upper Left, 1:Center}(Origin)]--| |--[int:{0~2000}(Width %)]---[int:{0~2000}(Height %)]---[int:{0~255}(Opacity)]---[int:{0:Normal, 1:Add, 2:Sub}]---END
390
- |--[int:1(Variable)]---[int(Map X Corresponded Variable ID)]---[int(Map Y Corresponded Variable ID)]--|
391
- =end
392
- 231 => 'ShowPicture',
393
-
394
- =begin
395
- |--[int:0(Constant)]---[int:{-9999~9999}(Map X)]---[int:{-9999~9999}(Map Y)]--------------------------|
396
- [int:{1~100}(Number)]---[int:{0:Upper Left, 1:Center}(Origin)]--| |--[int:{0~2000}(Width %)]---[int:{0~2000}(Height %)]---[int:{0~255}(Opacity)]---[int:{0:Normal, 1:Add, 2:Sub}]---[int:{0~600}(Time 1/60 sec)]---[bool(Wait for Completion)]---END
397
- |--[int:1(Variable)]---[int(Map X Corresponded Variable ID)]---[int(Map Y Corresponded Variable ID)]--|
398
- =end
399
- 232 => 'MovePicture',
400
-
401
- =begin
402
- [int:{1~100}(Number)]-[int:{-90~90}(Speed)]--END
403
- =end
404
- 233 => 'RotatePicture',
405
-
406
- =begin
407
- [int:{1~100}(Number)]---[RPG::Tone]---[int:{0~600}(Time 1/60 sec)]---[bool(Wait for Completion)]---END
408
- =end
409
- 234 => 'TintPicture',
410
-
411
- =begin
412
- [int:{1~100}(Number)]---END
413
- =end
414
- 235 => 'ErasePicture',
415
-
416
- =begin
417
- [string:{":none", ":rain", ":storm", ":snow"}]---[int:{0~9}(Power)]---[int:{0~600}(Time 1/60 sec)]---[bool(Wait for Completion)]---END
418
- =end
419
- 236 => 'SetWeatherEffects',
420
-
421
- =begin
422
- [RPG::BGM]---END
423
- =end
424
- 241 => 'PlayBGM',
425
-
426
- =begin
427
- [int:{1~60}(Time sec)]---END
428
- =end
429
- 242 => 'FadeoutBGM',
430
- 243 => 'SaveBGM',
431
- 244 => 'ReplayBGM',
432
-
433
- =begin
434
- [RPG::BGM]---END
435
- =end
436
- 245 => 'PlayBGS',
437
-
438
- =begin
439
- [int:{1~60}(Time sec)]---END
440
- =end
441
- 246 => 'FadeoutBGS',
442
-
443
- =begin
444
- [RPG::ME]---END
445
- =end
446
- 249 => 'PlayME',
447
-
448
- =begin
449
- [RPG::SE]---END
450
- =end
451
- 250 => 'PlaySE',
452
- 251 => 'StopSE',
453
-
454
- =begin
455
- [string(Movie Name)]---END
456
- =end
457
- 261 => 'PlayMovie',
458
-
459
- =begin
460
- [int:{0:ON, 1:OFF}]---END
461
- =end
462
- 281 => 'ChangeMapNameDisplay',
463
-
464
- =begin
465
- [int(Tileset ID)]---END
466
- =end
467
- 282 => 'ChangeTileset',
468
-
469
- =begin
470
- [string(Floor Picture)]---[string(Wall Picture)]---END
471
- =end
472
- 283 => 'ChangeBattleBack',
473
-
474
- =begin
475
- [string(Distant view Picture)]---[bool(Loop Horizontal)]---[bool(Loop Vertical)]---[int(-32~32)(Horizontal Scroll)]---[int(-32~32)(Vertical Scrool)]---END
476
- =end
477
- 284 => 'ChangeParallaxBack',
478
-
479
- =begin
480
- |--[int:0(Direct Designation)]---[int(Map X)]---[int(Map Y)]---END
481
- [int(Variable for Info)]---[int:{0:Terrain, 1:Event ID, 2:Tile ID(Layer 1), 3:Tile ID(Layer 2), 4:Tile ID(Layer 3), 5:Region ID}(Info Type)]--|
482
- |--[int:1(Designation with Variables)]---[int(Map X Corresponded Variable ID)]---[int(Map Y Corresponded Variable ID)]---END
483
- =end
484
- 285 => 'GetLocationInfo',
485
-
486
- =begin
487
- |--[int:0(Direct Designation)]---[int(Enemy ID)]-----------------------------------|
488
- | |--[bool(Can Escape)]---[bool(Continue Even When Loser)]---END
489
- |--[int:1(Designation with Variables)]---[int(Enemy ID Corresponded Variable ID)]--|
490
- =end
491
- 301 => 'BattleProcessing',
492
-
493
- =begin
494
- |--[int:0(Price: Standard)]---[int:0]------------------|
495
- [int:{0:Item, 1:Weapon, 2:Armor}]---[int(Corresponded Item ID)]--| |--[bool(Purchase Only)]---END
496
- |--[int:1(Price: Specify)]---[int:{0~9999999}(Price)]--|
497
- =end
498
- 302 => 'ShopProcessing',
499
-
500
- =begin
501
- [int(Actor ID)]---[int:{1~16}(Max Characters)]---END
502
- =end
503
- 303 => 'NameInputProcessing',
504
-
505
- =begin
506
- |--[int:0(Constant)]---[int:{1~9999}(Number)]--|
507
- |--[int:0(Increase)]--| |--[bool:false(Allow Knockout)]---END
508
- | |--[int:1(Variable)]---[int(Variable ID)]------|
509
- |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]--|
510
- | | |--[int:0(Constant)]---[int:{1~9999}(Number)]--|
511
- | |--[int:1(Decrease)]--| |--[bool(Allow Knockout)]---END
512
- | |--[int:1(Variable)]---[int(Variable ID)]------|
513
- |
514
- | |--[int:0(Constant)]---[int:{1~9999}(Number)]--|
515
- | |--[int:0(Increase)]--| |--[bool:false(Allow Knockout)]---END
516
- | | |--[int:1(Variable)]---[int(Variable ID)]------|
517
- |--[int:1(Variable)]---[int(Variable ID)]-----------------------|
518
- | |--[int:0(Constant)]---[int:{1~9999}(Number)]--|
519
- |--[int:1(Decrease)]--| |--[bool(Allow Knockout)]---END
520
- |--[int:1(Variable)]---[int(Variable ID)]------|
521
- =end
522
- 311 => 'ChangeHP',
523
-
524
- =begin
525
- |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]--| |--[int:0(Constant)]---[int:{1~9999}(Number)]---END
526
- | |--[int:{0:Increase, 1:Decrease}]--|
527
- |--[int:1(Variable)]---[int(Variable ID)]---------------------| |--[int:1(Variable)]---[int(Variable ID)]---END
528
- =end
529
- 312 => 'ChangeMP',
530
-
531
- =begin
532
- |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]--|
533
- | |--[int:{0:Add, 1:Remove}]---[int(State ID)]---END
534
- |--[int:1(Variable)]---[int(Variable ID)]---------------------|
535
- =end
536
- 313 => 'ChangeState',
537
-
538
- =begin
539
- |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]---END
540
- |
541
- |--[int:1(Variable)]---[int(Variable ID)]---END
542
- =end
543
- 314 => 'RecoverAll',
544
-
545
- =begin
546
- |--[int:0(:Constant)]---[int:{1~9999999}(Number)]--|
547
- |--[int:0(Increase)]--| |--[bool(Show Level Up Message)]---END
548
- | |--[int:1(Variable)]---[int(Variable ID)]----------|
549
- |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]--|
550
- | | |--[int:0(Constant)]---[int:{1~9999999}(Number)]--|
551
- | |--[int:1(Decrease)]--| |--[bool:false(Show Level Up Message)]---END
552
- | |--[int:1(Variable)]------------------------------|
553
- |
554
- | |--[int:0(Constant)]---[int:{1~9999999}(Number)]--|
555
- | |--[int:0(Increase)]--| |--[bool(Show Level Up Message)]---END
556
- | | |--[int:1(Variable)]---[int(Variable ID)]---------|
557
- |--[int:1(Variable)]---[int(Variable ID)]---------------------|
558
- | |--[int:0(Constant)]---[int:{1~9999999}(Number)]--|
559
- |--[int:1(Decrease)]--| |--[bool:false(Show Level Up Message)]---END
560
- |--[int:1(Variable)]---[int(Variable ID)]---------|
561
- =end
562
- 315 => 'ChangeEXP',
563
-
564
- =begin
565
- |--[int:0(Constant)]---[int:{1~98}(Number)]--|
566
- |--[int:0(Increase)]--| |--[bool(Show Level Up Message)]---END
567
- | |--[int:1(Variable)]---[int(Variable ID)]----|
568
- |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]--|
569
- | | |--[int:0(Constant)]---[int:{1~98}(Number)]--|
570
- | |--[int:1(Decrease)]--| |--[bool:false(Show Level Up Message)]---END
571
- | |--[int:1(Variable)]---[int(Variable ID)]----|
572
- |
573
- | |--[int:0(Constant)]---[int:{1~98}(Number)]--|
574
- | |--[int:0(Increase)]--| |--[bool(Show Level Up Message)]---END
575
- | | |--[int:1(Variable)]---[int(Variable ID)]----|
576
- |--[int:1(Variable)]---[int(Variable ID)]---------------------|
577
- | |--[int:0(Constant)]---[int:{1~98}(Number)]--|
578
- |--[int:1(Decrease)]--| |--[bool:false(Show Level Up Message)]---END
579
- |--[int:1(Variable)]---[int(Variable ID)]------|
580
- =end
581
- 316 => 'ChangeLevel',
582
-
583
- =begin
584
- |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]--| |--[int:0(Constant)]---[int:{0~9999999}(Number)]---END
585
- | |--[int:{0:MHP, 1:MMP, 2:ATK, 3:DEF, 4:MAT, 5:MDF, 6:AGI, 7:LUK}]---[int:{0:Increase, 1:Decrease}]--|
586
- |--[int:1(Variable)]---[int(Variable ID)]---------------------| |--[int:1(Variable)]---[int(Variable ID)]---END
587
- =end
588
- 317 => 'ChangeParameters',
589
-
590
- =begin
591
- |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]--|
592
- | |--[int:{0:Learn, 1:Forget}]---[int(Skill ID)]---END
593
- |--[int:1(Variable)]---[int(Variable ID)]---------------------|
594
- =end
595
- 318 => 'ChangeSkills',
596
-
597
- =begin
598
- [int(Actor ID)]---[int:{0:Weapon, 1:Shield, 2:Head, 3:Boby, 4:Accessory}]---[int:{0:None, 1:Equipment 001, ...}(Equipment ID)]---END
599
- =end
600
- 319 => 'ChangeEquipment',
601
-
602
- =begin
603
- [int(Actor ID)]---[string(New Actor Name)]---END
604
- =end
605
- 320 => 'ChangeActorName',
606
-
607
- =begin
608
- [int(Actor ID)]---[int(New Class ID)]---END
609
- =end
610
- 321 => 'ChangeActorClass',
611
-
612
- =begin
613
- [int(Actor ID)]---[string(New Actor walking Picture Name)]---[int(New Actor Walking Picture Index)]---[string(New Actor Portrait Picture Name)]---[int(New Actor Portrait Picture Index)]---END
614
- =end
615
- 322 => 'ChangeActorGraphic',
616
-
617
- =begin
618
- [int:{0:Boat, 1:Ship, 2:Airship}]---[string(New Vehicle Picture Name)]---[int(New Vehicle Picture Index)]---END
619
- =end
620
- 323 => 'ChangeVehicleGraphic',
621
-
622
- =begin
623
- [int(Actor ID)]---[string(New Actor Nickname)]---END
624
- =end
625
- 324 => 'ChangeActorNickname',
626
-
627
- =begin
628
- |--[int:0(Constant)]---[int:{1~999999}(Number)]--|
629
- |--[int:0(Increase)]--| |--[bool:false(Allow Knockout)]---END
630
- | |--[int:1(Variable)]---[int(Variable ID)]--------|
631
- [int:{-1:Entire Troop, 0:Troop 001, ...}]--|
632
- | |--[int:0(Constant)]---[int:{1~999999}(Number)]--|
633
- |--[int:1(Decrease)]--| |--[bool(Allow Knockout)]---END
634
- |--[int:1(Variable)]---[int(Variable ID)]--------|
635
-
636
- =end
637
- 331 => 'ChangeEnemyHP',
638
-
639
- =begin
640
- |--[int:0(Constant)]---[int:{1~9999}(Number)]---END
641
- [int:{-1:Entire Troop, 0:Troop 001, ...}]---[int:{0:Increase, 1:Decrease}]--|
642
- |--[int:1(Variable)]---[int(Variable ID)]---END
643
- =end
644
- 332 => 'ChangeEnemyMP',
645
-
646
- =begin
647
- [int:{-1:Entire Troop, 0:Troop 001, ...}]---[int:{0:Add, 1:Remove}]---[int(State ID)]---END
648
- =end
649
- 333 => 'ChangeEnemyState',
650
-
651
- =begin
652
- [int:{-1:Entire Troop, 0:Troop 001, ...}]---END
653
- =end
654
- 334 => 'EnemyRecoverAll',
655
-
656
- =begin
657
- [int:{-1:Entire Troop, 0:Troop 001, ...}]---END
658
- =end
659
- 335 => 'EnemyAppear',
660
-
661
- =begin
662
- [int(Troop ID)]---[int(Enemy ID)]---END
663
- =end
664
- 336 => 'EnemyTransform',
665
-
666
- =begin
667
- [int:{-1:Entire Troop, 0:Troop 001, ...}]---[int(Animation ID)]---END
668
- =end
669
- 337 => 'ShowBattleAnimation',
670
-
671
- =begin
672
- |--[int:0(Enemy)]---[int(Troop ID)]--|
673
- | |--[int(Skill ID)]---[int:{-2:Last Target, -1:Random, 0:Index 1,...}]---END
674
- |--[int:1(Actor)]---[int(Actor ID)]--|
675
- =end
676
- 339 => 'ForceAction',
677
- 340 => 'AbortBattle',
678
- 351 => 'OpenMenuScreen',
679
- 352 => 'OpenSaveScreen',
680
- 353 => 'GameOver',
681
- 354 => 'ReturnToTitleScreen',
682
-
683
- =begin
684
- [string]---END
685
- =end
686
- 355 => 'Script',
687
-
688
- =begin
689
- [string]---END
690
- =end
691
- 401 => 'ShowText',
692
-
693
- =begin
694
- [int(Choice Index)]---[string(Choice Name)]---END
695
- =end
696
- 402 => 'When',
697
- 403 => 'WhenCancel',
698
- 404 => 'ChoicesEnd',
699
-
700
- =begin
701
- [string]---END
702
- =end
703
- 405 => 'ShowScrollingText',
704
-
705
- =begin
706
- [string]---END
707
- =end
708
- 408 => 'CommentMore',
709
- 411 => 'Else',
710
- 412 => 'BranchEnd',
711
- 413 => 'RepeatAbove',
712
-
713
- =begin
714
- [RPG::MoveCommand(45 is script)]---END
715
- =end
716
- 505 => 'MoveRoute',
717
- 601 => 'IfWin',
718
- 602 => 'IfEscape',
719
- 603 => 'IfLose',
720
- 604 => 'BattleProcessingEnd',
721
-
722
- =begin
723
- |--[int:0(Price: Standard)]---[int:0]---END
724
- [int:{0:Item, 1:Weapon, 2:Armor}]---[int(Corresponded Item ID)]--|
725
- |--[int:1(Price: Specify)]---[int:{0~9999999}(Price)]---END
726
- =end
727
- 605 => 'ShopItem',
728
-
729
- =begin
730
- [string]---END
731
- =end
732
- 655 => 'ScriptMore' }
733
-
734
- # 红色
735
- RED_COLOR = "\e[31m"
736
-
737
- # 绿色
738
- GREEN_COLOR = "\e[32m"
739
-
740
- # 黄色
741
- YELLOW_COLOR = "\e[33m"
742
-
743
- # 蓝色
744
- BLUE_COLOR = "\e[34m"
745
-
746
- # 紫色
747
- MAGENTA_COLOR = "\e[35m"
748
-
749
- # 青色
750
- CYAN_COLOR = "\e[36m"
751
-
752
- # 重置颜色
753
- RESET_COLOR = "\e[0m"
754
-
755
- # 清除行
756
- ESCAPE = "\e[2K"
757
-
758
- # 根据 file_basename 检查 object 的类型在 module_name 中是否正确
759
- #
760
- # @param object [Object] 待检查的对象
761
- # @param file_basename [String] 文件名(不包含扩展名)
762
- # @param is_compact [Boolean] 是否为紧凑模式
763
- # @param module_name [Symbol] 模块名
764
- #
765
- # @raise [RPGTypeError] object 的类型不在 RPG 模块中
766
- # @raise [R3EXSTypeError] object 的类型不在 R3EXS 模块中
767
- # @raise [ModuleNameError] module_name 不是 :RPG 或 :R3EXS
768
- # @raise [FileBaseNameError] file_basename 无法匹配到对应的类
769
- #
770
- # @return [void]
771
- def Utils.check_type(object, file_basename, is_compact, module_name)
772
- case module_name
773
- when :RPG
774
- matched_class = FILE_BASENAME_TO_CLASS_RPG.find { |pattern, _| file_basename =~ pattern }&.last
775
- matched_class or raise FileBaseNameError.new(file_basename), "Invalid file basename: #{file_basename}"
776
- if object.is_a?(Array)
777
- if is_compact
778
- object.compact.all? { |item| item.is_a?(matched_class) } or raise RPGTypeError.new(object), "Invalid Object: #{object}, it's not an Array<#{matched_class}>"
779
- else
780
- object.all? { |item| item.is_a?(matched_class) } or raise RPGTypeError.new(object), "Invalid Object: #{object}, it's not an Array<#{matched_class}>"
781
- end
782
- elsif object.is_a?(Hash)
783
- if is_compact
784
- object.compact.values.all? { |item| item.is_a?(matched_class) } or raise RPGTypeError.new(object), "Invalid Object: #{object}, it's not a Hash<#{matched_class}>"
785
- else
786
- object.values.all? { |item| item.is_a?(matched_class) } or raise RPGTypeError.new(object), "Invalid Object: #{object}, it's not a Hash<#{matched_class}>"
787
- end
788
- else
789
- object.is_a?(matched_class) or raise RPGTypeError.new(object), "Invalid Object: #{object}, it's not a #{matched_class}"
790
- end
791
- when :R3EXS
792
- matched_class = FILE_BASENAME_TO_CLASS_R3EXS.find { |pattern, _| file_basename =~ pattern }&.last
793
- matched_class or raise FileBaseNameError.new(file_basename), "Invalid file basename: #{file_basename}"
794
- if object.is_a?(Array)
795
- if is_compact
796
- object.compact.all? { |item| item.is_a?(matched_class) } or raise R3EXSTypeError.new(object), "Invalid object: #{object}, it's not an Array<#{matched_class}>"
797
- else
798
- object.all? { |item| item.is_a?(matched_class) } or raise R3EXSTypeError.new(object), "Invalid object: #{object}, it's not an Array<#{matched_class}>"
799
- end
800
- elsif object.is_a?(Hash)
801
- if is_compact
802
- object.compact.values.all? { |item| item.is_a?(matched_class) } or raise R3EXSTypeError.new(object), "Invalid object: #{object}, it's not a Hash<#{matched_class}>"
803
- else
804
- object.values.all? { |item| item.is_a?(matched_class) } or raise R3EXSTypeError.new(object), "Invalid object: #{object}, it's not a Hash<#{matched_class}>"
805
- end
806
- else
807
- object.is_a?(matched_class) or raise R3EXSTypeError.new(object), "Invalid object: #{object}, it's not #{matched_class}"
808
- end
809
- else
810
- raise ModuleNameError.new(module_name), "Invalid module name: #{module_name}"
811
- end
812
-
813
- end
814
-
815
- # 将 RPG 中的对象转化为 R3EXS 对象
816
- #
817
- # @param object [Object] 待转化的 RPG 对象
818
- # @param file_basename [String] 文件名(不包含扩展名)
819
- # @param with_notes [Boolean] 是否包含注释
820
- #
821
- # @raise [RPGTypeError] object 的类型不在 RPG 模块中
822
- # @raise [FileBaseNameError] file_basename 无法匹配到对应的类
823
- #
824
- # @return [Object]
825
- def Utils.rpg_r3exs(object, file_basename, with_notes)
826
- check_type(object, file_basename, true, :RPG)
827
-
828
- # 首先根据 file_basename 找到对应的类
829
- matched_class = Utils::FILE_BASENAME_TO_CLASS_R3EXS.find { |pattern, _| file_basename =~ pattern }.last
830
-
831
- # 然后根据 object 的类型进行处理
832
- # 如果 object 是数组,则遍历数组,对每个元素进行处理
833
- # 如果 object 是哈希,则遍历哈希,对每个值进行处理
834
- # 如果 object 是其他类型,则直接处理
835
- if object.is_a?(Array)
836
- temp = []
837
- object.each_with_index do |obj, index|
838
- next if obj.nil?
839
- obj_r3exs = matched_class.new(obj, index, with_notes)
840
- temp << obj_r3exs unless obj_r3exs.empty?
841
- end
842
- elsif object.is_a?(Hash) # 只有 RPG::MapInfo 是Hash
843
- temp = []
844
- object.each do |key, obj|
845
- next if obj.nil?
846
- temp << matched_class.new(obj, key, with_notes)
847
- end
848
- else
849
- # 只有 RPG::Map 和 RPG::System 是单独一个对象,且不可能为 nil
850
- temp = matched_class.new(object, with_notes)
851
- end
852
- temp
853
- end
854
-
855
- # 读取 target_dir 下的所有 rvdata2 文件,将其反序列化为对象,并调用 block
856
- #
857
- # @note 注意传入 block object
858
- # - 如果 object 是数组或哈希,则其中可能存在 nil 元素
859
- # - 如果 object 是单独一个对象,则不可能为 nil
860
- # @param target_dir [String] 目标目录
861
- #
862
- # @yieldparam object [Object] rvdata2 文件反序列化后的对象
863
- # @yieldparam file_basename [String] 文件名(不包含扩展名)
864
- # @yieldreturn [void]
865
- #
866
- # @raise [Rvdata2FileError] rvdata2 文件可能损坏
867
- # @raise [Rvdata2DirError] target_dir 不存在
868
- #
869
- # @return [void]
870
- def Utils.all_rvdata2_files(target_dir)
871
- # 检查 target_dir 是否存在
872
- Dir.exist?(target_dir) or raise Rvdata2DirError.new(target_dir), "rvdata2 directory not found: #{target_dir}"
873
- # 获取 target_dir 下的所有文件
874
- Dir.each_child(target_dir) do |file_name|
875
- # 检查文件名是否在 RVDATA2_FILE_NAME 中与其正则表达式匹配
876
- next unless RVDATA2_FILE_NAME.any? { |pattern| file_name =~ pattern }
877
-
878
- file_path = File.join(target_dir, file_name)
879
- print "#{ESCAPE}#{BLUE_COLOR}Reading and Deserializing from #{RESET_COLOR}#{file_path}...\r" if $global_options[:verbose]
880
- object = File.open(file_path, 'rb') { |file| Marshal.load(file) }
881
-
882
- file_basename = File.basename(file_name, '.rvdata2')
883
- # 如果文件名不是 'Scripts',则检查 object 的类型是否正确
884
- unless file_basename == 'Scripts'
885
- # 检查 object 的类型是否正确
886
- # 这里的类型检查要用紧凑模式,因为 rvdata2 文件中可能存在 nil 元素,必须忽略
887
- begin
888
- check_type(object, file_basename, true, :RPG)
889
- rescue RPGTypeError
890
- raise Rvdata2FileError.new(file_path), "Invalid rvdata2 file: #{file_path}"
891
- end
892
- end
893
-
894
- yield object, file_basename
895
- end
896
- end
897
-
898
- # 读取 target_dir 下的 JSON 所有文件,将其反序列化为对象,并调用 block
899
- #
900
- # @note 注意传入 block 的 object
901
- # - 在 module_name 为 RPG 时,如果 object 是数组或哈希,则其中可能存在 nil 元素。如果 object 是单独一个对象,则不可能为 nil
902
- # - 在 module_name 为 R3EXS 时,object 不会为 nil
903
- # @param target_dir [String] 目标目录
904
- # @param module_name [Symbol] 模块名
905
- #
906
- # @yieldparam object [Object] JSON 文件反序列化后的对象
907
- # @yieldparam file_basename [String] 文件名(不包含扩展名)
908
- # @yieldreturn [void]
909
- #
910
- # @raise [RPGJsonFileError] json 文件不是 RPG 模块中的对象
911
- # @raise [R3EXSJsonFileError] json 文件不是 R3EXS 模块中的对象
912
- # @raise [ModuleNameError] module_name 不是 :RPG 或 :R3EXS
913
- # @raise [JsonDirError] target_dir 不存在
914
- #
915
- # @return [void]
916
- def Utils.all_json_files(target_dir, module_name)
917
- # 检查 target_dir 是否存在
918
- Dir.exist?(target_dir) or raise JsonDirError.new(target_dir), "JSON directory not found: #{target_dir}"
919
- # 获取 target_dir 下的所有文件
920
- Dir.each_child(target_dir) do |file_name|
921
- # 检查文件名是否在 JSON_FILE_NAME 中与其正则表达式匹配
922
- next unless JSON_FILE_NAME.any? { |pattern| file_name =~ pattern }
923
-
924
- file_path = File.join(target_dir, file_name)
925
- print "#{ESCAPE}#{BLUE_COLOR}Reading and Deserializing #{RESET_COLOR}#{file_path}...\r" if $global_options[:verbose]
926
- object = Oj.load_file(file_path)
927
-
928
- file_basename = File.basename(file_name, '.json')
929
- case module_name
930
- when :RPG
931
- # 这里的类型检查要用紧凑模式,因为这是从 rvdata2 文件直接全部序列化后的 JSON 文件中读取的 object,其中可能存在 nil 元素
932
- begin
933
- check_type(object, file_basename, true, module_name)
934
- rescue RPGTypeError
935
- raise RPGJsonFileError.new(file_path), "Invalid RPG JSON file: #{file_path}"
936
- end
937
- when :R3EXS
938
- # 这里的类型检查不能用紧凑模式,因为这是从 R3EXS 模块的类序列化后的 JSON 文件中读取的 object,程序设计中不应该存在 nil 元素
939
- begin
940
- check_type(object, file_basename, false, module_name)
941
- rescue R3EXSTypeError
942
- raise R3EXSJsonFileError.new(file_path), "Invalid R3EXS JSON file: #{file_path}"
943
- end
944
- else
945
- raise ModuleNameError.new(module_name), "Invalid module name: #{module_name}"
946
- end
947
-
948
- yield object, file_basename
949
- end
950
- end
951
-
952
- # 将 object 序列化为 json 文件
953
- #
954
- # @param object [Object] 待序列化的对象
955
- # @param output_file [String] 输出文件路径
956
- # @return [void]
957
- def Utils.object_json(object, output_file)
958
- File.write(output_file, Oj.dump(object, indent: 2), mode: 'w')
959
- end
960
-
961
- # 将 object 序列化为 rvdata2 文件
962
- #
963
- # @param object [Object] 待序列化的对象
964
- # @param output_file [String] 输出文件路径
965
- # @return [void]
966
- def Utils.object_rvdata2(object, output_file)
967
- File.write(output_file, Marshal.dump(object), mode: 'wb')
968
- end
969
-
970
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'oj'
4
+ require_relative 'RGSS3_R3EXS'
5
+
6
+ module R3EXS
7
+
8
+ # 工具模块
9
+ # 主要用来提供一些读取,写入,转换等功能
10
+ module Utils
11
+
12
+ # 用来匹配读取的 rvdata2 文件名
13
+ RVDATA2_FILE_NAME =
14
+ [
15
+ /\AActors\z/,
16
+ /\AAnimations\z/,
17
+ /\AArmors\z/,
18
+ /\AClasses\z/,
19
+ /\ACommonEvents\z/,
20
+ /\AEnemies\z/,
21
+ /\AItems\z/,
22
+ /\AMap\d{3}\z/,
23
+ /\AMapInfos\z/,
24
+ /\AScripts\z/,
25
+ /\ASkills\z/,
26
+ /\AStates\z/,
27
+ /\ASystem\z/,
28
+ /\ATilesets\z/,
29
+ /\ATroops\z/,
30
+ /\AWeapons\z/
31
+ ]
32
+
33
+ # 用来匹配读取的 JSON 文件名
34
+ JSON_FILE_NAME =
35
+ [
36
+ /\AActors\z/,
37
+ /\AAnimations\z/,
38
+ /\AArmors\z/,
39
+ /\AClasses\z/,
40
+ /\AEnemies\z/,
41
+ /\AItems\z/,
42
+ /\AMap\d{3}\z/,
43
+ /\AMapInfos\z/,
44
+ /\ASkills\z/,
45
+ /\AStates\z/,
46
+ /\ASystem\z/,
47
+ /\ATilesets\z/,
48
+ /\ATroops\z/,
49
+ /\AWeapons\z/
50
+ ]
51
+
52
+ # 用来匹配读取的文件名到对应的R3EXS的类
53
+ FILE_BASENAME_TO_CLASS_R3EXS = {
54
+ /\AActors\z/ => R3EXS::Actor,
55
+ /\AAnimations\z/ => R3EXS::Animation,
56
+ /\AArmors\z/ => R3EXS::Armor,
57
+ /\AClasses\z/ => R3EXS::Class,
58
+ /\ACommonEvents\z/ => R3EXS::CommonEvent,
59
+ /\AEnemies\z/ => R3EXS::Enemy,
60
+ /\AItems\z/ => R3EXS::Item,
61
+ /\AMap\d{3}\z/ => R3EXS::Map,
62
+ /\AMapInfos\z/ => R3EXS::MapInfo,
63
+ /\ASkills\z/ => R3EXS::Skill,
64
+ /\AStates\z/ => R3EXS::State,
65
+ /\ASystem\z/ => R3EXS::System,
66
+ /\ATilesets\z/ => R3EXS::Tileset,
67
+ /\ATroops\z/ => R3EXS::Troop,
68
+ /\AWeapons\z/ => R3EXS::Weapon
69
+ }
70
+
71
+ # 用来匹配读取的文件名到对应的RPG的类
72
+ FILE_BASENAME_TO_CLASS_RPG = {
73
+ /\AActors\z/ => RPG::Actor,
74
+ /\AAnimations\z/ => RPG::Animation,
75
+ /\AArmors\z/ => RPG::Armor,
76
+ /\AClasses\z/ => RPG::Class,
77
+ /\ACommonEvents\z/ => RPG::CommonEvent,
78
+ /\AEnemies\z/ => RPG::Enemy,
79
+ /\AItems\z/ => RPG::Item,
80
+ /\AMap\d{3}\z/ => RPG::Map,
81
+ /\AMapInfos\z/ => RPG::MapInfo,
82
+ /\ASkills\z/ => RPG::Skill,
83
+ /\AStates\z/ => RPG::State,
84
+ /\ASystem\z/ => RPG::System,
85
+ /\ATilesets\z/ => RPG::Tileset,
86
+ /\ATroops\z/ => RPG::Troop,
87
+ /\AWeapons\z/ => RPG::Weapon
88
+ }
89
+
90
+ # 事件指令的命令名称
91
+ EVENT_COMMANDS = {
92
+ 0 => 'Empty',
93
+
94
+ =begin
95
+ [string(Face Graphic name)]---[int(Face Graphic index)]---[int:{0:Normal Window, 1:Dim Background, 2:Transparent}]---[int:{0:Top, 1:Middle, 2:Bottom}]---END
96
+ =end
97
+ 101 => 'ShowTextAttributes',
98
+
99
+ =begin
100
+ [Array<string>(Choices Array)]---[int:{0:Disallow, 1:Choice 1, 2:Choice 2, 3:Choice 3, 4:Choice 4, 5:Branch}(When Cancel)]---END
101
+ =end
102
+ 102 => 'ShowChoices',
103
+
104
+ =begin
105
+ [int(Variable for Number)]---[int:{1~8}(Digits)]---END
106
+ =end
107
+ 103 => 'InputNumber',
108
+
109
+ =begin
110
+ [int(Variable for Item ID)]---END
111
+ =end
112
+ 104 => 'SelectKeyItem',
113
+
114
+ =begin
115
+ [int:{1~8}(Speed)]---[bool(No Fast Forward)]---END
116
+ =end
117
+ 105 => 'ShowScrollingTextAttributes',
118
+
119
+ =begin
120
+ [string]---END
121
+ =end
122
+ 108 => 'Comment',
123
+
124
+ =begin
125
+ |--[int:0(Switch)]---[int(Switch ID)]---[int{0:ON, 1:OFF}]---END
126
+ |
127
+ | |--[int:0(Compare to Constant)]---[int(Number)]-------|
128
+ |--[int:1(Variable)]---[int(Variable ID)]--| |--[int{0:==, 1:>=, 2:<=, 3:>, 4:<, 5:!=}]---END
129
+ | |--[int:1(Compare to Variable)]---[int(Variable ID)]--|
130
+ |
131
+ |--[int:2(Self Switch)]---[string{'A', 'B', 'C', 'D'}]---[int{0:ON, 1:OFF}]---END
132
+ |
133
+ |--[int:3(Timer)]---[int:{0~5999}(sec)]---[int{0:>=, 1:<=}]---END
134
+ |
135
+ | |--[int:0(In the Party)]---END
136
+ | |
137
+ | |--[int:1(Name)]---[string]---END
138
+ | |
139
+ | |--[int:2(Class)]---[int(Class ID)]---END
140
+ | |
141
+ |--[int:4(Actor)]---[int(Actor ID)]--------|--[int:3(Skill)]---[int(Skill ID)]---END
142
+ | |
143
+ | |--[int:4(Weapon)]---[int(Wwapon ID)]---END
144
+ | |
145
+ | |--[int:5(Armor)]---[int(Armor ID)]---END
146
+ | |
147
+ | |--[int:6(State)]---[int(State ID)]---END
148
+ |
149
+ | |--[int:0(Appeared)---END
150
+ |--[int:5(Enemy)]---[int(Enemy ID)]--------|
151
+ | |--[int:1(State)]---[int(State ID)]---END
152
+ |
153
+ |--[int:6(Character)]---[int:{-1:Player, 0:This event, 1:EV001, ...}]---[int:{2:Down, 4:Left, 6:Right, 8:Up}]---END
154
+ |
155
+ |--[int:7(Gold)]---[int(Money)]---[int{0:>=, 1:<=, 2:<}]---END
156
+ |
157
+ |--[int:8(Item)]---[int(Item ID)]---END
158
+ |
159
+ |--[int:9(Weapon)]---[int(Weapon ID)]---[bool(Include Equipments)]---END
160
+ |
161
+ |--[int:10(Armor)]---[int(Armor ID)]---[bool(Include Equipments)]---END
162
+ |
163
+ |--[int:11(Button)]---[int:{2:Down, 4:Left, 6:Right, 8:Up, 11:A, 12:B, 13:C, 14:X, 15:Y, 16:Z, 17:L, 18:R}]---END
164
+ |
165
+ |--[int:12(Script)]---[string]---END
166
+ |
167
+ |--[int:13(Vehicle)]---[int:{0:Boat, 1:Ship, 2:Airship}]---END
168
+ =end
169
+ 111 => 'ConditionalBranch',
170
+ 112 => 'Loop',
171
+ 113 => 'BreakLoop',
172
+ 115 => 'ExitEventProcessing',
173
+
174
+ =begin
175
+ [int(Common Event ID)]---END
176
+ =end
177
+ 117 => 'CallCommonEvent',
178
+
179
+ =begin
180
+ [string]---END
181
+ =end
182
+ 118 => 'Label',
183
+
184
+ =begin
185
+
186
+ [string]---END
187
+ =end
188
+ 119 => 'JumpToLabel',
189
+
190
+ =begin
191
+ [int(Switch Begin ID)]---[int(Switch End ID)]---[int:{0:ON, 1:OFF}]---END
192
+ =end
193
+ 121 => 'ControlSwitches',
194
+
195
+ =begin
196
+ |--[int:0(Constant)]---[int(Number)]---END
197
+ |
198
+ |--[int:1(Variable)]---[int(Variable ID)]---END
199
+ |
200
+ |--[int:2(Random)]---[int(Min)]---[int(Max)]---END
201
+ |
202
+ | |--[int:{0:Item, 1:Weapon, 2:Armor}]---[int(Corresponded Item ID)]---[int:0]---END
203
+ | |
204
+ [int(Variable Begin ID)]---[int(Variable End ID)]---[int:{0:Set, 1:Add, 2:Sub, 3:Mul, 4:Div, 5:Mod}]--| |--[int:3(Actor)]---[int:(Actor ID)]---[int:{0:Level, 1:EXP, 2:HP, 3:MP, 4:MHP, 5:MMP, 6:ATK, 7:DEF, 8:MAT, 9:MDF, 10:AGI, 11:LUK}]---END
205
+ | |
206
+ | |--[int:4(Enemy)]---[int:(Enemy ID)]---[int:{0:HP, 1:MP, 2:MHP, 3:MMP, 4:ATK, 5:DEF, 6:MAT, 7:MDF, 8:AGI, 9:LUK}]---END
207
+ |--[int:3(Game Data)]--|
208
+ | |--[int:5(Character)]---[int:{-1:Player, 0:This Event, 1:EV001, ...}]---[int:{0:Map X, 1:Map Y, 2:Direction, 3:Screen X ,4:Screen Y}]---END
209
+ | |
210
+ | |--[int:6(Party)]---[int:{0~7}(Member ID)]---[int:0]---END('s Actor ID)
211
+ | |
212
+ | |--[int:7(Other)]---[int:{0(Map ID), 1(Party Members), 2(Gold), 3(Steps), 4(Play Time), 5(Timer), 6(Save Count), 7(Battle Count)}]---[int:0]---END
213
+ |
214
+ |--[int:4(Scripts)]---[string]---END
215
+ =end
216
+ 122 => 'ControlVariables',
217
+
218
+ =begin
219
+ [string:{'A', 'B', 'C', 'D'}(Self Switch Name)]---[int:{0:ON, 1:OFF}]---END
220
+ =end
221
+ 123 => 'ControlSelfSwitch',
222
+
223
+ =begin
224
+ [int:{0:Start, 1:Stop}]---[int:{0~5999}(sec)]---END
225
+ =end
226
+ 124 => 'ControlTimer',
227
+
228
+ =begin
229
+ |--[int:0(Constant)]---[int:{0~9999999}(Number)]---END
230
+ [int:{0:Increase, 1:Decrease}]--|
231
+ |--[int:1(Variable)]---[int(Variable ID)]---END
232
+ =end
233
+ 125 => 'ChangeGold',
234
+
235
+ =begin
236
+ |--[int:0(Constant)]---[int:{0~9999999}(Number)]---END
237
+ [int(Item ID)]---[int:{0:Increase, 1:Decrease}]--|
238
+ |--[int:1(Variable)]---[int(Variable ID)]---END
239
+ =end
240
+ 126 => 'ChangeItems',
241
+
242
+ =begin
243
+ |--[int:0(Constant)]---[int:{0~9999999}(Number)]--|
244
+ |--[int:0(Increase)]--| |--[bool:false(Include Equipment)]---END
245
+ | |--[int:1(Variable)]---[int(Variable ID)]---------|
246
+ [int(Weapon ID)]--|
247
+ | |--[int:0(Constant)]---[int:{0~9999999}(Number)]--|
248
+ |--[int:1(Decrease)]--| |--[bool(Include Equipment)]---END
249
+ |--[int:1(Variable)]---[int(Variable ID)]---------|
250
+ =end
251
+ 127 => 'ChangeWeapons',
252
+
253
+ =begin
254
+ |--[int:0(Constant)]---[int:{0~9999999}(Number)]--|
255
+ |--[int:0(Increase)]--| |--[bool:false(Include Equipment)]---END
256
+ | |--[int:1(Variable)]---[int(Variable ID)]---------|
257
+ [int(Armor ID)]--|
258
+ | |--[int:0(Constant)]---[int:{0~9999999}(Number)]--|
259
+ |--[int:1(Decrease)]--| |--[bool(Include Equipment)]---END
260
+ |--[int:1(Variable)]---[int(Variable ID)]---------|
261
+ =end
262
+ 128 => 'ChangeArmor',
263
+
264
+ =begin
265
+ [int(Actor ID)]---[int:{0:Add, 1:Remove}]---[int:{0:NO, 1:YES}(Initialize)]---END
266
+ =end
267
+ 129 => 'ChangePartyMember',
268
+
269
+ =begin
270
+ [RPG::BGM]---END
271
+ =end
272
+ 132 => 'ChangeBattleBGM',
273
+
274
+ =begin
275
+ [RPG::ME]---END
276
+ =end
277
+ 133 => 'ChangeBattleEndME',
278
+
279
+ =begin
280
+ [int:{0:Disable, 1:Enable}]---END
281
+ =end
282
+ 134 => 'ChangeSaveAccess',
283
+
284
+ =begin
285
+ [int:{0:Disable, 1:Enable}]---END
286
+ =end
287
+ 135 => 'ChangeMenuAccess',
288
+
289
+ =begin
290
+ [int:{0:Disable, 1:Enable}]---END
291
+ =end
292
+ 136 => 'ChangeEncounter',
293
+
294
+ =begin
295
+ [int:{0:Disable, 1:Enable}]---END
296
+ =end
297
+ 137 => 'ChangeFormationAccess',
298
+
299
+ =begin
300
+ [RPG::Tone]---END
301
+ =end
302
+ 138 => 'ChangeWindowColor',
303
+
304
+ =begin
305
+ |--[int:0(Direct Designation)]---[int(Map ID)]---[int(Map X)]---[int(Map Y)]-------------------------------------------------------------------------------------|
306
+ | |--[int:{0:Retain, 2:Down, 4:Left, 6:Right, 8:Up}(Direction)]---[int:{0:Normal, 1:White, 2:None}(Fade)]---END
307
+ |--[int:1(Designation with Variables)]---[int(Map ID Corresponded Variable ID)]---[int(Map X Corresponded Variable ID)]---[int(Map Y Corresponded Variable ID)]--|
308
+ =end
309
+ 201 => 'TransferPlayer',
310
+
311
+ =begin
312
+ |--[int:0(Direct Designation)]---[int(Map ID)]---[int(Map X)]---[int(Map Y)]---END
313
+ [int:{0:Boat, 1:Ship, 2:Airship}]--|
314
+ |--[int:1(Designation with Variables)]---[int(Map ID Corresponded Variable ID)]---[int(Map X Corresponded Variable ID)]---[int(Map Y Corresponded Variable ID)]---END
315
+ =end
316
+ 202 => 'SetVehicleLocation',
317
+
318
+ =begin
319
+ |--[int:0(Direct Designation)]---[int(Map X)]---[int(Map Y)]------------------------------------------------------------|
320
+ | |
321
+ [int:{0:This Event, 1:EV001, ...}]----------|--[int:1(Designation with Variables)]---[int(Map X Corresponded Variable ID)]---[int(Map Y Corresponded Variable ID)]--|--[int:{0:Retain, 2:Down, 4:Left, 6:Right, 8:Up}(Direction)]---END
322
+ | |
323
+ |--[int:2(Exchange with Another Event)]---[int(Exchanged Event ID)]---[int:0]----------------------------------------- |
324
+ =end
325
+ 203 => 'SetEventLocation',
326
+
327
+ =begin
328
+ [int:{2:Down, 4:Left, 6:Right, 8:Up}]---[int:{0~100}(Distance)]---[int:{1:1/8 Speed, 2:1/4 Speed, 3:1/2 Speed, 4:Normal, 5:2 Speed, 6:4 Speed}]---END
329
+ =end
330
+ 204 => 'ScrollMap',
331
+
332
+ =begin
333
+ [int:{-1:Player, 0:This Event, 1:EV001, ...}]---[RPG::MoveRoute(45 is Script)]---END
334
+ =end
335
+ 205 => 'SetMoveRoute',
336
+
337
+ =begin
338
+ END
339
+ =end
340
+ 206 => 'GetSwitchVehicle',
341
+
342
+ =begin
343
+ [int:{0:ON, 1:OFF}]---END
344
+ =end
345
+ 211 => 'ChangeTransparency',
346
+
347
+ =begin
348
+ [int:{-1:Player, 0:This Event, 1:EV001, ...}]---[int(Animation ID)]---[bool(Wait for Completion)]---END
349
+ =end
350
+ 212 => 'ShowAnimation',
351
+
352
+ =begin
353
+ [int:{-1:Player, 0:This Event, 1:EV001, ...}]---[int(Ballon Icon ID)]---[bool(Wait for Completion)]---END
354
+ =end
355
+ 213 => 'ShowBalloonIcon',
356
+ 214 => 'EraseEvent',
357
+
358
+ =begin
359
+ [int:{0:ON, 1:OFF}]---END
360
+ =end
361
+ 216 => 'ChangePlayerFollowers',
362
+ 217 => 'GatherFollowers',
363
+ 221 => 'FadeoutScreen',
364
+ 222 => 'FadeinScreen',
365
+
366
+ =begin
367
+ [RPG::Tone]---[int:{0~600}(Time 1/60 sec)]---[bool(Wait for Completion)]---END
368
+ =end
369
+ 223 => 'TintScreen',
370
+
371
+ =begin
372
+ [RPG::Color]---[int:{0~600}(Time 1/60 sec)]---[bool(Wait for Completion)]---END
373
+ =end
374
+ 224 => 'FlashScreen',
375
+
376
+ =begin
377
+ [int:{1~9}(Power)]---[int:{1~9}(Speed)]---[int:{0~600}(Time 1/60 sec)]---[bool(Wait for Completion)]---END
378
+ =end
379
+ 225 => 'ShakeScreen',
380
+
381
+ =begin
382
+ [int:{0~999}(Time 1/60 sec)]---END
383
+ =end
384
+ 230 => 'Wait',
385
+
386
+ =begin
387
+ |--[int:0(Constant)]---[int:{-9999~9999}(Map X)]---[int:{-9999~9999}(Map Y)]--------------------------|
388
+ [int:{1~100}(Number)]---[string(Picture Graphic Name)]---[int:{0:Upper Left, 1:Center}(Origin)]--| |--[int:{0~2000}(Width %)]---[int:{0~2000}(Height %)]---[int:{0~255}(Opacity)]---[int:{0:Normal, 1:Add, 2:Sub}]---END
389
+ |--[int:1(Variable)]---[int(Map X Corresponded Variable ID)]---[int(Map Y Corresponded Variable ID)]--|
390
+ =end
391
+ 231 => 'ShowPicture',
392
+
393
+ =begin
394
+ |--[int:0(Constant)]---[int:{-9999~9999}(Map X)]---[int:{-9999~9999}(Map Y)]--------------------------|
395
+ [int:{1~100}(Number)]---[int:{0:Upper Left, 1:Center}(Origin)]--| |--[int:{0~2000}(Width %)]---[int:{0~2000}(Height %)]---[int:{0~255}(Opacity)]---[int:{0:Normal, 1:Add, 2:Sub}]---[int:{0~600}(Time 1/60 sec)]---[bool(Wait for Completion)]---END
396
+ |--[int:1(Variable)]---[int(Map X Corresponded Variable ID)]---[int(Map Y Corresponded Variable ID)]--|
397
+ =end
398
+ 232 => 'MovePicture',
399
+
400
+ =begin
401
+ [int:{1~100}(Number)]-[int:{-90~90}(Speed)]--END
402
+ =end
403
+ 233 => 'RotatePicture',
404
+
405
+ =begin
406
+ [int:{1~100}(Number)]---[RPG::Tone]---[int:{0~600}(Time 1/60 sec)]---[bool(Wait for Completion)]---END
407
+ =end
408
+ 234 => 'TintPicture',
409
+
410
+ =begin
411
+ [int:{1~100}(Number)]---END
412
+ =end
413
+ 235 => 'ErasePicture',
414
+
415
+ =begin
416
+ [string:{":none", ":rain", ":storm", ":snow"}]---[int:{0~9}(Power)]---[int:{0~600}(Time 1/60 sec)]---[bool(Wait for Completion)]---END
417
+ =end
418
+ 236 => 'SetWeatherEffects',
419
+
420
+ =begin
421
+ [RPG::BGM]---END
422
+ =end
423
+ 241 => 'PlayBGM',
424
+
425
+ =begin
426
+ [int:{1~60}(Time sec)]---END
427
+ =end
428
+ 242 => 'FadeoutBGM',
429
+ 243 => 'SaveBGM',
430
+ 244 => 'ReplayBGM',
431
+
432
+ =begin
433
+ [RPG::BGM]---END
434
+ =end
435
+ 245 => 'PlayBGS',
436
+
437
+ =begin
438
+ [int:{1~60}(Time sec)]---END
439
+ =end
440
+ 246 => 'FadeoutBGS',
441
+
442
+ =begin
443
+ [RPG::ME]---END
444
+ =end
445
+ 249 => 'PlayME',
446
+
447
+ =begin
448
+ [RPG::SE]---END
449
+ =end
450
+ 250 => 'PlaySE',
451
+ 251 => 'StopSE',
452
+
453
+ =begin
454
+ [string(Movie Name)]---END
455
+ =end
456
+ 261 => 'PlayMovie',
457
+
458
+ =begin
459
+ [int:{0:ON, 1:OFF}]---END
460
+ =end
461
+ 281 => 'ChangeMapNameDisplay',
462
+
463
+ =begin
464
+ [int(Tileset ID)]---END
465
+ =end
466
+ 282 => 'ChangeTileset',
467
+
468
+ =begin
469
+ [string(Floor Picture)]---[string(Wall Picture)]---END
470
+ =end
471
+ 283 => 'ChangeBattleBack',
472
+
473
+ =begin
474
+ [string(Distant view Picture)]---[bool(Loop Horizontal)]---[bool(Loop Vertical)]---[int(-32~32)(Horizontal Scroll)]---[int(-32~32)(Vertical Scrool)]---END
475
+ =end
476
+ 284 => 'ChangeParallaxBack',
477
+
478
+ =begin
479
+ |--[int:0(Direct Designation)]---[int(Map X)]---[int(Map Y)]---END
480
+ [int(Variable for Info)]---[int:{0:Terrain, 1:Event ID, 2:Tile ID(Layer 1), 3:Tile ID(Layer 2), 4:Tile ID(Layer 3), 5:Region ID}(Info Type)]--|
481
+ |--[int:1(Designation with Variables)]---[int(Map X Corresponded Variable ID)]---[int(Map Y Corresponded Variable ID)]---END
482
+ =end
483
+ 285 => 'GetLocationInfo',
484
+
485
+ =begin
486
+ |--[int:0(Direct Designation)]---[int(Enemy ID)]-----------------------------------|
487
+ | |--[bool(Can Escape)]---[bool(Continue Even When Loser)]---END
488
+ |--[int:1(Designation with Variables)]---[int(Enemy ID Corresponded Variable ID)]--|
489
+ =end
490
+ 301 => 'BattleProcessing',
491
+
492
+ =begin
493
+ |--[int:0(Price: Standard)]---[int:0]------------------|
494
+ [int:{0:Item, 1:Weapon, 2:Armor}]---[int(Corresponded Item ID)]--| |--[bool(Purchase Only)]---END
495
+ |--[int:1(Price: Specify)]---[int:{0~9999999}(Price)]--|
496
+ =end
497
+ 302 => 'ShopProcessing',
498
+
499
+ =begin
500
+ [int(Actor ID)]---[int:{1~16}(Max Characters)]---END
501
+ =end
502
+ 303 => 'NameInputProcessing',
503
+
504
+ =begin
505
+ |--[int:0(Constant)]---[int:{1~9999}(Number)]--|
506
+ |--[int:0(Increase)]--| |--[bool:false(Allow Knockout)]---END
507
+ | |--[int:1(Variable)]---[int(Variable ID)]------|
508
+ |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]--|
509
+ | | |--[int:0(Constant)]---[int:{1~9999}(Number)]--|
510
+ | |--[int:1(Decrease)]--| |--[bool(Allow Knockout)]---END
511
+ | |--[int:1(Variable)]---[int(Variable ID)]------|
512
+ |
513
+ | |--[int:0(Constant)]---[int:{1~9999}(Number)]--|
514
+ | |--[int:0(Increase)]--| |--[bool:false(Allow Knockout)]---END
515
+ | | |--[int:1(Variable)]---[int(Variable ID)]------|
516
+ |--[int:1(Variable)]---[int(Variable ID)]-----------------------|
517
+ | |--[int:0(Constant)]---[int:{1~9999}(Number)]--|
518
+ |--[int:1(Decrease)]--| |--[bool(Allow Knockout)]---END
519
+ |--[int:1(Variable)]---[int(Variable ID)]------|
520
+ =end
521
+ 311 => 'ChangeHP',
522
+
523
+ =begin
524
+ |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]--| |--[int:0(Constant)]---[int:{1~9999}(Number)]---END
525
+ | |--[int:{0:Increase, 1:Decrease}]--|
526
+ |--[int:1(Variable)]---[int(Variable ID)]---------------------| |--[int:1(Variable)]---[int(Variable ID)]---END
527
+ =end
528
+ 312 => 'ChangeMP',
529
+
530
+ =begin
531
+ |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]--|
532
+ | |--[int:{0:Add, 1:Remove}]---[int(State ID)]---END
533
+ |--[int:1(Variable)]---[int(Variable ID)]---------------------|
534
+ =end
535
+ 313 => 'ChangeState',
536
+
537
+ =begin
538
+ |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]---END
539
+ |
540
+ |--[int:1(Variable)]---[int(Variable ID)]---END
541
+ =end
542
+ 314 => 'RecoverAll',
543
+
544
+ =begin
545
+ |--[int:0(:Constant)]---[int:{1~9999999}(Number)]--|
546
+ |--[int:0(Increase)]--| |--[bool(Show Level Up Message)]---END
547
+ | |--[int:1(Variable)]---[int(Variable ID)]----------|
548
+ |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]--|
549
+ | | |--[int:0(Constant)]---[int:{1~9999999}(Number)]--|
550
+ | |--[int:1(Decrease)]--| |--[bool:false(Show Level Up Message)]---END
551
+ | |--[int:1(Variable)]------------------------------|
552
+ |
553
+ | |--[int:0(Constant)]---[int:{1~9999999}(Number)]--|
554
+ | |--[int:0(Increase)]--| |--[bool(Show Level Up Message)]---END
555
+ | | |--[int:1(Variable)]---[int(Variable ID)]---------|
556
+ |--[int:1(Variable)]---[int(Variable ID)]---------------------|
557
+ | |--[int:0(Constant)]---[int:{1~9999999}(Number)]--|
558
+ |--[int:1(Decrease)]--| |--[bool:false(Show Level Up Message)]---END
559
+ |--[int:1(Variable)]---[int(Variable ID)]---------|
560
+ =end
561
+ 315 => 'ChangeEXP',
562
+
563
+ =begin
564
+ |--[int:0(Constant)]---[int:{1~98}(Number)]--|
565
+ |--[int:0(Increase)]--| |--[bool(Show Level Up Message)]---END
566
+ | |--[int:1(Variable)]---[int(Variable ID)]----|
567
+ |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]--|
568
+ | | |--[int:0(Constant)]---[int:{1~98}(Number)]--|
569
+ | |--[int:1(Decrease)]--| |--[bool:false(Show Level Up Message)]---END
570
+ | |--[int:1(Variable)]---[int(Variable ID)]----|
571
+ |
572
+ | |--[int:0(Constant)]---[int:{1~98}(Number)]--|
573
+ | |--[int:0(Increase)]--| |--[bool(Show Level Up Message)]---END
574
+ | | |--[int:1(Variable)]---[int(Variable ID)]----|
575
+ |--[int:1(Variable)]---[int(Variable ID)]---------------------|
576
+ | |--[int:0(Constant)]---[int:{1~98}(Number)]--|
577
+ |--[int:1(Decrease)]--| |--[bool:false(Show Level Up Message)]---END
578
+ |--[int:1(Variable)]---[int(Variable ID)]------|
579
+ =end
580
+ 316 => 'ChangeLevel',
581
+
582
+ =begin
583
+ |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]--| |--[int:0(Constant)]---[int:{0~9999999}(Number)]---END
584
+ | |--[int:{0:MHP, 1:MMP, 2:ATK, 3:DEF, 4:MAT, 5:MDF, 6:AGI, 7:LUK}]---[int:{0:Increase, 1:Decrease}]--|
585
+ |--[int:1(Variable)]---[int(Variable ID)]---------------------| |--[int:1(Variable)]---[int(Variable ID)]---END
586
+ =end
587
+ 317 => 'ChangeParameters',
588
+
589
+ =begin
590
+ |--[int:0(Fixed)]---[int:{0:Entire Party, 1:Actor 001, ...}]--|
591
+ | |--[int:{0:Learn, 1:Forget}]---[int(Skill ID)]---END
592
+ |--[int:1(Variable)]---[int(Variable ID)]---------------------|
593
+ =end
594
+ 318 => 'ChangeSkills',
595
+
596
+ =begin
597
+ [int(Actor ID)]---[int:{0:Weapon, 1:Shield, 2:Head, 3:Boby, 4:Accessory}]---[int:{0:None, 1:Equipment 001, ...}(Equipment ID)]---END
598
+ =end
599
+ 319 => 'ChangeEquipment',
600
+
601
+ =begin
602
+ [int(Actor ID)]---[string(New Actor Name)]---END
603
+ =end
604
+ 320 => 'ChangeActorName',
605
+
606
+ =begin
607
+ [int(Actor ID)]---[int(New Class ID)]---END
608
+ =end
609
+ 321 => 'ChangeActorClass',
610
+
611
+ =begin
612
+ [int(Actor ID)]---[string(New Actor walking Picture Name)]---[int(New Actor Walking Picture Index)]---[string(New Actor Portrait Picture Name)]---[int(New Actor Portrait Picture Index)]---END
613
+ =end
614
+ 322 => 'ChangeActorGraphic',
615
+
616
+ =begin
617
+ [int:{0:Boat, 1:Ship, 2:Airship}]---[string(New Vehicle Picture Name)]---[int(New Vehicle Picture Index)]---END
618
+ =end
619
+ 323 => 'ChangeVehicleGraphic',
620
+
621
+ =begin
622
+ [int(Actor ID)]---[string(New Actor Nickname)]---END
623
+ =end
624
+ 324 => 'ChangeActorNickname',
625
+
626
+ =begin
627
+ |--[int:0(Constant)]---[int:{1~999999}(Number)]--|
628
+ |--[int:0(Increase)]--| |--[bool:false(Allow Knockout)]---END
629
+ | |--[int:1(Variable)]---[int(Variable ID)]--------|
630
+ [int:{-1:Entire Troop, 0:Troop 001, ...}]--|
631
+ | |--[int:0(Constant)]---[int:{1~999999}(Number)]--|
632
+ |--[int:1(Decrease)]--| |--[bool(Allow Knockout)]---END
633
+ |--[int:1(Variable)]---[int(Variable ID)]--------|
634
+
635
+ =end
636
+ 331 => 'ChangeEnemyHP',
637
+
638
+ =begin
639
+ |--[int:0(Constant)]---[int:{1~9999}(Number)]---END
640
+ [int:{-1:Entire Troop, 0:Troop 001, ...}]---[int:{0:Increase, 1:Decrease}]--|
641
+ |--[int:1(Variable)]---[int(Variable ID)]---END
642
+ =end
643
+ 332 => 'ChangeEnemyMP',
644
+
645
+ =begin
646
+ [int:{-1:Entire Troop, 0:Troop 001, ...}]---[int:{0:Add, 1:Remove}]---[int(State ID)]---END
647
+ =end
648
+ 333 => 'ChangeEnemyState',
649
+
650
+ =begin
651
+ [int:{-1:Entire Troop, 0:Troop 001, ...}]---END
652
+ =end
653
+ 334 => 'EnemyRecoverAll',
654
+
655
+ =begin
656
+ [int:{-1:Entire Troop, 0:Troop 001, ...}]---END
657
+ =end
658
+ 335 => 'EnemyAppear',
659
+
660
+ =begin
661
+ [int(Troop ID)]---[int(Enemy ID)]---END
662
+ =end
663
+ 336 => 'EnemyTransform',
664
+
665
+ =begin
666
+ [int:{-1:Entire Troop, 0:Troop 001, ...}]---[int(Animation ID)]---END
667
+ =end
668
+ 337 => 'ShowBattleAnimation',
669
+
670
+ =begin
671
+ |--[int:0(Enemy)]---[int(Troop ID)]--|
672
+ | |--[int(Skill ID)]---[int:{-2:Last Target, -1:Random, 0:Index 1,...}]---END
673
+ |--[int:1(Actor)]---[int(Actor ID)]--|
674
+ =end
675
+ 339 => 'ForceAction',
676
+ 340 => 'AbortBattle',
677
+ 351 => 'OpenMenuScreen',
678
+ 352 => 'OpenSaveScreen',
679
+ 353 => 'GameOver',
680
+ 354 => 'ReturnToTitleScreen',
681
+
682
+ =begin
683
+ [string]---END
684
+ =end
685
+ 355 => 'Script',
686
+
687
+ =begin
688
+ [string]---END
689
+ =end
690
+ 401 => 'ShowText',
691
+
692
+ =begin
693
+ [int(Choice Index)]---[string(Choice Name)]---END
694
+ =end
695
+ 402 => 'When',
696
+ 403 => 'WhenCancel',
697
+ 404 => 'ChoicesEnd',
698
+
699
+ =begin
700
+ [string]---END
701
+ =end
702
+ 405 => 'ShowScrollingText',
703
+
704
+ =begin
705
+ [string]---END
706
+ =end
707
+ 408 => 'CommentMore',
708
+ 411 => 'Else',
709
+ 412 => 'BranchEnd',
710
+ 413 => 'RepeatAbove',
711
+
712
+ =begin
713
+ [RPG::MoveCommand(45 is script)]---END
714
+ =end
715
+ 505 => 'MoveRoute',
716
+ 601 => 'IfWin',
717
+ 602 => 'IfEscape',
718
+ 603 => 'IfLose',
719
+ 604 => 'BattleProcessingEnd',
720
+
721
+ =begin
722
+ |--[int:0(Price: Standard)]---[int:0]---END
723
+ [int:{0:Item, 1:Weapon, 2:Armor}]---[int(Corresponded Item ID)]--|
724
+ |--[int:1(Price: Specify)]---[int:{0~9999999}(Price)]---END
725
+ =end
726
+ 605 => 'ShopItem',
727
+
728
+ =begin
729
+ [string]---END
730
+ =end
731
+ 655 => 'ScriptMore' }
732
+
733
+ # 红色
734
+ RED_COLOR = "\e[31m"
735
+
736
+ # 绿色
737
+ GREEN_COLOR = "\e[32m"
738
+
739
+ # 黄色
740
+ YELLOW_COLOR = "\e[33m"
741
+
742
+ # 蓝色
743
+ BLUE_COLOR = "\e[34m"
744
+
745
+ # 紫色
746
+ MAGENTA_COLOR = "\e[35m"
747
+
748
+ # 青色
749
+ CYAN_COLOR = "\e[36m"
750
+
751
+ # 重置颜色
752
+ RESET_COLOR = "\e[0m"
753
+
754
+ # 清除行
755
+ ESCAPE = "\e[2K"
756
+
757
+ # 根据 file_basename 检查 object 的类型在 module_name 中是否正确
758
+ #
759
+ # @param object [Object] 待检查的对象
760
+ # @param file_basename [String] 文件名(不包含扩展名)
761
+ # @param is_compact [Boolean] 是否为紧凑模式
762
+ # @param module_name [Symbol] 模块名
763
+ #
764
+ # @raise [RPGTypeError] object 的类型不在 RPG 模块中
765
+ # @raise [R3EXSTypeError] object 的类型不在 R3EXS 模块中
766
+ # @raise [ModuleNameError] module_name 不是 :RPG 或 :R3EXS
767
+ # @raise [FileBaseNameError] file_basename 无法匹配到对应的类
768
+ #
769
+ # @return [void]
770
+ def Utils.check_type(object, file_basename, is_compact, module_name)
771
+ case module_name
772
+ when :RPG
773
+ matched_class = FILE_BASENAME_TO_CLASS_RPG.find { |pattern, _| file_basename =~ pattern }&.last
774
+ matched_class or raise FileBaseNameError.new(file_basename), "Invalid file basename: #{file_basename}"
775
+ if object.is_a?(Array)
776
+ if is_compact
777
+ object.compact.all? { |item| item.is_a?(matched_class) } or raise RPGTypeError.new(object), "Invalid Object: #{object}, it's not an Array<#{matched_class}>"
778
+ else
779
+ object.all? { |item| item.is_a?(matched_class) } or raise RPGTypeError.new(object), "Invalid Object: #{object}, it's not an Array<#{matched_class}>"
780
+ end
781
+ elsif object.is_a?(Hash)
782
+ if is_compact
783
+ object.compact.values.all? { |item| item.is_a?(matched_class) } or raise RPGTypeError.new(object), "Invalid Object: #{object}, it's not a Hash<#{matched_class}>"
784
+ else
785
+ object.values.all? { |item| item.is_a?(matched_class) } or raise RPGTypeError.new(object), "Invalid Object: #{object}, it's not a Hash<#{matched_class}>"
786
+ end
787
+ else
788
+ object.is_a?(matched_class) or raise RPGTypeError.new(object), "Invalid Object: #{object}, it's not a #{matched_class}"
789
+ end
790
+ when :R3EXS
791
+ matched_class = FILE_BASENAME_TO_CLASS_R3EXS.find { |pattern, _| file_basename =~ pattern }&.last
792
+ matched_class or raise FileBaseNameError.new(file_basename), "Invalid file basename: #{file_basename}"
793
+ if object.is_a?(Array)
794
+ if is_compact
795
+ object.compact.all? { |item| item.is_a?(matched_class) } or raise R3EXSTypeError.new(object), "Invalid object: #{object}, it's not an Array<#{matched_class}>"
796
+ else
797
+ object.all? { |item| item.is_a?(matched_class) } or raise R3EXSTypeError.new(object), "Invalid object: #{object}, it's not an Array<#{matched_class}>"
798
+ end
799
+ elsif object.is_a?(Hash)
800
+ if is_compact
801
+ object.compact.values.all? { |item| item.is_a?(matched_class) } or raise R3EXSTypeError.new(object), "Invalid object: #{object}, it's not a Hash<#{matched_class}>"
802
+ else
803
+ object.values.all? { |item| item.is_a?(matched_class) } or raise R3EXSTypeError.new(object), "Invalid object: #{object}, it's not a Hash<#{matched_class}>"
804
+ end
805
+ else
806
+ object.is_a?(matched_class) or raise R3EXSTypeError.new(object), "Invalid object: #{object}, it's not #{matched_class}"
807
+ end
808
+ else
809
+ raise ModuleNameError.new(module_name), "Invalid module name: #{module_name}"
810
+ end
811
+
812
+ end
813
+
814
+ # 将 RPG 中的对象转化为 R3EXS 对象
815
+ #
816
+ # @param object [Object] 待转化的 RPG 对象
817
+ # @param file_basename [String] 文件名(不包含扩展名)
818
+ # @param with_notes [Boolean] 是否包含注释
819
+ #
820
+ # @raise [RPGTypeError] object 的类型不在 RPG 模块中
821
+ # @raise [FileBaseNameError] file_basename 无法匹配到对应的类
822
+ #
823
+ # @return [Object]
824
+ def Utils.rpg_r3exs(object, file_basename, with_notes)
825
+ check_type(object, file_basename, true, :RPG)
826
+
827
+ # 首先根据 file_basename 找到对应的类
828
+ matched_class = Utils::FILE_BASENAME_TO_CLASS_R3EXS.find { |pattern, _| file_basename =~ pattern }.last
829
+
830
+ # 然后根据 object 的类型进行处理
831
+ # 如果 object 是数组,则遍历数组,对每个元素进行处理
832
+ # 如果 object 是哈希,则遍历哈希,对每个值进行处理
833
+ # 如果 object 是其他类型,则直接处理
834
+ if object.is_a?(Array)
835
+ temp = []
836
+ object.each_with_index do |obj, index|
837
+ next if obj.nil?
838
+ obj_r3exs = matched_class.new(obj, index, with_notes)
839
+ temp << obj_r3exs unless obj_r3exs.empty?
840
+ end
841
+ elsif object.is_a?(Hash) # 只有 RPG::MapInfo 是 Hash,且 key 为整数
842
+ temp = []
843
+ object.each do |key, obj|
844
+ next if obj.nil?
845
+ temp << matched_class.new(obj, key, with_notes)
846
+ end
847
+ else
848
+ # 只有 RPG::Map 和 RPG::System 是单独一个对象,且不可能为 nil
849
+ temp = matched_class.new(object, with_notes)
850
+ end
851
+ temp
852
+ end
853
+
854
+ # 读取 target_dir 下的所有 rvdata2 文件,将其反序列化为对象,并调用 block
855
+ #
856
+ # @note 注意传入 block 的 object
857
+ # - 如果 object 是数组或哈希,则其中可能存在 nil 元素
858
+ # - 如果 object 是单独一个对象,则不可能为 nil
859
+ #
860
+ # @param target_dir [Pathname] 目标目录
861
+ #
862
+ # @yieldparam object [Object] rvdata2 文件反序列化后的对象
863
+ # @yieldparam file_basename [String] 文件名(不包含扩展名)
864
+ # @yieldparam parent_relative_dir [Pathname] 文件所在目录的相对路径
865
+ # @yieldreturn [void]
866
+ #
867
+ # @raise [Rvdata2FileError] rvdata2 文件可能损坏
868
+ # @raise [Rvdata2DirError] target_dir 不存在
869
+ #
870
+ # @return [void]
871
+ def Utils.all_rvdata2_files(target_dir)
872
+ # 检查 target_dir 目录是否存在
873
+ target_dir.exist? && target_dir.directory? or raise Rvdata2DirError.new(target_dir.to_s), "rvdata2 directory not found: #{target_dir}"
874
+ # 递归获取 target_dir 下的所有 *.rvdata2 文件
875
+ target_dir.glob('**/*.rvdata2').each do |file_path|
876
+ file_basename = file_path.basename('.rvdata2').to_s
877
+ # 检查文件名是否在 RVDATA2_FILE_NAME 中与其正则表达式匹配
878
+ next unless RVDATA2_FILE_NAME.any? { |pattern| file_basename =~ pattern }
879
+
880
+ print "#{ESCAPE}#{BLUE_COLOR}Reading and Deserializing from #{RESET_COLOR}#{file_path}...\r" if $global_options[:verbose]
881
+ object = Marshal.load(file_path.binread)
882
+
883
+ # 如果文件名不是 'Scripts',则检查 object 的类型是否正确
884
+ unless file_basename == 'Scripts'
885
+ # 检查 object 的类型是否正确
886
+ # 这里的类型检查要用紧凑模式,因为 rvdata2 文件中可能存在 nil 元素,必须忽略
887
+ begin
888
+ check_type(object, file_basename, true, :RPG)
889
+ rescue RPGTypeError
890
+ raise Rvdata2FileError.new(file_path.to_s), "Invalid rvdata2 file: #{file_path}"
891
+ end
892
+ end
893
+
894
+ yield object, file_basename, file_path.dirname.relative_path_from(target_dir)
895
+ end
896
+ end
897
+
898
+ # 读取 target_dir 下的所有常规 JSON 文件,将其反序列化为对象,并调用 block
899
+ #
900
+ # @note 注意传入 block 的 object
901
+ # - 在 module_name 为 RPG 时,如果 object 是数组或哈希,则其中可能存在 nil 元素。如果 object 是单独一个对象,则不可能为 nil
902
+ # - 在 module_name 为 R3EXS 时,object 不会为 nil
903
+ #
904
+ # @param target_dir [Pathname] 目标目录
905
+ # @param module_name [Symbol] 模块名
906
+ #
907
+ # @yieldparam object [Object] JSON 文件反序列化后的对象
908
+ # @yieldparam file_basename [String] 文件名(不包含扩展名)
909
+ # @yieldparam parent_relative_dir [Pathname] 文件所在目录的相对路径
910
+ # @yieldreturn [void]
911
+ #
912
+ # @raise [RPGJsonFileError] json 文件不是 RPG 模块中的对象
913
+ # @raise [R3EXSJsonFileError] json 文件不是 R3EXS 模块中的对象
914
+ # @raise [ModuleNameError] module_name 不是 :RPG 或 :R3EXS
915
+ # @raise [JsonDirError] target_dir 不存在
916
+ #
917
+ # @return [void]
918
+ def Utils.all_json_files(target_dir, module_name)
919
+ # 检查 target_dir 目录是否存在
920
+ target_dir.exist? && target_dir.directory? or raise JsonDirError.new(target_dir.to_s), "JSON directory not found: #{target_dir}"
921
+ # 递归获取 target_dir 下的所有 *.json 文件
922
+ target_dir.glob('**/*.json').each do |file_path|
923
+ file_basename = file_path.basename('.json').to_s
924
+ # 检查文件名是否在 JSON_FILE_NAME 中与其正则表达式匹配
925
+ next unless JSON_FILE_NAME.any? { |pattern| file_basename =~ pattern }
926
+
927
+ print "#{ESCAPE}#{BLUE_COLOR}Reading and Deserializing #{RESET_COLOR}#{file_path}...\r" if $global_options[:verbose]
928
+ object = Oj.load_file(file_path.to_s)
929
+
930
+ case module_name
931
+ when :RPG
932
+ # 这里的类型检查要用紧凑模式,因为这是从 rvdata2 文件直接全部序列化后的 JSON 文件中读取的 object,其中可能存在 nil 元素
933
+ begin
934
+ check_type(object, file_basename, true, module_name)
935
+ rescue RPGTypeError
936
+ raise RPGJsonFileError.new(file_path.to_s), "Invalid RPG JSON file: #{file_path}"
937
+ end
938
+ when :R3EXS
939
+ # 这里的类型检查不能用紧凑模式,因为这是从 R3EXS 模块的类序列化后的 JSON 文件中读取的 object,程序设计中不应该存在 nil 元素
940
+ begin
941
+ check_type(object, file_basename, false, module_name)
942
+ rescue R3EXSTypeError
943
+ raise R3EXSJsonFileError.new(file_path.to_s), "Invalid R3EXS JSON file: #{file_path}"
944
+ end
945
+ else
946
+ raise ModuleNameError.new(module_name), "Invalid module name: #{module_name}"
947
+ end
948
+
949
+ yield object, file_basename, file_path.dirname.relative_path_from(target_dir)
950
+ end
951
+ end
952
+
953
+ # 读取 target_dir 下的所有 CommonEvent JSON 文件,将其反序列化为对象数组,并调用 block
954
+ #
955
+ # @note 注意传入 block 的 object
956
+ # - module_name 为 RPG 时,object 可能存在 nil 元素
957
+ # - 在 module_name 为 R3EXS 时,object 不可能存在 nil 元素
958
+ #
959
+ # @param target_dir [Pathname] 目标目录
960
+ # @param module_name [Symbol] 模块名
961
+ #
962
+ # @yieldparam commonevents [Array<Object>] CommonEvent JSON 文件反序列化后的数组
963
+ # @yieldparam commonevents_basenames [String] CommonEvent JSON 文件名数组(不包含扩展名)
964
+ # @yieldparam parent_relative_dir [Pathname] 文件所在目录的相对路径
965
+ # @yieldreturn [void]
966
+ #
967
+ # @raise [RPGJsonFileError] json 文件不是 RPG 模块中的对象
968
+ # @raise [R3EXSJsonFileError] json 文件不是 R3EXS 模块中的对象
969
+ # @raise [ModuleNameError] module_name 不是 :RPG 或 :R3EXS
970
+ # @raise [JsonDirError] target_dir 不存在
971
+ #
972
+ # @return [void]
973
+ def Utils.all_commonevent_json_files(target_dir, module_name)
974
+ # 检查 target_dir 目录是否存在
975
+ target_dir.exist? && target_dir.directory? or raise JsonDirError.new(target_dir.to_s), "JSON directory not found: #{target_dir}"
976
+
977
+ # 用两个个Hash来存储每一个父目录下的所有的 CommonEvent_\d{5}.json 文件的反序列化后的对象数组以及其文件名数组
978
+ # Hash 的键是父目录的路径,值是一个数组,存储该目录下的所有 CommonEvent_\d{5}.json 文件的反序列化后的对象数组以及其文件名数组
979
+ commonevents_hash = Hash.new { |h, k| h[k] = [] }
980
+ commonevents_basenames_hash = Hash.new { |h, k| h[k] = [] }
981
+
982
+ # 递归获取 target_dir 下的所有 CommonEvent_\d{5}.json 文件
983
+ target_dir.glob('**/CommonEvent_[0-9][0-9][0-9][0-9][0-9].json').each do |file_path|
984
+ print "#{ESCAPE}#{BLUE_COLOR}Reading and Deserializing #{RESET_COLOR}#{file_path}...\r" if $global_options[:verbose]
985
+ object = Oj.load_file(file_path.to_s)
986
+ parent_dir = file_path.dirname
987
+ commonevents_hash[parent_dir] << object
988
+ commonevents_basenames_hash[parent_dir] << file_path.basename('.json').to_s
989
+ end
990
+
991
+ # 遍历每一个父目录的路径
992
+ commonevents_hash.each_key do |parent_dir|
993
+ commonevents = commonevents_hash[parent_dir]
994
+ commonevents_basenames = commonevents_basenames_hash[parent_dir]
995
+
996
+ case module_name
997
+ when :RPG
998
+ # 这里的类型检查要用紧凑模式,因为这是从 rvdata2 文件直接全部序列化后的 JSON 文件中读取的 object,其中可能存在 nil 元素
999
+ begin
1000
+ check_type(commonevents, 'CommonEvents', true, module_name)
1001
+ rescue RPGTypeError
1002
+ raise RPGJsonFileError.new(parent_dir.to_s), "Invalid RPG CommonEvents JSON file"
1003
+ end
1004
+ when :R3EXS
1005
+ # 这里的类型检查不能用紧凑模式,因为这是从 R3EXS 模块的类序列化后的 JSON 文件中读取的 object,程序设计中不应该存在 nil 元素
1006
+ begin
1007
+ check_type(commonevents, 'CommonEvents', false, module_name)
1008
+ rescue R3EXSTypeError
1009
+ raise R3EXSJsonFileError.new(parent_dir.to_s), "Invalid R3EXS CommonEvents JSON file"
1010
+ end
1011
+ else
1012
+ raise ModuleNameError.new(module_name), "Invalid module name: #{module_name}"
1013
+ end
1014
+
1015
+ yield commonevents, commonevents_basenames, parent_dir.relative_path_from(target_dir)
1016
+ end
1017
+ end
1018
+
1019
+ # 读取 target_dir 下的所有 Ruby 源码文件,并调用 block
1020
+ #
1021
+ # @note 注意这里以二进制方式读取文件,因为 Prism 里面的节点的位置是相对二进制下的位置
1022
+ #
1023
+ # @param target_dir [Pathname] 目标目录
1024
+ #
1025
+ # @yieldparam scripts [Array<String>] 读取的 Ruby 源码文件数组
1026
+ # @yieldparam scripts_basenames [Array<String>] Ruby 源码文件名数组(不包含扩展名)
1027
+ # @yieldparam parent_relative_dir [Pathname] 文件所在目录的相对路径
1028
+ # @yieldreturn [void]
1029
+ #
1030
+ # @raise [JsonDirError] target_dir 不存在
1031
+ #
1032
+ # @return [void]
1033
+ def Utils.all_rb_files(target_dir)
1034
+ # 检查 target_dir 目录是否存在
1035
+ target_dir.exist? && target_dir.directory? or raise JsonDirError.new(target_dir.to_s), "JSON directory not found: #{target_dir}"
1036
+
1037
+ # 用两个个Hash来存储每一个父目录下的所有的 \d{3}.rb 文件的反序列化后的对象数组以及其文件名数组
1038
+ # Hash 的键是父目录的路径,值是一个数组,存储该目录下的所有 \d{3}.rb 文件的反序列化后的对象数组以及其文件名数组
1039
+ scripts_hash = Hash.new { |h, k| h[k] = [] }
1040
+ scripts_basenames_hash = Hash.new { |h, k| h[k] = [] }
1041
+
1042
+ # 递归获取 target_dir 下的所有 \d{5}.rb 文件
1043
+ target_dir.glob('**/[0-9][0-9][0-9].rb').each do |file_path|
1044
+ print "#{ESCAPE}#{BLUE_COLOR}Reading and Deserializing #{RESET_COLOR}#{file_path}...\r" if $global_options[:verbose]
1045
+ object = file_path.binread
1046
+ parent_dir = file_path.dirname
1047
+ scripts_hash[parent_dir] << object
1048
+ scripts_basenames_hash[parent_dir] << file_path.basename('.rb').to_s
1049
+ end
1050
+
1051
+ # 遍历每一个父目录的路径
1052
+ scripts_hash.each_key do |parent_dir|
1053
+ scripts = scripts_hash[parent_dir]
1054
+ scripts_basenames = scripts_basenames_hash[parent_dir]
1055
+ yield scripts, scripts_basenames, parent_dir.relative_path_from(target_dir)
1056
+ end
1057
+ end
1058
+
1059
+ # 将 object 序列化为 json 文件
1060
+ #
1061
+ # @param object [Object] 待序列化的对象
1062
+ # @param output_file [Pathname] 输出文件路径
1063
+ # @return [void]
1064
+ def Utils.object_json(object, output_file)
1065
+ output_file.dirname.mkpath unless output_file.dirname.exist?
1066
+ output_file.write(Oj.dump(object, indent: 2))
1067
+ end
1068
+
1069
+ # 将 object 序列化为 rvdata2 文件
1070
+ #
1071
+ # @param object [Object] 待序列化的对象
1072
+ # @param output_file [Pathname] 输出文件路径
1073
+ # @return [void]
1074
+ def Utils.object_rvdata2(object, output_file)
1075
+ output_file.dirname.mkpath unless output_file.dirname.exist?
1076
+ output_file.binwrite(Marshal.dump(object))
1077
+ end
1078
+
1079
+ end
1080
+
971
1081
  end