mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-07 21:24:59 +00:00
Compare commits
838 Commits
5.3
...
develop-e2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13c7792686 | ||
|
|
4ecf97b777 | ||
|
|
6536fcda77 | ||
|
|
4a19fbc754 | ||
|
|
c0cf7da7bb | ||
|
|
bbd5ba09ea | ||
|
|
90c0e51e88 | ||
|
|
85d5f6206c | ||
|
|
b412ad7b39 | ||
|
|
7de024dafd | ||
|
|
95ef337de8 | ||
|
|
682323e255 | ||
|
|
8d0061bf3d | ||
|
|
39a11e8ea8 | ||
|
|
6f37cb7e33 | ||
|
|
db2df5c8b4 | ||
|
|
0c0c826e82 | ||
|
|
bfadd7ff9f | ||
|
|
e81fe77bcc | ||
|
|
d03f012162 | ||
|
|
77772bab6d | ||
|
|
fcb4a1cec3 | ||
|
|
00d1e431b4 | ||
|
|
098ca562d0 | ||
|
|
ae80d9dcd4 | ||
|
|
210cfc654f | ||
|
|
35be8fcf67 | ||
|
|
3eb2724794 | ||
|
|
6152b75cb1 | ||
|
|
89c344dc00 | ||
|
|
61b6bb5aeb | ||
|
|
fc538a09f7 | ||
|
|
b80de83b0d | ||
|
|
48292c2a28 | ||
|
|
d1b0f5bce8 | ||
|
|
a69e6bc6b9 | ||
|
|
6d1013d34e | ||
|
|
f62a357cbd | ||
|
|
012814f557 | ||
|
|
2c071b224f | ||
|
|
44c4a50a1a | ||
|
|
2816cbcd92 | ||
|
|
4770057818 | ||
|
|
801c2d35c6 | ||
|
|
d8263da05e | ||
|
|
9c95db2324 | ||
|
|
2190f7c251 | ||
|
|
fab5fc0641 | ||
|
|
89e6df6e06 | ||
|
|
9a7dfbb587 | ||
|
|
2abdf333db | ||
|
|
273e1bb565 | ||
|
|
45127be5b6 | ||
|
|
2c6fe70f0c | ||
|
|
f4358e1542 | ||
|
|
8841a534fe | ||
|
|
6cc07d1c7a | ||
|
|
509a414f37 | ||
|
|
225549bfce | ||
|
|
03b0fa100a | ||
|
|
195c34a7c8 | ||
|
|
ff2d8e5f55 | ||
|
|
8e9417c3b7 | ||
|
|
22b33ca6c2 | ||
|
|
454d5a216a | ||
|
|
5e23984765 | ||
|
|
6c3d9e77ad | ||
|
|
b86d5b5b57 | ||
|
|
209a1ff1b3 | ||
|
|
01c13ada76 | ||
|
|
5bef70fb3a | ||
|
|
63309a2ae9 | ||
|
|
5495bf565c | ||
|
|
34741ea840 | ||
|
|
8aacfe491f | ||
|
|
dba28332f2 | ||
|
|
aef67341d2 | ||
|
|
04985eab5c | ||
|
|
81ce6e515c | ||
|
|
99aec45c5c | ||
|
|
23a8c552d6 | ||
|
|
032ad25adc | ||
|
|
53eff70d63 | ||
|
|
a80dd5adb2 | ||
|
|
4480def33c | ||
|
|
15033d6114 | ||
|
|
a548a1ae9d | ||
|
|
184ce47b93 | ||
|
|
c14faf3fed | ||
|
|
44cc500fdc | ||
|
|
d0e15a8939 | ||
|
|
f34f9040c6 | ||
|
|
29140a517e | ||
|
|
9c3314843a | ||
|
|
494e646fd5 | ||
|
|
a2af2c36f9 | ||
|
|
1977bd866c | ||
|
|
76e2b5a4fb | ||
|
|
323b62b7d5 | ||
|
|
8a218ca834 | ||
|
|
054d7820e4 | ||
|
|
ae32d59eb9 | ||
|
|
1ff5b12acd | ||
|
|
f0fae4b9ec | ||
|
|
47be44a54c | ||
|
|
1c9ce0b01a | ||
|
|
24dda5128a | ||
|
|
3e167b9357 | ||
|
|
67acf46859 | ||
|
|
86c92e7657 | ||
|
|
e6fe242d4b | ||
|
|
4455c093b8 | ||
|
|
c78e32db09 | ||
|
|
97a66020ca | ||
|
|
c5d7d1447b | ||
|
|
94f0a9c8d0 | ||
|
|
732e09336a | ||
|
|
8c5911e4a4 | ||
|
|
6bd35d44c4 | ||
|
|
d5c7b8cc15 | ||
|
|
2f231a25bb | ||
|
|
b4e7b765d1 | ||
|
|
b69f1fc5a6 | ||
|
|
5553218507 | ||
|
|
973b93a524 | ||
|
|
01ff59606b | ||
|
|
c7e8848813 | ||
|
|
d3c9c6b360 | ||
|
|
1080f69a0d | ||
|
|
e0dcdef321 | ||
|
|
b54a96f23f | ||
|
|
d10892af47 | ||
|
|
f07b44d826 | ||
|
|
156a6fca74 | ||
|
|
092fbda34d | ||
|
|
ab2d2c1356 | ||
|
|
64890f3c9e | ||
|
|
340983e765 | ||
|
|
7031698d85 | ||
|
|
5cab0f407d | ||
|
|
389d43941d | ||
|
|
25f85a9a8b | ||
|
|
193f01f70b | ||
|
|
79ffcd3230 | ||
|
|
d267956c6e | ||
|
|
a6c7e2c1ff | ||
|
|
cd32b5e725 | ||
|
|
e96f16c484 | ||
|
|
2ff47cf40d | ||
|
|
d9c3898124 | ||
|
|
b2c66b7b0c | ||
|
|
bc18aa95f2 | ||
|
|
8f00307685 | ||
|
|
02e45ebf19 | ||
|
|
d4077875a4 | ||
|
|
1041883992 | ||
|
|
efea53aa5a | ||
|
|
ea7b5d56d2 | ||
|
|
bd70166dbb | ||
|
|
3d4a495849 | ||
|
|
4c25ade184 | ||
|
|
4f14108772 | ||
|
|
1b5c0f6f2f | ||
|
|
9a42b533f1 | ||
|
|
1c860a5544 | ||
|
|
0068695c54 | ||
|
|
fc95baf92c | ||
|
|
a5734eaf46 | ||
|
|
6053363715 | ||
|
|
f576db7c0b | ||
|
|
4ca2500d6b | ||
|
|
8287f32a5e | ||
|
|
104bf2b598 | ||
|
|
2986ab3ebb | ||
|
|
2078f6b116 | ||
|
|
60f8a0cf7b | ||
|
|
aecd9e5bb6 | ||
|
|
22fa0f9c0b | ||
|
|
7d77c5f3fc | ||
|
|
4fc0806c8a | ||
|
|
17e8be9dca | ||
|
|
539bc0fb50 | ||
|
|
b5e37248b9 | ||
|
|
9c2a9130a5 | ||
|
|
20affb4345 | ||
|
|
679e9d42dc | ||
|
|
3470f9769c | ||
|
|
1901675e33 | ||
|
|
68de25562a | ||
|
|
f27841a7f8 | ||
|
|
01a6869061 | ||
|
|
c756e2647a | ||
|
|
167155c67d | ||
|
|
276c052822 | ||
|
|
d112e2361a | ||
|
|
62e372f4d7 | ||
|
|
28a2b7c9c1 | ||
|
|
a96867d537 | ||
|
|
e7e153bf11 | ||
|
|
6ca7da0a06 | ||
|
|
a4d74a9663 | ||
|
|
7a8754c425 | ||
|
|
5a2f0723ab | ||
|
|
a397e60ca5 | ||
|
|
72469bbf79 | ||
|
|
48fb8dae73 | ||
|
|
5f20121e59 | ||
|
|
b7a40d0344 | ||
|
|
ce549ab62a | ||
|
|
da182bd98a | ||
|
|
4bab130785 | ||
|
|
d277658965 | ||
|
|
b9bf3e8b83 | ||
|
|
7f6f57dec3 | ||
|
|
af5256ae0f | ||
|
|
a714086a39 | ||
|
|
c654636bdc | ||
|
|
a22c5ea89c | ||
|
|
956a511ec5 | ||
|
|
5315b53eae | ||
|
|
6b690c4492 | ||
|
|
1ddf89c2df | ||
|
|
3d9d31621b | ||
|
|
cb4a1fd8af | ||
|
|
e7847fba9a | ||
|
|
b226e3cbb6 | ||
|
|
9d50b27aa0 | ||
|
|
5d9cc71a99 | ||
|
|
ad29a79e1c | ||
|
|
0bb0fb4a26 | ||
|
|
138d41f7bc | ||
|
|
1ead0a76f5 | ||
|
|
e2648032c1 | ||
|
|
941e238606 | ||
|
|
7f5aea63bb | ||
|
|
02129f5507 | ||
|
|
f5bf1f6ab1 | ||
|
|
e9a44377ce | ||
|
|
5a18f7fd65 | ||
|
|
e93c3c69ac | ||
|
|
9f96684048 | ||
|
|
3a9199da1b | ||
|
|
ee72ad371f | ||
|
|
e43fdeec25 | ||
|
|
05f5d621b7 | ||
|
|
6157c63fa2 | ||
|
|
ab58da4877 | ||
|
|
d0c99aa512 | ||
|
|
0e4053f837 | ||
|
|
81d069eef1 | ||
|
|
a8e024eb3e | ||
|
|
7e4ef4247b | ||
|
|
becce85550 | ||
|
|
8a3353973b | ||
|
|
01e98c8f97 | ||
|
|
3f5c1f0974 | ||
|
|
d0c39a3e89 | ||
|
|
4749bd5201 | ||
|
|
c233841bb6 | ||
|
|
5086f692df | ||
|
|
7678a13e94 | ||
|
|
80bb967aad | ||
|
|
4da9a8c4e3 | ||
|
|
13aab8d911 | ||
|
|
2d056052ce | ||
|
|
a0af8e6eb5 | ||
|
|
b0b6e675c3 | ||
|
|
f6213057d8 | ||
|
|
d8f38947f4 | ||
|
|
f7578002ea | ||
|
|
0c9df4627e | ||
|
|
3d9c3e2c00 | ||
|
|
2627d68782 | ||
|
|
98f16c2afa | ||
|
|
84bdd1f60b | ||
|
|
a22f75f500 | ||
|
|
632b0f8b4b | ||
|
|
ae0d193bba | ||
|
|
2e8329f70b | ||
|
|
707cd143d8 | ||
|
|
9dd774a767 | ||
|
|
522f78b75d | ||
|
|
3fa94bacc6 | ||
|
|
37246d8d01 | ||
|
|
4585533a4a | ||
|
|
05b954e262 | ||
|
|
3fe324d0da | ||
|
|
dd7cd414f0 | ||
|
|
1258e4b9c9 | ||
|
|
f33184d413 | ||
|
|
3a4b01e2dc | ||
|
|
7ace4c5289 | ||
|
|
539a47671d | ||
|
|
d654f3edbf | ||
|
|
b13c2ed2ed | ||
|
|
7c39a56a43 | ||
|
|
c53a52564b | ||
|
|
427cc45629 | ||
|
|
91efb4684b | ||
|
|
bd04112122 | ||
|
|
4d147a7bf7 | ||
|
|
f33eb4d896 | ||
|
|
1ff7307868 | ||
|
|
5d439de87d | ||
|
|
6f2e72eed6 | ||
|
|
8f014135e5 | ||
|
|
b31400b9ae | ||
|
|
55563463d8 | ||
|
|
3e73d1c1f9 | ||
|
|
bbe654028c | ||
|
|
5dd8c31ff0 | ||
|
|
4f42eca3ee | ||
|
|
096957bc20 | ||
|
|
c984fda1cf | ||
|
|
3408b038cf | ||
|
|
6f7a714d48 | ||
|
|
e12fd08eb1 | ||
|
|
5384a7afe4 | ||
|
|
2d411cf152 | ||
|
|
64f975072b | ||
|
|
5a49bbbc94 | ||
|
|
9eb90b784e | ||
|
|
9ad45d6b07 | ||
|
|
e8703e8b05 | ||
|
|
43290c39a2 | ||
|
|
58a624060a | ||
|
|
b41a46aacf | ||
|
|
de07341337 | ||
|
|
882f4c96f8 | ||
|
|
9695094b02 | ||
|
|
fa2758edaa | ||
|
|
2897476d1b | ||
|
|
4ddf689887 | ||
|
|
88dc215417 | ||
|
|
1ccbafb499 | ||
|
|
63ec037481 | ||
|
|
8c31ad994d | ||
|
|
2962944cab | ||
|
|
4fcd19e247 | ||
|
|
25a8d727ab | ||
|
|
662d023ff5 | ||
|
|
dcba641a86 | ||
|
|
eb8fc1d298 | ||
|
|
9bd31300ad | ||
|
|
eecb7a1453 | ||
|
|
b8c61a6038 | ||
|
|
db215a71d6 | ||
|
|
d870b027db | ||
|
|
429068f3cb | ||
|
|
ecb5e2ffd1 | ||
|
|
92c0fe5c90 | ||
|
|
931a47c5fe | ||
|
|
8275d40193 | ||
|
|
22dce593e8 | ||
|
|
9ed2f3e920 | ||
|
|
fbbddc8c2b | ||
|
|
265897f9e1 | ||
|
|
b6c84fa278 | ||
|
|
cfb870c944 | ||
|
|
b094a2fd8e | ||
|
|
4075204038 | ||
|
|
18ffd4fb94 | ||
|
|
963d2a515b | ||
|
|
ae91811537 | ||
|
|
b1cde2db42 | ||
|
|
aa9b1a9e23 | ||
|
|
c79b970d6b | ||
|
|
1d2f13f9c5 | ||
|
|
d890cd8a24 | ||
|
|
5ff0c04eed | ||
|
|
eeeb9b3494 | ||
|
|
a20f378b33 | ||
|
|
bff0cc6974 | ||
|
|
b2ddedbce1 | ||
|
|
6542d505a6 | ||
|
|
cca414a826 | ||
|
|
f083cddca5 | ||
|
|
b423f34da6 | ||
|
|
f22707f2f1 | ||
|
|
3c748c9d68 | ||
|
|
757798c8a8 | ||
|
|
72e45ab137 | ||
|
|
473d4cbb67 | ||
|
|
8ae07a6d15 | ||
|
|
3314477f08 | ||
|
|
b50ce948f6 | ||
|
|
e1dc7c91bc | ||
|
|
0b65865962 | ||
|
|
8f73319605 | ||
|
|
a85f672c73 | ||
|
|
2976ee93ce | ||
|
|
a2327c6280 | ||
|
|
6dd88e49e1 | ||
|
|
94c6b6db0c | ||
|
|
7e183a92aa | ||
|
|
76639c4ba5 | ||
|
|
03ffae6eed | ||
|
|
2486fa9fe2 | ||
|
|
040247536f | ||
|
|
ad93eb7774 | ||
|
|
8b3d95943a | ||
|
|
9261851701 | ||
|
|
9a53ee8a0e | ||
|
|
2e3ba2e09e | ||
|
|
b367b2442b | ||
|
|
9a03b25755 | ||
|
|
79f5e5d4aa | ||
|
|
4b895e44ef | ||
|
|
d42e35f8c4 | ||
|
|
cd47b9899c | ||
|
|
3d8e22690d | ||
|
|
3238ff817c | ||
|
|
b8e9251fb4 | ||
|
|
62b964adfa | ||
|
|
c0c672806d | ||
|
|
cc540b0132 | ||
|
|
8d4015c903 | ||
|
|
301ecb0ac7 | ||
|
|
732c167ad5 | ||
|
|
aec0215442 | ||
|
|
cdc82b6e65 | ||
|
|
248b0dd882 | ||
|
|
cb2f33d8f6 | ||
|
|
49c916e1bb | ||
|
|
101dca7a31 | ||
|
|
038be447fb | ||
|
|
d383d69cf4 | ||
|
|
2c65a9de7d | ||
|
|
ff1f9633f3 | ||
|
|
b441411b2e | ||
|
|
e3dbc5e690 | ||
|
|
17e386d33e | ||
|
|
0da046d2c3 | ||
|
|
1532be2410 | ||
|
|
a63d031da2 | ||
|
|
3338875dd8 | ||
|
|
2ba2893869 | ||
|
|
22018012c7 | ||
|
|
9f09851db9 | ||
|
|
aa2269c858 | ||
|
|
8310114252 | ||
|
|
6a046ff755 | ||
|
|
9ecbee910d | ||
|
|
325a1b2998 | ||
|
|
eebe93678a | ||
|
|
ff3c3acfa6 | ||
|
|
0d567db2cd | ||
|
|
ebf83649ec | ||
|
|
eab69f213a | ||
|
|
d94d1836c6 | ||
|
|
41479fac04 | ||
|
|
a280fea093 | ||
|
|
98aeff01c5 | ||
|
|
38d551f72b | ||
|
|
ce5d68a904 | ||
|
|
d5e26d13f7 | ||
|
|
0ab1e6242d | ||
|
|
d28ccd13e1 | ||
|
|
b344cb7fcc | ||
|
|
cc7ecf0326 | ||
|
|
622aa708b0 | ||
|
|
f5ee3b9c9f | ||
|
|
47ad801645 | ||
|
|
5fb8218098 | ||
|
|
e9cd62b8b6 | ||
|
|
d7f4434000 | ||
|
|
04f3b29fe3 | ||
|
|
e12b6fde1d | ||
|
|
cf338b3a6a | ||
|
|
22f0c8627a | ||
|
|
07d7403fbf | ||
|
|
823ce771a8 | ||
|
|
1caedc0ed2 | ||
|
|
7a88d47b4b | ||
|
|
5a1ef50e57 | ||
|
|
1b551b30f4 | ||
|
|
140ba4c622 | ||
|
|
c3af3c6f58 | ||
|
|
b7f230fcfc | ||
|
|
5714a2d6d3 | ||
|
|
fd5d3e332d | ||
|
|
ad29dc6dc4 | ||
|
|
8062b8ed6c | ||
|
|
a85ec1e51a | ||
|
|
77f9547687 | ||
|
|
d3b61a64ef | ||
|
|
144ad91bc1 | ||
|
|
408e63b5d7 | ||
|
|
d6c6b79705 | ||
|
|
20d6d4ff0a | ||
|
|
f66e8db906 | ||
|
|
90328df274 | ||
|
|
0d4c27d413 | ||
|
|
4a478ab6d0 | ||
|
|
0680f8665d | ||
|
|
22e0d1dfc5 | ||
|
|
026e6f5c0a | ||
|
|
e87d55f56f | ||
|
|
c012a7323a | ||
|
|
38edb15f0c | ||
|
|
3a4339c658 | ||
|
|
3c6799091e | ||
|
|
81578ac42c | ||
|
|
7d583aaaf7 | ||
|
|
2817c1998a | ||
|
|
21f7c57905 | ||
|
|
93a0173fe8 | ||
|
|
a0612b907f | ||
|
|
91f8d06797 | ||
|
|
7f8fa16a52 | ||
|
|
5d8dad58c4 | ||
|
|
a13771e8bc | ||
|
|
bcb31c7a56 | ||
|
|
a20a1775c0 | ||
|
|
fe159419f7 | ||
|
|
fe6b87c075 | ||
|
|
4fc6e7f289 | ||
|
|
15e70fa67e | ||
|
|
e5be233224 | ||
|
|
2057084f69 | ||
|
|
33cde3bf20 | ||
|
|
9b3e62b1f3 | ||
|
|
19e50bd507 | ||
|
|
dd78075657 | ||
|
|
f322b234c6 | ||
|
|
5f39363e69 | ||
|
|
789185eefb | ||
|
|
f68e699cc9 | ||
|
|
cca5989746 | ||
|
|
30c3f472ef | ||
|
|
e6c877fe06 | ||
|
|
4561cc66bf | ||
|
|
6c5c54a7d3 | ||
|
|
0465572ca0 | ||
|
|
6698149083 | ||
|
|
91c6f1f45b | ||
|
|
617f685694 | ||
|
|
af60c4df66 | ||
|
|
f9e34b8157 | ||
|
|
7c7a6d91bd | ||
|
|
2372322c24 | ||
|
|
8f69c555da | ||
|
|
98f311c394 | ||
|
|
c1de9a04d4 | ||
|
|
d0da7b0c1b | ||
|
|
8a3e5b01e0 | ||
|
|
7f0526114f | ||
|
|
b980d8505c | ||
|
|
a0d951edf7 | ||
|
|
e9afefb210 | ||
|
|
1279f8137e | ||
|
|
f872db2618 | ||
|
|
b550ad9c07 | ||
|
|
8a89b7fbf4 | ||
|
|
25b009b344 | ||
|
|
24efbccb67 | ||
|
|
ff465a78a6 | ||
|
|
767a47d90f | ||
|
|
507014e655 | ||
|
|
5fba3462c6 | ||
|
|
91e3d8190e | ||
|
|
f853816d63 | ||
|
|
f623fad42e | ||
|
|
6d23d0101a | ||
|
|
3f51ab44e4 | ||
|
|
a939406e60 | ||
|
|
aa18a59413 | ||
|
|
a6115faad6 | ||
|
|
2a34904baa | ||
|
|
4cf13f2942 | ||
|
|
7da449aec3 | ||
|
|
a6c092a574 | ||
|
|
f3c4893dbb | ||
|
|
ca9df4177a | ||
|
|
13cc9790ce | ||
|
|
fb29f19a28 | ||
|
|
a7e8005f53 | ||
|
|
3d37733d1a | ||
|
|
6339f5a577 | ||
|
|
63b157d7ec | ||
|
|
01ce5d347c | ||
|
|
3e9d3b0a68 | ||
|
|
139f2a74f2 | ||
|
|
aa643a6049 | ||
|
|
4a6324389b | ||
|
|
35126dfb6b | ||
|
|
b988638746 | ||
|
|
132a16950d | ||
|
|
514fe13ca2 | ||
|
|
022dc7aadb | ||
|
|
6b3fa5e1bf | ||
|
|
dfb3a51815 | ||
|
|
3c85c3fe55 | ||
|
|
5cdabe5b58 | ||
|
|
2e63556722 | ||
|
|
33fcbf623b | ||
|
|
db4acd3369 | ||
|
|
7f86db6da9 | ||
|
|
65b1a8d6c3 | ||
|
|
33781493f4 | ||
|
|
13a238cc6a | ||
|
|
d17fc40a47 | ||
|
|
f7b76ae62e | ||
|
|
2480ab0f9e | ||
|
|
5dc64f1709 | ||
|
|
b5ee1b211d | ||
|
|
eec29709ac | ||
|
|
8a77c2d9e1 | ||
|
|
15b86429a2 | ||
|
|
b706843888 | ||
|
|
7d2e1027cd | ||
|
|
a89d552f8e | ||
|
|
840e1a8be9 | ||
|
|
3da8b563da | ||
|
|
2444b70ef6 | ||
|
|
2ddedfb935 | ||
|
|
85bf1a334c | ||
|
|
c1695dd21b | ||
|
|
241851a75b | ||
|
|
b9d69b780b | ||
|
|
2e3d479752 | ||
|
|
6a56a8f7d0 | ||
|
|
c55f1f0a2a | ||
|
|
79e04bff6c | ||
|
|
054b4bc3e8 | ||
|
|
514ef510f1 | ||
|
|
6b841b78d3 | ||
|
|
a858408951 | ||
|
|
5a81d447d1 | ||
|
|
95916e242e | ||
|
|
3650a078e7 | ||
|
|
5337ee1e97 | ||
|
|
7c48148d35 | ||
|
|
479aeacc2c | ||
|
|
00c2df5772 | ||
|
|
a5f91f62ea | ||
|
|
d93d73caa8 | ||
|
|
c8b574ed7c | ||
|
|
ddb95a8bb6 | ||
|
|
ea9cacd6b9 | ||
|
|
b445f26a88 | ||
|
|
048a18b415 | ||
|
|
8307222009 | ||
|
|
7ec8f30f0e | ||
|
|
1c4819e5f0 | ||
|
|
6dacd6a139 | ||
|
|
06493fecbb | ||
|
|
99b6d86962 | ||
|
|
f00553c1eb | ||
|
|
9657eca3d7 | ||
|
|
a7f71e9620 | ||
|
|
46a92a33ef | ||
|
|
c6ecf60172 | ||
|
|
12fd500dbc | ||
|
|
15babcf835 | ||
|
|
34ab0b8afe | ||
|
|
ae7721316f | ||
|
|
c392f8c236 | ||
|
|
50d999e7da | ||
|
|
5ad9f60d61 | ||
|
|
cff6edac5b | ||
|
|
e8170a267c | ||
|
|
0ec67f78fa | ||
|
|
ee16c22388 | ||
|
|
67fc59ad4e | ||
|
|
308937a9f4 | ||
|
|
899d037255 | ||
|
|
0c3ec24936 | ||
|
|
f3abcb7caf | ||
|
|
6066797517 | ||
|
|
6c38f769c7 | ||
|
|
680c1de392 | ||
|
|
18049c22b9 | ||
|
|
e417e4c659 | ||
|
|
10a1fc4430 | ||
|
|
ca680c9feb | ||
|
|
5e51f702b3 | ||
|
|
e49cd8d498 | ||
|
|
fbddb9034f | ||
|
|
3a3b44574f | ||
|
|
d3a07df6ab | ||
|
|
e7522321ad | ||
|
|
e4e8e60d28 | ||
|
|
837208792a | ||
|
|
aee0595d3f | ||
|
|
50065754a0 | ||
|
|
f6a5ea86db | ||
|
|
36ff7c4ba3 | ||
|
|
72c50db6c0 | ||
|
|
c68e5e7abf | ||
|
|
56c9b69c44 | ||
|
|
a5bbd1fb8a | ||
|
|
de0eb8e4e1 | ||
|
|
0aad105c6d | ||
|
|
45fd570414 | ||
|
|
a090f50bc5 | ||
|
|
166a289a60 | ||
|
|
c8b594d38d | ||
|
|
c0ac135a69 | ||
|
|
8bb8c1149f | ||
|
|
3cc6a1201f | ||
|
|
1f9ba94432 | ||
|
|
929a039f04 | ||
|
|
559caf1046 | ||
|
|
c7858de42a | ||
|
|
af23f1ecc4 | ||
|
|
348b847b68 | ||
|
|
11544da43f | ||
|
|
f35a51f975 | ||
|
|
0b656edffc | ||
|
|
c496fed620 | ||
|
|
75a39dbc42 | ||
|
|
096f13f451 | ||
|
|
694e567f3d | ||
|
|
4edd06208a | ||
|
|
d4abc6ef2b | ||
|
|
1fb3ff5408 | ||
|
|
f00f030825 | ||
|
|
f9c6e142e5 | ||
|
|
df7c033a9d | ||
|
|
27be1cb330 | ||
|
|
c670c63bf5 | ||
|
|
c7fd147040 | ||
|
|
423961e524 | ||
|
|
885c1193e3 | ||
|
|
cef3d08917 | ||
|
|
86cbcad382 | ||
|
|
cfbefceb00 | ||
|
|
171f1aade2 | ||
|
|
218307d993 | ||
|
|
3c88c897f0 | ||
|
|
0405497868 | ||
|
|
c92bb2fb42 | ||
|
|
70ef588190 | ||
|
|
a9426b0802 | ||
|
|
f411867c52 | ||
|
|
a31ac0d4af | ||
|
|
6db668b449 | ||
|
|
c39eca3975 | ||
|
|
6551697b4f | ||
|
|
7318d304de | ||
|
|
8bb70a226e | ||
|
|
ecc5a040cd | ||
|
|
e57e1f4a1e | ||
|
|
e0e5cfebb7 | ||
|
|
1b9e7400f9 | ||
|
|
45fba56455 | ||
|
|
41ce9309d7 | ||
|
|
9c5c3c77ed | ||
|
|
f768df4696 | ||
|
|
7ae62d74b7 | ||
|
|
2112cdba37 | ||
|
|
153aa69bb8 | ||
|
|
4b768bec32 | ||
|
|
19535b8160 | ||
|
|
c360c4ddd2 | ||
|
|
61242a9836 | ||
|
|
2db3cc49af | ||
|
|
7f86115c36 | ||
|
|
76eaadda61 | ||
|
|
c6da16409e | ||
|
|
ec84d581ad | ||
|
|
c8b1b6251b | ||
|
|
34dd2a9fbd | ||
|
|
d71a3d47e8 | ||
|
|
a1cff9cc36 | ||
|
|
912631a8b1 | ||
|
|
cb0220b751 | ||
|
|
d21d3cb1fd | ||
|
|
1bd5652a3a | ||
|
|
551f64e8a1 | ||
|
|
03a7ff39ad | ||
|
|
4d9c8feb81 | ||
|
|
8f72876a23 | ||
|
|
14748f4999 | ||
|
|
78f5530cbe | ||
|
|
8b7a532e29 | ||
|
|
3d634a7f22 | ||
|
|
8ed9c5139e | ||
|
|
4b98850c3a | ||
|
|
33f0403945 | ||
|
|
ae7661edc5 | ||
|
|
d5aeeaca7b | ||
|
|
ba6806aa5b | ||
|
|
633a0b1a1b | ||
|
|
f4ba8951c6 | ||
|
|
16a11d314f | ||
|
|
66ed71dcad | ||
|
|
fc54ed5630 | ||
|
|
987cb7640c | ||
|
|
536a0b4f9a | ||
|
|
0af3fe46bd | ||
|
|
93b67c9047 | ||
|
|
5736ef404b | ||
|
|
d5459fb97c | ||
|
|
bc7f469308 | ||
|
|
c457d59a0e | ||
|
|
d4c01724c7 | ||
|
|
66169b56be | ||
|
|
753650acf3 | ||
|
|
cb60fa1299 | ||
|
|
84b1512c9b | ||
|
|
e93b08a87b | ||
|
|
18408d204e | ||
|
|
80e95dc48a | ||
|
|
49e7374c3d | ||
|
|
223d480e0f | ||
|
|
bb429a2680 | ||
|
|
feb9e3b2de | ||
|
|
0ad86e6b03 | ||
|
|
9344ef8d04 | ||
|
|
43900dca8c | ||
|
|
9e1e113333 | ||
|
|
eceb7f2084 | ||
|
|
3c3802b80b | ||
|
|
657ed7944d | ||
|
|
c194e1b711 | ||
|
|
565b15dca4 | ||
|
|
b1caf13110 | ||
|
|
ca09e8c092 | ||
|
|
53d27d3cf5 | ||
|
|
e201821919 | ||
|
|
7c42e4ec20 | ||
|
|
1a55a391a3 | ||
|
|
1cec4fc90d | ||
|
|
e4cdb95314 | ||
|
|
9b4bc66dc0 | ||
|
|
e472d0fcdf | ||
|
|
c55324145d | ||
|
|
49655165e1 | ||
|
|
6e188666a4 | ||
|
|
eaa915878a | ||
|
|
5358037986 | ||
|
|
e9457a3ea8 | ||
|
|
8c67127f06 | ||
|
|
0e8b1e70b1 | ||
|
|
5df5e83f68 | ||
|
|
9226bce078 |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -2,13 +2,16 @@
|
||||
Audio/
|
||||
Graphics/
|
||||
Plugins/
|
||||
Screenshots/
|
||||
|
||||
# Data folder, but not Data/Scripts folder
|
||||
# Data folder, but not Data/Scripts folder or messages_core.dat
|
||||
Data/*
|
||||
!Data/Scripts.rxdata
|
||||
!Data/Scripts/
|
||||
!Data/messages_core.dat
|
||||
|
||||
# Files in the main project folder
|
||||
errorlog.txt
|
||||
Game.ini
|
||||
Game.rxproj
|
||||
RGSS*.dll
|
||||
@@ -17,6 +20,7 @@ RGSS*.dll
|
||||
.vscode/
|
||||
*.code-workspace
|
||||
.idea/
|
||||
*.mkproj
|
||||
|
||||
# Operating system generated files & folders
|
||||
.DS_Store
|
||||
@@ -27,4 +31,4 @@ Thumbs.db
|
||||
|
||||
# Temp files
|
||||
|
||||
~*
|
||||
~*
|
||||
|
||||
225
.rubocop.yml
Normal file
225
.rubocop.yml
Normal file
@@ -0,0 +1,225 @@
|
||||
AllCops:
|
||||
TargetRubyVersion: "3.0"
|
||||
NewCops: enable
|
||||
|
||||
#===============================================================================
|
||||
# Layout
|
||||
#===============================================================================
|
||||
|
||||
# We don't need empty lines in methods to separate "return if"s from later code.
|
||||
Layout/EmptyLineAfterGuardClause:
|
||||
Enabled: false
|
||||
|
||||
# Extra whitespace often helps to make code more presentable.
|
||||
Layout/ExtraSpacing:
|
||||
AllowForAlignment: true
|
||||
AllowBeforeTrailingComments: true
|
||||
|
||||
# Looks better than having hash elements shifted way to the right just to line
|
||||
# up with the hash's opening bracket.
|
||||
Layout/FirstHashElementIndentation:
|
||||
EnforcedStyle: consistent
|
||||
|
||||
# In a hash with multiple values (one per line), prefer the => to be lined up
|
||||
# and text to otherwise be left-aligned.
|
||||
Layout/HashAlignment:
|
||||
EnforcedHashRocketStyle: table
|
||||
EnforcedColonStyle: table
|
||||
|
||||
# This interferes with the presentation of some code, notably registered procs.
|
||||
Layout/MultilineMethodCallBraceLayout:
|
||||
Enabled: false
|
||||
|
||||
# This means hashes and arrays are written the same way, rather than hashes
|
||||
# needing to be written like { foo => bar } while arrays are like [foo, bar].
|
||||
Layout/SpaceInsideHashLiteralBraces:
|
||||
EnforcedStyle: no_space
|
||||
|
||||
#===============================================================================
|
||||
# Lint
|
||||
#===============================================================================
|
||||
|
||||
# Some methods and blocks will have unused arguments. That's fine.
|
||||
Lint/UnusedBlockArgument:
|
||||
Enabled: false
|
||||
Lint/UnusedMethodArgument:
|
||||
Enabled: false
|
||||
|
||||
#===============================================================================
|
||||
# Metrics
|
||||
#===============================================================================
|
||||
|
||||
# Yes, Essentials has classes/modules/methods that are too big and complex.
|
||||
# That's just how it is.
|
||||
Metrics:
|
||||
Enabled: false
|
||||
|
||||
#===============================================================================
|
||||
# Naming
|
||||
#===============================================================================
|
||||
|
||||
# This cop forbids class/module names with underscores in them. Having
|
||||
# underscores isn't the end of the world.
|
||||
Naming/ClassAndModuleCamelCase:
|
||||
Enabled: false
|
||||
|
||||
# Script files are given names that look reasonable in the list of script
|
||||
# sections in RMXP, and are all numbered. They won't be camel_case.
|
||||
Naming/FileName:
|
||||
Enabled: false
|
||||
|
||||
# Disabled for sanity's sake. While this is a cop we want to obey, fixing all
|
||||
# this is a gargantuan task that may never be completed, and we don't need
|
||||
# rubocop telling us about the 4000+ instances of camelCase method names.
|
||||
Naming/MethodName:
|
||||
Enabled: false
|
||||
|
||||
# Disabled for sanity's sake. While this is a cop we want to obey, fixing all
|
||||
# this is a gargantuan task that may never be completed, and we don't need
|
||||
# rubocop telling us about the 1500+ instances of camelCase parameter names.
|
||||
Naming/MethodParameterName:
|
||||
Enabled: false
|
||||
|
||||
# Disabled for sanity's sake. While this is a cop we want to obey, fixing all
|
||||
# this is a gargantuan task that may never be completed, and we don't need
|
||||
# rubocop telling us about the 10000+ instances of camelCase variable names.
|
||||
Naming/VariableName:
|
||||
Enabled: false
|
||||
|
||||
#===============================================================================
|
||||
# Security
|
||||
#===============================================================================
|
||||
|
||||
# Script event conditions and script switches are eval'd, amongst other things.
|
||||
Security/Eval:
|
||||
Enabled: false
|
||||
|
||||
# Plenty of things are loaded via Marshal.
|
||||
Security/MarshalLoad:
|
||||
Enabled: false
|
||||
|
||||
#===============================================================================
|
||||
# Style
|
||||
#===============================================================================
|
||||
|
||||
# List the attr_reader/writer/accessor variables however you want.
|
||||
Style/AccessorGrouping:
|
||||
Enabled: false
|
||||
|
||||
# The assign_to_condition style looks awful, indenting loads of lines and
|
||||
# increasing the separation between variable and value being assigned to it.
|
||||
# Having said that, using "assign_inside_condition" flags every instance of
|
||||
# conditional assignment using a one-line ternary operator, so this cop has been
|
||||
# disabled because such assignment is fine.
|
||||
Style/ConditionalAssignment:
|
||||
Enabled: false
|
||||
EnforcedStyle: assign_inside_condition
|
||||
|
||||
# Check with yard instead.
|
||||
Style/Documentation:
|
||||
Enabled: false
|
||||
|
||||
# This is just shorthand that looks bad due to the lack of an "end" to a "def".
|
||||
Style/EndlessMethod:
|
||||
EnforcedStyle: disallow
|
||||
|
||||
# It's a choice between format and sprintf. We already make use of sprintf and
|
||||
# the translatable _ISPRINTF, so...
|
||||
Style/FormatString:
|
||||
EnforcedStyle: sprintf
|
||||
|
||||
# Prefer sprintf("%s", "Hello") over sprintf("%<greeting>s", greeting: "Hello")
|
||||
# because it should be easy enough to see which token is which, and it saves
|
||||
# space.
|
||||
Style/FormatStringToken:
|
||||
EnforcedStyle: unannotated
|
||||
|
||||
# String literals are not frozen by default, which makes this comment a
|
||||
# pointless bit of boilerplate that we neither need nor want.
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: false
|
||||
|
||||
# RMXP and Essentials use lots of global variables.
|
||||
Style/GlobalVars:
|
||||
Enabled: false
|
||||
|
||||
# Mixing the styles within a hash just looks silly.
|
||||
Style/HashSyntax:
|
||||
EnforcedStyle: no_mixed_keys
|
||||
|
||||
# Sometimes you want to clearly separate sets of code, one per "paradigm".
|
||||
Style/IfInsideElse:
|
||||
Enabled: false
|
||||
AllowIfModifier: true
|
||||
|
||||
# The alernative is ->(x) { x } which is less English than "lambda". This style
|
||||
# makes lambda definitions require the word "lambda".
|
||||
Style/Lambda:
|
||||
EnforcedStyle: lambda
|
||||
|
||||
# unless just adds mental gymnastics trying to figure out what it actually
|
||||
# means. I much prefer if !something.
|
||||
Style/NegatedIf:
|
||||
Enabled: false
|
||||
|
||||
# .zero?, .positive? and .negative? are more wordy than == 0, > 0 and < 0. They
|
||||
# also aren't consistent with other value comparisons, e.g. x > 42.
|
||||
Style/NumericPredicate:
|
||||
EnforcedStyle: comparison
|
||||
|
||||
# Following this just means that calls to an affected method need to know what
|
||||
# that method calls its parameters, which is ridiculous. Keep things short and
|
||||
# simple.
|
||||
Style/OptionalBooleanParameter:
|
||||
Enabled: false
|
||||
|
||||
# has_key? and has_value? are far more readable than key? and value?
|
||||
Style/PreferredHashMethods:
|
||||
Enabled: false
|
||||
|
||||
# Explicit returns help to show whether a method returns a value.
|
||||
Style/RedundantReturn:
|
||||
Enabled: false
|
||||
|
||||
# Enforcing the names of variables? To single letter ones? Just no.
|
||||
Style/SingleLineBlockParams:
|
||||
Enabled: false
|
||||
|
||||
# Single line methods use up less space, and they're easier to list next to each
|
||||
# other and see that they behave similarly.
|
||||
Style/SingleLineMethods:
|
||||
Enabled: false
|
||||
|
||||
# This requires writing array[n..] instead of array[n..-1], and I think endless
|
||||
# ranges look bad.
|
||||
Style/SlicingWithRange:
|
||||
Enabled: false
|
||||
|
||||
# Single quotes being faster is hardly measurable and only affects parse time.
|
||||
# Enforcing double quotes reduces the times where you need to change them
|
||||
# when introducing an interpolation or an apostrophe. Use single quotes only if
|
||||
# their semantics are needed.
|
||||
Style/StringLiterals:
|
||||
EnforcedStyle: double_quotes
|
||||
|
||||
# This cop requires arrays of symbols/text to be written like %i[a b c]. We
|
||||
# don't need that nonsense. ["a", "b", "c"] is clearer and introduces no
|
||||
# additional syntax to confuse people.
|
||||
Style/SymbolArray:
|
||||
EnforcedStyle: brackets
|
||||
Style/WordArray:
|
||||
EnforcedStyle: brackets
|
||||
|
||||
# Allows procs to be written like { |obj| obj.something } which is clearer.
|
||||
Style/SymbolProc:
|
||||
AllowMethodsWithArguments: true
|
||||
|
||||
# Parentheses around the condition in a ternary operator helps to differentiate
|
||||
# it from the true/false results.
|
||||
Style/TernaryParentheses:
|
||||
EnforcedStyle: require_parentheses
|
||||
|
||||
# This prefers "x += 1 while x < 10" and "x += 1 until x == 10". This hides
|
||||
# loops, which is not good.
|
||||
Style/WhileUntilModifier:
|
||||
Enabled: false
|
||||
Binary file not shown.
@@ -1,12 +1,12 @@
|
||||
#==============================================================================#
|
||||
# Pokémon Essentials #
|
||||
# Version 19.1.dev #
|
||||
# Version 21.1 #
|
||||
# https://github.com/Maruno17/pokemon-essentials #
|
||||
#==============================================================================#
|
||||
|
||||
module Settings
|
||||
# The version of your game. It has to adhere to the MAJOR.MINOR.PATCH format.
|
||||
GAME_VERSION = '1.0.0'
|
||||
GAME_VERSION = "1.0.0"
|
||||
|
||||
# The generation that the battle system follows. Used throughout the battle
|
||||
# scripts, and also by some other settings which are used in and out of battle
|
||||
@@ -14,40 +14,39 @@ module Settings
|
||||
# Note that this isn't perfect. Essentials doesn't accurately replicate every
|
||||
# single generation's mechanics. It's considered to be good enough. Only
|
||||
# generations 5 and later are reasonably supported.
|
||||
MECHANICS_GENERATION = 7
|
||||
MECHANICS_GENERATION = 9
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Credits
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# The default screen width (at a scale of 1.0).
|
||||
SCREEN_WIDTH = 512
|
||||
# The default screen height (at a scale of 1.0).
|
||||
SCREEN_HEIGHT = 384
|
||||
# The default screen scale factor. Possible values are 0.5, 1.0, 1.5 and 2.0.
|
||||
SCREEN_SCALE = 1.0
|
||||
# Your game's credits, in an array. You can allow certain lines to be
|
||||
# translated by wrapping them in _INTL() as shown. Blank lines are just "".
|
||||
# To split a line into two columns, put "<s>" in it. Plugin credits and
|
||||
# Essentials engine credits are added to the end of these credits
|
||||
# automatically.
|
||||
def self.game_credits
|
||||
return [
|
||||
_INTL("My Game by:"),
|
||||
"Maruno",
|
||||
"",
|
||||
_INTL("Also involved were:"),
|
||||
"A. Lee Uss<s>Anne O'Nymus",
|
||||
"Ecksam Pell<s>Jane Doe",
|
||||
"Joe Dan<s>Nick Nayme",
|
||||
"Sue Donnim<s>",
|
||||
"",
|
||||
_INTL("Special thanks to:"),
|
||||
"Pizza"
|
||||
]
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# The player and NPCs
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# The maximum level Pokémon can reach.
|
||||
MAXIMUM_LEVEL = 100
|
||||
# The level of newly hatched Pokémon.
|
||||
EGG_LEVEL = 1
|
||||
# The odds of a newly generated Pokémon being shiny (out of 65536).
|
||||
SHINY_POKEMON_CHANCE = (MECHANICS_GENERATION >= 6) ? 16 : 8
|
||||
# The odds of a wild Pokémon/bred egg having Pokérus (out of 65536).
|
||||
POKERUS_CHANCE = 3
|
||||
# Whether a bred baby Pokémon can inherit any TM/HM moves from its father. It
|
||||
# can never inherit TM/HM moves from its mother.
|
||||
BREEDING_CAN_INHERIT_MACHINE_MOVES = (MECHANICS_GENERATION <= 5)
|
||||
# Whether a bred baby Pokémon can inherit egg moves from its mother. It can
|
||||
# always inherit egg moves from its father.
|
||||
BREEDING_CAN_INHERIT_EGG_MOVES_FROM_MOTHER = (MECHANICS_GENERATION >= 6)
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# The amount of money the player starts the game with.
|
||||
INITIAL_MONEY = 3000
|
||||
# The maximum amount of money the player can have.
|
||||
MAX_MONEY = 999_999
|
||||
MAX_MONEY = 9_999_999
|
||||
# The maximum number of Game Corner coins the player can have.
|
||||
MAX_COINS = 99_999
|
||||
# The maximum number of Battle Points the player can have.
|
||||
@@ -55,65 +54,56 @@ module Settings
|
||||
# The maximum amount of soot the player can have.
|
||||
MAX_SOOT = 9_999
|
||||
# The maximum length, in characters, that the player's name can be.
|
||||
MAX_PLAYER_NAME_SIZE = 10
|
||||
# The maximum number of Pokémon that can be in the party.
|
||||
MAX_PARTY_SIZE = 6
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# A set of arrays each containing a trainer type followed by a Global Variable
|
||||
# number. If the variable isn't set to 0, then all trainers with the
|
||||
# associated trainer type will be named as whatever is in that variable.
|
||||
MAX_PLAYER_NAME_SIZE = 12
|
||||
# A set of arrays each containing a trainer type followed by a Game Variable
|
||||
# number. If the Variable isn't set to 0, then all trainers with the
|
||||
# associated trainer type will be named as whatever is in that Variable.
|
||||
RIVAL_NAMES = [
|
||||
[:RIVAL1, 12],
|
||||
[:RIVAL2, 12],
|
||||
[:CHAMPION, 12]
|
||||
]
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Overworld
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Whether outdoor maps should be shaded according to the time of day.
|
||||
TIME_SHADING = true
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# Whether poisoned Pokémon will lose HP while walking around in the field.
|
||||
POISON_IN_FIELD = (MECHANICS_GENERATION <= 4)
|
||||
# Whether poisoned Pokémon will faint while walking around in the field
|
||||
# (true), or survive the poisoning with 1 HP (false).
|
||||
POISON_FAINT_IN_FIELD = (MECHANICS_GENERATION <= 3)
|
||||
TIME_SHADING = true
|
||||
# Whether the reflections of the player/events will ripple horizontally.
|
||||
ANIMATE_REFLECTIONS = true
|
||||
# Whether planted berries grow according to Gen 4 mechanics (true) or Gen 3
|
||||
# mechanics (false).
|
||||
NEW_BERRY_PLANTS = (MECHANICS_GENERATION >= 4)
|
||||
NEW_BERRY_PLANTS = (MECHANICS_GENERATION >= 4)
|
||||
# Whether fishing automatically hooks the Pokémon (true), or whether there is
|
||||
# a reaction test first (false).
|
||||
FISHING_AUTO_HOOK = false
|
||||
FISHING_AUTO_HOOK = false
|
||||
# The ID of the common event that runs when the player starts fishing (runs
|
||||
# instead of showing the casting animation).
|
||||
FISHING_BEGIN_COMMON_EVENT = -1
|
||||
# The ID of the common event that runs when the player stops fishing (runs
|
||||
# instead of showing the reeling in animation).
|
||||
FISHING_END_COMMON_EVENT = -1
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# The number of steps allowed before a Safari Zone game is over (0=infinite).
|
||||
SAFARI_STEPS = 600
|
||||
# The number of seconds a Bug Catching Contest lasts for (0=infinite).
|
||||
BUG_CONTEST_TIME = 20 * 60 # 20 minutes
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# Pairs of map IDs, where the location signpost isn't shown when moving from
|
||||
# one of the maps in a pair to the other (and vice versa). Useful for single
|
||||
# long routes/towns that are spread over multiple maps.
|
||||
SAFARI_STEPS = 600
|
||||
# The number of seconds a Bug-Catching Contest lasts for (0=infinite).
|
||||
BUG_CONTEST_TIME = 20 * 60 # 20 minutes
|
||||
# Pairs of map IDs, where the location sign isn't shown when moving from one
|
||||
# of the maps in a pair to the other (and vice versa). Useful for single long
|
||||
# routes/towns that are spread over multiple maps.
|
||||
# e.g. [4,5,16,17,42,43] will be map pairs 4,5 and 16,17 and 42,43.
|
||||
# Moving between two maps that have the exact same name won't show the
|
||||
# location signpost anyway, so you don't need to list those maps here.
|
||||
NO_SIGNPOSTS = []
|
||||
|
||||
#=============================================================================
|
||||
# location sign anyway, so you don't need to list those maps here.
|
||||
NO_LOCATION_SIGNS = []
|
||||
# Whether poisoned Pokémon will lose HP while walking around in the field.
|
||||
POISON_IN_FIELD = (MECHANICS_GENERATION <= 4)
|
||||
# Whether poisoned Pokémon will faint while walking around in the field
|
||||
# (true), or survive the poisoning with 1 HP (false).
|
||||
POISON_FAINT_IN_FIELD = (MECHANICS_GENERATION <= 3)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Using moves in the overworld
|
||||
#-----------------------------------------------------------------------------
|
||||
# Whether you need at least a certain number of badges to use some hidden
|
||||
# moves in the field (true), or whether you need one specific badge to use
|
||||
# them (false). The amounts/specific badges are defined below.
|
||||
@@ -133,105 +123,54 @@ module Settings
|
||||
BADGE_FOR_DIVE = 7
|
||||
BADGE_FOR_WATERFALL = 8
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Pokémon
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# If a move taught by a TM/HM/TR replaces another move, this setting is
|
||||
# whether the machine's move retains the replaced move's PP (true), or whether
|
||||
# the machine's move has full PP (false).
|
||||
TAUGHT_MACHINES_KEEP_OLD_PP = (MECHANICS_GENERATION == 5)
|
||||
# Whether the Black/White Flutes will raise/lower the levels of wild Pokémon
|
||||
# respectively (true), or will lower/raise the wild encounter rate
|
||||
# respectively (false).
|
||||
FLUTES_CHANGE_WILD_ENCOUNTER_LEVELS = (MECHANICS_GENERATION >= 6)
|
||||
# Whether Repel uses the level of the first Pokémon in the party regardless of
|
||||
# its HP (true), or it uses the level of the first unfainted Pokémon (false).
|
||||
REPEL_COUNTS_FAINTED_POKEMON = (MECHANICS_GENERATION >= 6)
|
||||
# Whether Rage Candy Bar acts as a Full Heal (true) or a Potion (false).
|
||||
RAGE_CANDY_BAR_CURES_STATUS_PROBLEMS = (MECHANICS_GENERATION >= 7)
|
||||
# The maximum level Pokémon can reach.
|
||||
MAXIMUM_LEVEL = 100
|
||||
# The level of newly hatched Pokémon.
|
||||
EGG_LEVEL = 1
|
||||
# The odds of a newly generated Pokémon being shiny (out of 65536).
|
||||
SHINY_POKEMON_CHANCE = (MECHANICS_GENERATION >= 6) ? 16 : 8
|
||||
# Whether super shininess is enabled (uses a different shiny animation).
|
||||
SUPER_SHINY = (MECHANICS_GENERATION == 8)
|
||||
# Whether Pokémon with the "Legendary", "Mythical" or "Ultra Beast" flags will
|
||||
# have at least 3 perfect IVs.
|
||||
LEGENDARIES_HAVE_SOME_PERFECT_IVS = (MECHANICS_GENERATION >= 6)
|
||||
# The odds of a wild Pokémon/bred egg having Pokérus (out of 65536).
|
||||
POKERUS_CHANCE = 3
|
||||
# Whether IVs and EVs are treated as 0 when calculating a Pokémon's stats.
|
||||
# IVs and EVs still exist, and are used by Hidden Power and some cosmetic
|
||||
# things as normal.
|
||||
DISABLE_IVS_AND_EVS = false
|
||||
# Whether the Move Relearner can also teach egg moves that the Pokémon knew
|
||||
# when it hatched and moves that the Pokémon was once taught by a TR. Moves
|
||||
# from the Pokémon's level-up moveset of the same or a lower level than the
|
||||
# Pokémon can always be relearned.
|
||||
MOVE_RELEARNER_CAN_TEACH_MORE_MOVES = (MECHANICS_GENERATION >= 6)
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Breeding Pokémon and Day Care
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# The name of the person who created the Pokémon storage system.
|
||||
def self.storage_creator_name
|
||||
return _INTL("Bill")
|
||||
end
|
||||
# The number of boxes in Pokémon storage.
|
||||
NUM_STORAGE_BOXES = 30
|
||||
# Whether Pokémon in the Day Care gain Exp for each step the player takes.
|
||||
# This should be true for the Day Care and false for the Pokémon Nursery, both
|
||||
# of which use the same code in Essentials.
|
||||
DAY_CARE_POKEMON_GAIN_EXP_FROM_WALKING = (MECHANICS_GENERATION <= 6)
|
||||
# Whether two Pokémon in the Day Care can learn egg moves from each other if
|
||||
# they are the same species.
|
||||
DAY_CARE_POKEMON_CAN_SHARE_EGG_MOVES = (MECHANICS_GENERATION >= 8)
|
||||
# Whether a bred baby Pokémon can inherit any TM/TR/HM moves from its father.
|
||||
# It can never inherit TM/TR/HM moves from its mother.
|
||||
BREEDING_CAN_INHERIT_MACHINE_MOVES = (MECHANICS_GENERATION <= 5)
|
||||
# Whether a bred baby Pokémon can inherit egg moves from its mother. It can
|
||||
# always inherit egg moves from its father.
|
||||
BREEDING_CAN_INHERIT_EGG_MOVES_FROM_MOTHER = (MECHANICS_GENERATION >= 6)
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# The names of each pocket of the Bag. Ignore the first entry ("").
|
||||
def self.bag_pocket_names
|
||||
return ["",
|
||||
_INTL("Items"),
|
||||
_INTL("Medicine"),
|
||||
_INTL("Poké Balls"),
|
||||
_INTL("TMs & HMs"),
|
||||
_INTL("Berries"),
|
||||
_INTL("Mail"),
|
||||
_INTL("Battle Items"),
|
||||
_INTL("Key Items")
|
||||
]
|
||||
end
|
||||
# The maximum number of slots per pocket (-1 means infinite number). Ignore
|
||||
# the first number (0).
|
||||
BAG_MAX_POCKET_SIZE = [0, -1, -1, -1, -1, -1, -1, -1, -1]
|
||||
# The maximum number of items each slot in the Bag can hold.
|
||||
BAG_MAX_PER_SLOT = 999
|
||||
# Whether each pocket in turn auto-sorts itself by item ID number. Ignore the
|
||||
# first entry (the 0).
|
||||
BAG_POCKET_AUTO_SORT = [0, false, false, false, true, true, false, false, false]
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# Whether the Pokédex list shown is the one for the player's current region
|
||||
# (true), or whether a menu pops up for the player to manually choose which
|
||||
# Dex list to view if more than one is available (false).
|
||||
USE_CURRENT_REGION_DEX = false
|
||||
# The names of the Pokédex lists, in the order they are defined in the PBS
|
||||
# file "regionaldexes.txt". The last name is for the National Dex and is added
|
||||
# onto the end of this array (remember that you don't need to use it). This
|
||||
# array's order is also the order of $Trainer.pokedex.unlocked_dexes, which
|
||||
# records which Dexes have been unlocked (the first is unlocked by default).
|
||||
# If an entry is just a name, then the region map shown in the Area page while
|
||||
# viewing that Dex list will be the region map of the region the player is
|
||||
# currently in. The National Dex entry should always behave like this.
|
||||
# If an entry is of the form [name, number], then the number is a region
|
||||
# number. That region's map will appear in the Area page while viewing that
|
||||
# Dex list, no matter which region the player is currently in.
|
||||
def self.pokedex_names
|
||||
return [
|
||||
[_INTL("Kanto Pokédex"), 0],
|
||||
[_INTL("Johto Pokédex"), 1],
|
||||
_INTL("National Pokédex")
|
||||
]
|
||||
end
|
||||
# Whether all forms of a given species will be immediately available to view
|
||||
# in the Pokédex so long as that species has been seen at all (true), or
|
||||
# whether each form needs to be seen specifically before that form appears in
|
||||
# the Pokédex (false).
|
||||
DEX_SHOWS_ALL_FORMS = false
|
||||
# An array of numbers, where each number is that of a Dex list (in the same
|
||||
# order as above, except the National Dex is -1). All Dex lists included here
|
||||
# will begin their numbering at 0 rather than 1 (e.g. Victini in Unova's Dex).
|
||||
DEXES_WITH_OFFSETS = []
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# A set of arrays, each containing details of a graphic to be shown on the
|
||||
# region map if appropriate. The values for each array are as follows:
|
||||
# * Region number.
|
||||
# * Game Switch; the graphic is shown if this is ON (non-wall maps only).
|
||||
# * X coordinate of the graphic on the map, in squares.
|
||||
# * Y coordinate of the graphic on the map, in squares.
|
||||
# * Name of the graphic, found in the Graphics/Pictures folder.
|
||||
# * The graphic will always (true) or never (false) be shown on a wall map.
|
||||
REGION_MAP_EXTRAS = [
|
||||
[0, 51, 16, 15, "mapHiddenBerth", false],
|
||||
[0, 52, 20, 14, "mapHiddenFaraday", false]
|
||||
]
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Roaming Pokémon
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# A list of maps used by roaming Pokémon. Each map has an array of other maps
|
||||
# it can lead to.
|
||||
@@ -247,45 +186,198 @@ module Settings
|
||||
66 => [5, 21, 28, 31, 39, 41, 44, 47, 69],
|
||||
69 => [5, 21, 28, 31, 39, 41, 44, 47, 66 ]
|
||||
}
|
||||
# A set of arrays, each containing the details of a roaming Pokémon. The
|
||||
# information within each array is as follows:
|
||||
# * Species.
|
||||
# * Level.
|
||||
# * Game Switch; the Pokémon roams while this is ON.
|
||||
# * Encounter type (0=any, 1=grass/walking in cave, 2=surfing, 3=fishing,
|
||||
# 4=surfing/fishing). See the bottom of PField_RoamingPokemon for lists.
|
||||
# * Name of BGM to play for that encounter (optional).
|
||||
# * Roaming areas specifically for this Pokémon (optional).
|
||||
# A set of hashes, each containing the details of a roaming Pokémon. The
|
||||
# information within each hash is as follows:
|
||||
# * :species
|
||||
# * :level
|
||||
# * :icon - Filename in Graphics/UI/Town Map/ of the roamer's Town Map icon.
|
||||
# * :game_switch - The Pokémon roams if this is nil or <=0 or if that Game
|
||||
# Switch is ON. Optional.
|
||||
# * :encounter_type - One of:
|
||||
# :all = grass, walking in cave, surfing (default)
|
||||
# :land = grass, walking in cave
|
||||
# :water = surfing, fishing
|
||||
# :surfing = surfing
|
||||
# :fishing = fishing
|
||||
# * :bgm - The BGM to play for the encounter. Optional.
|
||||
# * :areas - A hash of map IDs that determine where this Pokémon roams. Used
|
||||
# instead of ROAMING_AREAS above. Optional.
|
||||
ROAMING_SPECIES = [
|
||||
[:LATIAS, 30, 53, 0, "Battle roaming"],
|
||||
[:LATIOS, 30, 53, 0, "Battle roaming"],
|
||||
[:KYOGRE, 40, 54, 2, nil, {
|
||||
2 => [ 21, 31 ],
|
||||
21 => [2, 31, 69],
|
||||
31 => [2, 21, 69],
|
||||
69 => [ 21, 31 ]
|
||||
}],
|
||||
[:ENTEI, 40, 55, 1, nil]
|
||||
# {
|
||||
# :species => :LATIAS,
|
||||
# :level => 30,
|
||||
# :icon => "pin_latias",
|
||||
# :game_switch => 53,
|
||||
# :encounter_type => :all,
|
||||
# :bgm => "Battle roaming"
|
||||
# },
|
||||
# {
|
||||
# :species => :LATIOS,
|
||||
# :level => 30,
|
||||
# :icon => "pin_latios",
|
||||
# :game_switch => 53,
|
||||
# :encounter_type => :all,
|
||||
# :bgm => "Battle roaming"
|
||||
# },
|
||||
# {
|
||||
# :species => :KYOGRE,
|
||||
# :level => 40,
|
||||
# :game_switch => 54,
|
||||
# :encounter_type => :surfing,
|
||||
# :areas => {
|
||||
# 2 => [ 21, 31 ],
|
||||
# 21 => [2, 31, 69],
|
||||
# 31 => [2, 21, 69],
|
||||
# 69 => [ 21, 31 ]
|
||||
# }
|
||||
# },
|
||||
# {
|
||||
# :species => :ENTEI,
|
||||
# :level => 40,
|
||||
# :icon => "pin_entei",
|
||||
# :game_switch => 55,
|
||||
# :encounter_type => :land
|
||||
# }
|
||||
]
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Party and Pokémon storage
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# A set of arrays, each containing the details of a wild encounter that can
|
||||
# only occur via using the Poké Radar. The information within each array is as
|
||||
# follows:
|
||||
# * Map ID on which this encounter can occur.
|
||||
# * Probability that this encounter will occur (as a percentage).
|
||||
# * Species.
|
||||
# * Minimum possible level.
|
||||
# * Maximum possible level (optional).
|
||||
POKE_RADAR_ENCOUNTERS = [
|
||||
[5, 20, :STARLY, 12, 15],
|
||||
[21, 10, :STANTLER, 14],
|
||||
[28, 20, :BUTTERFREE, 15, 18],
|
||||
[28, 20, :BEEDRILL, 15, 18]
|
||||
# The maximum number of Pokémon that can be in the party.
|
||||
MAX_PARTY_SIZE = 6
|
||||
# The number of boxes in Pokémon storage.
|
||||
NUM_STORAGE_BOXES = 40
|
||||
# Whether putting a Pokémon into Pokémon storage will heal it. If false, they
|
||||
# are healed by the Recover All: Entire Party event command (at Poké Centers).
|
||||
HEAL_STORED_POKEMON = (MECHANICS_GENERATION <= 7)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Items
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Whether various HP-healing items heal the amounts they do in Gen 7+ (true)
|
||||
# or in earlier Generations (false).
|
||||
REBALANCED_HEALING_ITEM_AMOUNTS = (MECHANICS_GENERATION >= 7)
|
||||
# Whether vitamins can add EVs no matter how many that stat already has in it
|
||||
# (true), or whether they can't make that stat's EVs greater than 100 (false).
|
||||
NO_VITAMIN_EV_CAP = (MECHANICS_GENERATION >= 8)
|
||||
# Whether Rage Candy Bar acts as a Full Heal (true) or a Potion (false).
|
||||
RAGE_CANDY_BAR_CURES_STATUS_PROBLEMS = (MECHANICS_GENERATION >= 7)
|
||||
# Whether the Black/White Flutes will raise/lower the levels of wild Pokémon
|
||||
# respectively (true), or will lower/raise the wild encounter rate
|
||||
# respectively (false).
|
||||
FLUTES_CHANGE_WILD_ENCOUNTER_LEVELS = (MECHANICS_GENERATION >= 6)
|
||||
# Whether Rare Candy can be used on a Pokémon that is already at its maximum
|
||||
# level if it is able to evolve by level-up (if so, triggers that evolution).
|
||||
RARE_CANDY_USABLE_AT_MAX_LEVEL = (MECHANICS_GENERATION >= 8)
|
||||
# Whether the player can choose how many of an item to use at once on a
|
||||
# Pokémon. This applies to Exp-changing items (Rare Candy, Exp Candies) and
|
||||
# EV-changing items (vitamins, feathers, EV-lowering berries).
|
||||
USE_MULTIPLE_STAT_ITEMS_AT_ONCE = (MECHANICS_GENERATION >= 8)
|
||||
# If a move taught by a TM/HM/TR replaces another move, this setting is
|
||||
# whether the machine's move retains the replaced move's PP (true), or whether
|
||||
# the machine's move has full PP (false).
|
||||
TAUGHT_MACHINES_KEEP_OLD_PP = (MECHANICS_GENERATION == 5)
|
||||
# Whether you get 1 Premier Ball for every 10 of any kind of Poké Ball bought
|
||||
# from a Mart at once (true), or 1 Premier Ball for buying 10+ regular Poké
|
||||
# Balls (false).
|
||||
MORE_BONUS_PREMIER_BALLS = (MECHANICS_GENERATION >= 8)
|
||||
# The default sell price of an item to a Poké Mart is its buy price divided by
|
||||
# this number.
|
||||
ITEM_SELL_PRICE_DIVISOR = (MECHANICS_GENERATION >= 9) ? 4 : 2
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Pokédex
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# The names of the Pokédex lists, in the order they are defined in the PBS
|
||||
# file "regional_dexes.txt". The last name is for the National Dex and is
|
||||
# added onto the end of this array.
|
||||
# Each entry is either just a name, or is an array containing a name and a
|
||||
# number. If there is a number, it is a region number as defined in
|
||||
# town_map.txt. If there is no number, the number of the region the player is
|
||||
# currently in will be used. The region number determines which Town Map is
|
||||
# shown in the Area page when viewing that Pokédex list.
|
||||
def self.pokedex_names
|
||||
return [
|
||||
[_INTL("Kanto Pokédex"), 0],
|
||||
[_INTL("Johto Pokédex"), 1],
|
||||
_INTL("National Pokédex")
|
||||
]
|
||||
end
|
||||
# Whether the Pokédex list shown is the one for the player's current region
|
||||
# (true), or whether a menu pops up for the player to manually choose which
|
||||
# Dex list to view if more than one is available (false).
|
||||
USE_CURRENT_REGION_DEX = false
|
||||
# Whether all forms of a given species will be immediately available to view
|
||||
# in the Pokédex so long as that species has been seen at all (true), or
|
||||
# whether each form needs to be seen specifically before that form appears in
|
||||
# the Pokédex (false).
|
||||
DEX_SHOWS_ALL_FORMS = false
|
||||
# An array of numbers, where each number is that of a Dex list (in the same
|
||||
# order as above, except the National Dex is -1). All Dex lists included here
|
||||
# will begin their numbering at 0 rather than 1 (e.g. Victini in Unova's Dex).
|
||||
DEXES_WITH_OFFSETS = []
|
||||
# Whether the Pokédex entry of a newly owned species will be shown after it
|
||||
# hatches from an egg, after it evolves and after obtaining it from a trade,
|
||||
# in addition to after catching it in battle.
|
||||
SHOW_NEW_SPECIES_POKEDEX_ENTRY_MORE_OFTEN = (MECHANICS_GENERATION >= 7)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Town Map
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# A set of arrays, each containing details of a graphic to be shown on the
|
||||
# region map if appropriate. The values for each array are as follows:
|
||||
# * Region number.
|
||||
# * Game Switch; the graphic is shown if this is ON (non-wall maps only).
|
||||
# * X coordinate of the graphic on the map, in squares.
|
||||
# * Y coordinate of the graphic on the map, in squares.
|
||||
# * Name of the graphic, found in the Graphics/UI/Town Map folder.
|
||||
# * The graphic will always (true) or never (false) be shown on a wall map.
|
||||
REGION_MAP_EXTRAS = [
|
||||
[0, 51, 16, 15, "hidden_Berth", false],
|
||||
[0, 52, 20, 14, "hidden_Faraday", false]
|
||||
]
|
||||
# Whether the player can use Fly while looking at the Town Map. This is only
|
||||
# allowed if the player can use Fly normally.
|
||||
CAN_FLY_FROM_TOWN_MAP = true
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Phone
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# The default setting for Phone.rematches_enabled, which determines whether
|
||||
# trainers registered in the Phone can become ready for a rematch. If false,
|
||||
# Phone.rematches_enabled = true will enable rematches at any point you want.
|
||||
PHONE_REMATCHES_POSSIBLE_FROM_BEGINNING = false
|
||||
# Whether the messages in a phone call with a trainer are colored blue or red
|
||||
# depending on that trainer's gender. Note that this doesn't apply to contacts
|
||||
# whose phone calls are in a Common Event; they will need to be colored
|
||||
# manually in their Common Events.
|
||||
COLOR_PHONE_CALL_MESSAGES_BY_CONTACT_GENDER = true
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Battle starting
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Whether Repel uses the level of the first Pokémon in the party regardless of
|
||||
# its HP (true), or it uses the level of the first unfainted Pokémon (false).
|
||||
REPEL_COUNTS_FAINTED_POKEMON = (MECHANICS_GENERATION >= 6)
|
||||
# Whether more abilities affect whether wild Pokémon appear, which Pokémon
|
||||
# they are, etc.
|
||||
MORE_ABILITIES_AFFECT_WILD_ENCOUNTERS = (MECHANICS_GENERATION >= 8)
|
||||
# Whether shiny wild Pokémon are more likely to appear if the player has
|
||||
# previously defeated/caught lots of other Pokémon of the same species.
|
||||
HIGHER_SHINY_CHANCES_WITH_NUMBER_BATTLED = (MECHANICS_GENERATION >= 8)
|
||||
# Whether overworld weather can set the default terrain effect in battle.
|
||||
# Storm weather sets Electric Terrain, and fog weather sets Misty Terrain.
|
||||
OVERWORLD_WEATHER_SETS_BATTLE_TERRAIN = (MECHANICS_GENERATION >= 8)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Game Switches
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# The Game Switch that is set to ON when the player blacks out.
|
||||
STARTING_OVER_SWITCH = 1
|
||||
@@ -297,14 +389,23 @@ module Settings
|
||||
# The Game Switch which, while ON, makes all Pokémon created considered to be
|
||||
# met via a fateful encounter.
|
||||
FATEFUL_ENCOUNTER_SWITCH = 32
|
||||
# The Game Switch which, while ON, disables the effect of the Pokémon Box Link
|
||||
# and prevents the player from accessing Pokémon storage via the party screen
|
||||
# with it.
|
||||
DISABLE_BOX_LINK_SWITCH = 35
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Overworld animation IDs
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# ID of the animation played when the player steps on grass (grass rustling).
|
||||
GRASS_ANIMATION_ID = 1
|
||||
# ID of the animation played when the player lands on the ground after hopping
|
||||
# over a ledge (shows a dust impact).
|
||||
DUST_ANIMATION_ID = 2
|
||||
# ID of the animation played when the player finishes taking a step onto still
|
||||
# water (shows a water ripple).
|
||||
WATER_RIPPLE_ANIMATION_ID = 8
|
||||
# ID of the animation played when a trainer notices the player (an exclamation
|
||||
# bubble).
|
||||
EXCLAMATION_ANIMATION_ID = 3
|
||||
@@ -321,17 +422,46 @@ module Settings
|
||||
# is on the map (for new plant growth mechanics only).
|
||||
PLANT_SPARKLE_ANIMATION_ID = 7
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Files
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# An array of available languages in the game, and their corresponding message
|
||||
# file in the Data folder. Edit only if you have 2 or more languages to choose
|
||||
# from.
|
||||
DEFAULT_WILD_BATTLE_BGM = "Battle wild"
|
||||
DEFAULT_WILD_VICTORY_BGM = "Battle victory"
|
||||
DEFAULT_WILD_CAPTURE_ME = "Battle capture success"
|
||||
DEFAULT_TRAINER_BATTLE_BGM = "Battle trainer"
|
||||
DEFAULT_TRAINER_VICTORY_BGM = "Battle victory"
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Languages
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# An array of available languages in the game. Each one is an array containing
|
||||
# the display name of the language in-game, and that language's filename
|
||||
# fragment. A language will use the language data files from the Data folder
|
||||
# called messages_FRAGMENT_core.dat and messages_FRAGMENT_game.dat (if they
|
||||
# exist).
|
||||
LANGUAGES = [
|
||||
# ["English", "english.dat"],
|
||||
# ["Deutsch", "deutsch.dat"]
|
||||
# ["English", "english"],
|
||||
# ["Deutsch", "deutsch"]
|
||||
]
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Screen size and zoom
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# The default screen width (at a scale of 1.0). You should also edit the
|
||||
# property "defScreenW" in mkxp.json to match.
|
||||
SCREEN_WIDTH = 512
|
||||
# The default screen height (at a scale of 1.0). You should also edit the
|
||||
# property "defScreenH" in mkxp.json to match.
|
||||
SCREEN_HEIGHT = 384
|
||||
# The default screen scale factor. Possible values are 0.5, 1.0, 1.5 and 2.0.
|
||||
SCREEN_SCALE = 1.0
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Messages
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Available speech frames. These are graphic files in "Graphics/Windowskins/".
|
||||
SPEECH_WINDOWSKINS = [
|
||||
@@ -357,7 +487,6 @@ module Settings
|
||||
"speech hgss 20",
|
||||
"speech pl 18"
|
||||
]
|
||||
|
||||
# Available menu frames. These are graphic files in "Graphics/Windowskins/".
|
||||
MENU_WINDOWSKINS = [
|
||||
"choice 1",
|
||||
@@ -389,10 +518,30 @@ module Settings
|
||||
"choice 27",
|
||||
"choice 28"
|
||||
]
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Debug helpers
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Whether the game will ask you if you want to fully compile every time you
|
||||
# start the game (in Debug mode). You will not need to hold Ctrl/Shift to
|
||||
# compile anything.
|
||||
PROMPT_TO_COMPILE = false
|
||||
# Whether the game will skip the intro splash screens and title screen, and go
|
||||
# straight to the Continue/New Game screen. Only applies to playing in Debug
|
||||
# mode.
|
||||
SKIP_TITLE_SCREEN = true
|
||||
# Whether the game will skip the Continue/New Game screen and go straight into
|
||||
# a saved game (if there is one) or start a new game (if there isn't). Only
|
||||
# applies to playing in Debug mode.
|
||||
SKIP_CONTINUE_SCREEN = false
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# DO NOT EDIT THESE!
|
||||
#===============================================================================
|
||||
module Essentials
|
||||
VERSION = "19.1.dev"
|
||||
VERSION = "21.1"
|
||||
ERROR_TEXT = ""
|
||||
MKXPZ_VERSION = "2.4.2/c9378cf"
|
||||
end
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module PBDebug
|
||||
@@log = []
|
||||
|
||||
@@ -7,28 +10,65 @@ module PBDebug
|
||||
rescue
|
||||
PBDebug.log("")
|
||||
PBDebug.log("**Exception: #{$!.message}")
|
||||
PBDebug.log("#{$!.backtrace.inspect}")
|
||||
backtrace = ""
|
||||
$!.backtrace.each { |line| backtrace += line + "\r\n" }
|
||||
PBDebug.log(backtrace)
|
||||
PBDebug.log("")
|
||||
# if $INTERNAL
|
||||
pbPrintException($!)
|
||||
# end
|
||||
pbPrintException($!) # if $INTERNAL
|
||||
PBDebug.flush
|
||||
end
|
||||
end
|
||||
|
||||
def self.flush
|
||||
if $DEBUG && $INTERNAL && @@log.length>0
|
||||
File.open("Data/debuglog.txt", "a+b") { |f| f.write("#{@@log}") }
|
||||
if $DEBUG && $INTERNAL && @@log.length > 0
|
||||
File.open("Data/debuglog.txt", "a+b") { |f| f.write(@@log.join) }
|
||||
end
|
||||
@@log.clear
|
||||
end
|
||||
|
||||
def self.log(msg)
|
||||
if $DEBUG && $INTERNAL
|
||||
@@log.push("#{msg}\r\n")
|
||||
# if @@log.length>1024
|
||||
PBDebug.flush
|
||||
# end
|
||||
echoln msg.gsub("%", "%%")
|
||||
@@log.push(msg + "\r\n")
|
||||
PBDebug.flush # if @@log.length > 1024
|
||||
end
|
||||
end
|
||||
|
||||
def self.log_header(msg)
|
||||
if $DEBUG && $INTERNAL
|
||||
echoln Console.markup_style(msg.gsub("%", "%%"), text: :light_purple)
|
||||
@@log.push(msg + "\r\n")
|
||||
PBDebug.flush # if @@log.length > 1024
|
||||
end
|
||||
end
|
||||
|
||||
def self.log_message(msg)
|
||||
if $DEBUG && $INTERNAL
|
||||
msg = "\"" + msg + "\""
|
||||
echoln Console.markup_style(msg.gsub("%", "%%"), text: :dark_gray)
|
||||
@@log.push(msg + "\r\n")
|
||||
PBDebug.flush # if @@log.length > 1024
|
||||
end
|
||||
end
|
||||
|
||||
def self.log_ai(msg)
|
||||
if $DEBUG && $INTERNAL
|
||||
msg = "[AI] " + msg
|
||||
echoln msg.gsub("%", "%%")
|
||||
@@log.push(msg + "\r\n")
|
||||
PBDebug.flush # if @@log.length > 1024
|
||||
end
|
||||
end
|
||||
|
||||
def self.log_score_change(amt, msg)
|
||||
return if amt == 0
|
||||
if $DEBUG && $INTERNAL
|
||||
sign = (amt > 0) ? "+" : "-"
|
||||
amt_text = sprintf("%3d", amt.abs)
|
||||
msg = " #{sign}#{amt_text}: #{msg}"
|
||||
echoln msg.gsub("%", "%%")
|
||||
@@log.push(msg + "\r\n")
|
||||
PBDebug.flush # if @@log.length > 1024
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
# To use the console, use the executable explicitly built
|
||||
# with the console enabled on Windows. On Linux and macOS,
|
||||
# just launch the executable directly from a terminal.
|
||||
#===============================================================================
|
||||
# To use the console, use the executable explicitly built with the console
|
||||
# enabled on Windows. On Linux and macOS, just launch the executable directly
|
||||
# from a terminal.
|
||||
#===============================================================================
|
||||
module Console
|
||||
def self.setup_console
|
||||
return unless $DEBUG
|
||||
echoln "--------------------------------"
|
||||
echoln "GPU Cache Max: #{Bitmap.max_size}"
|
||||
echoln "-------------------------------------------------------------------------------"
|
||||
echoln "#{System.game_title} Output Window"
|
||||
echoln "--------------------------------"
|
||||
echoln "If you are seeing this window, you are running"
|
||||
echoln "#{System.game_title} in Debug Mode. This means"
|
||||
echoln "that you're either playing a Debug Version, or"
|
||||
echoln "you are playing from within RPG Maker XP."
|
||||
echoln "-------------------------------------------------------------------------------"
|
||||
echoln "If you can see this window, you are running the game in Debug Mode. This means"
|
||||
echoln "that you're either playing a debug version of the game, or you're playing from"
|
||||
echoln "within RPG Maker XP."
|
||||
echoln ""
|
||||
echoln "Closing this window will close the game. If"
|
||||
echoln "you want to get rid of this window, run the"
|
||||
echoln "program from the Shell, or download a Release"
|
||||
echoln "version."
|
||||
echoln ""
|
||||
echoln "--------------------------------"
|
||||
echoln "Closing this window will close the game. If you want to get rid of this window,"
|
||||
echoln "run the program from the Shell, or download a release version of the game."
|
||||
echoln "-------------------------------------------------------------------------------"
|
||||
echoln "Debug Output:"
|
||||
echoln "--------------------------------"
|
||||
echoln "-------------------------------------------------------------------------------"
|
||||
echoln ""
|
||||
end
|
||||
|
||||
@@ -36,6 +35,9 @@ module Console
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module Kernel
|
||||
def echo(string)
|
||||
return unless $DEBUG
|
||||
@@ -43,9 +45,199 @@ module Kernel
|
||||
end
|
||||
|
||||
def echoln(string)
|
||||
caller_info = caller(1..1).first
|
||||
file, line, method = caller_info.split(":")
|
||||
echo "#{file}, #{line}:\t"
|
||||
echo(string)
|
||||
echo("\r\n")
|
||||
end
|
||||
end
|
||||
|
||||
Console.setup_console
|
||||
|
||||
#===============================================================================
|
||||
# Console message formatting
|
||||
#===============================================================================
|
||||
module Console
|
||||
module_function
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# echo string into console (example shorthand for common options)
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# heading 1
|
||||
def echo_h1(msg)
|
||||
echoln markup_style("*** #{msg} ***", text: :brown)
|
||||
echoln ""
|
||||
end
|
||||
|
||||
# heading 2
|
||||
def echo_h2(msg, **options)
|
||||
echoln markup_style(msg, **options)
|
||||
echoln ""
|
||||
end
|
||||
|
||||
# heading 3
|
||||
def echo_h3(msg)
|
||||
echoln markup(msg)
|
||||
echoln ""
|
||||
end
|
||||
|
||||
# list item
|
||||
def echo_li(msg, pad = 0, color = :brown)
|
||||
echo markup_style(" -> ", text: color)
|
||||
pad = (pad - msg.length) > 0 ? "." * (pad - msg.length) : ""
|
||||
echo markup(msg + pad)
|
||||
end
|
||||
|
||||
# list item with line break after
|
||||
def echoln_li(msg, pad = 0, color = :brown)
|
||||
self.echo_li(msg, pad, color)
|
||||
echoln ""
|
||||
end
|
||||
|
||||
# Same as echoln_li but text is in green
|
||||
def echoln_li_done(msg)
|
||||
self.echo_li(markup_style(msg, text: :green), 0, :green)
|
||||
echoln ""
|
||||
echoln ""
|
||||
end
|
||||
|
||||
# paragraph with markup
|
||||
def echo_p(msg)
|
||||
echoln markup(msg)
|
||||
end
|
||||
|
||||
# warning message
|
||||
def echo_warn(msg)
|
||||
echoln markup_style("WARNING: #{msg}", text: :yellow)
|
||||
end
|
||||
|
||||
# error message
|
||||
def echo_error(msg)
|
||||
echoln markup_style("ERROR: #{msg}", text: :light_red)
|
||||
end
|
||||
|
||||
# status output
|
||||
def echo_status(status)
|
||||
if status
|
||||
echoln markup_style("OK", text: :green)
|
||||
else
|
||||
echoln markup_style("FAIL", text: :red)
|
||||
end
|
||||
end
|
||||
|
||||
# completion output
|
||||
def echo_done(status)
|
||||
if status
|
||||
echoln markup_style("done", text: :green)
|
||||
else
|
||||
echoln markup_style("error", text: :red)
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Markup options
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def string_colors
|
||||
{
|
||||
default: "38", black: "30", red: "31", green: "32", brown: "33",
|
||||
blue: "34", purple: "35", cyan: "36", gray: "37",
|
||||
dark_gray: "1;30", light_red: "1;31", light_green: "1;32", yellow: "1;33",
|
||||
light_blue: "1;34", light_purple: "1;35", light_cyan: "1;36", white: "1;37"
|
||||
}
|
||||
end
|
||||
|
||||
def background_colors
|
||||
{
|
||||
default: "0", black: "40", red: "41", green: "42", brown: "43",
|
||||
blue: "44", purple: "45", cyan: "46", gray: "47",
|
||||
dark_gray: "100", light_red: "101", light_green: "102", yellow: "103",
|
||||
light_blue: "104", light_purple: "105", light_cyan: "106", white: "107"
|
||||
}
|
||||
end
|
||||
|
||||
def font_options
|
||||
{
|
||||
bold: "1", dim: "2", italic: "3", underline: "4", reverse: "7",
|
||||
hidden: "8"
|
||||
}
|
||||
end
|
||||
|
||||
# Text markup that turns text between them a certain color
|
||||
def markup_colors
|
||||
{
|
||||
"`" => :cyan, '"' => :purple, "==" => :purple, "$" => :green, "~" => :red
|
||||
}
|
||||
end
|
||||
|
||||
def markup_options
|
||||
{
|
||||
"__" => :underline, "*" => :bold, "|" => :italic
|
||||
}
|
||||
end
|
||||
|
||||
# apply console coloring
|
||||
def markup_style(string, text: :default, bg: :default, **options)
|
||||
# get colors
|
||||
code_text = string_colors[text]
|
||||
code_bg = background_colors[bg]
|
||||
# get options
|
||||
options_pool = options.select { |key, val| font_options.key?(key) && val }
|
||||
markup_pool = options_pool.keys.map { |opt| font_options[opt] }.join(";").squeeze
|
||||
# return formatted string
|
||||
return "\e[#{code_bg};#{markup_pool};#{code_text}m#{string}\e[0m".squeeze(";")
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Perform markup on text
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def markup_all_options
|
||||
@markup_all_options ||= markup_colors.merge(markup_options)
|
||||
end
|
||||
|
||||
def markup_component(string, component, key, options)
|
||||
# trim inner markup content
|
||||
l = key.length
|
||||
trimmed = component[l...-l]
|
||||
# merge markup options
|
||||
options[trimmed] = {} unless options[trimmed]
|
||||
options[trimmed].deep_merge!({}.tap do |new_opt|
|
||||
new_opt[:text] = markup_colors[key] if markup_colors.key?(key)
|
||||
new_opt[markup_options[key]] = true if markup_options.key?(key)
|
||||
end)
|
||||
# remove markup from input string
|
||||
string.gsub!(component, trimmed)
|
||||
# return output
|
||||
return string, options
|
||||
end
|
||||
|
||||
def markup_breakdown(string, options = {})
|
||||
# iterate through all options
|
||||
markup_all_options.each_key do |key|
|
||||
# ensure escape
|
||||
key_char = key.chars.map { |c| "\\#{c}" }.join
|
||||
# define regex
|
||||
regex = "#{key_char}.*?#{key_char}"
|
||||
# go through matches
|
||||
string.scan(/#{regex}/).each do |component|
|
||||
return *markup_breakdown(*markup_component(string, component, key, options))
|
||||
end
|
||||
end
|
||||
# return output
|
||||
return string, options
|
||||
end
|
||||
|
||||
def markup(string)
|
||||
# get a breakdown of all markup options
|
||||
string, options = markup_breakdown(string)
|
||||
# iterate through each option and apply
|
||||
options.each do |key, opt|
|
||||
string.gsub!(key, markup_style(key, **opt))
|
||||
end
|
||||
# return string
|
||||
return string
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,12 +4,29 @@
|
||||
class Reset < Exception
|
||||
end
|
||||
|
||||
def pbGetExceptionMessage(e,_script="")
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class EventScriptError < Exception
|
||||
attr_accessor :event_message
|
||||
|
||||
def initialize(message)
|
||||
super(nil)
|
||||
@event_message = message
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
def pbGetExceptionMessage(e, _script = "")
|
||||
return e.event_message.dup if e.is_a?(EventScriptError) # Message with map/event ID generated elsewhere
|
||||
emessage = e.message.dup
|
||||
emessage.force_encoding(Encoding::UTF_8)
|
||||
if e.is_a?(Hangup)
|
||||
case e
|
||||
when Hangup
|
||||
emessage = "The script is taking too long. The game will restart."
|
||||
elsif e.is_a?(Errno::ENOENT)
|
||||
when Errno::ENOENT
|
||||
filename = emessage.sub("No such file or directory - ", "")
|
||||
emessage = "File #{filename} not found."
|
||||
end
|
||||
@@ -18,30 +35,28 @@ def pbGetExceptionMessage(e,_script="")
|
||||
end
|
||||
|
||||
def pbPrintException(e)
|
||||
emessage = ""
|
||||
if $EVENTHANGUPMSG && $EVENTHANGUPMSG!=""
|
||||
emessage = $EVENTHANGUPMSG # Message with map/event ID generated elsewhere
|
||||
$EVENTHANGUPMSG = nil
|
||||
else
|
||||
emessage = pbGetExceptionMessage(e)
|
||||
end
|
||||
emessage = pbGetExceptionMessage(e)
|
||||
# begin message formatting
|
||||
message = "[Pokémon Essentials version #{Essentials::VERSION}]\r\n"
|
||||
message += "#{Essentials::ERROR_TEXT}\r\n" # For third party scripts to add to
|
||||
message += "Exception: #{e.class}\r\n"
|
||||
message += "Message: #{emessage}\r\n"
|
||||
# show last 10/25 lines of backtrace
|
||||
message += "\r\nBacktrace:\r\n"
|
||||
btrace = ""
|
||||
if e.backtrace
|
||||
maxlength = ($INTERNAL) ? 25 : 10
|
||||
e.backtrace[0, maxlength].each { |i| btrace += "#{i}\r\n" }
|
||||
if !e.is_a?(EventScriptError)
|
||||
message += "Exception: #{e.class}\r\n"
|
||||
message += "Message: "
|
||||
end
|
||||
message += emessage
|
||||
# show last 10/25 lines of backtrace
|
||||
if !e.is_a?(EventScriptError)
|
||||
message += "\r\n\r\nBacktrace:\r\n"
|
||||
backtrace_text = ""
|
||||
if e.backtrace
|
||||
maxlength = ($INTERNAL) ? 25 : 10
|
||||
e.backtrace[0, maxlength].each { |i| backtrace_text += "#{i}\r\n" }
|
||||
end
|
||||
backtrace_text.gsub!(/Section(\d+)/) { $RGSS_SCRIPTS[$1.to_i][1] } rescue nil
|
||||
message += backtrace_text
|
||||
end
|
||||
btrace.gsub!(/Section(\d+)/) { $RGSS_SCRIPTS[$1.to_i][1] } rescue nil
|
||||
message += btrace
|
||||
# output to log
|
||||
errorlog = "errorlog.txt"
|
||||
errorlog = RTP.getSaveFileName("errorlog.txt") if (Object.const_defined?(:RTP) rescue false)
|
||||
File.open(errorlog, "ab") do |f|
|
||||
f.write("\r\n=================\r\n\r\n[#{Time.now}]\r\n")
|
||||
f.write(message)
|
||||
@@ -54,8 +69,8 @@ def pbPrintException(e)
|
||||
# output message
|
||||
print("#{message}\r\nThis exception was logged in #{errorlogline}.\r\nHold Ctrl when closing this message to copy it to the clipboard.")
|
||||
# Give a ~500ms coyote time to start holding Control
|
||||
t = System.delta
|
||||
until (System.delta - t) >= 500000
|
||||
t = System.uptime
|
||||
until System.uptime - t >= 0.5
|
||||
Input.update
|
||||
if Input.press?(Input::CTRL)
|
||||
Input.clipboard = message
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#===============================================================================
|
||||
# The Kernel module is extended to include the validate method.
|
||||
#===============================================================================
|
||||
module Kernel
|
||||
private
|
||||
|
||||
|
||||
# Used to check whether method arguments are of a given class or respond to a method.
|
||||
# @param value_pairs [Hash{Object => Class, Array<Class>, Symbol}] value pairs to validate
|
||||
# @example Validate a class or method
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#===============================================================================
|
||||
# The Deprecation module is used to warn game & plugin creators of deprecated
|
||||
# methods.
|
||||
#===============================================================================
|
||||
module Deprecation
|
||||
module_function
|
||||
|
||||
@@ -8,19 +10,21 @@ module Deprecation
|
||||
# @param removal_version [String] version the method is removed in
|
||||
# @param alternative [String] preferred alternative method
|
||||
def warn_method(method_name, removal_version = nil, alternative = nil)
|
||||
text = _INTL('WARN: usage of deprecated method "{1}" or its alias.', method_name)
|
||||
text = _INTL('Usage of deprecated method "{1}" or its alias.', method_name)
|
||||
unless removal_version.nil?
|
||||
text += _INTL("\nThe method is slated to be"\
|
||||
" removed in Essentials {1}.", removal_version)
|
||||
text += "\n" + _INTL("The method is slated to be removed in Essentials {1}.", removal_version)
|
||||
end
|
||||
unless alternative.nil?
|
||||
text += _INTL("\nUse \"{1}\" instead.", alternative)
|
||||
text += "\n" + _INTL("Use \"{1}\" instead.", alternative)
|
||||
end
|
||||
echoln text
|
||||
Console.echo_warn text
|
||||
end
|
||||
end
|
||||
|
||||
# The Module class is extended to allow easy deprecation of instance and class methods.
|
||||
#===============================================================================
|
||||
# The Module class is extended to allow easy deprecation of instance and class
|
||||
# methods.
|
||||
#===============================================================================
|
||||
class Module
|
||||
private
|
||||
|
||||
@@ -41,11 +45,11 @@ class Module
|
||||
raise ArgumentError, "#{class_name} does not have method #{aliased_method} defined"
|
||||
end
|
||||
|
||||
delimiter = class_method ? '.' : '#'
|
||||
delimiter = class_method ? "." : "#"
|
||||
|
||||
target.define_method(name) do |*args, **kvargs|
|
||||
alias_name = format('%s%s%s', class_name, delimiter, name)
|
||||
aliased_method_name = format('%s%s%s', class_name, delimiter, aliased_method)
|
||||
alias_name = sprintf("%s%s%s", class_name, delimiter, name)
|
||||
aliased_method_name = sprintf("%s%s%s", class_name, delimiter, aliased_method)
|
||||
Deprecation.warn_method(alias_name, removal_in, aliased_method_name)
|
||||
method(aliased_method).call(*args, **kvargs)
|
||||
end
|
||||
|
||||
@@ -1,27 +1,16 @@
|
||||
# Using mkxp-z v2.2.0 - https://gitlab.com/mkxp-z/mkxp-z/-/releases/v2.2.0
|
||||
#===============================================================================
|
||||
# Using mkxp-z v2.4.2/c9378cf - built 2023-07-07
|
||||
# https://github.com/mkxp-z/mkxp-z/actions/runs/5482601942
|
||||
#===============================================================================
|
||||
$VERBOSE = nil
|
||||
Font.default_shadow = false if Font.respond_to?(:default_shadow)
|
||||
Graphics.frame_rate = 40
|
||||
Encoding.default_internal = Encoding::UTF_8
|
||||
Encoding.default_external = Encoding::UTF_8
|
||||
|
||||
def pbSetWindowText(string)
|
||||
System.set_window_title(string || System.game_title)
|
||||
end
|
||||
|
||||
class Bitmap
|
||||
alias mkxp_draw_text draw_text unless method_defined?(:mkxp_draw_text)
|
||||
|
||||
def draw_text(x, y, width, height, text, align = 0)
|
||||
height = text_size(text).height
|
||||
mkxp_draw_text(x, y, width, height, text, align)
|
||||
end
|
||||
end
|
||||
|
||||
module Graphics
|
||||
def self.delta_s
|
||||
return self.delta.to_f / 1_000_000
|
||||
end
|
||||
end
|
||||
|
||||
def pbSetResizeFactor(factor)
|
||||
if !$ResizeInitialized
|
||||
Graphics.resize_screen(Settings::SCREEN_WIDTH, Settings::SCREEN_HEIGHT)
|
||||
@@ -35,3 +24,33 @@ def pbSetResizeFactor(factor)
|
||||
Graphics.center
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Bitmap
|
||||
attr_accessor :text_offset_y
|
||||
|
||||
alias mkxp_draw_text draw_text unless method_defined?(:mkxp_draw_text)
|
||||
|
||||
def draw_text(x, y, width, height = nil, text = "", align = 0)
|
||||
if x.is_a?(Rect)
|
||||
x.y -= (@text_offset_y || 0)
|
||||
# rect, string & alignment
|
||||
mkxp_draw_text(x, y, width)
|
||||
else
|
||||
y -= (@text_offset_y || 0)
|
||||
height = text_size(text).height
|
||||
mkxp_draw_text(x, y, width, height, text, align)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
if System::VERSION != Essentials::MKXPZ_VERSION
|
||||
printf(sprintf("\e[1;33mWARNING: mkxp-z version %s detected, but this version of Pokémon Essentials was designed for mkxp-z version %s.\e[0m\r\n",
|
||||
System::VERSION, Essentials::MKXPZ_VERSION))
|
||||
printf("\e[1;33mWARNING: Pokémon Essentials may not work properly.\e[0m\r\n")
|
||||
end
|
||||
|
||||
@@ -1,28 +1,25 @@
|
||||
#===============================================================================
|
||||
# Reads files of certain format from a directory
|
||||
# Reads files of certain format from a directory
|
||||
#===============================================================================
|
||||
class Dir
|
||||
#-----------------------------------------------------------------------------
|
||||
# Reads all files in a directory
|
||||
#-----------------------------------------------------------------------------
|
||||
# Reads all files in a directory
|
||||
def self.get(dir, filters = "*", full = true)
|
||||
files = []
|
||||
filters = [filters] if !filters.is_a?(Array)
|
||||
self.chdir(dir) do
|
||||
for filter in filters
|
||||
self.glob(filter){ |f| files.push(full ? (dir + "/" + f) : f) }
|
||||
filters.each do |filter|
|
||||
self.glob(filter) { |f| files.push(full ? (dir + "/" + f) : f) }
|
||||
end
|
||||
end
|
||||
return files.sort
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Generates entire file/folder tree from a certain directory
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Generates entire file/folder tree from a certain directory
|
||||
def self.all(dir, filters = "*", full = true)
|
||||
# sets variables for starting
|
||||
files = []
|
||||
subfolders = []
|
||||
for file in self.get(dir, filters, full)
|
||||
self.get(dir, filters, full).each do |file|
|
||||
# engages in recursion to read the entire file tree
|
||||
if self.safe?(file) # Is a directory
|
||||
subfolders += self.all(file, filters, full)
|
||||
@@ -33,70 +30,60 @@ class Dir
|
||||
# returns all found files
|
||||
return files + subfolders
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Checks for existing directory, gets around accents
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Checks for existing directory
|
||||
def self.safe?(dir)
|
||||
return false if !FileTest.directory?(dir)
|
||||
ret = false
|
||||
self.chdir(dir) { ret = true } rescue nil
|
||||
return ret
|
||||
return FileTest.directory?(dir)
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# extensions for file class
|
||||
#===============================================================================
|
||||
class File
|
||||
#-----------------------------------------------------------------------------
|
||||
# Checks for existing file, gets around accents
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.safe?(file)
|
||||
ret = false
|
||||
self.open(file, 'rb') { ret = true } rescue nil
|
||||
return ret
|
||||
# Creates all the required directories for filename path
|
||||
def self.create(path)
|
||||
path.gsub!("\\", "/") # Windows compatibility
|
||||
# get path tree
|
||||
dirs = path.split("/")
|
||||
full = ""
|
||||
dirs.each do |dir|
|
||||
full += dir + "/"
|
||||
# creates directories
|
||||
self.mkdir(full) if !self.safe?(full)
|
||||
end
|
||||
end
|
||||
|
||||
# Generates entire folder tree from a certain directory
|
||||
def self.all_dirs(dir)
|
||||
# sets variables for starting
|
||||
dirs = []
|
||||
self.get(dir, "*", true).each do |file|
|
||||
# engages in recursion to read the entire folder tree
|
||||
dirs += self.all_dirs(file) if self.safe?(file)
|
||||
end
|
||||
# returns all found directories
|
||||
return dirs.length > 0 ? (dirs + [dir]) : [dir]
|
||||
end
|
||||
|
||||
# Deletes all the files in a directory and all the sub directories (allows for non-empty dirs)
|
||||
def self.delete_all(dir)
|
||||
# delete all files in dir
|
||||
self.all(dir).each { |f| File.delete(f) }
|
||||
# delete all dirs in dir
|
||||
self.all_dirs(dir).each { |f| Dir.delete(f) }
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Checking for files and directories
|
||||
#===============================================================================
|
||||
# Works around a problem with FileTest.directory if directory contains accent marks
|
||||
def safeIsDirectory?(f)
|
||||
ret = false
|
||||
Dir.chdir(f) { ret = true } rescue nil
|
||||
return ret
|
||||
end
|
||||
|
||||
# Works around a problem with FileTest.exist if path contains accent marks
|
||||
def safeExists?(f)
|
||||
return FileTest.exist?(f) if f[/\A[\x20-\x7E]*\z/]
|
||||
ret = false
|
||||
begin
|
||||
File.open(f,"rb") { ret = true }
|
||||
rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES
|
||||
ret = false
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
# Similar to "Dir.glob", but designed to work around a problem with accessing
|
||||
# files if a path contains accent marks.
|
||||
# "dir" is the directory path, "wildcard" is the filename pattern to match.
|
||||
def safeGlob(dir,wildcard)
|
||||
def safeGlob(dir, wildcard)
|
||||
ret = []
|
||||
afterChdir = false
|
||||
begin
|
||||
Dir.chdir(dir) {
|
||||
Dir.chdir(dir) do
|
||||
afterChdir = true
|
||||
Dir.glob(wildcard) { |f| ret.push(dir+"/"+f) }
|
||||
}
|
||||
Dir.glob(wildcard) { |f| ret.push(dir + "/" + f) }
|
||||
end
|
||||
rescue Errno::ENOENT
|
||||
raise if afterChdir
|
||||
end
|
||||
@@ -108,8 +95,8 @@ end
|
||||
|
||||
def pbResolveAudioSE(file)
|
||||
return nil if !file
|
||||
if RTP.exists?("Audio/SE/"+file,["",".wav",".mp3",".ogg"])
|
||||
return RTP.getPath("Audio/SE/"+file,["",".wav",".mp3",".ogg"])
|
||||
if RTP.exists?("Audio/SE/" + file, ["", ".wav", ".ogg", ".mp3", ".wma"])
|
||||
return RTP.getPath("Audio/SE/" + file, ["", ".wav", ".ogg", ".mp3", ".wma"])
|
||||
end
|
||||
return nil
|
||||
end
|
||||
@@ -118,19 +105,19 @@ end
|
||||
# archives. Returns nil if the path can't be found.
|
||||
def pbResolveBitmap(x)
|
||||
return nil if !x
|
||||
noext = x.gsub(/\.(bmp|png|gif|jpg|jpeg)$/,"")
|
||||
noext = x.gsub(/\.(bmp|png|gif|jpg|jpeg)$/, "")
|
||||
filename = nil
|
||||
# RTP.eachPathFor(x) { |path|
|
||||
# filename = pbTryString(path) if !filename
|
||||
# filename = pbTryString(path+".gif") if !filename
|
||||
# filename = pbTryString(path + ".gif") if !filename
|
||||
# }
|
||||
RTP.eachPathFor(noext) { |path|
|
||||
filename = pbTryString(path+".png") if !filename
|
||||
filename = pbTryString(path+".gif") if !filename
|
||||
# filename = pbTryString(path+".jpg") if !filename
|
||||
# filename = pbTryString(path+".jpeg") if !filename
|
||||
# filename = pbTryString(path+".bmp") if !filename
|
||||
}
|
||||
RTP.eachPathFor(noext) do |path|
|
||||
filename = pbTryString(path + ".png") if !filename
|
||||
filename = pbTryString(path + ".gif") if !filename
|
||||
# filename = pbTryString(path + ".jpg") if !filename
|
||||
# filename = pbTryString(path + ".jpeg") if !filename
|
||||
# filename = pbTryString(path + ".bmp") if !filename
|
||||
end
|
||||
return filename
|
||||
end
|
||||
|
||||
@@ -157,7 +144,7 @@ def canonicalize(c)
|
||||
pos = -1
|
||||
ret = []
|
||||
retstr = ""
|
||||
for x in csplit
|
||||
csplit.each do |x|
|
||||
if x == ".."
|
||||
if pos >= 0
|
||||
ret.delete_at(pos)
|
||||
@@ -168,50 +155,51 @@ def canonicalize(c)
|
||||
pos += 1
|
||||
end
|
||||
end
|
||||
for i in 0...ret.length
|
||||
ret.length.times do |i|
|
||||
retstr += "/" if i > 0
|
||||
retstr += ret[i]
|
||||
end
|
||||
return retstr
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module RTP
|
||||
@rtpPaths = nil
|
||||
|
||||
def self.exists?(filename,extensions=[])
|
||||
def self.exists?(filename, extensions = [])
|
||||
return false if nil_or_empty?(filename)
|
||||
eachPathFor(filename) { |path|
|
||||
return true if safeExists?(path)
|
||||
for ext in extensions
|
||||
return true if safeExists?(path+ext)
|
||||
eachPathFor(filename) do |path|
|
||||
return true if FileTest.exist?(path)
|
||||
extensions.each do |ext|
|
||||
return true if FileTest.exist?(path + ext)
|
||||
end
|
||||
}
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def self.getImagePath(filename)
|
||||
return self.getPath(filename,["",".png",".gif"]) # ".jpg", ".jpeg", ".bmp"
|
||||
return self.getPath(filename, ["", ".png", ".gif"]) # ".jpg", ".jpeg", ".bmp"
|
||||
end
|
||||
|
||||
def self.getAudioPath(filename)
|
||||
return self.getPath(filename,["",".mp3",".wav",".wma",".mid",".ogg",".midi"])
|
||||
return self.getPath(filename, ["", ".wav", ".ogg", ".mp3", ".midi", ".mid", ".wma"])
|
||||
end
|
||||
|
||||
def self.getPath(filename,extensions=[])
|
||||
def self.getPath(filename, extensions = [])
|
||||
return filename if nil_or_empty?(filename)
|
||||
eachPathFor(filename) { |path|
|
||||
return path if safeExists?(path)
|
||||
for ext in extensions
|
||||
file = path+ext
|
||||
return file if safeExists?(file)
|
||||
eachPathFor(filename) do |path|
|
||||
return path if FileTest.exist?(path)
|
||||
extensions.each do |ext|
|
||||
file = path + ext
|
||||
return file if FileTest.exist?(file)
|
||||
end
|
||||
}
|
||||
end
|
||||
return filename
|
||||
end
|
||||
|
||||
# Gets the absolute RGSS paths for the given file name
|
||||
# Gets the absolute RGSS paths for the given file name
|
||||
def self.eachPathFor(filename)
|
||||
return if !filename
|
||||
if filename[/^[A-Za-z]\:[\/\\]/] || filename[/^[\/\\]/]
|
||||
@@ -219,13 +207,13 @@ module RTP
|
||||
yield filename
|
||||
else
|
||||
# relative path
|
||||
RTP.eachPath { |path|
|
||||
if path=="./"
|
||||
RTP.eachPath do |path|
|
||||
if path == "./"
|
||||
yield filename
|
||||
else
|
||||
yield path+filename
|
||||
yield path + filename
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -237,11 +225,9 @@ module RTP
|
||||
def self.eachPath
|
||||
# XXX: Use "." instead of Dir.pwd because of problems retrieving files if
|
||||
# the current directory contains an accent mark
|
||||
yield ".".gsub(/[\/\\]/,"/").gsub(/[\/\\]$/,"")+"/"
|
||||
yield ".".gsub(/[\/\\]/, "/").gsub(/[\/\\]$/, "") + "/"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.getSaveFileName(fileName)
|
||||
File.join(getSaveFolder, fileName)
|
||||
end
|
||||
@@ -257,50 +243,47 @@ module RTP
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module FileTest
|
||||
Image_ext = ['.png', '.gif'] # '.jpg', '.jpeg', '.bmp',
|
||||
Audio_ext = ['.mp3', '.mid', '.midi', '.ogg', '.wav', '.wma']
|
||||
IMAGE_EXTENSIONS = [".png", ".gif"] # ".jpg", ".jpeg", ".bmp",
|
||||
AUDIO_EXTENSIONS = [".wav", ".ogg", ".mp3", ".midi", ".mid", ".wma"]
|
||||
|
||||
def self.audio_exist?(filename)
|
||||
return RTP.exists?(filename,Audio_ext)
|
||||
return RTP.exists?(filename, AUDIO_EXTENSIONS)
|
||||
end
|
||||
|
||||
def self.image_exist?(filename)
|
||||
return RTP.exists?(filename,Image_ext)
|
||||
return RTP.exists?(filename, IMAGE_EXTENSIONS)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
# Used to determine whether a data file exists (rather than a graphics or
|
||||
# audio file). Doesn't check RTP, but does check encrypted archives.
|
||||
|
||||
# Note: pbGetFileChar checks anything added in MKXP's RTP setting,
|
||||
# and matching mount points added through System.mount
|
||||
# NOTE: pbGetFileChar checks anything added in MKXP's RTP setting, and matching
|
||||
# mount points added through System.mount.
|
||||
def pbRgssExists?(filename)
|
||||
if safeExists?("./Game.rgssad")
|
||||
return pbGetFileChar(filename)!=nil
|
||||
else
|
||||
filename = canonicalize(filename)
|
||||
return safeExists?(filename)
|
||||
end
|
||||
return !pbGetFileChar(filename).nil? if FileTest.exist?("./Game.rgssad")
|
||||
filename = canonicalize(filename)
|
||||
return FileTest.exist?(filename)
|
||||
end
|
||||
|
||||
# Opens an IO, even if the file is in an encrypted archive.
|
||||
# Doesn't check RTP for the file.
|
||||
|
||||
# Note: load_data checks anything added in MKXP's RTP setting,
|
||||
# and matching mount points added through System.mount
|
||||
def pbRgssOpen(file,mode=nil)
|
||||
#File.open("debug.txt","ab") { |fw| fw.write([file,mode,Time.now.to_f].inspect+"\r\n") }
|
||||
if !safeExists?("./Game.rgssad")
|
||||
# NOTE: load_data checks anything added in MKXP's RTP setting, and matching
|
||||
# mount points added through System.mount.
|
||||
def pbRgssOpen(file, mode = nil)
|
||||
# File.open("debug.txt", "ab") { |fw| fw.write([file, mode, Time.now.to_f].inspect + "\r\n") }
|
||||
if !FileTest.exist?("./Game.rgssad")
|
||||
if block_given?
|
||||
File.open(file,mode) { |f| yield f }
|
||||
File.open(file, mode) { |f| yield f }
|
||||
return nil
|
||||
else
|
||||
return File.open(file,mode)
|
||||
return File.open(file, mode)
|
||||
end
|
||||
end
|
||||
file = canonicalize(file)
|
||||
@@ -318,9 +301,9 @@ end
|
||||
# encrypted archives.
|
||||
def pbGetFileChar(file)
|
||||
canon_file = canonicalize(file)
|
||||
if !safeExists?("./Game.rgssad")
|
||||
return nil if !safeExists?(canon_file)
|
||||
return nil if file.last == '/' # Is a directory
|
||||
if !FileTest.exist?("./Game.rgssad")
|
||||
return nil if !FileTest.exist?(canon_file)
|
||||
return nil if file.last == "/" # Is a directory
|
||||
begin
|
||||
File.open(canon_file, "rb") { |f| return f.read(1) } # read one byte
|
||||
rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES, Errno::EISDIR
|
||||
@@ -338,20 +321,19 @@ end
|
||||
|
||||
def pbTryString(x)
|
||||
ret = pbGetFileChar(x)
|
||||
return (ret!=nil && ret!="") ? x : nil
|
||||
return nil_or_empty?(ret) ? nil : x
|
||||
end
|
||||
|
||||
# Gets the contents of a file. Doesn't check RTP, but does check
|
||||
# encrypted archives.
|
||||
|
||||
# Note: load_data will check anything added in MKXP's RTP setting,
|
||||
# and matching mount points added through System.mount
|
||||
# NOTE: load_data will check anything added in MKXP's RTP setting, and matching
|
||||
# mount points added through System.mount.
|
||||
def pbGetFileString(file)
|
||||
file = canonicalize(file)
|
||||
if !safeExists?("./Game.rgssad")
|
||||
return nil if !safeExists?(file)
|
||||
if !FileTest.exist?("./Game.rgssad")
|
||||
return nil if !FileTest.exist?(file)
|
||||
begin
|
||||
File.open(file,"rb") { |f| return f.read } # read all data
|
||||
File.open(file, "rb") { |f| return f.read } # read all data
|
||||
rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES
|
||||
return nil
|
||||
end
|
||||
@@ -365,22 +347,22 @@ def pbGetFileString(file)
|
||||
return str
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class StringInput
|
||||
include Enumerable
|
||||
|
||||
attr_reader :lineno, :string
|
||||
|
||||
class << self
|
||||
def new( str )
|
||||
def new(str)
|
||||
if block_given?
|
||||
begin
|
||||
f = super
|
||||
yield f
|
||||
ensure
|
||||
f.close if f
|
||||
f&.close
|
||||
end
|
||||
else
|
||||
super
|
||||
@@ -389,21 +371,19 @@ class StringInput
|
||||
alias open new
|
||||
end
|
||||
|
||||
def initialize( str )
|
||||
def initialize(str)
|
||||
@string = str
|
||||
@pos = 0
|
||||
@closed = false
|
||||
@lineno = 0
|
||||
end
|
||||
|
||||
attr_reader :lineno,:string
|
||||
|
||||
def inspect
|
||||
return "#<#{self.class}:#{@closed ? 'closed' : 'open'},src=#{@string[0,30].inspect}>"
|
||||
return "#<#{self.class}:#{@closed ? 'closed' : 'open'},src=#{@string[0, 30].inspect}>"
|
||||
end
|
||||
|
||||
def close
|
||||
raise IOError, 'closed stream' if @closed
|
||||
raise IOError, "closed stream" if @closed
|
||||
@pos = nil
|
||||
@closed = true
|
||||
end
|
||||
@@ -411,7 +391,7 @@ class StringInput
|
||||
def closed?; @closed; end
|
||||
|
||||
def pos
|
||||
raise IOError, 'closed stream' if @closed
|
||||
raise IOError, "closed stream" if @closed
|
||||
[@pos, @string.size].min
|
||||
end
|
||||
|
||||
@@ -421,8 +401,8 @@ class StringInput
|
||||
|
||||
def pos=(value); seek(value); end
|
||||
|
||||
def seek(offset, whence=IO::SEEK_SET)
|
||||
raise IOError, 'closed stream' if @closed
|
||||
def seek(offset, whence = IO::SEEK_SET)
|
||||
raise IOError, "closed stream" if @closed
|
||||
case whence
|
||||
when IO::SEEK_SET then @pos = offset
|
||||
when IO::SEEK_CUR then @pos += offset
|
||||
@@ -436,12 +416,12 @@ class StringInput
|
||||
end
|
||||
|
||||
def eof?
|
||||
raise IOError, 'closed stream' if @closed
|
||||
raise IOError, "closed stream" if @closed
|
||||
@pos > @string.size
|
||||
end
|
||||
|
||||
def each( &block )
|
||||
raise IOError, 'closed stream' if @closed
|
||||
def each(&block)
|
||||
raise IOError, "closed stream" if @closed
|
||||
begin
|
||||
@string.each(&block)
|
||||
ensure
|
||||
@@ -450,14 +430,15 @@ class StringInput
|
||||
end
|
||||
|
||||
def gets
|
||||
raise IOError, 'closed stream' if @closed
|
||||
if idx = @string.index(?\n, @pos)
|
||||
raise IOError, "closed stream" if @closed
|
||||
idx = @string.index("\n", @pos)
|
||||
if idx
|
||||
idx += 1 # "\n".size
|
||||
line = @string[ @pos ... idx ]
|
||||
line = @string[@pos...idx]
|
||||
@pos = idx
|
||||
@pos += 1 if @pos == @string.size
|
||||
else
|
||||
line = @string[ @pos .. -1 ]
|
||||
line = @string[@pos..-1]
|
||||
@pos = @string.size + 1
|
||||
end
|
||||
@lineno += 1
|
||||
@@ -465,18 +446,18 @@ class StringInput
|
||||
end
|
||||
|
||||
def getc
|
||||
raise IOError, 'closed stream' if @closed
|
||||
raise IOError, "closed stream" if @closed
|
||||
ch = @string[@pos]
|
||||
@pos += 1
|
||||
@pos += 1 if @pos == @string.size
|
||||
ch
|
||||
end
|
||||
|
||||
def read( len = nil )
|
||||
raise IOError, 'closed stream' if @closed
|
||||
def read(len = nil)
|
||||
raise IOError, "closed stream" if @closed
|
||||
if !len
|
||||
return nil if eof?
|
||||
rest = @string[@pos ... @string.size]
|
||||
rest = @string[@pos...@string.size]
|
||||
@pos = @string.size + 1
|
||||
return rest
|
||||
end
|
||||
@@ -485,8 +466,6 @@ class StringInput
|
||||
@pos += 1 if @pos == @string.size
|
||||
str
|
||||
end
|
||||
|
||||
def read_all; read(); end
|
||||
|
||||
alias read_all read
|
||||
alias sysread read
|
||||
end
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module FileInputMixin
|
||||
def fgetb
|
||||
ret = 0
|
||||
@@ -67,7 +70,7 @@ module FileInputMixin
|
||||
self.pos = 0
|
||||
offset = fgetdw >> 3
|
||||
return 0 if index >= offset
|
||||
self.pos = index * 8 + 4
|
||||
self.pos = (index * 8) + 4
|
||||
return fgetdw
|
||||
end
|
||||
|
||||
@@ -85,6 +88,9 @@ module FileInputMixin
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module FileOutputMixin
|
||||
def fputb(b)
|
||||
b &= 0xFF
|
||||
@@ -108,27 +114,32 @@ module FileOutputMixin
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class File < IO
|
||||
=begin
|
||||
unless defined?(debugopen)
|
||||
class << self
|
||||
alias debugopen open
|
||||
end
|
||||
end
|
||||
# unless defined?(debugopen)
|
||||
# class << self
|
||||
# alias debugopen open
|
||||
# end
|
||||
# end
|
||||
|
||||
# def open(f, m = "r")
|
||||
# debugopen("debug.txt", "ab") { |file| file.write([f, m, Time.now.to_f].inspect + "\r\n") }
|
||||
# if block_given?
|
||||
# debugopen(f, m) { |file| yield file }
|
||||
# else
|
||||
# return debugopen(f, m)
|
||||
# end
|
||||
# end
|
||||
|
||||
def open(f, m = "r")
|
||||
debugopen("debug.txt", "ab") { |file| file.write([f, m, Time.now.to_f].inspect + "\r\n") }
|
||||
if block_given?
|
||||
debugopen(f, m) { |file| yield file }
|
||||
else
|
||||
return debugopen(f, m)
|
||||
end
|
||||
end
|
||||
=end
|
||||
include FileInputMixin
|
||||
include FileOutputMixin
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class StringInput
|
||||
include FileInputMixin
|
||||
|
||||
@@ -137,7 +148,7 @@ class StringInput
|
||||
end
|
||||
|
||||
def each_byte
|
||||
while !eof?
|
||||
until eof?
|
||||
yield getc
|
||||
end
|
||||
end
|
||||
@@ -145,6 +156,9 @@ class StringInput
|
||||
def binmode; end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class StringOutput
|
||||
include FileOutputMixin
|
||||
end
|
||||
|
||||
@@ -1,37 +1,35 @@
|
||||
#############################
|
||||
#
|
||||
#===============================================================================
|
||||
# HTTP utility functions
|
||||
#
|
||||
#############################
|
||||
def pbPostData(url, postdata, filename=nil, depth=0)
|
||||
#===============================================================================
|
||||
def pbPostData(url, postdata, filename = nil, depth = 0)
|
||||
if url[/^http:\/\/([^\/]+)(.*)$/]
|
||||
host = $1
|
||||
path = $2
|
||||
path = "/" if path.length==0
|
||||
# path = $2
|
||||
# path = "/" if path.length == 0
|
||||
userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14"
|
||||
body = postdata.map { |key, value|
|
||||
body = postdata.map do |key, value|
|
||||
keyString = key.to_s
|
||||
valueString = value.to_s
|
||||
keyString.gsub!(/[^a-zA-Z0-9_\.\-]/n) { |s| sprintf('%%%02x', s[0]) }
|
||||
valueString.gsub!(/[^a-zA-Z0-9_\.\-]/n) { |s| sprintf('%%%02x', s[0]) }
|
||||
keyString.gsub!(/[^a-zA-Z0-9_\.\-]/n) { |s| sprintf("%%%02x", s[0]) }
|
||||
valueString.gsub!(/[^a-zA-Z0-9_\.\-]/n) { |s| sprintf("%%%02x", s[0]) }
|
||||
next "#{keyString}=#{valueString}"
|
||||
}.join('&')
|
||||
end.join("&")
|
||||
ret = HTTPLite.post_body(
|
||||
url,
|
||||
body,
|
||||
"application/x-www-form-urlencoded",
|
||||
{
|
||||
"Host" => host, # might not be necessary
|
||||
"Host" => host, # might not be necessary
|
||||
"Proxy-Connection" => "Close",
|
||||
"Content-Length" => body.bytesize.to_s,
|
||||
"Pragma" => "no-cache",
|
||||
"User-Agent" => userAgent
|
||||
"Content-Length" => body.bytesize.to_s,
|
||||
"Pragma" => "no-cache",
|
||||
"User-Agent" => userAgent
|
||||
}
|
||||
) rescue ""
|
||||
return ret if !ret.is_a?(Hash)
|
||||
return "" if ret[:status] != 200
|
||||
return ret[:body] if !filename
|
||||
File.open(filename, "wb"){|f|f.write(ret[:body])}
|
||||
File.open(filename, "wb") { |f| f.write(ret[:body]) }
|
||||
return ""
|
||||
end
|
||||
return ""
|
||||
@@ -40,8 +38,8 @@ end
|
||||
def pbDownloadData(url, filename = nil, authorization = nil, depth = 0, &block)
|
||||
headers = {
|
||||
"Proxy-Connection" => "Close",
|
||||
"Pragma" => "no-cache",
|
||||
"User-Agent" => "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14"
|
||||
"Pragma" => "no-cache",
|
||||
"User-Agent" => "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14"
|
||||
}
|
||||
headers["authorization"] = authorization if authorization
|
||||
ret = HTTPLite.get(url, headers) rescue ""
|
||||
@@ -63,7 +61,7 @@ end
|
||||
|
||||
def pbDownloadToFile(url, file)
|
||||
begin
|
||||
pbDownloadData(url,file)
|
||||
pbDownloadData(url, file)
|
||||
rescue
|
||||
end
|
||||
end
|
||||
@@ -79,7 +77,7 @@ end
|
||||
|
||||
def pbPostToFile(url, postdata, file)
|
||||
begin
|
||||
pbPostData(url, postdata,file)
|
||||
pbPostData(url, postdata, file)
|
||||
rescue
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# class Object
|
||||
#===============================================================================
|
||||
class Object
|
||||
alias full_inspect inspect
|
||||
alias full_inspect inspect unless method_defined?(:full_inspect)
|
||||
|
||||
def inspect
|
||||
return "#<#{self.class}>"
|
||||
@@ -23,32 +23,21 @@ end
|
||||
#===============================================================================
|
||||
class String
|
||||
def starts_with_vowel?
|
||||
return ['a', 'e', 'i', 'o', 'u'].include?(self[0, 1].downcase)
|
||||
return ["a", "e", "i", "o", "u"].include?(self[0].downcase)
|
||||
end
|
||||
|
||||
def first(n = 1)
|
||||
return self[0...n]
|
||||
end
|
||||
def first(n = 1); return self[0...n]; end
|
||||
|
||||
def last(n = 1)
|
||||
return self[-n..-1] || self
|
||||
end
|
||||
def last(n = 1); return self[-n..-1] || self; end
|
||||
|
||||
def blank?
|
||||
blank = true
|
||||
s = self.scan(/./)
|
||||
for l in s
|
||||
blank = false if l != ""
|
||||
end
|
||||
return blank
|
||||
end
|
||||
def blank?; return self.strip.empty?; end
|
||||
|
||||
def cut(bitmap, width)
|
||||
string = self
|
||||
width -= bitmap.text_size("...").width
|
||||
string_width = 0
|
||||
text = []
|
||||
for char in string.scan(/./)
|
||||
string.scan(/./).each do |char|
|
||||
wdh = bitmap.text_size(char).width
|
||||
next if (wdh + string_width) > width
|
||||
string_width += wdh
|
||||
@@ -56,19 +45,30 @@ class String
|
||||
end
|
||||
text.push("...") if text.length < string.length
|
||||
new_string = ""
|
||||
for char in text
|
||||
text.each do |char|
|
||||
new_string += char
|
||||
end
|
||||
return new_string
|
||||
end
|
||||
|
||||
def numeric?
|
||||
return !self[/\A[+-]?\d+(?:\.\d+)?\Z/].nil?
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# class Numeric
|
||||
#===============================================================================
|
||||
class Numeric
|
||||
# Turns a number into a string formatted like 12,345,678.
|
||||
# Turns a number into a string formatted like 12,345,678. Some languages use
|
||||
# different characters as the thousands separator.
|
||||
def to_s_formatted
|
||||
case System.user_language[0..1]
|
||||
when "fr", "es"
|
||||
return self.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\1 ').reverse
|
||||
when "it", "de"
|
||||
return self.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\1.').reverse
|
||||
end
|
||||
return self.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\1,').reverse
|
||||
end
|
||||
|
||||
@@ -79,17 +79,47 @@ class Numeric
|
||||
_INTL("twelve"), _INTL("thirteen"), _INTL("fourteen"), _INTL("fifteen"),
|
||||
_INTL("sixteen"), _INTL("seventeen"), _INTL("eighteen"), _INTL("nineteen"),
|
||||
_INTL("twenty")]
|
||||
return ret[self] if self.is_a?(Integer) && self >= 0 && self <= ret.length
|
||||
return ret[self] if self.is_a?(Integer) && self >= 0 && self <= ret.length - 1
|
||||
return self.to_s
|
||||
end
|
||||
|
||||
def to_ordinal
|
||||
ret = [_INTL("zeroth"), _INTL("first"), _INTL("second"), _INTL("third"),
|
||||
_INTL("fourth"), _INTL("fifth"), _INTL("sixth"), _INTL("seventh"),
|
||||
_INTL("eighth"), _INTL("ninth"), _INTL("tenth"), _INTL("eleventh"),
|
||||
_INTL("twelfth"), _INTL("thirteenth"), _INTL("fourteenth"), _INTL("fifteenth"),
|
||||
_INTL("sixteenth"), _INTL("seventeenth"), _INTL("eighteenth"), _INTL("nineteenth"),
|
||||
_INTL("twentieth")]
|
||||
return ret[self] if self.is_a?(Integer) && self >= 0 && self <= ret.length - 1
|
||||
return self.to_ord
|
||||
end
|
||||
|
||||
# Returns "1st", "2nd", "3rd", etc.
|
||||
def to_ord
|
||||
return self.to_s if !self.is_a?(Integer)
|
||||
ret = self.to_s
|
||||
if ((self % 100) / 10) == 1 # 10-19
|
||||
ret += "th"
|
||||
elsif (self % 10) == 1
|
||||
ret += "st"
|
||||
elsif (self % 10) == 2
|
||||
ret += "nd"
|
||||
elsif (self % 10) == 3
|
||||
ret += "rd"
|
||||
else
|
||||
ret += "th"
|
||||
end
|
||||
return ret
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# class Array
|
||||
#===============================================================================
|
||||
class Array
|
||||
def ^(other) # xor of two arrays
|
||||
return (self|other) - (self&other)
|
||||
# xor of two arrays
|
||||
def ^(other)
|
||||
return (self | other) - (self & other)
|
||||
end
|
||||
|
||||
def swap(val1, val2)
|
||||
@@ -100,6 +130,29 @@ class Array
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# class Hash
|
||||
#===============================================================================
|
||||
class Hash
|
||||
def deep_merge(hash)
|
||||
merged_hash = self.clone
|
||||
merged_hash.deep_merge!(hash) if hash.is_a?(Hash)
|
||||
return merged_hash
|
||||
end
|
||||
|
||||
def deep_merge!(hash)
|
||||
# failsafe
|
||||
return unless hash.is_a?(Hash)
|
||||
hash.each do |key, val|
|
||||
if self[key].is_a?(Hash)
|
||||
self[key].deep_merge!(val)
|
||||
else
|
||||
self[key] = val
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# module Enumerable
|
||||
#===============================================================================
|
||||
@@ -111,6 +164,238 @@ module Enumerable
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Collision testing
|
||||
#===============================================================================
|
||||
class Rect < Object
|
||||
def contains?(cx, cy)
|
||||
return cx >= self.x && cx < self.x + self.width &&
|
||||
cy >= self.y && cy < self.y + self.height
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# class File
|
||||
#===============================================================================
|
||||
class File
|
||||
# Copies the source file to the destination path.
|
||||
def self.copy(source, destination)
|
||||
data = ""
|
||||
t = System.uptime
|
||||
File.open(source, "rb") do |f|
|
||||
loop do
|
||||
r = f.read(4096)
|
||||
break if !r
|
||||
if System.uptime - t >= 5
|
||||
t += 5
|
||||
Graphics.update
|
||||
end
|
||||
data += r
|
||||
end
|
||||
end
|
||||
File.delete(destination) if File.file?(destination)
|
||||
f = File.new(destination, "wb")
|
||||
f.write data
|
||||
f.close
|
||||
end
|
||||
|
||||
# Copies the source to the destination and deletes the source.
|
||||
def self.move(source, destination)
|
||||
File.copy(source, destination)
|
||||
File.delete(source)
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# class Color
|
||||
#===============================================================================
|
||||
class Color
|
||||
# alias for old constructor
|
||||
alias init_original initialize unless self.private_method_defined?(:init_original)
|
||||
|
||||
# New constructor, accepts RGB values as well as a hex number or string value.
|
||||
def initialize(*args)
|
||||
pbPrintException("Wrong number of arguments! At least 1 is needed!") if args.length < 1
|
||||
case args.length
|
||||
when 1
|
||||
case args.first
|
||||
when Integer
|
||||
hex = args.first.to_s(16)
|
||||
when String
|
||||
try_rgb_format = args.first.split(",")
|
||||
init_original(*try_rgb_format.map(&:to_i)) if try_rgb_format.length.between?(3, 4)
|
||||
hex = args.first.delete("#")
|
||||
end
|
||||
pbPrintException("Wrong type of argument given!") if !hex
|
||||
r = hex[0...2].to_i(16)
|
||||
g = hex[2...4].to_i(16)
|
||||
b = hex[4...6].to_i(16)
|
||||
when 3
|
||||
r, g, b = *args
|
||||
end
|
||||
init_original(r, g, b) if r && g && b
|
||||
init_original(*args)
|
||||
end
|
||||
|
||||
def self.new_from_rgb(param)
|
||||
return Font.default_color if !param
|
||||
base_int = param.to_i(16)
|
||||
case param.length
|
||||
when 8 # 32-bit hex
|
||||
return Color.new(
|
||||
(base_int >> 24) & 0xFF,
|
||||
(base_int >> 16) & 0xFF,
|
||||
(base_int >> 8) & 0xFF,
|
||||
(base_int) & 0xFF
|
||||
)
|
||||
when 6 # 24-bit hex
|
||||
return Color.new(
|
||||
(base_int >> 16) & 0xFF,
|
||||
(base_int >> 8) & 0xFF,
|
||||
(base_int) & 0xFF
|
||||
)
|
||||
when 4 # 15-bit hex
|
||||
return Color.new(
|
||||
((base_int) & 0x1F) << 3,
|
||||
((base_int >> 5) & 0x1F) << 3,
|
||||
((base_int >> 10) & 0x1F) << 3
|
||||
)
|
||||
when 1, 2 # Color number
|
||||
case base_int
|
||||
when 0 then return Color.white
|
||||
when 1 then return Color.blue
|
||||
when 2 then return Color.red
|
||||
when 3 then return Color.green
|
||||
when 4 then return Color.cyan
|
||||
when 5 then return Color.pink
|
||||
when 6 then return Color.yellow
|
||||
when 7 then return Color.gray
|
||||
else return Font.default_color
|
||||
end
|
||||
end
|
||||
return Font.default_color
|
||||
end
|
||||
|
||||
# @return [String] the 15-bit representation of this color in a string, ignoring its alpha
|
||||
def to_rgb15
|
||||
ret = (self.red.to_i >> 3)
|
||||
ret |= ((self.green.to_i >> 3) << 5)
|
||||
ret |= ((self.blue.to_i >> 3) << 10)
|
||||
return sprintf("%04X", ret)
|
||||
end
|
||||
|
||||
# @return [String] this color in the format "RRGGBB", ignoring its alpha
|
||||
def to_rgb24
|
||||
return sprintf("%02X%02X%02X", self.red.to_i, self.green.to_i, self.blue.to_i)
|
||||
end
|
||||
|
||||
# @return [String] this color in the format "RRGGBBAA" (or "RRGGBB" if this color's alpha is 255)
|
||||
def to_rgb32(always_include_alpha = false)
|
||||
if self.alpha.to_i == 255 && !always_include_alpha
|
||||
return sprintf("%02X%02X%02X", self.red.to_i, self.green.to_i, self.blue.to_i)
|
||||
end
|
||||
return sprintf("%02X%02X%02X%02X", self.red.to_i, self.green.to_i, self.blue.to_i, self.alpha.to_i)
|
||||
end
|
||||
|
||||
# @return [String] this color in the format "#RRGGBB", ignoring its alpha
|
||||
def to_hex
|
||||
return "#" + to_rgb24
|
||||
end
|
||||
|
||||
# @return [Integer] this color in RGB format converted to an integer
|
||||
def to_i
|
||||
return self.to_rgb24.to_i(16)
|
||||
end
|
||||
|
||||
# @return [Color] the contrasting color to this one
|
||||
def get_contrast_color
|
||||
r = self.red
|
||||
g = self.green
|
||||
b = self.blue
|
||||
yuv = [
|
||||
(r * 0.299) + (g * 0.587) + (b * 0.114),
|
||||
(r * -0.1687) + (g * -0.3313) + (b * 0.500) + 0.5,
|
||||
(r * 0.500) + (g * -0.4187) + (b * -0.0813) + 0.5
|
||||
]
|
||||
if yuv[0] < 127.5
|
||||
yuv[0] += (255 - yuv[0]) / 2
|
||||
else
|
||||
yuv[0] = yuv[0] / 2
|
||||
end
|
||||
return Color.new(
|
||||
yuv[0] + (1.4075 * (yuv[2] - 0.5)),
|
||||
yuv[0] - (0.3455 * (yuv[1] - 0.5)) - (0.7169 * (yuv[2] - 0.5)),
|
||||
yuv[0] + (1.7790 * (yuv[1] - 0.5)),
|
||||
self.alpha
|
||||
)
|
||||
end
|
||||
|
||||
# Converts the provided hex string/24-bit integer to RGB values.
|
||||
def self.hex_to_rgb(hex)
|
||||
hex = hex.delete("#") if hex.is_a?(String)
|
||||
hex = hex.to_s(16) if hex.is_a?(Numeric)
|
||||
r = hex[0...2].to_i(16)
|
||||
g = hex[2...4].to_i(16)
|
||||
b = hex[4...6].to_i(16)
|
||||
return r, g, b
|
||||
end
|
||||
|
||||
# Parses the input as a Color and returns a Color object made from it.
|
||||
def self.parse(color)
|
||||
case color
|
||||
when Color
|
||||
return color
|
||||
when String, Numeric
|
||||
return Color.new(color)
|
||||
end
|
||||
# returns nothing if wrong input
|
||||
return nil
|
||||
end
|
||||
|
||||
# Returns color object for some commonly used colors.
|
||||
def self.red; return Color.new(255, 128, 128); end
|
||||
def self.green; return Color.new(128, 255, 128); end
|
||||
def self.blue; return Color.new(128, 128, 255); end
|
||||
def self.yellow; return Color.new(255, 255, 128); end
|
||||
def self.magenta; return Color.new(255, 0, 255); end
|
||||
def self.cyan; return Color.new(128, 255, 255); end
|
||||
def self.white; return Color.new(255, 255, 255); end
|
||||
def self.gray; return Color.new(192, 192, 192); end
|
||||
def self.black; return Color.new( 0, 0, 0); end
|
||||
def self.pink; return Color.new(255, 128, 255); end
|
||||
def self.orange; return Color.new(255, 155, 0); end
|
||||
def self.purple; return Color.new(155, 0, 255); end
|
||||
def self.brown; return Color.new(112, 72, 32); end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Wrap code blocks in a class which passes data accessible as instance variables
|
||||
# within the code block.
|
||||
#
|
||||
# wrapper = CallbackWrapper.new { puts @test }
|
||||
# wrapper.set(test: "Hi")
|
||||
# wrapper.execute #=> "Hi"
|
||||
#===============================================================================
|
||||
class CallbackWrapper
|
||||
@params = {}
|
||||
|
||||
def initialize(&block)
|
||||
@code_block = block
|
||||
end
|
||||
|
||||
def execute(given_block = nil, *args)
|
||||
execute_block = given_block || @code_block
|
||||
@params.each do |key, value|
|
||||
args.instance_variable_set("@#{key}", value)
|
||||
end
|
||||
args.instance_eval(&execute_block)
|
||||
end
|
||||
|
||||
def set(params = {})
|
||||
@params = params
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Kernel methods
|
||||
#===============================================================================
|
||||
@@ -132,11 +417,26 @@ class << Kernel
|
||||
return oldRand(a)
|
||||
end
|
||||
elsif a.nil?
|
||||
return (b) ? oldRand(b) : oldRand(2)
|
||||
return oldRand(b)
|
||||
end
|
||||
return oldRand
|
||||
end
|
||||
end
|
||||
|
||||
def nil_or_empty?(string)
|
||||
return string.nil? || !string.is_a?(String) || string.size == 0
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Linear interpolation between two values, given the duration of the change and
|
||||
# either:
|
||||
# - the time passed since the start of the change (delta), or
|
||||
# - the start time of the change (delta) and the current time (now)
|
||||
#===============================================================================
|
||||
def lerp(start_val, end_val, duration, delta, now = nil)
|
||||
return end_val if duration <= 0
|
||||
delta = now - delta if now
|
||||
return start_val if delta <= 0
|
||||
return end_val if delta >= duration
|
||||
return start_val + ((end_val - start_val) * delta / duration.to_f)
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,6 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module Input
|
||||
USE = C
|
||||
BACK = B
|
||||
@@ -16,18 +19,17 @@ module Input
|
||||
|
||||
def self.update
|
||||
update_KGC_ScreenCapture
|
||||
if trigger?(Input::F8)
|
||||
pbScreenCapture
|
||||
end
|
||||
pbScreenCapture if trigger?(Input::F8)
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module Mouse
|
||||
module_function
|
||||
|
||||
# Returns the position of the mouse relative to the game window.
|
||||
def getMousePos(catch_anywhere = false)
|
||||
return nil unless System.mouse_in_window || catch_anywhere
|
||||
def self.getMousePos(catch_anywhere = false)
|
||||
return nil unless Input.mouse_in_window || catch_anywhere
|
||||
return Input.mouse_x, Input.mouse_y
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#==============================================================================#
|
||||
# Plugin Manager #
|
||||
# by Marin #
|
||||
# support for external plugin scripts by Luka S.J. #
|
||||
# tweaked by Maruno #
|
||||
# Support for external plugin scripts by Luka S.J. #
|
||||
# Tweaked by Maruno #
|
||||
#------------------------------------------------------------------------------#
|
||||
# Provides a simple interface that allows plugins to require dependencies #
|
||||
# at specific versions, and to specify incompatibilities between plugins. #
|
||||
@@ -12,181 +12,118 @@
|
||||
#------------------------------------------------------------------------------#
|
||||
# Usage: #
|
||||
# #
|
||||
# A Pokémon Essentials plugin should register itself using the PluginManager. #
|
||||
# The simplest way to do so, for a plugin without dependencies, is as follows: #
|
||||
# Each plugin should have its own folder in the "Plugins" folder found in the #
|
||||
# main directory. The "Plugins" folder is similar in concept to the "PBS" #
|
||||
# folder, in that its contents are compiled and recorded as existing. The #
|
||||
# plugin's script file(s) are placed in its folder - they must be .rb files. #
|
||||
# #
|
||||
# PluginManager.register({ #
|
||||
# :name => "Basic Plugin", #
|
||||
# :version => "1.0", #
|
||||
# :link => "https://reliccastle.com/link-to-the-plugin/", #
|
||||
# :credits => "Marin" #
|
||||
# }) #
|
||||
# A plugin's folder must also contain a "meta.txt" file. This file is what #
|
||||
# makes Essentials recognise that the plugin exists, and contains important #
|
||||
# information about the plugin; if this file does not exist, the folder's #
|
||||
# contents are ignored. Each line in this file is a property. #
|
||||
# #
|
||||
# The link portion here is optional, but recommended. This will be shown in #
|
||||
# the error message if the PluginManager detects that this plugin needs to be #
|
||||
# updated. #
|
||||
# Required lines: #
|
||||
# #
|
||||
# A plugin's version should be in the format X.Y.Z, but the number of digits #
|
||||
# you use does not matter. You can also use Xa, Xb, Xc, Ya, etc. #
|
||||
# What matters is that you use it consistently, so that it can be compared. #
|
||||
# Name = Simple Extension The plugin's name #
|
||||
# Version = 1.0 The plugin's version #
|
||||
# Essentials = 19.1,20 Compatible version(s) of Essentials #
|
||||
# Link = https://reliccastle.com/link-to-the-plugin/ #
|
||||
# Credits = Luka S.J.,Maruno,Marin One or more names #
|
||||
# #
|
||||
# IF there are multiple people to credit, their names should be in an array. #
|
||||
# If there is only one credit, it does not need an array: #
|
||||
# A plugin's version should be in the format X or X.Y or X.Y.Z, where X/Y/Z #
|
||||
# are numbers. You can also use Xa, Xb, Xc, Ya, etc. What matters is that you #
|
||||
# use version numbers consistently for your plugin. A later version will be #
|
||||
# alphanumerically higher than an older version. #
|
||||
# #
|
||||
# :credits => "Marin" #
|
||||
# :credits => ["Marin", "Maruno"], #
|
||||
# Plugins can interact with each other in several ways, such as requiring #
|
||||
# another one to exist or by clashing with each other. These interactions are #
|
||||
# known as dependencies and conflicts. The lines below are all optional, and #
|
||||
# go in "meta.txt" to define how your plugin works (or doesn't work) with #
|
||||
# others. You can have multiples of each of these lines. #
|
||||
# #
|
||||
# Requires = Basic Plugin Must have this plugin (any version) #
|
||||
# Requires = Useful Utils,1.1 Must have this plugin/min. version #
|
||||
# Exact = Scene Tweaks,2 Must have this plugin/version #
|
||||
# Optional = Extended Windows,1.2 If this plugin exists, load it first #
|
||||
# Conflicts = Complex Extension Incompatible plugin #
|
||||
# #
|
||||
# A plugin that depends on another one ("Requires"/"Exact"/"Optional") will #
|
||||
# make that other plugin be loaded first. The "Optional" line is for a plugin #
|
||||
# which isn't necessary, but if it does exist in the same project, it must be #
|
||||
# at the given version or higher. #
|
||||
# #
|
||||
# Dependency: #
|
||||
# When plugins are compiled, their scripts are stored in the file #
|
||||
# "PluginScripts.rxdata" in the "Data" folder. Dependencies defined above will #
|
||||
# ensure that they are loaded in a suitable order. Scripts within a plugin are #
|
||||
# loaded alphanumerically, going through subfolders depth-first. #
|
||||
# #
|
||||
# A plugin can require another plugin to be installed in order to work. For #
|
||||
# example, the "Simple Extension" plugin depends on the above "Basic Plugin" #
|
||||
# like so: #
|
||||
# #
|
||||
# PluginManager.register({ #
|
||||
# :name => "Simple Extension", #
|
||||
# :version => "1.0", #
|
||||
# :link => "https://reliccastle.com/link-to-the-plugin/", #
|
||||
# :credits => ["Marin", "Maruno"], #
|
||||
# :dependencies => ["Basic Plugin"] #
|
||||
# }) #
|
||||
# #
|
||||
# If there are multiple dependencies, they should be listed in an array. If #
|
||||
# there is only one dependency, it does not need an array: #
|
||||
# #
|
||||
# :dependencies => "Basic Plugin" #
|
||||
# #
|
||||
# To require a minimum version of a dependency plugin, you should turn the #
|
||||
# dependency's name into an array which contains the name and the version #
|
||||
# (both as strings). For example, to require "Basic Plugin" version 1.2 or #
|
||||
# higher, you would write: #
|
||||
# #
|
||||
# :dependencies => [ #
|
||||
# ["Basic Plugin", "1.2"] #
|
||||
# ] #
|
||||
# #
|
||||
# To require a specific version (no higher and no lower) of a dependency #
|
||||
# plugin, you should add the :exact flag as the first thing in the array for #
|
||||
# that dependency: #
|
||||
# #
|
||||
# :dependencies => [ #
|
||||
# [:exact, "Basic Plugin", "1.2"] #
|
||||
# ] #
|
||||
# #
|
||||
# If your plugin can work without another plugin, but it is incompatible with #
|
||||
# an old version of that other plugin, you should list it as an optional #
|
||||
# dependency. If that other plugin is present in a game, then this optional #
|
||||
# dependency will check whether it meets the minimum version required for your #
|
||||
# plugin. Write it in the same way as any other dependency as described above, #
|
||||
# but use the :optional flag instead. #
|
||||
# #
|
||||
# :dependencies => [ #
|
||||
# [:optional, "QoL Improvements", "1.1"] #
|
||||
# ] #
|
||||
# #
|
||||
# The :optional_exact flag is a combination of :optional and :exact. #
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# Incompatibility: #
|
||||
# #
|
||||
# If your plugin is known to be incompatible with another plugin, you should #
|
||||
# list that other plugin as such. Only one of the two plugins needs to list #
|
||||
# that it is incompatible with the other. #
|
||||
# #
|
||||
# PluginManager.register({ #
|
||||
# :name => "QoL Improvements", #
|
||||
# :version => "1.0", #
|
||||
# :link => "https://reliccastle.com/link-to-the-plugin/", #
|
||||
# :credits => "Marin", #
|
||||
# :incompatibilities => [ #
|
||||
# "Simple Extension" #
|
||||
# ] #
|
||||
# }) #
|
||||
# The "Plugins" folder should be deleted when the game is released. Scripts in #
|
||||
# there are compiled, but any other files used by a plugin (graphics/audio) #
|
||||
# should go into other folders and not the plugin's folder. #
|
||||
# #
|
||||
#------------------------------------------------------------------------------#
|
||||
# Plugin folder: #
|
||||
# The code behind plugins: #
|
||||
# #
|
||||
# The Plugin folder is treated like the PBS folder, but for script files for #
|
||||
# plugins. Each plugin has its own folder within the Plugin folder. Each #
|
||||
# plugin must have a meta.txt file in its folder, which contains information #
|
||||
# about that plugin. Folders without this meta.txt file are ignored. #
|
||||
# When a plugin's "meta.txt" file is read, its contents are registered in the #
|
||||
# PluginManager. A simple example of registering a plugin is as follows: #
|
||||
# #
|
||||
# Scripts must be in .rb files. You should not put any other files into a #
|
||||
# plugin's folder except for script files and meta.txt. #
|
||||
# PluginManager.register({ #
|
||||
# :name => "Basic Plugin", #
|
||||
# :version => "1.0", #
|
||||
# :essentials => "20", #
|
||||
# :link => "https://reliccastle.com/link-to-the-plugin/", #
|
||||
# :credits => ["Marin"] #
|
||||
# }) #
|
||||
# #
|
||||
# When the game is compiled, scripts in these folders are read and converted #
|
||||
# into a usable format, and saved in the file Data/PluginScripts.rxdata. #
|
||||
# Script files are loaded in order of their name and subfolder, so it is wise #
|
||||
# to name script files "001_first script.rb", "002_second script.rb", etc. to #
|
||||
# ensure they are loaded in the correct order. #
|
||||
# The :link value is optional, but recommended. This will be shown in the #
|
||||
# message if the PluginManager detects that this plugin needs to be updated. #
|
||||
# #
|
||||
# When the game is compressed for distribution, the Plugin folder and all its #
|
||||
# contents should be deleted (like the PBS folder), because its contents will #
|
||||
# be unused (they will have been compiled into the PluginScripts.rxdata file). #
|
||||
# Here is the same example but also with dependencies and conflicts: #
|
||||
# #
|
||||
# The contents of meta.txt are as follows: #
|
||||
# PluginManager.register({ #
|
||||
# :name => "Basic Plugin", #
|
||||
# :version => "1.0", #
|
||||
# :essentials => "20", #
|
||||
# :link => "https://reliccastle.com/link-to-the-plugin/", #
|
||||
# :credits => ["Marin"], #
|
||||
# :dependencies => ["Basic Plugin", #
|
||||
# ["Useful Utils", "1.1"], #
|
||||
# [:exact, "Scene Tweaks", "2"], #
|
||||
# [:optional, "Extended Windows", "1.2"], #
|
||||
# ], #
|
||||
# :incompatibilities => ["Simple Extension"] #
|
||||
# }) #
|
||||
# #
|
||||
# Name = Simple Extension #
|
||||
# Version = 1.0 #
|
||||
# Requires = Basic Plugin #
|
||||
# Requires = Useful Utilities,1.1 #
|
||||
# Conflicts = Complex Extension #
|
||||
# Conflicts = Extended Windows #
|
||||
# Link = https://reliccastle.com/link-to-the-plugin/ #
|
||||
# Credits = Luka S.J.,Maruno,Marin #
|
||||
# #
|
||||
# These lines are related to what is described above. You can have multiple #
|
||||
# "Requires" and "Conflicts" lines, each listing a single other plugin that is #
|
||||
# either a dependency or a conflict respectively. #
|
||||
# #
|
||||
# Examples of the "Requires" line: #
|
||||
# #
|
||||
# Requires = Basic Plugin #
|
||||
# Requires = Basic Plugin,1.1 #
|
||||
# Requires = Basic Plugin,1.1,exact #
|
||||
# Requires = Basic Plugin,1.1,optional #
|
||||
# Exact = Basic Plugin,1.1 #
|
||||
# Optional = Basic Plugin,1.1 #
|
||||
# #
|
||||
# The "Exact" and "Optional" lines are equivalent to the "Requires" lines #
|
||||
# that contain those keywords. #
|
||||
# #
|
||||
# There is also a "Scripts" line, which lists one or more script files that #
|
||||
# should be loaded first. You can have multiple "Scripts" lines. However, you #
|
||||
# can achieve the same effect by simply naming your script files in #
|
||||
# alphanumeric order to make them load in a particular order, so the "Scripts" #
|
||||
# line should not be necessary. #
|
||||
# The example dependencies/conflict are the same as the examples shown above #
|
||||
# for lines in "meta.txt". :optional_exact is a combination of :exact and #
|
||||
# :optional, and there is no way to make use of its combined functionality via #
|
||||
# "meta.txt". #
|
||||
# #
|
||||
#------------------------------------------------------------------------------#
|
||||
# Please give credit when using this. #
|
||||
#==============================================================================#
|
||||
|
||||
module PluginManager
|
||||
# Holds all registered plugin data.
|
||||
@@Plugins = {}
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Registers a plugin and tests its dependencies and incompatibilities.
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.register(options)
|
||||
name = nil
|
||||
version = nil
|
||||
essentials = nil
|
||||
link = nil
|
||||
dependencies = nil
|
||||
incompats = nil
|
||||
credits = []
|
||||
order = [:name, :version, :link, :dependencies, :incompatibilities, :credits]
|
||||
order = [:name, :version, :essentials, :link, :dependencies, :incompatibilities, :credits]
|
||||
# Ensure it first reads the plugin's name, which is used in error reporting,
|
||||
# by sorting the keys
|
||||
keys = options.keys.sort do |a, b|
|
||||
idx_a = order.index(a)
|
||||
idx_a = order.size if idx_a == -1
|
||||
idx_b = order.index(b)
|
||||
idx_b = order.size if idx_b == -1
|
||||
idx_a = order.index(a) || order.size
|
||||
idx_b = order.index(b) || order.size
|
||||
next idx_a <=> idx_b
|
||||
end
|
||||
for key in keys
|
||||
keys.each do |key|
|
||||
value = options[key]
|
||||
case key
|
||||
when :name # Plugin name
|
||||
@@ -198,10 +135,10 @@ module PluginManager
|
||||
end
|
||||
name = value
|
||||
when :version # Plugin version
|
||||
if nil_or_empty?(value)
|
||||
self.error("Plugin version must be a string.")
|
||||
end
|
||||
self.error("Plugin version must be a string.") if nil_or_empty?(value)
|
||||
version = value
|
||||
when :essentials
|
||||
essentials = value
|
||||
when :link # Plugin website
|
||||
if nil_or_empty?(value)
|
||||
self.error("Plugin link must be a non-empty string.")
|
||||
@@ -210,12 +147,13 @@ module PluginManager
|
||||
when :dependencies # Plugin dependencies
|
||||
dependencies = value
|
||||
dependencies = [dependencies] if !dependencies.is_a?(Array) || !dependencies[0].is_a?(Array)
|
||||
for dep in value
|
||||
if dep.is_a?(String) # "plugin name"
|
||||
value.each do |dep|
|
||||
case dep
|
||||
when String # "plugin name"
|
||||
if !self.installed?(dep)
|
||||
self.error("Plugin '#{name}' requires plugin '#{dep}' to be installed above it.")
|
||||
end
|
||||
elsif dep.is_a?(Array)
|
||||
when Array
|
||||
case dep.size
|
||||
when 1 # ["plugin name"]
|
||||
if dep[0].is_a?(String)
|
||||
@@ -236,7 +174,8 @@ module PluginManager
|
||||
if self.installed?(dep_name) # Have plugin but lower version
|
||||
msg = "Plugin '#{name}' requires plugin '#{dep_name}' version #{dep_version} or higher, " +
|
||||
"but the installed version is #{self.version(dep_name)}."
|
||||
if dep_link = self.link(dep_name)
|
||||
dep_link = self.link(dep_name)
|
||||
if dep_link
|
||||
msg += "\r\nCheck #{dep_link} for an update to plugin '#{dep_name}'."
|
||||
end
|
||||
self.error(msg)
|
||||
@@ -278,7 +217,8 @@ module PluginManager
|
||||
msg = "Plugin '#{name}' requires plugin '#{dep_name}', if installed, to be version #{dep_version}"
|
||||
msg << " or higher" if !exact
|
||||
msg << ", but the installed version was #{self.version(dep_name)}."
|
||||
if dep_link = self.link(dep_name)
|
||||
dep_link = self.link(dep_name)
|
||||
if dep_link
|
||||
msg << "\r\nCheck #{dep_link} for an update to plugin '#{dep_name}'."
|
||||
end
|
||||
self.error(msg)
|
||||
@@ -288,16 +228,16 @@ module PluginManager
|
||||
msg = "Plugin '#{name}' requires plugin '#{dep_name}' to be version #{dep_version}"
|
||||
msg << " or later" if !exact
|
||||
msg << ", but the installed version was #{self.version(dep_name)}."
|
||||
if dep_link = self.link(dep_name)
|
||||
dep_link = self.link(dep_name)
|
||||
if dep_link
|
||||
msg << "\r\nCheck #{dep_link} for an update to plugin '#{dep_name}'."
|
||||
end
|
||||
self.error(msg)
|
||||
else # Don't have plugin
|
||||
msg = "Plugin '#{name}' requires plugin '#{dep_name}' version #{dep_version} "
|
||||
msg << "or later" if !exact
|
||||
msg << "or later " if !exact
|
||||
msg << "to be installed above it."
|
||||
self.error(msg)
|
||||
end
|
||||
self.error(msg)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -305,20 +245,19 @@ module PluginManager
|
||||
when :incompatibilities # Plugin incompatibilities
|
||||
incompats = value
|
||||
incompats = [incompats] if !incompats.is_a?(Array)
|
||||
for incompat in incompats
|
||||
incompats.each do |incompat|
|
||||
if self.installed?(incompat)
|
||||
self.error("Plugin '#{name}' is incompatible with '#{incompat}'. " +
|
||||
"They cannot both be used at the same time.")
|
||||
self.error("Plugin '#{name}' is incompatible with '#{incompat}'. They cannot both be used at the same time.")
|
||||
end
|
||||
end
|
||||
when :credits # Plugin credits
|
||||
value = [value] if value.is_a?(String)
|
||||
if value.is_a?(Array)
|
||||
for entry in value
|
||||
if !entry.is_a?(String)
|
||||
self.error("Plugin '#{name}'s credits array contains a non-string value.")
|
||||
else
|
||||
value.each do |entry|
|
||||
if entry.is_a?(String)
|
||||
credits << entry
|
||||
else
|
||||
self.error("Plugin '#{name}'s credits array contains a non-string value.")
|
||||
end
|
||||
end
|
||||
else
|
||||
@@ -328,30 +267,29 @@ module PluginManager
|
||||
self.error("Invalid plugin registry key '#{key}'.")
|
||||
end
|
||||
end
|
||||
for plugin in @@Plugins.values
|
||||
if plugin[:incompatibilities] && plugin[:incompatibilities].include?(name)
|
||||
self.error("Plugin '#{plugin[:name]}' is incompatible with '#{name}'. " +
|
||||
"They cannot both be used at the same time.")
|
||||
@@Plugins.each_value do |plugin|
|
||||
if plugin[:incompatibilities]&.include?(name)
|
||||
self.error("Plugin '#{plugin[:name]}' is incompatible with '#{name}'. They cannot both be used at the same time.")
|
||||
end
|
||||
end
|
||||
# Add plugin to class variable
|
||||
@@Plugins[name] = {
|
||||
:name => name,
|
||||
:version => version,
|
||||
:link => link,
|
||||
:dependencies => dependencies,
|
||||
:name => name,
|
||||
:version => version,
|
||||
:essentials => essentials,
|
||||
:link => link,
|
||||
:dependencies => dependencies,
|
||||
:incompatibilities => incompats,
|
||||
:credits => credits
|
||||
:credits => credits
|
||||
}
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Throws a pure error message without stack trace or any other useless info.
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.error(msg)
|
||||
Graphics.update
|
||||
t = Thread.new do
|
||||
echoln "Plugin Error:\r\n#{msg}"
|
||||
p "Plugin Error: #{msg}"
|
||||
Console.echo_error("Plugin Error:\r\n#{msg}")
|
||||
print("Plugin Error:\r\n#{msg}")
|
||||
Thread.exit
|
||||
end
|
||||
while t.status
|
||||
@@ -359,11 +297,10 @@ module PluginManager
|
||||
end
|
||||
Kernel.exit! true
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Returns true if the specified plugin is installed.
|
||||
# If the version is specified, this version is taken into account.
|
||||
# If mustequal is true, the version must be a match with the specified version.
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.installed?(plugin_name, plugin_version = nil, mustequal = false)
|
||||
plugin = @@Plugins[plugin_name]
|
||||
return false if plugin.nil?
|
||||
@@ -372,87 +309,97 @@ module PluginManager
|
||||
return true if !mustequal && comparison >= 0
|
||||
return true if mustequal && comparison == 0
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Returns the string names of all installed plugins.
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.plugins
|
||||
return @@Plugins.keys
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Returns the installed version of the specified plugin.
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.version(plugin_name)
|
||||
return if !installed?(plugin_name)
|
||||
return @@Plugins[plugin_name][:version]
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Returns the link of the specified plugin.
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.link(plugin_name)
|
||||
return if !installed?(plugin_name)
|
||||
return @@Plugins[plugin_name][:link]
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Returns the credits of the specified plugin.
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.credits(plugin_name)
|
||||
return if !installed?(plugin_name)
|
||||
return @@Plugins[plugin_name][:credits]
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Compares two versions given in string form. v1 should be the plugin version
|
||||
# you actually have, and v2 should be the minimum/desired plugin version.
|
||||
# Return values:
|
||||
# 1 if v1 is higher than v2
|
||||
# 0 if v1 is equal to v2
|
||||
# -1 if v1 is lower than v2
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.compare_versions(v1, v2)
|
||||
d1 = v1.split("")
|
||||
d1.insert(0, "0") if d1[0] == "." # Turn ".123" into "0.123"
|
||||
while d1[-1] == "."; d1 = d1[0..-2]; end # Turn "123." into "123"
|
||||
d2 = v2.split("")
|
||||
d2.insert(0, "0") if d2[0] == "." # Turn ".123" into "0.123"
|
||||
while d2[-1] == "."; d2 = d2[0..-2]; end # Turn "123." into "123"
|
||||
for i in 0...[d1.size, d2.size].max # Compare each digit in turn
|
||||
c1 = d1[i]
|
||||
c2 = d2[i]
|
||||
if c1
|
||||
return 1 if !c2
|
||||
return 1 if c1.to_i(16) > c2.to_i(16)
|
||||
return -1 if c1.to_i(16) < c2.to_i(16)
|
||||
else
|
||||
return -1 if c2
|
||||
version_chunks1 = v1.split(".")
|
||||
version_chunks1.each_with_index do |val, i|
|
||||
next if val != ""
|
||||
version_chunks1[i] = (i == 0) ? "0" : nil
|
||||
end
|
||||
version_chunks1.compact!
|
||||
version_chunks2 = v2.split(".")
|
||||
version_chunks2.each_with_index do |val, i|
|
||||
next if val != ""
|
||||
version_chunks2[i] = (i == 0) ? "0" : nil
|
||||
end
|
||||
version_chunks2.compact!
|
||||
# Compare each chunk in turn
|
||||
decision = :equal # Could be :higher or :lower
|
||||
[version_chunks1.length, version_chunks2.length].max.times do |i|
|
||||
chunk1 = version_chunks1[i]
|
||||
chunk2 = version_chunks2[i]
|
||||
if !chunk1
|
||||
decision = :lower if decision == :equal
|
||||
break
|
||||
elsif !chunk2
|
||||
decision = :higher if decision == :equal
|
||||
break
|
||||
end
|
||||
# Make both chunks the same left by pre-padding with "0"
|
||||
chars_count = [chunk1.length, chunk2.length].max
|
||||
chunk1 = chunk1.rjust(chars_count, "0").chars
|
||||
chunk2 = chunk2.rjust(chars_count, "0").chars
|
||||
chunk1.length.times do |j|
|
||||
c1 = chunk1[j]
|
||||
c2 = chunk2[j]
|
||||
next if c1 == c2
|
||||
decision = (c1.to_i(16) > c2.to_i(16)) ? :higher : :lower
|
||||
break
|
||||
end
|
||||
break if decision != :equal
|
||||
end
|
||||
case decision
|
||||
when :equal then return 0
|
||||
when :higher then return 1
|
||||
when :lower then return -1
|
||||
end
|
||||
return 0
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# formats the error message
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Formats the error message
|
||||
def self.pluginErrorMsg(name, script)
|
||||
e = $!
|
||||
# begin message formatting
|
||||
message = "[Pokémon Essentials version #{Essentials::VERSION}]\r\n"
|
||||
message = "[Pokémon Essentials version #{Essentials::VERSION}]\r\n"
|
||||
message += "#{Essentials::ERROR_TEXT}\r\n" # For third party scripts to add to
|
||||
message += "Error in Plugin [#{name}]:\r\n"
|
||||
message += "#{$!.class} occurred.\r\n"
|
||||
# go through message content
|
||||
for line in $!.message.split("\r\n")
|
||||
next if nil_or_empty?(line)
|
||||
n = line[/\d+/]
|
||||
err = line.split(":")[-1].strip
|
||||
lms = line.split(":")[0].strip
|
||||
err.gsub!(n, "") if n
|
||||
err = err.capitalize if err.is_a?(String) && !err.empty?
|
||||
linum = n ? "Line #{n}: " : ""
|
||||
message += "#{linum}#{err}: #{lms}\r\n"
|
||||
end
|
||||
message += "Error in Plugin: [#{name}]\r\n"
|
||||
message += "Exception: #{e.class}\r\n"
|
||||
message += "Message: "
|
||||
message += e.message
|
||||
# show last 10 lines of backtrace
|
||||
message += "\r\nBacktrace:\r\n"
|
||||
$!.backtrace[0, 10].each { |i| message += "#{i}\r\n" }
|
||||
message += "\r\n\r\nBacktrace:\r\n"
|
||||
e.backtrace[0, 10].each { |i| message += "#{i}\r\n" }
|
||||
# output to log
|
||||
errorlog = "errorlog.txt"
|
||||
errorlog = RTP.getSaveFileName("errorlog.txt") if (Object.const_defined?(:RTP) rescue false)
|
||||
File.open(errorlog, "ab") do |f|
|
||||
f.write("\r\n=================\r\n\r\n[#{Time.now}]\r\n")
|
||||
f.write(message)
|
||||
@@ -465,8 +412,8 @@ module PluginManager
|
||||
# output message
|
||||
print("#{message}\r\nThis exception was logged in #{errorlogline}.\r\nHold Ctrl when closing this message to copy it to the clipboard.")
|
||||
# Give a ~500ms coyote time to start holding Control
|
||||
t = System.delta
|
||||
until (System.delta - t) >= 500000
|
||||
t = System.uptime
|
||||
until System.uptime - t >= 0.5
|
||||
Input.update
|
||||
if Input.press?(Input::CTRL)
|
||||
Input.clipboard = message
|
||||
@@ -474,24 +421,26 @@ module PluginManager
|
||||
end
|
||||
end
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Used to read the metadata file
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.readMeta(dir, file)
|
||||
filename = "#{dir}/#{file}"
|
||||
meta = {}
|
||||
# read file
|
||||
Compiler.pbCompilerEachPreppedLine(filename) { |line, line_no|
|
||||
Compiler.pbCompilerEachPreppedLine(filename) do |line, line_no|
|
||||
# split line up into property name and values
|
||||
if !line[/^\s*(\w+)\s*=\s*(.*)$/]
|
||||
raise _INTL("Bad line syntax (expected syntax like XXX=YYY)\r\n{1}", FileLineData.linereport)
|
||||
raise _INTL("Bad line syntax (expected syntax like XXX=YYY).") + "\n" + FileLineData.linereport
|
||||
end
|
||||
property = $~[1].upcase
|
||||
data = $~[2].split(',')
|
||||
data = $~[2].split(",")
|
||||
data.each_with_index { |value, i| data[i] = value.strip }
|
||||
# begin formatting data hash
|
||||
case property
|
||||
when 'REQUIRES'
|
||||
when "ESSENTIALS"
|
||||
meta[:essentials] = [] if !meta[:essentials]
|
||||
data.each { |ver| meta[:essentials].push(ver) }
|
||||
when "REQUIRES"
|
||||
meta[:dependencies] = [] if !meta[:dependencies]
|
||||
if data.length < 2 # No version given, just push name of plugin dependency
|
||||
meta[:dependencies].push(data[0])
|
||||
@@ -501,33 +450,33 @@ module PluginManager
|
||||
else # Push dependency type, name and version of plugin dependency
|
||||
meta[:dependencies].push([data[2].downcase.to_sym, data[0], data[1]])
|
||||
end
|
||||
when 'EXACT'
|
||||
when "EXACT"
|
||||
next if data.length < 2 # Exact dependencies must have a version given; ignore if not
|
||||
meta[:dependencies] = [] if !meta[:dependencies]
|
||||
meta[:dependencies].push([:exact, data[0], data[1]])
|
||||
when 'OPTIONAL'
|
||||
when "OPTIONAL"
|
||||
next if data.length < 2 # Optional dependencies must have a version given; ignore if not
|
||||
meta[:dependencies] = [] if !meta[:dependencies]
|
||||
meta[:dependencies].push([:optional, data[0], data[1]])
|
||||
when 'CONFLICTS'
|
||||
when "CONFLICTS"
|
||||
meta[:incompatibilities] = [] if !meta[:incompatibilities]
|
||||
data.each { |value| meta[:incompatibilities].push(value) if value && !value.empty? }
|
||||
when 'SCRIPTS'
|
||||
when "SCRIPTS"
|
||||
meta[:scripts] = [] if !meta[:scripts]
|
||||
data.each { |scr| meta[:scripts].push(scr) }
|
||||
when 'CREDITS'
|
||||
when "CREDITS"
|
||||
meta[:credits] = data
|
||||
when 'LINK', 'WEBSITE'
|
||||
when "LINK", "WEBSITE"
|
||||
meta[:link] = data[0]
|
||||
else
|
||||
meta[property.downcase.to_sym] = data[0]
|
||||
end
|
||||
}
|
||||
end
|
||||
# generate a list of all script files to be loaded, in the order they are to
|
||||
# be loaded (files listed in the meta file are loaded first)
|
||||
meta[:scripts] = [] if !meta[:scripts]
|
||||
# get all script files from plugin Dir
|
||||
for fl in Dir.all(dir)
|
||||
Dir.all(dir).each do |fl|
|
||||
next if !fl.include?(".rb")
|
||||
meta[:scripts].push(fl.gsub("#{dir}/", ""))
|
||||
end
|
||||
@@ -536,26 +485,24 @@ module PluginManager
|
||||
# return meta hash
|
||||
return meta
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Get a list of all the plugin directories to inspect
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.listAll
|
||||
return [] if !$DEBUG || safeExists?("Game.rgssad")
|
||||
return [] if !$DEBUG || FileTest.exist?("Game.rgssad") || !Dir.safe?("Plugins")
|
||||
# get a list of all directories in the `Plugins/` folder
|
||||
dirs = []
|
||||
Dir.get("Plugins").each { |d| dirs.push(d) if Dir.safe?(d) }
|
||||
# return all plugins
|
||||
return dirs
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Catch any potential loop with dependencies and raise an error
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.validateDependencies(name, meta, og = nil)
|
||||
# exit if no registered dependency
|
||||
return nil if !meta[name] || !meta[name][:dependencies]
|
||||
og = [name] if !og
|
||||
# go through all dependencies
|
||||
for dname in meta[name][:dependencies]
|
||||
meta[name][:dependencies].each do |dname|
|
||||
# clean the name to a simple string
|
||||
dname = dname[0] if dname.is_a?(Array) && dname.length == 2
|
||||
dname = dname[1] if dname.is_a?(Array) && dname.length == 3
|
||||
@@ -567,20 +514,25 @@ module PluginManager
|
||||
end
|
||||
return name
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Sort load order based on dependencies (this ends up in reverse order)
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.sortLoadOrder(order, plugins)
|
||||
# go through the load order
|
||||
for o in order
|
||||
order.each do |o|
|
||||
next if !plugins[o] || !plugins[o][:dependencies]
|
||||
# go through all dependencies
|
||||
for dname in plugins[o][:dependencies]
|
||||
plugins[o][:dependencies].each do |dname|
|
||||
optional = false
|
||||
# clean the name to a simple string
|
||||
dname = dname[0] if dname.is_a?(Array) && dname.length == 2
|
||||
dname = dname[1] if dname.is_a?(Array) && dname.length == 3
|
||||
if dname.is_a?(Array)
|
||||
optional = [:optional, :optional_exact].include?(dname[0])
|
||||
dname = dname[dname.length - 2]
|
||||
end
|
||||
# catch missing dependency
|
||||
self.error("Plugin '#{o}' requires plugin '#{dname}' to work properly.") if !order.include?(dname)
|
||||
if !order.include?(dname)
|
||||
next if optional
|
||||
self.error("Plugin '#{o}' requires plugin '#{dname}' to work properly.")
|
||||
end
|
||||
# skip if already sorted
|
||||
next if order.index(dname) > order.index(o)
|
||||
# catch looping dependency issue
|
||||
@@ -590,17 +542,16 @@ module PluginManager
|
||||
end
|
||||
return order
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Get the order in which to load plugins
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.getPluginOrder
|
||||
plugins = {}
|
||||
order = []
|
||||
# Find all plugin folders that have a meta.txt and add them to the list of
|
||||
# plugins.
|
||||
for dir in self.listAll
|
||||
self.listAll.each do |dir|
|
||||
# skip if there is no meta file
|
||||
next if !safeExists?(dir + "/meta.txt")
|
||||
next if !FileTest.exist?(dir + "/meta.txt")
|
||||
ndx = order.length
|
||||
meta = self.readMeta(dir, "meta.txt")
|
||||
meta[:dir] = dir
|
||||
@@ -618,44 +569,53 @@ module PluginManager
|
||||
# sort the load order
|
||||
return self.sortLoadOrder(order, plugins).reverse, plugins
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Check if plugins need compiling
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.needCompiling?(order, plugins)
|
||||
# fixed actions
|
||||
return false if !$DEBUG || safeExists?("Game.rgssad")
|
||||
return true if !safeExists?("Data/PluginScripts.rxdata")
|
||||
return false if !$DEBUG || FileTest.exist?("Game.rgssad")
|
||||
return true if $full_compile
|
||||
return true if !FileTest.exist?("Data/PluginScripts.rxdata")
|
||||
Input.update
|
||||
return true if Input.press?(Input::CTRL)
|
||||
# analyze whether or not to push recompile
|
||||
# Force compiling if holding Shift or Ctrl
|
||||
return true if Input.press?(Input::SHIFT) || Input.press?(Input::CTRL)
|
||||
# Should compile if the number of plugins has changed
|
||||
scripts = load_data("Data/PluginScripts.rxdata")
|
||||
return true if scripts.length != plugins.length
|
||||
# Should compile if any plugins have changed version or been replaced
|
||||
found_plugins = []
|
||||
plugins.each_pair { |name, meta| found_plugins.push([meta[:name], meta[:version]]) }
|
||||
existing_plugins = []
|
||||
scripts.each { |plugin| existing_plugins.push([plugin[1][:name], plugin[1][:version]]) }
|
||||
return true if found_plugins != existing_plugins
|
||||
# Should compile if any plugin files have been recently modified
|
||||
mtime = File.mtime("Data/PluginScripts.rxdata")
|
||||
for o in order
|
||||
order.each do |o|
|
||||
# go through all the registered plugin scripts
|
||||
scr = plugins[o][:scripts]
|
||||
dir = plugins[o][:dir]
|
||||
for sc in scr
|
||||
scr.each do |sc|
|
||||
return true if File.mtime("#{dir}/#{sc}") > mtime
|
||||
end
|
||||
return true if File.mtime("#{dir}/meta.txt") > mtime
|
||||
end
|
||||
return false
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Check if plugins need compiling
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.compilePlugins(order, plugins)
|
||||
echo 'Compiling plugin scripts...'
|
||||
Console.echo_li("Compiling plugin scripts...")
|
||||
scripts = []
|
||||
# go through the entire order one by one
|
||||
for o in order
|
||||
order.each do |o|
|
||||
# save name, metadata and scripts array
|
||||
meta = plugins[o].clone
|
||||
meta.delete(:scripts)
|
||||
meta.delete(:dir)
|
||||
dat = [o, meta, []]
|
||||
# iterate through each file to deflate
|
||||
for file in plugins[o][:scripts]
|
||||
File.open("#{plugins[o][:dir]}/#{file}", 'rb') do |f|
|
||||
plugins[o][:scripts].each do |file|
|
||||
File.open("#{plugins[o][:dir]}/#{file}", "rb") do |f|
|
||||
dat[2].push([file, Zlib::Deflate.deflate(f.read)])
|
||||
end
|
||||
end
|
||||
@@ -663,41 +623,47 @@ module PluginManager
|
||||
scripts.push(dat)
|
||||
end
|
||||
# save to main `PluginScripts.rxdata` file
|
||||
File.open("Data/PluginScripts.rxdata", 'wb') { |f| Marshal.dump(scripts, f) }
|
||||
File.open("Data/PluginScripts.rxdata", "wb") { |f| Marshal.dump(scripts, f) }
|
||||
# collect garbage
|
||||
GC.start
|
||||
echoln ' done.'
|
||||
echoln ''
|
||||
Console.echo_done(true)
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Check if plugins need compiling
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.runPlugins
|
||||
Console.echo_h1("Checking plugins")
|
||||
# get the order of plugins to interpret
|
||||
order, plugins = self.getPluginOrder
|
||||
# compile if necessary
|
||||
self.compilePlugins(order, plugins) if self.needCompiling?(order, plugins)
|
||||
if self.needCompiling?(order, plugins)
|
||||
self.compilePlugins(order, plugins)
|
||||
else
|
||||
Console.echoln_li("Plugins were not compiled")
|
||||
end
|
||||
# load plugins
|
||||
scripts = load_data("Data/PluginScripts.rxdata")
|
||||
echoed_plugins = []
|
||||
for plugin in scripts
|
||||
scripts.each do |plugin|
|
||||
# get the required data
|
||||
name, meta, script = plugin
|
||||
if !meta[:essentials] || !meta[:essentials].include?(Essentials::VERSION)
|
||||
Console.echo_warn("Plugin '#{name}' may not be compatible with Essentials v#{Essentials::VERSION}. Trying to load anyway.")
|
||||
end
|
||||
# register plugin
|
||||
self.register(meta)
|
||||
# go through each script and interpret
|
||||
for scr in script
|
||||
script.each do |scr|
|
||||
# turn code into plaintext
|
||||
code = Zlib::Inflate.inflate(scr[1]).force_encoding(Encoding::UTF_8)
|
||||
# get rid of tabs
|
||||
code.gsub!("\t", " ")
|
||||
# construct filename
|
||||
sname = scr[0].gsub("\\","/").split("/")[-1]
|
||||
sname = scr[0].gsub("\\", "/").split("/")[-1]
|
||||
fname = "[#{name}] #{sname}"
|
||||
# try to run the code
|
||||
begin
|
||||
eval(code, TOPLEVEL_BINDING, fname)
|
||||
echoln "Loaded plugin: #{name}" if !echoed_plugins.include?(name)
|
||||
Console.echoln_li("Loaded plugin: ==#{name}== (ver. #{meta[:version]})") if !echoed_plugins.include?(name)
|
||||
echoed_plugins.push(name)
|
||||
rescue Exception # format error message to display
|
||||
self.pluginErrorMsg(name, sname)
|
||||
@@ -705,7 +671,24 @@ module PluginManager
|
||||
end
|
||||
end
|
||||
end
|
||||
echoln '' if !echoed_plugins.empty?
|
||||
if scripts.length > 0
|
||||
Console.echoln_li_done("Successfully loaded #{scripts.length} plugin(s)")
|
||||
else
|
||||
Console.echoln_li_done("No plugins found")
|
||||
end
|
||||
end
|
||||
|
||||
# Get plugin dir from name based on meta entries
|
||||
def self.findDirectory(name)
|
||||
# go through the plugins folder
|
||||
Dir.get("Plugins").each do |dir|
|
||||
next if !Dir.safe?(dir)
|
||||
next if !FileTest.exist?(dir + "/meta.txt")
|
||||
# read meta
|
||||
meta = self.readMeta(dir, "meta.txt")
|
||||
return dir if meta[:name] == name
|
||||
end
|
||||
# return nil if no plugin dir found
|
||||
return nil
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
end
|
||||
|
||||
@@ -1,534 +1,103 @@
|
||||
class SpriteAnimation
|
||||
@@_animations = []
|
||||
@@_reference_count = {}
|
||||
|
||||
def initialize(sprite)
|
||||
@sprite = sprite
|
||||
end
|
||||
|
||||
%w[
|
||||
x y ox oy viewport flash src_rect opacity tone
|
||||
].each_with_index do |s, _i|
|
||||
eval <<-__END__
|
||||
|
||||
def #{s}(*arg)
|
||||
@sprite.#{s}(*arg)
|
||||
end
|
||||
|
||||
__END__
|
||||
end
|
||||
|
||||
def self.clear
|
||||
@@_animations.clear
|
||||
end
|
||||
|
||||
def dispose
|
||||
dispose_animation
|
||||
dispose_loop_animation
|
||||
end
|
||||
|
||||
def animation(animation, hit, height = 3)
|
||||
dispose_animation
|
||||
@_animation = animation
|
||||
return if @_animation == nil
|
||||
@_animation_hit = hit
|
||||
@_animation_height = height
|
||||
@_animation_duration = @_animation.frame_max
|
||||
fr = 20
|
||||
if @_animation.name[/\[\s*(\d+?)\s*\]\s*$/]
|
||||
fr = $~[1].to_i
|
||||
end
|
||||
@_animation_frame_skip = Graphics.frame_rate / fr
|
||||
animation_name = @_animation.animation_name
|
||||
animation_hue = @_animation.animation_hue
|
||||
bitmap = pbGetAnimation(animation_name, animation_hue)
|
||||
if @@_reference_count.include?(bitmap)
|
||||
@@_reference_count[bitmap] += 1
|
||||
else
|
||||
@@_reference_count[bitmap] = 1
|
||||
end
|
||||
@_animation_sprites = []
|
||||
if @_animation.position != 3 || !@@_animations.include?(animation)
|
||||
16.times do
|
||||
sprite = ::Sprite.new(self.viewport)
|
||||
sprite.bitmap = bitmap
|
||||
sprite.visible = false
|
||||
@_animation_sprites.push(sprite)
|
||||
end
|
||||
unless @@_animations.include?(animation)
|
||||
@@_animations.push(animation)
|
||||
end
|
||||
end
|
||||
update_animation
|
||||
end
|
||||
|
||||
def loop_animation(animation)
|
||||
return if animation == @_loop_animation
|
||||
dispose_loop_animation
|
||||
@_loop_animation = animation
|
||||
return if @_loop_animation == nil
|
||||
@_loop_animation_index = 0
|
||||
fr = 20
|
||||
if @_animation.name[/\[\s*(\d+?)\s*\]\s*$/]
|
||||
fr = $~[1].to_i
|
||||
end
|
||||
@_loop_animation_frame_skip = Graphics.frame_rate / fr
|
||||
animation_name = @_loop_animation.animation_name
|
||||
animation_hue = @_loop_animation.animation_hue
|
||||
bitmap = pbGetAnimation(animation_name, animation_hue)
|
||||
if @@_reference_count.include?(bitmap)
|
||||
@@_reference_count[bitmap] += 1
|
||||
else
|
||||
@@_reference_count[bitmap] = 1
|
||||
end
|
||||
@_loop_animation_sprites = []
|
||||
16.times do
|
||||
sprite = ::Sprite.new(self.viewport)
|
||||
sprite.bitmap = bitmap
|
||||
sprite.visible = false
|
||||
@_loop_animation_sprites.push(sprite)
|
||||
end
|
||||
update_loop_animation
|
||||
end
|
||||
|
||||
def dispose_animation
|
||||
return if @_animation_sprites == nil
|
||||
sprite = @_animation_sprites[0]
|
||||
if sprite != nil
|
||||
@@_reference_count[sprite.bitmap] -= 1
|
||||
if @@_reference_count[sprite.bitmap] == 0
|
||||
sprite.bitmap.dispose
|
||||
end
|
||||
end
|
||||
for sprite in @_animation_sprites
|
||||
sprite.dispose
|
||||
end
|
||||
@_animation_sprites = nil
|
||||
@_animation = nil
|
||||
end
|
||||
|
||||
def dispose_loop_animation
|
||||
return if @_loop_animation_sprites == nil
|
||||
sprite = @_loop_animation_sprites[0]
|
||||
if sprite != nil
|
||||
@@_reference_count[sprite.bitmap] -= 1
|
||||
if @@_reference_count[sprite.bitmap] == 0
|
||||
sprite.bitmap.dispose
|
||||
end
|
||||
end
|
||||
for sprite in @_loop_animation_sprites
|
||||
sprite.dispose
|
||||
end
|
||||
@_loop_animation_sprites = nil
|
||||
@_loop_animation = nil
|
||||
end
|
||||
|
||||
def active?
|
||||
return @_loop_animation_sprites != nil || @_animation_sprites != nil
|
||||
end
|
||||
|
||||
def effect?
|
||||
return @_animation_duration > 0
|
||||
end
|
||||
|
||||
def update
|
||||
if @_animation != nil
|
||||
quick_update = true
|
||||
if Graphics.frame_count % @_animation_frame_skip == 0
|
||||
@_animation_duration -= 1
|
||||
quick_update = false
|
||||
end
|
||||
update_animation(quick_update)
|
||||
end
|
||||
if @_loop_animation != nil
|
||||
quick_update = (Graphics.frame_count % @_loop_animation_frame_skip != 0)
|
||||
update_loop_animation(quick_update)
|
||||
if !quick_update
|
||||
@_loop_animation_index += 1
|
||||
@_loop_animation_index %= @_loop_animation.frame_max
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update_animation(quick_update = false)
|
||||
if @_animation_duration <= 0
|
||||
dispose_animation
|
||||
return
|
||||
end
|
||||
frame_index = @_animation.frame_max - @_animation_duration
|
||||
cell_data = @_animation.frames[frame_index].cell_data
|
||||
position = @_animation.position
|
||||
animation_set_sprites(@_animation_sprites, cell_data, position, quick_update)
|
||||
return if quick_update
|
||||
for timing in @_animation.timings
|
||||
next if timing.frame != frame_index
|
||||
animation_process_timing(timing, @_animation_hit)
|
||||
end
|
||||
end
|
||||
|
||||
def update_loop_animation(quick_update = false)
|
||||
frame_index = @_loop_animation_index
|
||||
cell_data = @_loop_animation.frames[frame_index].cell_data
|
||||
position = @_loop_animation.position
|
||||
animation_set_sprites(@_loop_animation_sprites, cell_data, position, quick_update)
|
||||
return if quick_update
|
||||
for timing in @_loop_animation.timings
|
||||
next if timing.frame != frame_index
|
||||
animation_process_timing(timing, true)
|
||||
end
|
||||
end
|
||||
|
||||
def animation_set_sprites(sprites, cell_data, position, quick_update = false)
|
||||
sprite_x = 320
|
||||
sprite_y = 240
|
||||
if position == 3
|
||||
if self.viewport != nil
|
||||
sprite_x = self.viewport.rect.width / 2
|
||||
sprite_y = self.viewport.rect.height - 160
|
||||
end
|
||||
else
|
||||
sprite_x = self.x - self.ox + self.src_rect.width / 2
|
||||
sprite_y = self.y - self.oy
|
||||
sprite_y += self.src_rect.height / 2 if position == 1
|
||||
sprite_y += self.src_rect.height if position == 2
|
||||
end
|
||||
for i in 0..15
|
||||
sprite = sprites[i]
|
||||
pattern = cell_data[i, 0]
|
||||
if sprite == nil || pattern == nil || pattern == -1
|
||||
sprite.visible = false if sprite != nil
|
||||
next
|
||||
end
|
||||
sprite.x = sprite_x + cell_data[i, 1]
|
||||
sprite.y = sprite_y + cell_data[i, 2]
|
||||
next if quick_update
|
||||
sprite.visible = true
|
||||
sprite.src_rect.set(pattern % 5 * 192, pattern / 5 * 192, 192, 192)
|
||||
case @_animation_height
|
||||
when 0 then sprite.z = 1
|
||||
when 1 then sprite.z = sprite.y+32+15
|
||||
when 2 then sprite.z = sprite.y+32+32+17
|
||||
else sprite.z = 2000
|
||||
end
|
||||
sprite.ox = 96
|
||||
sprite.oy = 96
|
||||
sprite.zoom_x = cell_data[i, 3] / 100.0
|
||||
sprite.zoom_y = cell_data[i, 3] / 100.0
|
||||
sprite.angle = cell_data[i, 4]
|
||||
sprite.mirror = (cell_data[i, 5] == 1)
|
||||
sprite.tone = self.tone
|
||||
sprite.opacity = cell_data[i, 6] * self.opacity / 255.0
|
||||
sprite.blend_type = cell_data[i, 7]
|
||||
end
|
||||
end
|
||||
|
||||
def animation_process_timing(timing, hit)
|
||||
if timing.condition == 0 ||
|
||||
(timing.condition == 1 && hit == true) ||
|
||||
(timing.condition == 2 && hit == false)
|
||||
if timing.se.name != ""
|
||||
se = timing.se
|
||||
pbSEPlay(se)
|
||||
end
|
||||
case timing.flash_scope
|
||||
when 1
|
||||
self.flash(timing.flash_color, timing.flash_duration * 2)
|
||||
when 2
|
||||
if self.viewport != nil
|
||||
self.viewport.flash(timing.flash_color, timing.flash_duration * 2)
|
||||
end
|
||||
when 3
|
||||
self.flash(nil, timing.flash_duration * 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def x=(x)
|
||||
sx = x - self.x
|
||||
return if sx == 0
|
||||
if @_animation_sprites != nil
|
||||
for i in 0..15
|
||||
@_animation_sprites[i].x += sx
|
||||
end
|
||||
end
|
||||
if @_loop_animation_sprites != nil
|
||||
for i in 0..15
|
||||
@_loop_animation_sprites[i].x += sx
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def y=(y)
|
||||
sy = y - self.y
|
||||
return if sy == 0
|
||||
if @_animation_sprites != nil
|
||||
for i in 0..15
|
||||
@_animation_sprites[i].y += sy
|
||||
end
|
||||
end
|
||||
if @_loop_animation_sprites != nil
|
||||
for i in 0..15
|
||||
@_loop_animation_sprites[i].y += sy
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Additions to class Sprite that allows class AnimationContainerSprite to attach
|
||||
# overworld animations to itself.
|
||||
#===============================================================================
|
||||
module RPG
|
||||
class Sprite < ::Sprite
|
||||
def initialize(viewport = nil)
|
||||
super(viewport)
|
||||
@_whiten_duration = 0
|
||||
@_appear_duration = 0
|
||||
@_escape_duration = 0
|
||||
@_collapse_duration = 0
|
||||
@_damage_duration = 0
|
||||
@_animation_duration = 0
|
||||
@_blink = false
|
||||
@animations = []
|
||||
@_animation_frame = 0
|
||||
@animations = []
|
||||
@loopAnimations = []
|
||||
end
|
||||
|
||||
def dispose
|
||||
dispose_damage
|
||||
dispose_animation
|
||||
dispose_loop_animation
|
||||
super
|
||||
end
|
||||
|
||||
def whiten
|
||||
self.blend_type = 0
|
||||
self.color.set(255, 255, 255, 128)
|
||||
self.opacity = 255
|
||||
@_whiten_duration = 16
|
||||
@_appear_duration = 0
|
||||
@_escape_duration = 0
|
||||
@_collapse_duration = 0
|
||||
def dispose_animation
|
||||
@animations.each { |a| a&.dispose_animation }
|
||||
@animations.clear
|
||||
end
|
||||
|
||||
def appear
|
||||
self.blend_type = 0
|
||||
self.color.set(0, 0, 0, 0)
|
||||
self.opacity = 0
|
||||
@_appear_duration = 16
|
||||
@_whiten_duration = 0
|
||||
@_escape_duration = 0
|
||||
@_collapse_duration = 0
|
||||
def dispose_loop_animation
|
||||
@loopAnimations.each { |a| a&.dispose_loop_animation }
|
||||
@loopAnimations.clear
|
||||
end
|
||||
|
||||
def escape
|
||||
self.blend_type = 0
|
||||
self.color.set(0, 0, 0, 0)
|
||||
self.opacity = 255
|
||||
@_escape_duration = 32
|
||||
@_whiten_duration = 0
|
||||
@_appear_duration = 0
|
||||
@_collapse_duration = 0
|
||||
def x=(x)
|
||||
@animations.each { |a| a.x = x if a }
|
||||
@loopAnimations.each { |a| a.x = x if a }
|
||||
super
|
||||
end
|
||||
|
||||
def collapse
|
||||
self.blend_type = 1
|
||||
self.color.set(255, 64, 64, 255)
|
||||
self.opacity = 255
|
||||
@_collapse_duration = 48
|
||||
@_whiten_duration = 0
|
||||
@_appear_duration = 0
|
||||
@_escape_duration = 0
|
||||
end
|
||||
|
||||
def damage(value, critical)
|
||||
dispose_damage
|
||||
damage_string = (value.is_a?(Numeric)) ? value.abs.to_s : value.to_s
|
||||
bitmap = Bitmap.new(160, 48)
|
||||
bitmap.font.name = "Arial Black"
|
||||
bitmap.font.size = 32
|
||||
bitmap.font.color.set(0, 0, 0)
|
||||
bitmap.draw_text(-1, 12-1, 160, 36, damage_string, 1)
|
||||
bitmap.draw_text(+1, 12-1, 160, 36, damage_string, 1)
|
||||
bitmap.draw_text(-1, 12+1, 160, 36, damage_string, 1)
|
||||
bitmap.draw_text(+1, 12+1, 160, 36, damage_string, 1)
|
||||
if value.is_a?(Numeric) && value < 0
|
||||
bitmap.font.color.set(176, 255, 144)
|
||||
else
|
||||
bitmap.font.color.set(255, 255, 255)
|
||||
end
|
||||
bitmap.draw_text(0, 12, 160, 36, damage_string, 1)
|
||||
if critical
|
||||
bitmap.font.size = 20
|
||||
bitmap.font.color.set(0, 0, 0)
|
||||
bitmap.draw_text(-1, -1, 160, 20, "CRITICAL", 1)
|
||||
bitmap.draw_text(+1, -1, 160, 20, "CRITICAL", 1)
|
||||
bitmap.draw_text(-1, +1, 160, 20, "CRITICAL", 1)
|
||||
bitmap.draw_text(+1, +1, 160, 20, "CRITICAL", 1)
|
||||
bitmap.font.color.set(255, 255, 255)
|
||||
bitmap.draw_text(0, 0, 160, 20, "CRITICAL", 1)
|
||||
end
|
||||
@_damage_sprite = ::Sprite.new(self.viewport)
|
||||
@_damage_sprite.bitmap = bitmap
|
||||
@_damage_sprite.ox = 80
|
||||
@_damage_sprite.oy = 20
|
||||
@_damage_sprite.x = self.x
|
||||
@_damage_sprite.y = self.y - self.oy / 2
|
||||
@_damage_sprite.z = 3000
|
||||
@_damage_duration = 40
|
||||
def y=(y)
|
||||
@animations.each { |a| a.y = y if a }
|
||||
@loopAnimations.each { |a| a.y = y if a }
|
||||
super
|
||||
end
|
||||
|
||||
def pushAnimation(array, anim)
|
||||
for i in 0...array.length
|
||||
next if array[i] && array[i].active?
|
||||
array.length.times do |i|
|
||||
next if array[i]&.active?
|
||||
array[i] = anim
|
||||
return
|
||||
end
|
||||
array.push(anim)
|
||||
end
|
||||
|
||||
def animation(animation, hit, height = 3)
|
||||
def animation(animation, hit, height = 3, no_tone = false)
|
||||
anim = SpriteAnimation.new(self)
|
||||
anim.animation(animation,hit,height)
|
||||
pushAnimation(@animations,anim)
|
||||
anim.animation(animation, hit, height, no_tone)
|
||||
pushAnimation(@animations, anim)
|
||||
end
|
||||
|
||||
def loop_animation(animation)
|
||||
anim = SpriteAnimation.new(self)
|
||||
anim.loop_animation(animation)
|
||||
pushAnimation(@loopAnimations,anim)
|
||||
end
|
||||
|
||||
def dispose_damage
|
||||
return if @_damage_sprite == nil
|
||||
@_damage_sprite.bitmap.dispose
|
||||
@_damage_sprite.dispose
|
||||
@_damage_sprite = nil
|
||||
@_damage_duration = 0
|
||||
end
|
||||
|
||||
def dispose_animation
|
||||
for a in @animations
|
||||
a.dispose_animation if a
|
||||
end
|
||||
@animations.clear
|
||||
end
|
||||
|
||||
def dispose_loop_animation
|
||||
for a in @loopAnimations
|
||||
a.dispose_loop_animation if a
|
||||
end
|
||||
@loopAnimations.clear
|
||||
end
|
||||
|
||||
def blink_on
|
||||
return if @_blink
|
||||
@_blink = true
|
||||
@_blink_count = 0
|
||||
end
|
||||
|
||||
def blink_off
|
||||
return unless @_blink
|
||||
@_blink = false
|
||||
self.color.set(0, 0, 0, 0)
|
||||
end
|
||||
|
||||
def blink?
|
||||
return @_blink
|
||||
pushAnimation(@loopAnimations, anim)
|
||||
end
|
||||
|
||||
def effect?
|
||||
return true if @_whiten_duration > 0
|
||||
return true if @_appear_duration > 0
|
||||
return true if @_escape_duration > 0
|
||||
return true if @_collapse_duration > 0
|
||||
return true if @_damage_duration > 0
|
||||
for a in @animations
|
||||
return true if a.effect?
|
||||
end
|
||||
@animations.each { |a| return true if a.effect? }
|
||||
return false
|
||||
end
|
||||
|
||||
def update_animation
|
||||
@animations.each { |a| a.update_animation if a&.active? }
|
||||
end
|
||||
|
||||
def update_loop_animation
|
||||
@loopAnimations.each { |a| a.update_loop_animation if a&.active? }
|
||||
end
|
||||
|
||||
def update
|
||||
super
|
||||
if @_whiten_duration > 0
|
||||
@_whiten_duration -= 1
|
||||
self.color.alpha = 128 - (16 - @_whiten_duration) * 10
|
||||
end
|
||||
if @_appear_duration > 0
|
||||
@_appear_duration -= 1
|
||||
self.opacity = (16 - @_appear_duration) * 16
|
||||
end
|
||||
if @_escape_duration > 0
|
||||
@_escape_duration -= 1
|
||||
self.opacity = 256 - (32 - @_escape_duration) * 10
|
||||
end
|
||||
if @_collapse_duration > 0
|
||||
@_collapse_duration -= 1
|
||||
self.opacity = 256 - (48 - @_collapse_duration) * 6
|
||||
end
|
||||
if @_damage_duration > 0
|
||||
@_damage_duration -= 1
|
||||
case @_damage_duration
|
||||
when 38..39
|
||||
@_damage_sprite.y -= 4
|
||||
when 36..37
|
||||
@_damage_sprite.y -= 2
|
||||
when 34..35
|
||||
@_damage_sprite.y += 2
|
||||
when 28..33
|
||||
@_damage_sprite.y += 4
|
||||
end
|
||||
@_damage_sprite.opacity = 256 - (12 - @_damage_duration) * 32
|
||||
if @_damage_duration == 0
|
||||
dispose_damage
|
||||
end
|
||||
end
|
||||
for a in @animations
|
||||
a.update
|
||||
end
|
||||
for a in @loopAnimations
|
||||
a.update
|
||||
end
|
||||
if @_blink
|
||||
@_blink_count = (@_blink_count + 1) % 32
|
||||
if @_blink_count < 16
|
||||
alpha = (16 - @_blink_count) * 6
|
||||
else
|
||||
alpha = (@_blink_count - 16) * 6
|
||||
end
|
||||
self.color.set(255, 255, 255, alpha)
|
||||
end
|
||||
@animations.each { |a| a.update }
|
||||
@loopAnimations.each { |a| a.update }
|
||||
SpriteAnimation.clear
|
||||
end
|
||||
|
||||
def update_animation
|
||||
for a in @animations
|
||||
a.update_animation if a && a.active?
|
||||
end
|
||||
end
|
||||
|
||||
def update_loop_animation
|
||||
for a in @loopAnimations
|
||||
a.update_loop_animation if a && a.active?
|
||||
end
|
||||
end
|
||||
|
||||
def x=(x)
|
||||
for a in @animations
|
||||
a.x = x if a
|
||||
end
|
||||
for a in @loopAnimations
|
||||
a.x = x if a
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
def y=(y)
|
||||
for a in @animations
|
||||
a.y = y if a
|
||||
end
|
||||
for a in @loopAnimations
|
||||
a.y = y if a
|
||||
end
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# A version of class Sprite that allows its coordinates to be floats rather than
|
||||
# integers.
|
||||
#===============================================================================
|
||||
class FloatSprite < Sprite
|
||||
def x; return @float_x; end
|
||||
def y; return @float_y; end
|
||||
|
||||
def x=(value)
|
||||
@float_x = value
|
||||
super
|
||||
end
|
||||
|
||||
def y=(value)
|
||||
@float_y = value
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,39 +1,49 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module Settings
|
||||
# Whether a move's physical/special category depends on the move itself as in
|
||||
# newer Gens (true), or on its type as in older Gens (false).
|
||||
MOVE_CATEGORY_PER_MOVE = (MECHANICS_GENERATION >= 4)
|
||||
#-----------------------------------------------------------------------------
|
||||
# Turn order and disobedience
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Whether turn order is recalculated after a Pokémon Mega Evolves.
|
||||
RECALCULATE_TURN_ORDER_AFTER_MEGA_EVOLUTION = (MECHANICS_GENERATION >= 7)
|
||||
# Whether turn order is recalculated after a Pokémon's Speed stat changes.
|
||||
RECALCULATE_TURN_ORDER_AFTER_SPEED_CHANGES = (MECHANICS_GENERATION >= 8)
|
||||
# Whether any Pokémon (originally owned by the player or foreign) can disobey
|
||||
# the player's commands if the Pokémon is too high a level compared to the
|
||||
# number of Gym Badges the player has.
|
||||
ANY_HIGH_LEVEL_POKEMON_CAN_DISOBEY = false
|
||||
# Whether foreign Pokémon can disobey the player's commands if the Pokémon is
|
||||
# too high a level compared to the number of Gym Badges the player has.
|
||||
FOREIGN_HIGH_LEVEL_POKEMON_CAN_DISOBEY = true
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Mega Evolution
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# The Game Switch which, while ON, prevents all Pokémon in battle from Mega
|
||||
# Evolving even if they otherwise could.
|
||||
NO_MEGA_EVOLUTION = 34
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Move usage calculations
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Whether a move's physical/special category depends on the move itself as in
|
||||
# newer Gens (true), or on its type as in older Gens (false).
|
||||
MOVE_CATEGORY_PER_MOVE = (MECHANICS_GENERATION >= 4)
|
||||
# Whether critical hits do 1.5x damage and have 4 stages (true), or they do 2x
|
||||
# damage and have 5 stages as in Gen 5 (false). Also determines whether
|
||||
# critical hit rate can be copied by Transform/Psych Up.
|
||||
NEW_CRITICAL_HIT_RATE_MECHANICS = (MECHANICS_GENERATION >= 6)
|
||||
NEW_CRITICAL_HIT_RATE_MECHANICS = (MECHANICS_GENERATION >= 6)
|
||||
# Whether several effects apply relating to a Pokémon's type:
|
||||
# * Electric-type immunity to paralysis
|
||||
# * Ghost-type immunity to being trapped
|
||||
# * Grass-type immunity to powder moves and Effect Spore
|
||||
# * Poison-type Pokémon can't miss when using Toxic
|
||||
MORE_TYPE_EFFECTS = (MECHANICS_GENERATION >= 6)
|
||||
# Whether weather caused by an ability lasts 5 rounds (true) or forever (false).
|
||||
FIXED_DURATION_WEATHER_FROM_ABILITY = (MECHANICS_GENERATION >= 6)
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# Whether X items (X Attack, etc.) raise their stat by 2 stages (true) or 1
|
||||
# (false).
|
||||
X_STAT_ITEMS_RAISE_BY_TWO_STAGES = (MECHANICS_GENERATION >= 7)
|
||||
# Whether some Poké Balls have catch rate multipliers from Gen 7 (true) or
|
||||
# from earlier generations (false).
|
||||
NEW_POKE_BALL_CATCH_RATES = (MECHANICS_GENERATION >= 7)
|
||||
# Whether Soul Dew powers up Psychic and Dragon-type moves by 20% (true) or
|
||||
# raises the holder's Special Attack and Special Defense by 50% (false).
|
||||
SOUL_DEW_POWERS_UP_TYPES = (MECHANICS_GENERATION >= 7)
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# The minimum number of badges required to boost each stat of a player's
|
||||
MORE_TYPE_EFFECTS = (MECHANICS_GENERATION >= 6)
|
||||
# The minimum number of Gym Badges required to boost each stat of a player's
|
||||
# Pokémon by 1.1x, in battle only.
|
||||
NUM_BADGES_BOOST_ATTACK = (MECHANICS_GENERATION >= 4) ? 999 : 1
|
||||
NUM_BADGES_BOOST_DEFENSE = (MECHANICS_GENERATION >= 4) ? 999 : 5
|
||||
@@ -41,38 +51,94 @@ module Settings
|
||||
NUM_BADGES_BOOST_SPDEF = (MECHANICS_GENERATION >= 4) ? 999 : 7
|
||||
NUM_BADGES_BOOST_SPEED = (MECHANICS_GENERATION >= 4) ? 999 : 3
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Move, ability and item effects
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# An array of items which act as Mega Rings for the player (NPCs don't need a
|
||||
# Mega Ring item, just a Mega Stone held by their Pokémon).
|
||||
MEGA_RINGS = [:MEGARING, :MEGABRACELET, :MEGACUFF, :MEGACHARM]
|
||||
# The Game Switch which, while ON, prevents all Pokémon in battle from Mega
|
||||
# Evolving even if they otherwise could.
|
||||
NO_MEGA_EVOLUTION = 34
|
||||
# Whether the in-battle hail weather is replaced by Snowstorm (from Gen 9+)
|
||||
# instead.
|
||||
USE_SNOWSTORM_WEATHER_INSTEAD_OF_HAIL = (MECHANICS_GENERATION >= 9)
|
||||
# Whether weather caused by an ability lasts 5 rounds (true) or forever (false).
|
||||
FIXED_DURATION_WEATHER_FROM_ABILITY = (MECHANICS_GENERATION >= 6)
|
||||
# Whether X items (X Attack, etc.) raise their stat by 2 stages (true) or 1
|
||||
# (false).
|
||||
X_STAT_ITEMS_RAISE_BY_TWO_STAGES = (MECHANICS_GENERATION >= 7)
|
||||
# Whether some Poké Balls have catch rate multipliers from Gen 7 (true) or
|
||||
# from earlier generations (false).
|
||||
NEW_POKE_BALL_CATCH_RATES = (MECHANICS_GENERATION >= 7)
|
||||
# Whether Soul Dew powers up Psychic and Dragon-type moves by 20% (true) or
|
||||
# raises the holder's Special Attack and Special Defense by 50% (false).
|
||||
SOUL_DEW_POWERS_UP_TYPES = (MECHANICS_GENERATION >= 7)
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Affection
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Whether Pokémon with high happiness will gain more Exp from battles, have a
|
||||
# chance of avoiding/curing negative effects by themselves, resisting
|
||||
# fainting, etc.
|
||||
AFFECTION_EFFECTS = false
|
||||
# Whether a Pokémon's happiness is limited to 179, and can only be increased
|
||||
# further with friendship-raising berries. Related to AFFECTION_EFFECTS by
|
||||
# default because affection effects only start applying above a happiness of
|
||||
# 179. Also lowers the happiness evolution threshold to 160.
|
||||
APPLY_HAPPINESS_SOFT_CAP = AFFECTION_EFFECTS
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Capturing Pokémon
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Whether the Exp gained from beating a Pokémon should be scaled depending on
|
||||
# the gainer's level.
|
||||
SCALED_EXP_FORMULA = (MECHANICS_GENERATION == 5 || MECHANICS_GENERATION >= 7)
|
||||
# Whether the Exp gained from beating a Pokémon should be divided equally
|
||||
# between each participant (true), or whether each participant should gain
|
||||
# that much Exp (false). This also applies to Exp gained via the Exp Share
|
||||
# (held item version) being distributed to all Exp Share holders.
|
||||
SPLIT_EXP_BETWEEN_GAINERS = (MECHANICS_GENERATION <= 5)
|
||||
# Whether the critical capture mechanic applies. Note that its calculation is
|
||||
# based on a total of 600+ species (i.e. that many species need to be caught
|
||||
# to provide the greatest critical capture chance of 2.5x), and there may be
|
||||
# fewer species in your game.
|
||||
ENABLE_CRITICAL_CAPTURES = (MECHANICS_GENERATION >= 5)
|
||||
ENABLE_CRITICAL_CAPTURES = (MECHANICS_GENERATION >= 5)
|
||||
# Whether the player is asked what to do with a newly caught Pokémon if their
|
||||
# party is full. If true, the player can toggle whether they are asked this in
|
||||
# the Options screen.
|
||||
NEW_CAPTURE_CAN_REPLACE_PARTY_MEMBER = (MECHANICS_GENERATION >= 7)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Exp and EV gain
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Whether the Exp gained from beating a Pokémon should be scaled depending on
|
||||
# the gainer's level.
|
||||
SCALED_EXP_FORMULA = (MECHANICS_GENERATION == 5 || MECHANICS_GENERATION >= 7)
|
||||
# Whether the Exp gained from beating a Pokémon should be divided equally
|
||||
# between each participant (true), or whether each participant should gain
|
||||
# that much Exp (false). This also applies to Exp gained via the Exp Share
|
||||
# (held item version) being distributed to all Exp Share holders.
|
||||
SPLIT_EXP_BETWEEN_GAINERS = (MECHANICS_GENERATION <= 5)
|
||||
# Whether the Exp gained from beating a Pokémon is multiplied by 1.5 if that
|
||||
# Pokémon is owned by another trainer.
|
||||
MORE_EXP_FROM_TRAINER_POKEMON = (MECHANICS_GENERATION <= 6)
|
||||
# Whether a Pokémon holding a Power item gains 8 (true) or 4 (false) EVs in
|
||||
# the relevant stat.
|
||||
MORE_EVS_FROM_POWER_ITEMS = (MECHANICS_GENERATION >= 7)
|
||||
# Whether Pokémon gain Exp for capturing a Pokémon.
|
||||
GAIN_EXP_FOR_CAPTURE = (MECHANICS_GENERATION >= 6)
|
||||
# The Game Switch which, whie ON, prevents the player from losing money if
|
||||
GAIN_EXP_FOR_CAPTURE = (MECHANICS_GENERATION >= 6)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# End of battle
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
CAN_FORFEIT_TRAINER_BATTLES = (MECHANICS_GENERATION >= 9)
|
||||
# The Game Switch which, while ON, prevents the player from losing money if
|
||||
# they lose a battle (they can still gain money from trainers for winning).
|
||||
NO_MONEY_LOSS = 33
|
||||
NO_MONEY_LOSS = 33
|
||||
# Whether party Pokémon check whether they can evolve after all battles
|
||||
# regardless of the outcome (true), or only after battles the player won (false).
|
||||
CHECK_EVOLUTION_AFTER_ALL_BATTLES = (MECHANICS_GENERATION >= 6)
|
||||
# Whether fainted Pokémon can try to evolve after a battle.
|
||||
CHECK_EVOLUTION_FOR_FAINTED_POKEMON = true
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# AI
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Whether wild Pokémon with the "Legendary", "Mythical" or "UltraBeast" flag
|
||||
# (as defined in pokemon.txt) have a smarter AI. Their skill level is set to
|
||||
# 32, which is a medium skill level.
|
||||
SMARTER_WILD_LEGENDARY_POKEMON = true
|
||||
end
|
||||
|
||||
@@ -1,19 +1,30 @@
|
||||
#===============================================================================
|
||||
# The SaveData module is used to manipulate save data. It contains the {Value}s
|
||||
# that make up the save data and {Conversion}s for resolving incompatibilities
|
||||
# between Essentials and game versions.
|
||||
# @see SaveData.register
|
||||
# @see SaveData.register_conversion
|
||||
#===============================================================================
|
||||
module SaveData
|
||||
# Contains the file path of the save file.
|
||||
FILE_PATH = if File.directory?(System.data_directory)
|
||||
System.data_directory + '/Game.rxdata'
|
||||
else
|
||||
'./Game.rxdata'
|
||||
end
|
||||
DIRECTORY = (File.directory?(System.data_directory)) ? System.data_directory : "./"
|
||||
FILENAME_REGEX = /Game(\d*)\.rxdata$/
|
||||
|
||||
# @return [Boolean] whether the save file exists
|
||||
# @return [Boolean] whether any save files exist
|
||||
def self.exists?
|
||||
return File.file?(FILE_PATH)
|
||||
return !all_save_files.empty?
|
||||
end
|
||||
|
||||
# @return[Array] array of filenames in the save folder that are save files
|
||||
def self.all_save_files
|
||||
files = Dir.get(DIRECTORY, "*", false)
|
||||
ret = []
|
||||
files.each do |file|
|
||||
next if !file[FILENAME_REGEX]
|
||||
ret.push([$~[1].to_i, file])
|
||||
end
|
||||
ret.sort! { |a, b| a[0] <=> b[0] }
|
||||
ret.map! { |val| val[1] }
|
||||
return ret
|
||||
end
|
||||
|
||||
# Fetches the save data from the given file.
|
||||
@@ -43,9 +54,9 @@ module SaveData
|
||||
def self.read_from_file(file_path)
|
||||
validate file_path => String
|
||||
save_data = get_data_from_file(file_path)
|
||||
save_data = to_hash_format(save_data) if save_data.is_a?(Array)
|
||||
save_data = to_hash_format(save_data) if save_data.is_a?(Array) # Pre-v19 save file support
|
||||
if !save_data.empty? && run_conversions(save_data)
|
||||
File.open(file_path, 'wb') { |file| Marshal.dump(save_data, file) }
|
||||
File.open(file_path, "wb") { |file| Marshal.dump(save_data, file) }
|
||||
end
|
||||
return save_data
|
||||
end
|
||||
@@ -57,14 +68,19 @@ module SaveData
|
||||
def self.save_to_file(file_path)
|
||||
validate file_path => String
|
||||
save_data = self.compile_save_hash
|
||||
File.open(file_path, 'wb') { |file| Marshal.dump(save_data, file) }
|
||||
File.open(file_path, "wb") { |file| Marshal.dump(save_data, file) }
|
||||
end
|
||||
|
||||
# Deletes the save file (and a possible .bak backup file if one exists)
|
||||
# @raise [Error::ENOENT]
|
||||
def self.delete_file
|
||||
File.delete(FILE_PATH)
|
||||
File.delete(FILE_PATH + '.bak') if File.file?(FILE_PATH + '.bak')
|
||||
def self.delete_file(filename)
|
||||
File.delete(DIRECTORY + filename)
|
||||
File.delete(DIRECTORY + filename + ".bak") if File.file?(DIRECTORY + filename + ".bak")
|
||||
end
|
||||
|
||||
def self.filename_from_index(index = 0)
|
||||
return "Game.rxdata" if index <= 0
|
||||
return "Game#{index}.rxdata"
|
||||
end
|
||||
|
||||
# Converts the pre-v19 format data to the new format.
|
||||
@@ -79,19 +95,4 @@ module SaveData
|
||||
end
|
||||
return hash
|
||||
end
|
||||
|
||||
# Moves a save file from the old Saved Games folder to the new
|
||||
# location specified by {FILE_PATH}. Does nothing if a save file
|
||||
# already exists in {FILE_PATH}.
|
||||
def self.move_old_windows_save
|
||||
return if File.file?(FILE_PATH)
|
||||
game_title = System.game_title.gsub(/[^\w ]/, '_')
|
||||
home = ENV['HOME'] || ENV['HOMEPATH']
|
||||
return if home.nil?
|
||||
old_location = File.join(home, 'Saved Games', game_title)
|
||||
return unless File.directory?(old_location)
|
||||
old_file = File.join(old_location, 'Game.rxdata')
|
||||
return unless File.file?(old_file)
|
||||
File.move(old_file, FILE_PATH)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module SaveData
|
||||
# Contains Value objects for each save element.
|
||||
# Populated during runtime by SaveData.register calls.
|
||||
# @type [Array<Value>]
|
||||
@values = []
|
||||
|
||||
#=============================================================================
|
||||
# An error raised if an invalid save value is being saved or loaded.
|
||||
#=============================================================================
|
||||
class InvalidValueError < RuntimeError; end
|
||||
|
||||
#=============================================================================
|
||||
# Represents a single value in save data.
|
||||
# New values are added using {SaveData.register}.
|
||||
#=============================================================================
|
||||
class Value
|
||||
# @return [Symbol] the value id
|
||||
attr_reader :id
|
||||
@@ -20,6 +26,7 @@ module SaveData
|
||||
@id = id
|
||||
@loaded = false
|
||||
@load_in_bootup = false
|
||||
@reset_on_new_game = false
|
||||
instance_eval(&block)
|
||||
raise "No save_value defined for save value #{id.inspect}" if @save_proc.nil?
|
||||
raise "No load_value defined for save value #{id.inspect}" if @load_proc.nil?
|
||||
@@ -70,11 +77,24 @@ module SaveData
|
||||
return @load_in_bootup
|
||||
end
|
||||
|
||||
def reset_on_new_game
|
||||
@reset_on_new_game = true
|
||||
end
|
||||
|
||||
def reset_on_new_game?
|
||||
return @reset_on_new_game
|
||||
end
|
||||
|
||||
# @return [Boolean] whether the value has been loaded
|
||||
def loaded?
|
||||
return @loaded
|
||||
end
|
||||
|
||||
# Marks value as unloaded.
|
||||
def mark_as_unloaded
|
||||
@loaded = false
|
||||
end
|
||||
|
||||
# Uses the {#from_old_format} proc to select the correct data from
|
||||
# +old_format+ and return it.
|
||||
# Returns nil if the proc is undefined.
|
||||
@@ -85,6 +105,8 @@ module SaveData
|
||||
return @old_format_get_proc.call(old_format)
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
private
|
||||
|
||||
# Raises an {InvalidValueError} if the given value is invalid.
|
||||
@@ -109,21 +131,21 @@ module SaveData
|
||||
# Requires a block with the loaded value as its parameter.
|
||||
# @see SaveData.register
|
||||
def load_value(&block)
|
||||
raise ArgumentError, 'No block given to load_value' unless block_given?
|
||||
raise ArgumentError, "No block given to load_value" unless block_given?
|
||||
@load_proc = block
|
||||
end
|
||||
|
||||
# Defines what is saved into save data. Requires a block.
|
||||
# @see SaveData.register
|
||||
def save_value(&block)
|
||||
raise ArgumentError, 'No block given to save_value' unless block_given?
|
||||
raise ArgumentError, "No block given to save_value" unless block_given?
|
||||
@save_proc = block
|
||||
end
|
||||
|
||||
# If present, defines what the value is set to at the start of a new game.
|
||||
# @see SaveData.register
|
||||
def new_game_value(&block)
|
||||
raise ArgumentError, 'No block given to new_game_value' unless block_given?
|
||||
raise ArgumentError, "No block given to new_game_value" unless block_given?
|
||||
@new_game_value_proc = block
|
||||
end
|
||||
|
||||
@@ -137,14 +159,15 @@ module SaveData
|
||||
# save format. Requires a block with the old format array as its parameter.
|
||||
# @see SaveData.register
|
||||
def from_old_format(&block)
|
||||
raise ArgumentError, 'No block given to from_old_format' unless block_given?
|
||||
raise ArgumentError, "No block given to from_old_format" unless block_given?
|
||||
@old_format_get_proc = block
|
||||
end
|
||||
|
||||
# @!endgroup
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# Registers a {Value} to be saved into save data.
|
||||
# Takes a block which defines the value's saving ({Value#save_value})
|
||||
# and loading ({Value#load_value}) procedures.
|
||||
@@ -166,7 +189,6 @@ module SaveData
|
||||
# save_value { $foo }
|
||||
# load_value { |value| $foo = value }
|
||||
# new_game_value { Foo.new }
|
||||
# from_old_format { |old_format| old_format[16] if old_format[16].is_a?(Foo) }
|
||||
# end
|
||||
# @example Registering a value to be loaded on bootup
|
||||
# SaveData.register(:bar) do
|
||||
@@ -176,15 +198,20 @@ module SaveData
|
||||
# new_game_value { Bar.new }
|
||||
# end
|
||||
# @param id [Symbol] value id
|
||||
# @yieldself [Value]
|
||||
# @yield the block of code to be saved as a Value
|
||||
def self.register(id, &block)
|
||||
validate id => Symbol
|
||||
unless block_given?
|
||||
raise ArgumentError, 'No block given to SaveData.register'
|
||||
raise ArgumentError, "No block given to SaveData.register"
|
||||
end
|
||||
@values << Value.new(id, &block)
|
||||
end
|
||||
|
||||
def self.unregister(id)
|
||||
validate id => Symbol
|
||||
@values.delete_if { |value| value.id == id }
|
||||
end
|
||||
|
||||
# @param save_data [Hash] save data to validate
|
||||
# @return [Boolean] whether the given save data is valid
|
||||
def self.valid?(save_data)
|
||||
@@ -221,13 +248,20 @@ module SaveData
|
||||
load_values(save_data) { |value| !value.loaded? }
|
||||
end
|
||||
|
||||
# Marks all values that aren't loaded on bootup as unloaded.
|
||||
def self.mark_values_as_unloaded
|
||||
@values.each do |value|
|
||||
value.mark_as_unloaded if !value.load_in_bootup? || value.reset_on_new_game?
|
||||
end
|
||||
end
|
||||
|
||||
# Loads each value from the given save data that has
|
||||
# been set to be loaded during bootup. Done when a save file exists.
|
||||
# @param save_data [Hash] save data to load
|
||||
# @raise [InvalidValueError] if an invalid value is being loaded
|
||||
def self.load_bootup_values(save_data)
|
||||
def self.load_bootup_values(save_data, reload = false)
|
||||
validate save_data => Hash
|
||||
load_values(save_data) { |value| !value.loaded? && value.load_in_bootup? }
|
||||
load_values(save_data) { |value| (reload || !value.loaded?) && value.load_in_bootup? }
|
||||
end
|
||||
|
||||
# Goes through each value with {Value#load_in_bootup} enabled and loads their
|
||||
@@ -243,7 +277,7 @@ module SaveData
|
||||
# new game.
|
||||
def self.load_new_game_values
|
||||
@values.each do |value|
|
||||
value.load_new_game_value if value.has_new_game_proc? && !value.loaded?
|
||||
value.load_new_game_value if value.has_new_game_proc? && (!value.loaded? || value.reset_on_new_game?)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module SaveData
|
||||
# Contains Conversion objects for each defined conversion:
|
||||
# {
|
||||
@@ -15,12 +18,13 @@ module SaveData
|
||||
# Populated during runtime by SaveData.register_conversion calls.
|
||||
@conversions = {
|
||||
essentials: {},
|
||||
game: {}
|
||||
game: {}
|
||||
}
|
||||
|
||||
#=============================================================================
|
||||
# Represents a conversion made to save data.
|
||||
# New conversions are added using {SaveData.register_conversion}.
|
||||
#=============================================================================
|
||||
class Conversion
|
||||
# @return [Symbol] conversion ID
|
||||
attr_reader :id
|
||||
@@ -71,6 +75,8 @@ module SaveData
|
||||
@value_procs[key].call(object) if @value_procs[key].is_a?(Proc)
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
private
|
||||
|
||||
# @!group Configuration
|
||||
@@ -112,7 +118,7 @@ module SaveData
|
||||
# @see SaveData.register_conversion
|
||||
def to_value(value_id, &block)
|
||||
validate value_id => Symbol
|
||||
raise ArgumentError, 'No block given to to_value' unless block_given?
|
||||
raise ArgumentError, "No block given to to_value" unless block_given?
|
||||
if @value_procs[value_id].is_a?(Proc)
|
||||
raise "Multiple to_value definitions in conversion #{@id} for #{value_id}"
|
||||
end
|
||||
@@ -122,7 +128,7 @@ module SaveData
|
||||
# Defines a conversion to the entire save data.
|
||||
# @see SaveData.register_conversion
|
||||
def to_all(&block)
|
||||
raise ArgumentError, 'No block given to to_all' unless block_given?
|
||||
raise ArgumentError, "No block given to to_all" unless block_given?
|
||||
if @all_proc.is_a?(Proc)
|
||||
raise "Multiple to_all definitions in conversion #{@id}"
|
||||
end
|
||||
@@ -132,7 +138,8 @@ module SaveData
|
||||
# @!endgroup
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# Registers a {Conversion} to occur for save data that meets the given criteria.
|
||||
# Two types of criteria can be defined: {Conversion#essentials_version} and
|
||||
# {Conversion#game_version}. The conversion is automatically run on save data
|
||||
@@ -152,11 +159,11 @@ module SaveData
|
||||
# save_data[:new_value] = Foo.new
|
||||
# end
|
||||
# end
|
||||
# @yield self [Conversion]
|
||||
# @yield the block of code to be saved as a Conversion
|
||||
def self.register_conversion(id, &block)
|
||||
validate id => Symbol
|
||||
unless block_given?
|
||||
raise ArgumentError, 'No block given to SaveData.register_conversion'
|
||||
raise ArgumentError, "No block given to SaveData.register_conversion"
|
||||
end
|
||||
conversion = Conversion.new(id, &block)
|
||||
@conversions[conversion.trigger_type][conversion.version] ||= []
|
||||
@@ -168,8 +175,8 @@ module SaveData
|
||||
def self.get_conversions(save_data)
|
||||
conversions_to_run = []
|
||||
versions = {
|
||||
essentials: save_data[:essentials_version] || '18.1',
|
||||
game: save_data[:game_version] || '0.0.0'
|
||||
essentials: save_data[:essentials_version] || "18.1",
|
||||
game: save_data[:game_version] || "0.0.0"
|
||||
}
|
||||
[:essentials, :game].each do |trigger_type|
|
||||
# Ensure the versions are sorted from lowest to highest
|
||||
@@ -194,14 +201,15 @@ module SaveData
|
||||
validate save_data => Hash
|
||||
conversions_to_run = self.get_conversions(save_data)
|
||||
return false if conversions_to_run.none?
|
||||
File.open(SaveData::FILE_PATH + '.bak', 'wb') { |f| Marshal.dump(save_data, f) }
|
||||
echoln "Running #{conversions_to_run.length} conversions..."
|
||||
filepath = SaveData::DIRECTORY + SaveData.filename_from_index(save_data[:stats].save_filename_number || 0)
|
||||
File.open(filepath + ".bak", "wb") { |f| Marshal.dump(save_data, f) }
|
||||
Console.echo_h1(_INTL("Converting save file"))
|
||||
conversions_to_run.each do |conversion|
|
||||
echo "#{conversion.title}..."
|
||||
Console.echo_li("#{conversion.title}...")
|
||||
conversion.run(save_data)
|
||||
echoln ' done.'
|
||||
Console.echo_done(true)
|
||||
end
|
||||
echoln '' if conversions_to_run.length > 0
|
||||
Console.echoln_li_done(_INTL("Successfully applied {1} save file conversion(s)", conversions_to_run.length))
|
||||
save_data[:essentials_version] = Essentials::VERSION
|
||||
save_data[:game_version] = Settings::GAME_VERSION
|
||||
return true
|
||||
|
||||
@@ -1,41 +1,27 @@
|
||||
#===============================================================================
|
||||
# Contains the save values defined in Essentials by default.
|
||||
#===============================================================================
|
||||
|
||||
SaveData.register(:player) do
|
||||
ensure_class :Player
|
||||
save_value { $Trainer }
|
||||
load_value { |value| $Trainer = value }
|
||||
new_game_value {
|
||||
trainer_type = nil # Get the first defined trainer type as a placeholder
|
||||
GameData::TrainerType.each { |t| trainer_type = t.id; break }
|
||||
Player.new("Unnamed", trainer_type)
|
||||
}
|
||||
from_old_format { |old_format| old_format[0] }
|
||||
end
|
||||
|
||||
SaveData.register(:frame_count) do
|
||||
ensure_class :Integer
|
||||
save_value { Graphics.frame_count }
|
||||
load_value { |value| Graphics.frame_count = value }
|
||||
new_game_value { 0 }
|
||||
from_old_format { |old_format| old_format[1] }
|
||||
save_value { $player }
|
||||
load_value { |value| $player = value }
|
||||
new_game_value { Player.new("Unnamed", GameData::TrainerType.keys.first) }
|
||||
end
|
||||
|
||||
SaveData.register(:game_system) do
|
||||
load_in_bootup
|
||||
ensure_class :Game_System
|
||||
save_value { $game_system }
|
||||
load_value { |value| $game_system = value }
|
||||
new_game_value { Game_System.new }
|
||||
from_old_format { |old_format| old_format[2] }
|
||||
end
|
||||
|
||||
SaveData.register(:pokemon_system) do
|
||||
load_in_bootup
|
||||
load_in_bootup # Because this contains values for the Options screen
|
||||
ensure_class :PokemonSystem
|
||||
save_value { $PokemonSystem }
|
||||
load_value { |value| $PokemonSystem = value }
|
||||
new_game_value { PokemonSystem.new }
|
||||
from_old_format { |old_format| old_format[3] }
|
||||
end
|
||||
|
||||
SaveData.register(:switches) do
|
||||
@@ -43,7 +29,6 @@ SaveData.register(:switches) do
|
||||
save_value { $game_switches }
|
||||
load_value { |value| $game_switches = value }
|
||||
new_game_value { Game_Switches.new }
|
||||
from_old_format { |old_format| old_format[5] }
|
||||
end
|
||||
|
||||
SaveData.register(:variables) do
|
||||
@@ -51,7 +36,6 @@ SaveData.register(:variables) do
|
||||
save_value { $game_variables }
|
||||
load_value { |value| $game_variables = value }
|
||||
new_game_value { Game_Variables.new }
|
||||
from_old_format { |old_format| old_format[6] }
|
||||
end
|
||||
|
||||
SaveData.register(:self_switches) do
|
||||
@@ -59,7 +43,6 @@ SaveData.register(:self_switches) do
|
||||
save_value { $game_self_switches }
|
||||
load_value { |value| $game_self_switches = value }
|
||||
new_game_value { Game_SelfSwitches.new }
|
||||
from_old_format { |old_format| old_format[7] }
|
||||
end
|
||||
|
||||
SaveData.register(:game_screen) do
|
||||
@@ -67,14 +50,12 @@ SaveData.register(:game_screen) do
|
||||
save_value { $game_screen }
|
||||
load_value { |value| $game_screen = value }
|
||||
new_game_value { Game_Screen.new }
|
||||
from_old_format { |old_format| old_format[8] }
|
||||
end
|
||||
|
||||
SaveData.register(:map_factory) do
|
||||
ensure_class :PokemonMapFactory
|
||||
save_value { $MapFactory }
|
||||
load_value { |value| $MapFactory = value }
|
||||
from_old_format { |old_format| old_format[9] }
|
||||
save_value { $map_factory }
|
||||
load_value { |value| $map_factory = value }
|
||||
end
|
||||
|
||||
SaveData.register(:game_player) do
|
||||
@@ -82,7 +63,6 @@ SaveData.register(:game_player) do
|
||||
save_value { $game_player }
|
||||
load_value { |value| $game_player = value }
|
||||
new_game_value { Game_Player.new }
|
||||
from_old_format { |old_format| old_format[10] }
|
||||
end
|
||||
|
||||
SaveData.register(:global_metadata) do
|
||||
@@ -90,7 +70,6 @@ SaveData.register(:global_metadata) do
|
||||
save_value { $PokemonGlobal }
|
||||
load_value { |value| $PokemonGlobal = value }
|
||||
new_game_value { PokemonGlobalMetadata.new }
|
||||
from_old_format { |old_format| old_format[11] }
|
||||
end
|
||||
|
||||
SaveData.register(:map_metadata) do
|
||||
@@ -98,15 +77,13 @@ SaveData.register(:map_metadata) do
|
||||
save_value { $PokemonMap }
|
||||
load_value { |value| $PokemonMap = value }
|
||||
new_game_value { PokemonMapMetadata.new }
|
||||
from_old_format { |old_format| old_format[12] }
|
||||
end
|
||||
|
||||
SaveData.register(:bag) do
|
||||
ensure_class :PokemonBag
|
||||
save_value { $PokemonBag }
|
||||
load_value { |value| $PokemonBag = value }
|
||||
save_value { $bag }
|
||||
load_value { |value| $bag = value }
|
||||
new_game_value { PokemonBag.new }
|
||||
from_old_format { |old_format| old_format[13] }
|
||||
end
|
||||
|
||||
SaveData.register(:storage_system) do
|
||||
@@ -114,22 +91,25 @@ SaveData.register(:storage_system) do
|
||||
save_value { $PokemonStorage }
|
||||
load_value { |value| $PokemonStorage = value }
|
||||
new_game_value { PokemonStorage.new }
|
||||
from_old_format { |old_format| old_format[14] }
|
||||
end
|
||||
|
||||
SaveData.register(:essentials_version) do
|
||||
load_in_bootup
|
||||
ensure_class :String
|
||||
save_value { Essentials::VERSION }
|
||||
load_value { |value| $SaveVersion = value }
|
||||
load_value { |value| $save_engine_version = value }
|
||||
new_game_value { Essentials::VERSION }
|
||||
from_old_format { |old_format| old_format[15] }
|
||||
end
|
||||
|
||||
SaveData.register(:game_version) do
|
||||
load_in_bootup
|
||||
ensure_class :String
|
||||
save_value { Settings::GAME_VERSION }
|
||||
load_value { |value| $game_version = value }
|
||||
load_value { |value| $save_game_version = value }
|
||||
new_game_value { Settings::GAME_VERSION }
|
||||
end
|
||||
|
||||
SaveData.register(:stats) do
|
||||
ensure_class :GameStats
|
||||
save_value { $stats }
|
||||
load_value { |value| $stats = value }
|
||||
new_game_value { GameStats.new }
|
||||
end
|
||||
|
||||
@@ -1,242 +1,134 @@
|
||||
# Contains conversions defined in Essentials by default.
|
||||
#===============================================================================
|
||||
# Conversions required to support backwards compatibility with old save files
|
||||
# (within reason).
|
||||
#===============================================================================
|
||||
|
||||
SaveData.register_conversion(:v19_define_versions) do
|
||||
essentials_version 19
|
||||
display_title 'Adding game version and Essentials version to save data'
|
||||
to_all do |save_data|
|
||||
unless save_data.has_key?(:essentials_version)
|
||||
save_data[:essentials_version] = Essentials::VERSION
|
||||
end
|
||||
unless save_data.has_key?(:game_version)
|
||||
save_data[:game_version] = Settings::GAME_VERSION
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SaveData.register_conversion(:v19_convert_PokemonSystem) do
|
||||
essentials_version 19
|
||||
display_title 'Updating PokemonSystem class'
|
||||
to_all do |save_data|
|
||||
new_system = PokemonSystem.new
|
||||
new_system.textspeed = save_data[:pokemon_system].textspeed || new_system.textspeed
|
||||
new_system.battlescene = save_data[:pokemon_system].battlescene || new_system.battlescene
|
||||
new_system.battlestyle = save_data[:pokemon_system].battlestyle || new_system.battlestyle
|
||||
new_system.frame = save_data[:pokemon_system].frame || new_system.frame
|
||||
new_system.textskin = save_data[:pokemon_system].textskin || new_system.textskin
|
||||
new_system.screensize = save_data[:pokemon_system].screensize || new_system.screensize
|
||||
new_system.language = save_data[:pokemon_system].language || new_system.language
|
||||
new_system.runstyle = save_data[:pokemon_system].runstyle || new_system.runstyle
|
||||
new_system.bgmvolume = save_data[:pokemon_system].bgmvolume || new_system.bgmvolume
|
||||
new_system.sevolume = save_data[:pokemon_system].sevolume || new_system.sevolume
|
||||
new_system.textinput = save_data[:pokemon_system].textinput || new_system.textinput
|
||||
save_data[:pokemon_system] = new_system
|
||||
end
|
||||
end
|
||||
|
||||
SaveData.register_conversion(:v19_convert_player) do
|
||||
essentials_version 19
|
||||
display_title 'Converting player trainer class'
|
||||
to_all do |save_data|
|
||||
next if save_data[:player].is_a?(Player)
|
||||
# Conversion of the party is handled in PokeBattle_Trainer.convert
|
||||
save_data[:player] = PokeBattle_Trainer.convert(save_data[:player])
|
||||
end
|
||||
end
|
||||
|
||||
SaveData.register_conversion(:v19_move_global_data_to_player) do
|
||||
essentials_version 19
|
||||
display_title 'Moving some global metadata data to player'
|
||||
to_all do |save_data|
|
||||
global = save_data[:global_metadata]
|
||||
player = save_data[:player]
|
||||
player.character_ID = global.playerID
|
||||
global.playerID = nil
|
||||
global.pokedexUnlocked.each_with_index do |value, i|
|
||||
if value
|
||||
player.pokedex.unlock(i)
|
||||
else
|
||||
player.pokedex.lock(i)
|
||||
SaveData.register_conversion(:v21_replace_phone_data) do
|
||||
essentials_version 21
|
||||
display_title "Updating Phone data format"
|
||||
to_value :global_metadata do |global|
|
||||
if !global.phone
|
||||
global.instance_eval do
|
||||
@phone = Phone.new
|
||||
@phoneTime = nil # Don't bother using this
|
||||
if @phoneNumbers
|
||||
@phoneNumbers.each do |contact|
|
||||
if contact.length > 4
|
||||
# Trainer
|
||||
@phone.add(contact[6], contact[7], contact[1], contact[2], contact[5], 0)
|
||||
new_contact = @phone.get(contact[1], contact[2], 0)
|
||||
new_contact.visible = contact[0]
|
||||
new_contact.rematch_flag = [contact[4] - 1, 0].max
|
||||
else
|
||||
# Non-trainer
|
||||
@phone.add(contact[3], contact[2], contact[1])
|
||||
end
|
||||
end
|
||||
@phoneNumbers = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
player.coins = global.coins
|
||||
global.coins = nil
|
||||
player.soot = global.sootsack
|
||||
global.sootsack = nil
|
||||
player.has_running_shoes = global.runningShoes
|
||||
global.runningShoes = nil
|
||||
player.seen_storage_creator = global.seenStorageCreator
|
||||
global.seenStorageCreator = nil
|
||||
player.has_snag_machine = global.snagMachine
|
||||
global.snagMachine = nil
|
||||
player.seen_purify_chamber = global.seenPurifyChamber
|
||||
global.seenPurifyChamber = nil
|
||||
end
|
||||
end
|
||||
|
||||
SaveData.register_conversion(:v19_convert_global_metadata) do
|
||||
essentials_version 19
|
||||
display_title 'Adding encounter version variable to global metadata'
|
||||
to_value :global_metadata do |global|
|
||||
global.bridge ||= 0
|
||||
global.encounter_version ||= 0
|
||||
if global.pcItemStorage
|
||||
global.pcItemStorage.items.each_with_index do |slot, i|
|
||||
item_data = GameData::Item.try_get(slot[0])
|
||||
if item_data
|
||||
slot[0] = item_data.id
|
||||
#===============================================================================
|
||||
|
||||
SaveData.register_conversion(:v21_replace_flute_booleans) do
|
||||
essentials_version 21
|
||||
display_title "Updating Black/White Flute variables"
|
||||
to_value :map_metadata do |metadata|
|
||||
metadata.instance_eval do
|
||||
if !@blackFluteUsed.nil?
|
||||
if Settings::FLUTES_CHANGE_WILD_ENCOUNTER_LEVELS
|
||||
@higher_level_wild_pokemon = @blackFluteUsed
|
||||
else
|
||||
global.pcItemStorage.items[i] = nil
|
||||
@lower_encounter_rate = @blackFluteUsed
|
||||
end
|
||||
@blackFluteUsed = nil
|
||||
end
|
||||
global.pcItemStorage.items.compact!
|
||||
end
|
||||
if global.mailbox
|
||||
global.mailbox.each_with_index do |mail, i|
|
||||
global.mailbox[i] = PokemonMail.convert(mail) if mail
|
||||
end
|
||||
end
|
||||
global.phoneNumbers.each do |contact|
|
||||
contact[1] = GameData::TrainerType.get(contact[1]).id if contact && contact.length == 8
|
||||
end
|
||||
if global.partner
|
||||
global.partner[0] = GameData::TrainerType.get(global.partner[0]).id
|
||||
global.partner[3].each_with_index do |pkmn, i|
|
||||
global.partner[3][i] = PokeBattle_Pokemon.convert(pkmn) if pkmn
|
||||
end
|
||||
end
|
||||
if global.daycare
|
||||
global.daycare.each do |slot|
|
||||
slot[0] = PokeBattle_Pokemon.convert(slot[0]) if slot && slot[0]
|
||||
end
|
||||
end
|
||||
if global.roamPokemon
|
||||
global.roamPokemon.each_with_index do |pkmn, i|
|
||||
global.roamPokemon[i] = PokeBattle_Pokemon.convert(pkmn) if pkmn && pkmn != true
|
||||
end
|
||||
end
|
||||
global.purifyChamber.sets.each do |set|
|
||||
set.shadow = PokeBattle_Pokemon.convert(set.shadow) if set.shadow
|
||||
set.list.each_with_index do |pkmn, i|
|
||||
set.list[i] = PokeBattle_Pokemon.convert(pkmn) if pkmn
|
||||
end
|
||||
end
|
||||
if global.hallOfFame
|
||||
global.hallOfFame.each do |team|
|
||||
next if !team
|
||||
team.each_with_index do |pkmn, i|
|
||||
team[i] = PokeBattle_Pokemon.convert(pkmn) if pkmn
|
||||
if !@whiteFluteUsed.nil?
|
||||
if Settings::FLUTES_CHANGE_WILD_ENCOUNTER_LEVELS
|
||||
@lower_level_wild_pokemon = @whiteFluteUsed
|
||||
else
|
||||
@higher_encounter_rate = @whiteFluteUsed
|
||||
end
|
||||
end
|
||||
end
|
||||
if global.triads
|
||||
global.triads.items.each do |card|
|
||||
card[0] = GameData::Species.get(card[0]).id if card && card[0] && card[0] != 0
|
||||
@whiteFluteUsed = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SaveData.register_conversion(:v19_1_fix_phone_contacts) do
|
||||
essentials_version 19.1
|
||||
display_title 'Fixing phone contacts data'
|
||||
to_value :global_metadata do |global|
|
||||
global.phoneNumbers.each do |contact|
|
||||
contact[1] = GameData::TrainerType.get(contact[1]).id if contact && contact.length == 8
|
||||
#===============================================================================
|
||||
|
||||
SaveData.register_conversion(:v21_add_bump_stat) do
|
||||
essentials_version 21
|
||||
display_title "Adding a bump stat"
|
||||
to_value :stats do |stats|
|
||||
stats.instance_eval do
|
||||
@bump_count = 0 if !@bump_count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SaveData.register_conversion(:v19_convert_bag) do
|
||||
essentials_version 19
|
||||
display_title 'Converting item IDs in Bag'
|
||||
#===============================================================================
|
||||
|
||||
SaveData.register_conversion(:v22_add_adventure_magic_number) do
|
||||
essentials_version 22
|
||||
display_title "Adding adventure ID"
|
||||
to_value :game_system do |game_system|
|
||||
game_system.instance_eval do
|
||||
@adventure_magic_number ||= rand(2**32)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
|
||||
SaveData.register_conversion(:v22_add_new_stats) do
|
||||
essentials_version 22
|
||||
display_title "Adding some more stats"
|
||||
to_value :stats do |stats|
|
||||
stats.instance_eval do
|
||||
@wild_battles_fled = 0 if !@wild_battles_fled
|
||||
@pokemon_release_count = 0 if !@pokemon_release_count
|
||||
@primal_reversion_count = 0 if !@primal_reversion_count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
|
||||
SaveData.register_conversion(:v22_convert_bag_object) do
|
||||
essentials_version 22
|
||||
display_title "Converting Bag's pockets"
|
||||
to_value :bag do |bag|
|
||||
bag.instance_eval do
|
||||
for pocket in self.pockets
|
||||
pocket.each_with_index do |item, i|
|
||||
next if !item || !item[0] || item[0] == 0
|
||||
item_data = GameData::Item.try_get(item[0])
|
||||
if item_data
|
||||
item[0] = item_data.id
|
||||
else
|
||||
pocket[i] = nil
|
||||
all_pockets = GameData::BagPocket.all_pockets
|
||||
if @pockets.is_a?(Array)
|
||||
new_pockets = {}
|
||||
all_pockets.each { |pckt| new_pockets[pckt] = [] }
|
||||
@pockets.each_with_index do |value, i|
|
||||
next if i == 0
|
||||
value.each do |item|
|
||||
pckt = GameData::Item.get(item[0]).bag_pocket
|
||||
new_pockets[pckt].push(item)
|
||||
end
|
||||
end
|
||||
pocket.compact!
|
||||
@pockets = new_pockets
|
||||
end
|
||||
self.registeredIndex # Just to ensure this data exists
|
||||
self.registeredItems.each_with_index do |item, i|
|
||||
next if !item
|
||||
if item == 0
|
||||
self.registeredItems[i] = nil
|
||||
else
|
||||
item_data = GameData::Item.try_get(item)
|
||||
if item_data
|
||||
self.registeredItems[i] = item_data.id
|
||||
else
|
||||
self.registeredItems[i] = nil
|
||||
end
|
||||
end
|
||||
if @last_viewed_pocket.is_a?(Integer)
|
||||
@last_viewed_pocket = all_pockets[@last_viewed_pocket - 1] || all_pockets.first
|
||||
end
|
||||
self.registeredItems.compact!
|
||||
end # bag.instance_eval
|
||||
end # to_value
|
||||
end
|
||||
|
||||
SaveData.register_conversion(:v19_convert_game_variables) do
|
||||
essentials_version 19
|
||||
display_title 'Converting classes of things in Game Variables'
|
||||
to_all do |save_data|
|
||||
variables = save_data[:variables]
|
||||
for i in 0..5000
|
||||
value = variables[i]
|
||||
next if value.nil?
|
||||
if value.is_a?(Array)
|
||||
value.each_with_index do |value2, j|
|
||||
if value2.is_a?(PokeBattle_Pokemon)
|
||||
value[j] = PokeBattle_Pokemon.convert(value2)
|
||||
end
|
||||
if @last_pocket_selections.is_a?(Array)
|
||||
new_sels = {}
|
||||
all_pockets.each { |pckt| new_sels[pckt] = 0 }
|
||||
@last_pocket_selections.each_with_index do |value, i|
|
||||
next if i == 0
|
||||
pckt = all_pockets[i - 1]
|
||||
new_sels[pckt] = value if pckt && value <= @pockets[pckt].length - 1
|
||||
end
|
||||
elsif value.is_a?(PokeBattle_Pokemon)
|
||||
variables[i] = PokeBattle_Pokemon.convert(value)
|
||||
elsif value.is_a?(PokemonBag)
|
||||
SaveData.run_single_conversions(value, :bag, save_data)
|
||||
@last_pocket_selections = new_sels
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SaveData.register_conversion(:v19_convert_storage) do
|
||||
essentials_version 19
|
||||
display_title 'Converting classes of Pokémon in storage'
|
||||
to_value :storage_system do |storage|
|
||||
storage.instance_eval do
|
||||
for box in 0...self.maxBoxes
|
||||
for i in 0...self.maxPokemon(box)
|
||||
self[box, i] = PokeBattle_Pokemon.convert(self[box, i]) if self[box, i]
|
||||
end
|
||||
end
|
||||
self.unlockedWallpapers # Just to ensure this data exists
|
||||
end # storage.instance_eval
|
||||
end # to_value
|
||||
end
|
||||
|
||||
SaveData.register_conversion(:v19_convert_game_player) do
|
||||
essentials_version 19
|
||||
display_title 'Converting game player character'
|
||||
to_value :game_player do |game_player|
|
||||
game_player.width = 1
|
||||
game_player.height = 1
|
||||
game_player.sprite_size = [Game_Map::TILE_WIDTH, Game_Map::TILE_HEIGHT]
|
||||
game_player.pattern_surf ||= 0
|
||||
game_player.lock_pattern ||= false
|
||||
game_player.move_speed = game_player.move_speed
|
||||
end
|
||||
end
|
||||
|
||||
SaveData.register_conversion(:v19_convert_game_screen) do
|
||||
essentials_version 19
|
||||
display_title 'Converting game screen'
|
||||
to_value :game_screen do |game_screen|
|
||||
game_screen.weather(game_screen.weather_type, game_screen.weather_max, 0)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,52 +1,53 @@
|
||||
#===============================================================================
|
||||
# The Game module contains methods for saving and loading the game.
|
||||
#===============================================================================
|
||||
module Game
|
||||
module_function
|
||||
|
||||
# Initializes various global variables and loads the game data.
|
||||
def self.initialize
|
||||
$PokemonTemp = PokemonTemp.new
|
||||
def initialize
|
||||
$game_temp = Game_Temp.new
|
||||
$game_system = Game_System.new
|
||||
$data_animations = load_data('Data/Animations.rxdata')
|
||||
$data_tilesets = load_data('Data/Tilesets.rxdata')
|
||||
$data_common_events = load_data('Data/CommonEvents.rxdata')
|
||||
$data_system = load_data('Data/System.rxdata')
|
||||
$data_animations = load_data("Data/Animations.rxdata")
|
||||
$data_tilesets = load_data("Data/Tilesets.rxdata")
|
||||
$data_common_events = load_data("Data/CommonEvents.rxdata")
|
||||
$data_system = load_data("Data/System.rxdata")
|
||||
pbLoadBattleAnimations
|
||||
GameData.load_all
|
||||
map_file = format('Data/Map%03d.rxdata', $data_system.start_map_id)
|
||||
map_file = sprintf("Data/Map%03d.rxdata", $data_system.start_map_id)
|
||||
if $data_system.start_map_id == 0 || !pbRgssExists?(map_file)
|
||||
raise _INTL('No starting position was set in the map editor.')
|
||||
raise _INTL("No starting position was set in the map editor.")
|
||||
end
|
||||
end
|
||||
|
||||
# Loads bootup data from save file (if it exists) or creates bootup data (if
|
||||
# it doesn't).
|
||||
def self.set_up_system
|
||||
SaveData.move_old_windows_save if System.platform[/Windows/]
|
||||
save_data = (SaveData.exists?) ? SaveData.read_from_file(SaveData::FILE_PATH) : {}
|
||||
if save_data.empty?
|
||||
SaveData.initialize_bootup_values
|
||||
else
|
||||
SaveData.load_bootup_values(save_data)
|
||||
end
|
||||
# Set resize factor
|
||||
def set_up_system
|
||||
SaveData.initialize_bootup_values
|
||||
pbSetResizeFactor([$PokemonSystem.screensize, 4].min)
|
||||
# Set language (and choose language if there is no save file)
|
||||
if Settings::LANGUAGES.length >= 2
|
||||
$PokemonSystem.language = pbChooseLanguage if save_data.empty?
|
||||
pbLoadMessages('Data/' + Settings::LANGUAGES[$PokemonSystem.language][1])
|
||||
if !Settings::LANGUAGES.empty?
|
||||
$PokemonSystem.language = pbChooseLanguage if !SaveData.exists? && Settings::LANGUAGES.length >= 2
|
||||
MessageTypes.load_message_files(Settings::LANGUAGES[$PokemonSystem.language][1])
|
||||
end
|
||||
end
|
||||
|
||||
# Called when starting a new game. Initializes global variables
|
||||
# and transfers the player into the map scene.
|
||||
def self.start_new
|
||||
if $game_map && $game_map.events
|
||||
def start_new
|
||||
# Essentials 21 renamed the global variable $Trainer
|
||||
# It's still used everywhere in events, global events so this makes things simpler
|
||||
if $game_map&.events
|
||||
$game_map.events.each_value { |event| event.clear_starting }
|
||||
end
|
||||
$game_temp.common_event_id = 0 if $game_temp
|
||||
$PokemonTemp.begunNewGame = true
|
||||
pbMapInterpreter&.clear
|
||||
pbMapInterpreter&.setup(nil, 0, 0)
|
||||
$scene = Scene_Map.new
|
||||
SaveData.load_new_game_values
|
||||
$MapFactory = PokemonMapFactory.new($data_system.start_map_id)
|
||||
$game_temp.last_uptime_refreshed_play_time = System.uptime
|
||||
$stats.play_sessions += 1
|
||||
$map_factory = PokemonMapFactory.new($data_system.start_map_id)
|
||||
$game_player.moveto($data_system.start_x, $data_system.start_y)
|
||||
$game_player.refresh
|
||||
$PokemonEncounters = PokemonEncounters.new
|
||||
@@ -58,10 +59,17 @@ module Game
|
||||
# Loads the game from the given save data and starts the map scene.
|
||||
# @param save_data [Hash] hash containing the save data
|
||||
# @raise [SaveData::InvalidValueError] if an invalid value is being loaded
|
||||
def self.load(save_data)
|
||||
def load(save_data)
|
||||
# Essentials 21 renamed the global variable $Trainer
|
||||
# It's still used everywhere in events, global events so this makes things simpler
|
||||
$Trainer = $player
|
||||
|
||||
|
||||
validate save_data => Hash
|
||||
SaveData.load_all_values(save_data)
|
||||
self.load_map
|
||||
$game_temp.last_uptime_refreshed_play_time = System.uptime
|
||||
$stats.play_sessions += 1
|
||||
load_map
|
||||
pbAutoplayOnSave
|
||||
$game_map.update
|
||||
$PokemonMap.updateMap
|
||||
@@ -69,32 +77,30 @@ module Game
|
||||
end
|
||||
|
||||
# Loads and validates the map. Called when loading a saved game.
|
||||
def self.load_map
|
||||
$game_map = $MapFactory.map
|
||||
def load_map
|
||||
$game_map = $map_factory.map
|
||||
magic_number_matches = ($game_system.magic_number == $data_system.magic_number)
|
||||
if !magic_number_matches || $PokemonGlobal.safesave
|
||||
if pbMapInterpreterRunning?
|
||||
pbMapInterpreter.setup(nil, 0)
|
||||
end
|
||||
pbMapInterpreter.setup(nil, 0) if pbMapInterpreterRunning?
|
||||
begin
|
||||
$MapFactory.setup($game_map.map_id)
|
||||
$map_factory.setup($game_map.map_id)
|
||||
rescue Errno::ENOENT
|
||||
if $DEBUG
|
||||
pbMessage(_INTL('Map {1} was not found.', $game_map.map_id))
|
||||
pbMessage(_INTL("Map {1} was not found.", $game_map.map_id))
|
||||
map = pbWarpToMap
|
||||
exit unless map
|
||||
$MapFactory.setup(map[0])
|
||||
$map_factory.setup(map[0])
|
||||
$game_player.moveto(map[1], map[2])
|
||||
else
|
||||
raise _INTL('The map was not found. The game cannot continue.')
|
||||
raise _INTL("The map was not found. The game cannot continue.")
|
||||
end
|
||||
end
|
||||
$game_player.center($game_player.x, $game_player.y)
|
||||
else
|
||||
$MapFactory.setMapChanged($game_map.map_id)
|
||||
$map_factory.setMapChanged($game_map.map_id)
|
||||
end
|
||||
if $game_map.events.nil?
|
||||
raise _INTL('The map is corrupt. The game cannot continue.')
|
||||
raise _INTL("The map is corrupt. The game cannot continue.")
|
||||
end
|
||||
$PokemonEncounters = PokemonEncounters.new
|
||||
$PokemonEncounters.setup($game_map.map_id)
|
||||
@@ -102,17 +108,21 @@ module Game
|
||||
end
|
||||
|
||||
# Saves the game. Returns whether the operation was successful.
|
||||
# @param save_file [String] the save file path
|
||||
# @param index [Integer] the number to put in the save file's name Game#.rzdata
|
||||
# @param directory [String] the folder to put the save file in
|
||||
# @param safe [Boolean] whether $PokemonGlobal.safesave should be set to true
|
||||
# @return [Boolean] whether the operation was successful
|
||||
# @raise [SaveData::InvalidValueError] if an invalid value is being saved
|
||||
def self.save(save_file = SaveData::FILE_PATH, safe: false)
|
||||
validate save_file => String, safe => [TrueClass, FalseClass]
|
||||
def save(index, directory = SaveData::DIRECTORY, safe: false)
|
||||
validate index => Integer, directory => String, safe => [TrueClass, FalseClass]
|
||||
filename = SaveData.filename_from_index(index)
|
||||
$PokemonGlobal.safesave = safe
|
||||
$game_system.save_count += 1
|
||||
$game_system.magic_number = $data_system.magic_number
|
||||
$stats.set_time_last_saved
|
||||
$stats.save_filename_number = index
|
||||
begin
|
||||
SaveData.save_to_file(save_file)
|
||||
SaveData.save_to_file(directory + filename)
|
||||
Graphics.frame_reset
|
||||
rescue IOError, SystemCallError
|
||||
$game_system.save_count -= 1
|
||||
|
||||
@@ -1,45 +1,52 @@
|
||||
#===============================================================================
|
||||
# ** Modified Scene_Map class for Pokémon.
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Modified Scene_Map class for Pokémon.
|
||||
#===============================================================================
|
||||
class Scene_Map
|
||||
attr_reader :spritesetGlobal
|
||||
attr_reader :map_renderer
|
||||
|
||||
def spriteset
|
||||
for i in @spritesets.values
|
||||
return i if i.map==$game_map
|
||||
def spriteset(map_id = -1)
|
||||
return @spritesets[map_id] if map_id > 0 && @spritesets[map_id]
|
||||
@spritesets.each_value do |i|
|
||||
return i if i.map == $game_map
|
||||
end
|
||||
return @spritesets.values[0]
|
||||
end
|
||||
|
||||
def createSpritesets
|
||||
@spritesetGlobal = Spriteset_Global.new
|
||||
@map_renderer = TilemapRenderer.new(Spriteset_Map.viewport) if !@map_renderer || @map_renderer.disposed?
|
||||
@spritesetGlobal = Spriteset_Global.new if !@spritesetGlobal
|
||||
@spritesets = {}
|
||||
for map in $MapFactory.maps
|
||||
$map_factory.maps.each do |map|
|
||||
@spritesets[map.map_id] = Spriteset_Map.new(map)
|
||||
end
|
||||
$MapFactory.setSceneStarted(self)
|
||||
updateSpritesets
|
||||
$map_factory.setSceneStarted(self)
|
||||
updateSpritesets(true)
|
||||
end
|
||||
|
||||
def createSingleSpriteset(map)
|
||||
temp = $scene.spriteset.getAnimations
|
||||
@spritesets[map] = Spriteset_Map.new($MapFactory.maps[map])
|
||||
@spritesets[map] = Spriteset_Map.new($map_factory.maps[map])
|
||||
$scene.spriteset.restoreAnimations(temp)
|
||||
$MapFactory.setSceneStarted(self)
|
||||
updateSpritesets
|
||||
$map_factory.setSceneStarted(self)
|
||||
updateSpritesets(true)
|
||||
end
|
||||
|
||||
def disposeSpritesets
|
||||
return if !@spritesets
|
||||
for i in @spritesets.keys
|
||||
@spritesets.each_key do |i|
|
||||
next if !@spritesets[i]
|
||||
@spritesets[i].dispose
|
||||
@spritesets[i] = nil
|
||||
end
|
||||
@spritesets.clear
|
||||
@spritesets = {}
|
||||
end
|
||||
|
||||
def dispose
|
||||
disposeSpritesets
|
||||
@map_renderer.dispose
|
||||
@map_renderer = nil
|
||||
@spritesetGlobal.dispose
|
||||
@spritesetGlobal = nil
|
||||
end
|
||||
@@ -50,26 +57,24 @@ class Scene_Map
|
||||
return if !playingBGM && !playingBGS
|
||||
map = load_data(sprintf("Data/Map%03d.rxdata", mapid))
|
||||
if playingBGM && map.autoplay_bgm
|
||||
if (PBDayNight.isNight? rescue false)
|
||||
pbBGMFade(0.8) if playingBGM.name!=map.bgm.name && playingBGM.name!=map.bgm.name+"_n"
|
||||
else
|
||||
pbBGMFade(0.8) if playingBGM.name!=map.bgm.name
|
||||
end
|
||||
test_filename = map.bgm.name
|
||||
test_filename += "_n" if PBDayNight.isNight? && FileTest.audio_exist?("Audio/BGM/" + test_filename + "_n")
|
||||
pbBGMFade(0.8) if playingBGM.name != test_filename
|
||||
end
|
||||
if playingBGS && map.autoplay_bgs
|
||||
pbBGMFade(0.8) if playingBGS.name!=map.bgs.name
|
||||
if playingBGS && map.autoplay_bgs && playingBGS.name != map.bgs.name
|
||||
pbBGMFade(0.8)
|
||||
end
|
||||
Graphics.frame_reset
|
||||
end
|
||||
|
||||
def transfer_player(cancelVehicles=true)
|
||||
def transfer_player(cancel_swimming = true)
|
||||
$game_temp.player_transferring = false
|
||||
pbCancelVehicles($game_temp.player_new_map_id) if cancelVehicles
|
||||
pbCancelVehicles($game_temp.player_new_map_id, cancel_swimming)
|
||||
autofade($game_temp.player_new_map_id)
|
||||
pbBridgeOff
|
||||
@spritesetGlobal.playersprite.clearShadows
|
||||
if $game_map.map_id!=$game_temp.player_new_map_id
|
||||
$MapFactory.setup($game_temp.player_new_map_id)
|
||||
if $game_map.map_id != $game_temp.player_new_map_id
|
||||
$map_factory.setup($game_temp.player_new_map_id)
|
||||
end
|
||||
$game_player.moveto($game_temp.player_new_x, $game_temp.player_new_y)
|
||||
case $game_temp.player_new_direction
|
||||
@@ -79,13 +84,14 @@ class Scene_Map
|
||||
when 8 then $game_player.turn_up
|
||||
end
|
||||
$game_player.straighten
|
||||
$game_temp.followers.map_transfer_followers
|
||||
$game_map.update
|
||||
disposeSpritesets
|
||||
RPG::Cache.clear
|
||||
createSpritesets
|
||||
if $game_temp.transition_processing
|
||||
$game_temp.transition_processing = false
|
||||
Graphics.transition(20)
|
||||
Graphics.transition
|
||||
end
|
||||
$game_map.autoplay
|
||||
Graphics.frame_reset
|
||||
@@ -97,9 +103,7 @@ class Scene_Map
|
||||
$game_temp.in_menu = true
|
||||
$game_player.straighten
|
||||
$game_map.update
|
||||
sscene = PokemonPauseMenu_Scene.new
|
||||
sscreen = PokemonPauseMenu.new(sscene)
|
||||
sscreen.pbStartPokemonMenu
|
||||
UI::PauseMenu.new.main
|
||||
$game_temp.in_menu = false
|
||||
end
|
||||
|
||||
@@ -111,107 +115,119 @@ class Scene_Map
|
||||
end
|
||||
|
||||
def miniupdate
|
||||
$PokemonTemp.miniupdate = true
|
||||
$game_temp.in_mini_update = true
|
||||
loop do
|
||||
updateMaps
|
||||
$game_player.update
|
||||
updateMaps
|
||||
$game_system.update
|
||||
$game_screen.update
|
||||
break unless $game_temp.player_transferring
|
||||
transfer_player
|
||||
break if !$game_temp.player_transferring
|
||||
transfer_player(false)
|
||||
break if $game_temp.transition_processing
|
||||
end
|
||||
updateSpritesets
|
||||
$PokemonTemp.miniupdate = false
|
||||
$game_temp.in_mini_update = false
|
||||
end
|
||||
|
||||
def updateMaps
|
||||
for map in $MapFactory.maps
|
||||
$map_factory.maps.each do |map|
|
||||
map.update
|
||||
end
|
||||
$MapFactory.updateMaps(self)
|
||||
$map_factory.updateMaps(self)
|
||||
end
|
||||
|
||||
def updateSpritesets
|
||||
def updateSpritesets(refresh = false)
|
||||
@spritesets = {} if !@spritesets
|
||||
$map_factory.maps.each do |map|
|
||||
@spritesets[map.map_id] = Spriteset_Map.new(map) if !@spritesets[map.map_id]
|
||||
end
|
||||
keys = @spritesets.keys.clone
|
||||
for i in keys
|
||||
if !$MapFactory.hasMap?(i)
|
||||
@spritesets[i].dispose if @spritesets[i]
|
||||
keys.each do |i|
|
||||
if $map_factory.hasMap?(i)
|
||||
@spritesets[i].update
|
||||
else
|
||||
@spritesets[i]&.dispose
|
||||
@spritesets[i] = nil
|
||||
@spritesets.delete(i)
|
||||
else
|
||||
@spritesets[i].update
|
||||
end
|
||||
end
|
||||
@spritesetGlobal.update
|
||||
for map in $MapFactory.maps
|
||||
@spritesets[map.map_id] = Spriteset_Map.new(map) if !@spritesets[map.map_id]
|
||||
end
|
||||
Events.onMapUpdate.trigger(self)
|
||||
pbDayNightTint(@map_renderer)
|
||||
@map_renderer.refresh if refresh
|
||||
@map_renderer.update
|
||||
EventHandlers.trigger(:on_frame_update)
|
||||
end
|
||||
|
||||
def update
|
||||
loop do
|
||||
updateMaps
|
||||
pbMapInterpreter.update
|
||||
$game_player.update
|
||||
updateMaps
|
||||
$game_system.update
|
||||
$game_screen.update
|
||||
break unless $game_temp.player_transferring
|
||||
transfer_player
|
||||
break if !$game_temp.player_transferring
|
||||
transfer_player(false)
|
||||
break if $game_temp.transition_processing
|
||||
end
|
||||
updateSpritesets
|
||||
if $game_temp.to_title
|
||||
if $game_temp.title_screen_calling
|
||||
SaveData.mark_values_as_unloaded
|
||||
$scene = pbCallTitle
|
||||
return
|
||||
end
|
||||
if $game_temp.transition_processing
|
||||
$game_temp.transition_processing = false
|
||||
if $game_temp.transition_name == ""
|
||||
Graphics.transition(20)
|
||||
Graphics.transition
|
||||
else
|
||||
Graphics.transition(40, "Graphics/Transitions/" + $game_temp.transition_name)
|
||||
end
|
||||
end
|
||||
return if $game_temp.message_window_showing
|
||||
if !pbMapInterpreterRunning?
|
||||
if !pbMapInterpreterRunning? && !$PokemonGlobal.forced_movement?
|
||||
if Input.trigger?(Input::USE)
|
||||
$PokemonTemp.hiddenMoveEventCalling = true
|
||||
elsif Input.trigger?(Input::BACK)
|
||||
unless $game_system.menu_disabled || $game_player.moving?
|
||||
$game_temp.interact_calling = true
|
||||
elsif Input.trigger?(Input::ACTION)
|
||||
if !$game_system.menu_disabled && !$game_player.moving?
|
||||
$game_temp.menu_calling = true
|
||||
$game_temp.menu_beep = true
|
||||
end
|
||||
elsif Input.trigger?(Input::SPECIAL)
|
||||
unless $game_player.moving?
|
||||
$PokemonTemp.keyItemCalling = true
|
||||
end
|
||||
$game_temp.ready_menu_calling = true if !$game_player.moving?
|
||||
elsif Input.press?(Input::F9)
|
||||
$game_temp.debug_calling = true if $DEBUG
|
||||
end
|
||||
end
|
||||
unless $game_player.moving?
|
||||
if !$game_player.moving?
|
||||
if $game_temp.menu_calling
|
||||
call_menu
|
||||
elsif $game_temp.debug_calling
|
||||
call_debug
|
||||
elsif $PokemonTemp.keyItemCalling
|
||||
$PokemonTemp.keyItemCalling = false
|
||||
elsif $game_temp.ready_menu_calling
|
||||
$game_temp.ready_menu_calling = false
|
||||
$game_player.straighten
|
||||
pbUseKeyItem
|
||||
elsif $PokemonTemp.hiddenMoveEventCalling
|
||||
$PokemonTemp.hiddenMoveEventCalling = false
|
||||
$game_player.straighten
|
||||
Events.onAction.trigger(self)
|
||||
elsif $game_temp.interact_calling
|
||||
$game_temp.interact_calling = false
|
||||
triggered = false
|
||||
# Try to trigger an event the player is standing on, and one in front of
|
||||
# the player
|
||||
if !$game_temp.in_mini_update
|
||||
triggered ||= $game_player.check_event_trigger_here([0])
|
||||
triggered ||= $game_player.check_event_trigger_there([0, 2]) if !triggered
|
||||
end
|
||||
# Try to trigger an interaction with a tile
|
||||
if !triggered
|
||||
$game_player.straighten
|
||||
EventHandlers.trigger(:on_player_interact)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def main
|
||||
createSpritesets
|
||||
Graphics.transition(20)
|
||||
Graphics.transition
|
||||
loop do
|
||||
Graphics.update
|
||||
Input.update
|
||||
@@ -219,9 +235,13 @@ class Scene_Map
|
||||
break if $scene != self
|
||||
end
|
||||
Graphics.freeze
|
||||
disposeSpritesets
|
||||
if $game_temp.to_title
|
||||
Graphics.transition(20)
|
||||
dispose
|
||||
if $game_temp.title_screen_calling
|
||||
pbMapInterpreter.command_end if pbMapInterpreterRunning?
|
||||
$game_temp.last_uptime_refreshed_play_time = nil
|
||||
$game_temp.title_screen_calling = false
|
||||
pbBGMFade(1.0)
|
||||
Graphics.transition
|
||||
Graphics.freeze
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
# Game_System class and the Game_Event class.
|
||||
#===============================================================================
|
||||
class Interpreter
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Object Initialization
|
||||
# Object Initialization
|
||||
# depth : nest depth
|
||||
# main : main flag
|
||||
#-----------------------------------------------------------------------------
|
||||
def initialize(depth = 0, main = false)
|
||||
@depth = depth
|
||||
@main = main
|
||||
@@ -22,25 +20,28 @@ class Interpreter
|
||||
|
||||
def inspect
|
||||
str = super.chop
|
||||
str << format(' @event_id: %d>', @event_id)
|
||||
str << sprintf(" @event_id: %d>", @event_id)
|
||||
return str
|
||||
end
|
||||
|
||||
def clear
|
||||
@map_id = 0 # map ID when starting up
|
||||
@event_id = 0 # event ID
|
||||
@event_id = 0
|
||||
@message_waiting = false # waiting for message to end
|
||||
@move_route_waiting = false # waiting for move completion
|
||||
@wait_count = 0 # wait count
|
||||
@child_interpreter = nil # child interpreter
|
||||
@branch = {} # branch data
|
||||
@wait_count = 0
|
||||
@wait_start = nil
|
||||
@child_interpreter = nil
|
||||
@branch = {}
|
||||
@buttonInput = false
|
||||
@hidden_choices = []
|
||||
@renamed_choices = []
|
||||
end_follower_overrides
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Event Setup
|
||||
|
||||
# Event Setup
|
||||
# list : list of event commands
|
||||
# event_id : event ID
|
||||
#-----------------------------------------------------------------------------
|
||||
def setup(list, event_id, map_id = nil)
|
||||
clear
|
||||
@map_id = map_id || $game_map.map_id
|
||||
@@ -59,7 +60,7 @@ class Interpreter
|
||||
return
|
||||
end
|
||||
# Check all map events for one that wants to start, and set it up
|
||||
for event in $game_map.events.values
|
||||
$game_map.events.each_value do |event|
|
||||
next if !event.starting
|
||||
if event.trigger < 3 # Isn't autorun or parallel processing
|
||||
event.lock
|
||||
@@ -69,7 +70,7 @@ class Interpreter
|
||||
return
|
||||
end
|
||||
# Check all common events for one that is autorun, and set it up
|
||||
for common_event in $data_common_events.compact
|
||||
$data_common_events.compact.each do |common_event|
|
||||
next if common_event.trigger != 1 || !$game_switches[common_event.switch_id]
|
||||
setup(common_event.list, 0)
|
||||
return
|
||||
@@ -77,11 +78,9 @@ class Interpreter
|
||||
end
|
||||
|
||||
def running?
|
||||
return @list != nil
|
||||
return !@list.nil?
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Frame Update
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def update
|
||||
@loop_count = 0
|
||||
loop do
|
||||
@@ -92,7 +91,7 @@ class Interpreter
|
||||
end
|
||||
# If this interpreter's map isn't the current map or connected to it,
|
||||
# forget this interpreter's event ID
|
||||
if $game_map.map_id != @map_id && !$MapFactory.areConnected?($game_map.map_id, @map_id)
|
||||
if $game_map.map_id != @map_id && !$map_factory.areConnected?($game_map.map_id, @map_id)
|
||||
@event_id = 0
|
||||
end
|
||||
# Update child interpreter if one exists
|
||||
@@ -106,15 +105,21 @@ class Interpreter
|
||||
# Do nothing if any event or the player is in the middle of a move route
|
||||
if @move_route_waiting
|
||||
return if $game_player.move_route_forcing
|
||||
for event in $game_map.events.values
|
||||
$game_map.events.each_value do |event|
|
||||
return if event.move_route_forcing
|
||||
end
|
||||
$game_temp.followers.each_follower do |event, follower|
|
||||
return if event.move_route_forcing
|
||||
end
|
||||
@move_route_waiting = false
|
||||
end
|
||||
# Do nothing if the player is jumping out of surfing
|
||||
return if $game_temp.ending_surf
|
||||
# Do nothing while waiting
|
||||
if @wait_count > 0
|
||||
@wait_count -= 1
|
||||
return
|
||||
return if System.uptime - @wait_start < @wait_count
|
||||
@wait_count = 0
|
||||
@wait_start = nil
|
||||
end
|
||||
# Do nothing if the pause menu is going to open
|
||||
return if $game_temp.menu_calling
|
||||
@@ -129,70 +134,52 @@ class Interpreter
|
||||
@index += 1
|
||||
end
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Execute script
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def execute_script(script)
|
||||
begin
|
||||
result = eval(script)
|
||||
return result
|
||||
rescue Exception
|
||||
e = $!
|
||||
raise if e.is_a?(SystemExit) || "#{e.class}" == "Reset"
|
||||
raise if e.is_a?(SystemExit) || e.class.to_s == "Reset"
|
||||
event = get_self
|
||||
s = "Backtrace:\r\n"
|
||||
# Gather text for error message
|
||||
message = pbGetExceptionMessage(e)
|
||||
backtrace_text = ""
|
||||
if e.is_a?(SyntaxError)
|
||||
script.each_line { |line|
|
||||
script.each_line do |line|
|
||||
line.gsub!(/\s+$/, "")
|
||||
if line[/^\s*\(/]
|
||||
message += "\r\n***Line '#{line}' shouldn't begin with '('. Try\r\n"
|
||||
message += "putting the '(' at the end of the previous line instead,\r\n"
|
||||
message += "or using 'extendtext.exe'."
|
||||
message += "\r\n***Line '#{line}' shouldn't begin with '('. Try putting the '('\r\n"
|
||||
message += "at the end of the previous line instead, or using 'extendtext.exe'."
|
||||
end
|
||||
if line[/\:\:\s*$/]
|
||||
message += "\r\n***Line '#{line}' can't end with '::'. Try putting\r\n"
|
||||
message += "the next word on the same line, e.g. 'PBSpecies:" + ":MEW'"
|
||||
end
|
||||
}
|
||||
else
|
||||
for bt in e.backtrace[0, 10]
|
||||
s += bt + "\r\n"
|
||||
end
|
||||
s.gsub!(/Section(\d+)/) { $RGSS_SCRIPTS[$1.to_i][1] }
|
||||
end
|
||||
message = "Exception: #{e.class}\r\nMessage: " + message + "\r\n"
|
||||
message += "\r\n***Full script:\r\n#{script}\r\n"
|
||||
if event && $game_map
|
||||
map_name = ($game_map.name rescue nil) || "???"
|
||||
err = "Script error in event #{event.id} (coords #{event.x},#{event.y}), map #{$game_map.map_id} (#{map_name}):\r\n"
|
||||
err += "#{message}\r\n#{s}"
|
||||
if e.is_a?(Hangup)
|
||||
$EVENTHANGUPMSG = err
|
||||
raise
|
||||
end
|
||||
elsif $game_map
|
||||
map_name = ($game_map.name rescue nil) || "???"
|
||||
err = "Script error in map #{$game_map.map_id} (#{map_name}):\r\n"
|
||||
err += "#{message}\r\n#{s}"
|
||||
if e.is_a?(Hangup)
|
||||
$EVENTHANGUPMSG = err
|
||||
raise
|
||||
end
|
||||
else
|
||||
err = "Script error in interpreter:\r\n#{message}\r\n#{s}"
|
||||
if e.is_a?(Hangup)
|
||||
$EVENTHANGUPMSG = err
|
||||
raise
|
||||
backtrace_text += "\r\n"
|
||||
backtrace_text += "Backtrace:"
|
||||
e.backtrace[0, 10].each { |i| backtrace_text += "\r\n#{i}" }
|
||||
backtrace_text.gsub!(/Section(\d+)/) { $RGSS_SCRIPTS[$1.to_i][1] } rescue nil
|
||||
backtrace_text += "\r\n"
|
||||
end
|
||||
# Assemble error message
|
||||
err = "Script error in Interpreter\r\n"
|
||||
if $game_map
|
||||
map_name = (pbGetBasicMapNameFromId($game_map.map_id) rescue nil) || "???"
|
||||
if event
|
||||
err = "Script error in event #{event.id} (coords #{event.x},#{event.y}), map #{$game_map.map_id} (#{map_name})\r\n"
|
||||
else
|
||||
err = "Script error in Common Event, map #{$game_map.map_id} (#{map_name})\r\n"
|
||||
end
|
||||
end
|
||||
raise err
|
||||
err += "Exception: #{e.class}\r\n"
|
||||
err += "Message: #{message}\r\n\r\n"
|
||||
err += "***Full script:\r\n#{script}" # \r\n"
|
||||
err += backtrace_text
|
||||
# Raise error
|
||||
raise EventScriptError.new(err)
|
||||
end
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Get Character
|
||||
# parameter : parameter
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def get_character(parameter = 0)
|
||||
case parameter
|
||||
when -1 # player
|
||||
@@ -217,21 +204,18 @@ class Interpreter
|
||||
def get_event(parameter)
|
||||
return get_character(parameter)
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Freezes all events on the map (for use at the beginning of common events)
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Freezes all events on the map (for use at the beginning of common events)
|
||||
def pbGlobalLock
|
||||
$game_map.events.values.each { |event| event.minilock }
|
||||
$game_map.events.each_value { |event| event.minilock }
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Unfreezes all events on the map (for use at the end of common events)
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Unfreezes all events on the map (for use at the end of common events)
|
||||
def pbGlobalUnlock
|
||||
$game_map.events.values.each { |event| event.unlock }
|
||||
$game_map.events.each_value { |event| event.unlock }
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Gets the next index in the interpreter, ignoring certain commands between messages
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Gets the next index in the interpreter, ignoring certain commands between messages
|
||||
def pbNextIndex(index)
|
||||
return -1 if !@list || @list.length == 0
|
||||
i = index + 1
|
||||
@@ -281,12 +265,27 @@ class Interpreter
|
||||
temp_index += 1
|
||||
end
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Various methods to be used in a script event command.
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def follower_move_route(id = nil)
|
||||
@follower_move_route = true
|
||||
@follower_move_route_id = id
|
||||
end
|
||||
|
||||
def follower_animation(id = nil)
|
||||
@follower_animation = true
|
||||
@follower_animation_id = id
|
||||
end
|
||||
|
||||
def end_follower_overrides
|
||||
@follower_move_route = false
|
||||
@follower_move_route_id = nil
|
||||
@follower_animation = false
|
||||
@follower_animation_id = nil
|
||||
end
|
||||
|
||||
# Helper function that shows a picture in a script.
|
||||
def pbShowPicture(number, name, origin, x, y, zoomX = 100, zoomY = 100, opacity = 255, blendType = 0)
|
||||
number = number + ($game_temp.in_battle ? 50 : 0)
|
||||
number += ($game_temp.in_battle ? 50 : 0)
|
||||
$game_screen.pictures[number].show(name, origin, x, y, zoomX, zoomY, opacity, blendType)
|
||||
end
|
||||
|
||||
@@ -295,7 +294,7 @@ class Interpreter
|
||||
def pbEraseThisEvent
|
||||
if $game_map.events[@event_id]
|
||||
$game_map.events[@event_id].erase
|
||||
$PokemonMap.addErasedEvent(@event_id) if $PokemonMap
|
||||
$PokemonMap&.addErasedEvent(@event_id)
|
||||
end
|
||||
@index += 1
|
||||
return true
|
||||
@@ -325,8 +324,8 @@ class Interpreter
|
||||
mapid = @map_id if mapid < 0
|
||||
old_value = $game_self_switches[[mapid, eventid, switch_name]]
|
||||
$game_self_switches[[mapid, eventid, switch_name]] = value
|
||||
if value != old_value && $MapFactory.hasMap?(mapid)
|
||||
$MapFactory.getMap(mapid, false).need_refresh = true
|
||||
if value != old_value && $map_factory.hasMap?(mapid)
|
||||
$map_factory.getMap(mapid, false).need_refresh = true
|
||||
end
|
||||
end
|
||||
|
||||
@@ -368,7 +367,7 @@ class Interpreter
|
||||
end
|
||||
|
||||
def pbGetPokemon(id)
|
||||
return $Trainer.party[pbGet(id)]
|
||||
return $player.party[pbGet(id)]
|
||||
end
|
||||
|
||||
def pbSetEventTime(*arg)
|
||||
@@ -377,28 +376,30 @@ class Interpreter
|
||||
time = time.to_i
|
||||
pbSetSelfSwitch(@event_id, "A", true)
|
||||
$PokemonGlobal.eventvars[[@map_id, @event_id]] = time
|
||||
for otherevt in arg
|
||||
arg.each do |otherevt|
|
||||
pbSetSelfSwitch(otherevt, "A", true)
|
||||
$PokemonGlobal.eventvars[[@map_id, otherevt]] = time
|
||||
end
|
||||
end
|
||||
|
||||
# Used in boulder events. Allows an event to be pushed.
|
||||
def pbPushThisEvent
|
||||
def pbPushThisEvent(strength = false)
|
||||
event = get_self
|
||||
old_x = event.x
|
||||
old_y = event.y
|
||||
# Apply strict version of passable, which treats tiles that are passable
|
||||
# only from certain directions as fully impassible
|
||||
return if !event.can_move_in_direction?($game_player.direction, true)
|
||||
$stats.strength_push_count += 1
|
||||
case $game_player.direction
|
||||
when 2 then event.move_down
|
||||
when 4 then event.move_left
|
||||
when 6 then event.move_right
|
||||
when 8 then event.move_up
|
||||
end
|
||||
$PokemonMap.addMovedEvent(@event_id) if $PokemonMap
|
||||
$PokemonMap&.addMovedEvent(@event_id)
|
||||
if old_x != event.x || old_y != event.y
|
||||
pbSEPlay("Strength push") if strength
|
||||
$game_player.lock
|
||||
loop do
|
||||
Graphics.update
|
||||
@@ -411,7 +412,7 @@ class Interpreter
|
||||
end
|
||||
|
||||
def pbPushThisBoulder
|
||||
pbPushThisEvent if $PokemonMap.strengthUsed
|
||||
pbPushThisEvent(true) if $PokemonMap.strengthUsed
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -426,14 +427,14 @@ class Interpreter
|
||||
return true if $DEBUG && !GameData::TrainerType.exists?(symbol)
|
||||
tr_type = GameData::TrainerType.get(symbol).id
|
||||
pbGlobalLock
|
||||
pbPlayTrainerIntroME(tr_type)
|
||||
pbPlayTrainerIntroBGM(tr_type)
|
||||
return true
|
||||
end
|
||||
|
||||
def pbTrainerEnd
|
||||
pbGlobalUnlock
|
||||
event = get_self
|
||||
event.erase_route if event
|
||||
event&.erase_route
|
||||
end
|
||||
|
||||
def setPrice(item, buy_price = -1, sell_price = -1)
|
||||
@@ -441,9 +442,9 @@ class Interpreter
|
||||
$game_temp.mart_prices[item] = [-1, -1] if !$game_temp.mart_prices[item]
|
||||
$game_temp.mart_prices[item][0] = buy_price if buy_price > 0
|
||||
if sell_price >= 0 # 0=can't sell
|
||||
$game_temp.mart_prices[item][1] = sell_price * 2
|
||||
else
|
||||
$game_temp.mart_prices[item][1] = buy_price if buy_price > 0
|
||||
$game_temp.mart_prices[item][1] = sell_price
|
||||
elsif buy_price > 0
|
||||
$game_temp.mart_prices[item][1] = buy_price / Settings::ITEM_SELL_PRICE_DIVISOR
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class Interpreter
|
||||
when 134 then return command_134 # Change Save Access
|
||||
when 135 then return command_135 # Change Menu Access
|
||||
when 136 then return command_136 # Change Encounter
|
||||
when 201 then return command_201 # Transfer Player
|
||||
when 201 then return command_201 # Transfer Overrides
|
||||
when 202 then return command_202 # Set Event Location
|
||||
when 203 then return command_203 # Scroll Map
|
||||
when 204 then return command_204 # Change Map Settings
|
||||
@@ -121,16 +121,19 @@ class Interpreter
|
||||
def command_dummy
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * End Event
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_end
|
||||
@list = nil
|
||||
end_follower_overrides
|
||||
# If main map event and event ID are valid, unlock event
|
||||
if @main && @event_id > 0 && $game_map.events[@event_id]
|
||||
$game_map.events[@event_id].unlock
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Command Skip
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -141,6 +144,7 @@ class Interpreter
|
||||
@index += 1
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Command If
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -151,6 +155,7 @@ class Interpreter
|
||||
end
|
||||
return command_skip
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Show Text
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -158,7 +163,7 @@ class Interpreter
|
||||
return false if $game_temp.message_window_showing
|
||||
message = @list[@index].parameters[0]
|
||||
message_end = ""
|
||||
commands = nil
|
||||
choices = nil
|
||||
number_input_variable = nil
|
||||
number_input_max_digits = nil
|
||||
# Check the next command(s) for things to add on to this text
|
||||
@@ -174,8 +179,8 @@ class Interpreter
|
||||
when 101 # Show Text
|
||||
message_end = "\1"
|
||||
when 102 # Show Choices
|
||||
commands = @list[next_index].parameters
|
||||
@index = next_index
|
||||
choices = setup_choices(@list[@index].parameters)
|
||||
when 103 # Input Number
|
||||
number_input_variable = @list[next_index].parameters[0]
|
||||
number_input_max_digits = @list[next_index].parameters[1]
|
||||
@@ -185,15 +190,11 @@ class Interpreter
|
||||
end
|
||||
# Translate the text
|
||||
message = _MAPINTL($game_map.map_id, message)
|
||||
# Display the text, with commands/number choosing if appropriate
|
||||
# Display the text, with choices/number choosing if appropriate
|
||||
@message_waiting = true # Lets parallel process events work while a message is displayed
|
||||
if commands
|
||||
cmd_texts = []
|
||||
for cmd in commands[0]
|
||||
cmd_texts.push(_MAPINTL($game_map.map_id, cmd))
|
||||
end
|
||||
command = pbMessage(message + message_end, cmd_texts, commands[1])
|
||||
@branch[@list[@index].indent] = command
|
||||
if choices
|
||||
command = pbMessage(message + message_end, choices[0], choices[1])
|
||||
@branch[@list[@index].indent] = choices[2][command] || command
|
||||
elsif number_input_variable
|
||||
params = ChooseNumberParams.new
|
||||
params.setMaxDigits(number_input_max_digits)
|
||||
@@ -206,37 +207,118 @@ class Interpreter
|
||||
@message_waiting = false
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Show Choices
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_102
|
||||
choices = setup_choices(@list[@index].parameters)
|
||||
@message_waiting = true
|
||||
command = pbShowCommands(nil, @list[@index].parameters[0], @list[@index].parameters[1])
|
||||
command = pbShowCommands(nil, choices[0], choices[1])
|
||||
@message_waiting = false
|
||||
@branch[@list[@index].indent] = command
|
||||
@branch[@list[@index].indent] = choices[2][command] || command
|
||||
Input.update # Must call Input.update again to avoid extra triggers
|
||||
return true
|
||||
end
|
||||
|
||||
def setup_choices(params)
|
||||
# Get initial options
|
||||
choices = params[0].clone
|
||||
cancel_index = params[1]
|
||||
# Clone @list so the original isn't modified
|
||||
@list = Marshal.load(Marshal.dump(@list))
|
||||
# Get more choices
|
||||
@choice_branch_index = 4
|
||||
ret = add_more_choices(choices, cancel_index, @index + 1, @list[@index].indent)
|
||||
# Rename choices
|
||||
ret[0].each_with_index { |choice, i| ret[0][i] = @renamed_choices[i] if @renamed_choices[i] }
|
||||
@renamed_choices.clear
|
||||
# Remove hidden choices
|
||||
ret[2] = Array.new(ret[0].length) { |i| i }
|
||||
@hidden_choices.each_with_index do |condition, i|
|
||||
next if !condition
|
||||
ret[0][i] = nil
|
||||
ret[2][i] = nil
|
||||
end
|
||||
ret[0].compact!
|
||||
ret[2].compact!
|
||||
@hidden_choices.clear
|
||||
# Translate choices
|
||||
ret[0].map! { |ch| _MAPINTL($game_map.map_id, ch) }
|
||||
return ret
|
||||
end
|
||||
|
||||
def add_more_choices(choices, cancel_index, choice_index, indent)
|
||||
# Find index of next command after the current Show Choices command
|
||||
loop do
|
||||
break if @list[choice_index].indent == indent && ![402, 403, 404].include?(@list[choice_index].code)
|
||||
choice_index += 1
|
||||
end
|
||||
next_cmd = @list[choice_index]
|
||||
# If the next command isn't another Show Choices, we're done
|
||||
return [choices, cancel_index] if next_cmd.code != 102
|
||||
# Add more choices
|
||||
old_length = choices.length
|
||||
choices += next_cmd.parameters[0]
|
||||
# Update cancel option
|
||||
if next_cmd.parameters[1] == 5 # Branch
|
||||
cancel_index = choices.length + 1
|
||||
@choice_branch_index = cancel_index - 1
|
||||
elsif next_cmd.parameters[1] > 0 # A choice
|
||||
cancel_index = old_length + next_cmd.parameters[1]
|
||||
@choice_branch_index = -1
|
||||
end
|
||||
# Update first Show Choices command to include all options and result of cancelling
|
||||
@list[@index].parameters[0] = choices
|
||||
@list[@index].parameters[1] = cancel_index
|
||||
# Find the "When" lines for this Show Choices command and update their index parameter
|
||||
temp_index = choice_index + 1
|
||||
loop do
|
||||
break if @list[temp_index].indent == indent && ![402, 403, 404].include?(@list[temp_index].code)
|
||||
if @list[temp_index].code == 402 && @list[temp_index].indent == indent
|
||||
@list[temp_index].parameters[0] += old_length
|
||||
end
|
||||
temp_index += 1
|
||||
end
|
||||
# Delete the "Show Choices" line
|
||||
@list.delete(next_cmd)
|
||||
# Find more choices to add
|
||||
return add_more_choices(choices, cancel_index, choice_index + 1, indent)
|
||||
end
|
||||
|
||||
def hide_choice(number, condition = true)
|
||||
@hidden_choices[number - 1] = condition
|
||||
end
|
||||
|
||||
def rename_choice(number, new_name, condition = true)
|
||||
return if !condition || nil_or_empty?(new_name)
|
||||
@renamed_choices[number - 1] = new_name
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * When [**]
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_402
|
||||
# @parameters[0] is 0/1/2/3 for Choice 1/2/3/4 respectively
|
||||
if @branch[@list[@index].indent] == @parameters[0]
|
||||
@branch.delete(@list[@index].indent)
|
||||
return true
|
||||
end
|
||||
return command_skip
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * When Cancel
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_403
|
||||
if @branch[@list[@index].indent] == 4
|
||||
# @parameters[0] is 4 for "Branch"
|
||||
if @branch[@list[@index].indent] == @choice_branch_index
|
||||
@branch.delete(@list[@index].indent)
|
||||
return true
|
||||
end
|
||||
return command_skip
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Input Number
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -251,6 +333,7 @@ class Interpreter
|
||||
@message_waiting = false
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Text Options
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -260,26 +343,22 @@ class Interpreter
|
||||
$game_system.message_frame = @parameters[1]
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Button Input Processing
|
||||
#-----------------------------------------------------------------------------
|
||||
def pbButtonInputProcessing(variable_number = 0, timeout_frames = 0)
|
||||
ret = 0
|
||||
timer = timeout_frames * Graphics.frame_rate / 20
|
||||
timer_start = System.uptime
|
||||
loop do
|
||||
Graphics.update
|
||||
Input.update
|
||||
pbUpdateSceneMap
|
||||
# Check for input and break if there is one
|
||||
for i in 1..18
|
||||
ret = i if Input.trigger?(i)
|
||||
end
|
||||
(1..18).each { |i| ret = i if Input.trigger?(i) }
|
||||
break if ret != 0
|
||||
# Count down the timer and break if it runs out
|
||||
if timeout_frames > 0
|
||||
timer -= 1
|
||||
break if timer <= 0
|
||||
end
|
||||
# Break if the timer runs out
|
||||
break if timeout_frames > 0 && System.uptime - timer_start >= timeout_frames / 20.0
|
||||
end
|
||||
Input.update
|
||||
if variable_number && variable_number > 0
|
||||
@@ -297,13 +376,16 @@ class Interpreter
|
||||
@index += 1
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Wait
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_106
|
||||
@wait_count = @parameters[0] * Graphics.frame_rate / 20
|
||||
@wait_count = @parameters[0] / 20.0
|
||||
@wait_start = System.uptime
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Conditional Branch
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -318,8 +400,22 @@ class Interpreter
|
||||
result = ($game_switches[@parameters[1]] == (@parameters[2] == 0))
|
||||
end
|
||||
when 1 # variable
|
||||
value1 = $game_variables[@parameters[1]]
|
||||
value2 = (@parameters[2] == 0) ? @parameters[3] : $game_variables[@parameters[3]]
|
||||
variable1_name = $data_system.variables[@parameters[1]]
|
||||
if variable1_name && variable1_name[/^s\:/]
|
||||
value1 = eval($~.post_match)
|
||||
else
|
||||
value1 = $game_variables[@parameters[1]]
|
||||
end
|
||||
if @parameters[2] == 0
|
||||
value2 = @parameters[3]
|
||||
else
|
||||
variable2_name = $data_system.variables[@parameters[3]]
|
||||
if variable2_name && variable2_name[/^s\:/]
|
||||
value2 = eval($~.post_match)
|
||||
else
|
||||
value2 = $game_variables[@parameters[3]]
|
||||
end
|
||||
end
|
||||
case @parameters[4]
|
||||
when 0 then result = (value1 == value2)
|
||||
when 1 then result = (value1 >= value2)
|
||||
@@ -334,8 +430,8 @@ class Interpreter
|
||||
result = ($game_self_switches[key] == (@parameters[2] == 0))
|
||||
end
|
||||
when 3 # timer
|
||||
if $game_system.timer_working
|
||||
sec = $game_system.timer / Graphics.frame_rate
|
||||
if $game_system.timer_start
|
||||
sec = $game_system.timer
|
||||
result = (@parameters[2] == 0) ? (sec >= @parameters[1]) : (sec <= @parameters[1])
|
||||
end
|
||||
# when 4, 5 # actor, enemy
|
||||
@@ -343,7 +439,7 @@ class Interpreter
|
||||
character = get_character(@parameters[1])
|
||||
result = (character.direction == @parameters[2]) if character
|
||||
when 7 # gold
|
||||
gold = $Trainer.money
|
||||
gold = $player.money
|
||||
result = (@parameters[2] == 0) ? (gold >= @parameters[1]) : (gold <= @parameters[1])
|
||||
# when 8, 9, 10 # item, weapon, armor
|
||||
when 11 # button
|
||||
@@ -359,6 +455,7 @@ class Interpreter
|
||||
end
|
||||
return command_skip
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Else
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -369,12 +466,14 @@ class Interpreter
|
||||
end
|
||||
return command_skip
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Loop
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_112
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Repeat Above
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -385,6 +484,7 @@ class Interpreter
|
||||
return true if @list[@index].indent == indent
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Break Loop
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -401,6 +501,7 @@ class Interpreter
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Exit Event Processing
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -408,17 +509,19 @@ class Interpreter
|
||||
command_end
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Erase Event
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_116
|
||||
if @event_id > 0
|
||||
$game_map.events[@event_id].erase if $game_map.events[@event_id]
|
||||
$PokemonMap.addErasedEvent(@event_id) if $PokemonMap
|
||||
$game_map.events[@event_id]&.erase
|
||||
$PokemonMap&.addErasedEvent(@event_id)
|
||||
end
|
||||
@index += 1
|
||||
return false
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Call Common Event
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -430,12 +533,14 @@ class Interpreter
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Label
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_118
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Jump to Label
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -454,12 +559,13 @@ class Interpreter
|
||||
temp_index += 1
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Control Switches
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_121
|
||||
should_refresh = false
|
||||
for i in @parameters[0]..@parameters[1]
|
||||
(@parameters[0]..@parameters[1]).each do |i|
|
||||
next if $game_switches[i] == (@parameters[2] == 0)
|
||||
$game_switches[i] = (@parameters[2] == 0)
|
||||
should_refresh = true
|
||||
@@ -468,6 +574,7 @@ class Interpreter
|
||||
$game_map.need_refresh = true if should_refresh
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Control Variables
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -495,43 +602,44 @@ class Interpreter
|
||||
end
|
||||
when 7 # other
|
||||
case @parameters[4]
|
||||
when 0 then value = $game_map.map_id # map ID
|
||||
when 1 then value = $Trainer.pokemon_party.length # party members
|
||||
when 2 then value = $Trainer.money # gold
|
||||
# when 3 # steps
|
||||
when 4 then value = Graphics.frame_count / Graphics.frame_rate # play time
|
||||
when 5 then value = $game_system.timer / Graphics.frame_rate # timer
|
||||
when 6 then value = $game_system.save_count # save count
|
||||
when 0 then value = $game_map.map_id # map ID
|
||||
when 1 then value = $player.pokemon_count # party members
|
||||
when 2 then value = $player.money # gold
|
||||
when 3 then value = $stats.distance_moved # steps
|
||||
when 4 then value = $stats.play_time # play time
|
||||
when 5 then value = $game_system.timer # timer
|
||||
when 6 then value = $game_system.save_count # save count
|
||||
end
|
||||
end
|
||||
# Apply value and operation to all specified game variables
|
||||
for i in @parameters[0]..@parameters[1]
|
||||
(@parameters[0]..@parameters[1]).each do |i|
|
||||
case @parameters[2]
|
||||
when 0 # set
|
||||
next if $game_variables[i] == value
|
||||
$game_variables[i] = value
|
||||
when 1 # add
|
||||
next if $game_variables[i] >= 99999999
|
||||
next if $game_variables[i] >= 99_999_999
|
||||
$game_variables[i] += value
|
||||
when 2 # subtract
|
||||
next if $game_variables[i] <= -99999999
|
||||
next if $game_variables[i] <= -99_999_999
|
||||
$game_variables[i] -= value
|
||||
when 3 # multiply
|
||||
next if value == 1
|
||||
$game_variables[i] *= value
|
||||
when 4 # divide
|
||||
next if value == 1 || value == 0
|
||||
next if [0, 1].include?(value)
|
||||
$game_variables[i] /= value
|
||||
when 5 # remainder
|
||||
next if value == 1 || value == 0
|
||||
next if [0, 1].include?(value)
|
||||
$game_variables[i] %= value
|
||||
end
|
||||
$game_variables[i] = 99999999 if $game_variables[i] > 99999999
|
||||
$game_variables[i] = -99999999 if $game_variables[i] < -99999999
|
||||
$game_variables[i] = 99_999_999 if $game_variables[i] > 99_999_999
|
||||
$game_variables[i] = -99_999_999 if $game_variables[i] < -99_999_999
|
||||
$game_map.need_refresh = true
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Control Self Switch
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -546,21 +654,23 @@ class Interpreter
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Control Timer
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_124
|
||||
$game_system.timer_working = (@parameters[0] == 0)
|
||||
$game_system.timer = @parameters[1] * Graphics.frame_rate if @parameters[0] == 0
|
||||
$game_system.timer_start = (@parameters[0] == 0) ? $stats.play_time : nil
|
||||
$game_system.timer_duration = @parameters[1] if @parameters[0] == 0
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Gold
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_125
|
||||
value = (@parameters[1] == 0) ? @parameters[2] : $game_variables[@parameters[2]]
|
||||
value = -value if @parameters[0] == 1 # Decrease
|
||||
$Trainer.money += value
|
||||
$player.money += value
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -568,11 +678,12 @@ class Interpreter
|
||||
def command_127; command_dummy; end # Change Weapons
|
||||
def command_128; command_dummy; end # Change Armor
|
||||
def command_129; command_dummy; end # Change Party Member
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Windowskin
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_131
|
||||
for i in 0...Settings::SPEECH_WINDOWSKINS.length
|
||||
Settings::SPEECH_WINDOWSKINS.length.times do |i|
|
||||
next if Settings::SPEECH_WINDOWSKINS[i] != @parameters[0]
|
||||
$PokemonSystem.textskin = i
|
||||
MessageConfig.pbSetSpeechFrame("Graphics/Windowskins/" + Settings::SPEECH_WINDOWSKINS[i])
|
||||
@@ -580,6 +691,7 @@ class Interpreter
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Battle BGM
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -587,13 +699,12 @@ class Interpreter
|
||||
($PokemonGlobal.nextBattleBGM = @parameters[0]) ? @parameters[0].clone : nil
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Battle End ME
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_133
|
||||
($PokemonGlobal.nextBattleME = @parameters[0]) ? @parameters[0].clone : nil
|
||||
return true
|
||||
end
|
||||
def command_133; command_dummy; end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Save Access
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -601,6 +712,7 @@ class Interpreter
|
||||
$game_system.save_disabled = (@parameters[0] == 0)
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Menu Access
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -608,6 +720,7 @@ class Interpreter
|
||||
$game_system.menu_disabled = (@parameters[0] == 0)
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Encounter
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -616,8 +729,9 @@ class Interpreter
|
||||
$game_player.make_encounter_count
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Transfer Player
|
||||
# * Transfer Overrides
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_201
|
||||
return true if $game_temp.in_battle
|
||||
@@ -630,13 +744,12 @@ class Interpreter
|
||||
$game_temp.player_new_map_id = @parameters[1]
|
||||
$game_temp.player_new_x = @parameters[2]
|
||||
$game_temp.player_new_y = @parameters[3]
|
||||
$game_temp.player_new_direction = @parameters[4]
|
||||
else # Appoint with variables
|
||||
$game_temp.player_new_map_id = $game_variables[@parameters[1]]
|
||||
$game_temp.player_new_x = $game_variables[@parameters[2]]
|
||||
$game_temp.player_new_y = $game_variables[@parameters[3]]
|
||||
$game_temp.player_new_direction = @parameters[4]
|
||||
end
|
||||
$game_temp.player_new_direction = @parameters[4]
|
||||
@index += 1
|
||||
# If transition happens with a fade, do the fade
|
||||
if @parameters[5] == 0
|
||||
@@ -646,6 +759,7 @@ class Interpreter
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Set Event Location
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -654,9 +768,10 @@ class Interpreter
|
||||
character = get_character(@parameters[0])
|
||||
return true if character.nil?
|
||||
# Move the character
|
||||
if @parameters[1] == 0 # Direct appointment
|
||||
case @parameters[1]
|
||||
when 0 # Direct appointment
|
||||
character.moveto(@parameters[2], @parameters[3])
|
||||
elsif @parameters[1] == 1 # Appoint with variables
|
||||
when 1 # Appoint with variables
|
||||
character.moveto($game_variables[@parameters[2]], $game_variables[@parameters[3]])
|
||||
else # Exchange with another event
|
||||
character2 = get_character(@parameters[2])
|
||||
@@ -676,6 +791,7 @@ class Interpreter
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Scroll Map
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -685,6 +801,7 @@ class Interpreter
|
||||
$game_map.start_scroll(@parameters[0], @parameters[1], @parameters[2])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Map Settings
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -707,29 +824,38 @@ class Interpreter
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Fog Color Tone
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_205
|
||||
$game_map.start_fog_tone_change(@parameters[0], @parameters[1] * Graphics.frame_rate / 20)
|
||||
$game_map.start_fog_tone_change(@parameters[0], @parameters[1])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Fog Opacity
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_206
|
||||
$game_map.start_fog_opacity_change(@parameters[0], @parameters[1] * Graphics.frame_rate / 20)
|
||||
$game_map.start_fog_opacity_change(@parameters[0], @parameters[1])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Show Animation
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_207
|
||||
character = get_character(@parameters[0])
|
||||
if @follower_animation
|
||||
character = Followers.get(@follower_animation_id)
|
||||
@follower_animation = false
|
||||
@follower_animation_id = nil
|
||||
end
|
||||
return true if character.nil?
|
||||
character.animation_id = @parameters[1]
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Transparent Flag
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -737,15 +863,22 @@ class Interpreter
|
||||
$game_player.transparent = (@parameters[0] == 0)
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Set Move Route
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_209
|
||||
character = get_character(@parameters[0])
|
||||
if @follower_move_route
|
||||
character = Followers.get(@follower_move_route_id)
|
||||
@follower_move_route = false
|
||||
@follower_move_route_id = nil
|
||||
end
|
||||
return true if character.nil?
|
||||
character.force_move_route(@parameters[1])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Wait for Move's Completion
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -753,6 +886,7 @@ class Interpreter
|
||||
@move_route_waiting = true if !$game_temp.in_battle
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Prepare for Transition
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -761,6 +895,7 @@ class Interpreter
|
||||
Graphics.freeze
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Execute Transition
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -771,27 +906,31 @@ class Interpreter
|
||||
@index += 1
|
||||
return false
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Screen Color Tone
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_223
|
||||
$game_screen.start_tone_change(@parameters[0], @parameters[1] * Graphics.frame_rate / 20)
|
||||
$game_screen.start_tone_change(@parameters[0], @parameters[1])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Screen Flash
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_224
|
||||
$game_screen.start_flash(@parameters[0], @parameters[1] * Graphics.frame_rate / 20)
|
||||
$game_screen.start_flash(@parameters[0], @parameters[1])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Screen Shake
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_225
|
||||
$game_screen.start_shake(@parameters[0], @parameters[1], @parameters[2] * Graphics.frame_rate / 20)
|
||||
$game_screen.start_shake(@parameters[0], @parameters[1], @parameters[2])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Show Picture
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -805,9 +944,10 @@ class Interpreter
|
||||
y = $game_variables[@parameters[5]]
|
||||
end
|
||||
$game_screen.pictures[number].show(@parameters[1], @parameters[2],
|
||||
x, y, @parameters[6], @parameters[7], @parameters[8], @parameters[9])
|
||||
x, y, @parameters[6], @parameters[7], @parameters[8], @parameters[9])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Move Picture
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -820,10 +960,12 @@ class Interpreter
|
||||
x = $game_variables[@parameters[4]]
|
||||
y = $game_variables[@parameters[5]]
|
||||
end
|
||||
$game_screen.pictures[number].move(@parameters[1] * Graphics.frame_rate / 20,
|
||||
@parameters[2], x, y, @parameters[6], @parameters[7], @parameters[8], @parameters[9])
|
||||
$game_screen.pictures[number].move(@parameters[1], @parameters[2], x, y,
|
||||
@parameters[6], @parameters[7],
|
||||
@parameters[8], @parameters[9])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Rotate Picture
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -832,15 +974,16 @@ class Interpreter
|
||||
$game_screen.pictures[number].rotate(@parameters[1])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Picture Color Tone
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_234
|
||||
number = @parameters[0] + ($game_temp.in_battle ? 50 : 0)
|
||||
$game_screen.pictures[number].start_tone_change(@parameters[1],
|
||||
@parameters[2] * Graphics.frame_rate / 20)
|
||||
$game_screen.pictures[number].start_tone_change(@parameters[1], @parameters[2])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Erase Picture
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -849,6 +992,7 @@ class Interpreter
|
||||
$game_screen.pictures[number].erase
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Set Weather Effects
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -856,6 +1000,7 @@ class Interpreter
|
||||
$game_screen.weather(@parameters[0], @parameters[1], @parameters[2])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Play BGM
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -863,6 +1008,7 @@ class Interpreter
|
||||
pbBGMPlay(@parameters[0])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Fade Out BGM
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -870,6 +1016,7 @@ class Interpreter
|
||||
pbBGMFade(@parameters[0])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Play BGS
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -877,6 +1024,7 @@ class Interpreter
|
||||
pbBGSPlay(@parameters[0])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Fade Out BGS
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -884,6 +1032,7 @@ class Interpreter
|
||||
pbBGSFade(@parameters[0])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Memorize BGM/BGS
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -892,6 +1041,7 @@ class Interpreter
|
||||
$game_system.bgs_memorize
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Restore BGM/BGS
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -900,6 +1050,7 @@ class Interpreter
|
||||
$game_system.bgs_restore
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Play ME
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -907,6 +1058,7 @@ class Interpreter
|
||||
pbMEPlay(@parameters[0])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Play SE
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -914,6 +1066,7 @@ class Interpreter
|
||||
pbSEPlay(@parameters[0])
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Stop SE
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -927,23 +1080,25 @@ class Interpreter
|
||||
def command_602; command_if(1); end # If Escape
|
||||
def command_603; command_if(2); end # If Lose
|
||||
def command_302; command_dummy; end # Shop Processing
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Name Input Processing
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_303
|
||||
if $Trainer
|
||||
$Trainer.name = pbEnterPlayerName(_INTL("Your name?"), 1, @parameters[1], $Trainer.name)
|
||||
if $player
|
||||
$player.name = pbEnterPlayerName(_INTL("Your name?"), 1, @parameters[1], $player.name)
|
||||
return true
|
||||
end
|
||||
if $game_actors && $data_actors && $data_actors[@parameters[0]] != nil
|
||||
if $game_actors && $data_actors && $data_actors[@parameters[0]]
|
||||
$game_temp.battle_abort = true
|
||||
pbFadeOutIn {
|
||||
pbFadeOutIn do
|
||||
sscene = PokemonEntryScene.new
|
||||
sscreen = PokemonEntry.new(sscene)
|
||||
$game_actors[@parameters[0]].name = sscreen.pbStartScreen(
|
||||
_INTL("Enter {1}'s name.", $game_actors[@parameters[0]].name),
|
||||
1, @parameters[1], $game_actors[@parameters[0]].name)
|
||||
}
|
||||
_INTL("Enter {1}'s name.", $game_actors[@parameters[0]].name),
|
||||
1, @parameters[1], $game_actors[@parameters[0]].name
|
||||
)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
@@ -951,11 +1106,18 @@ class Interpreter
|
||||
def command_311; command_dummy; end # Change HP
|
||||
def command_312; command_dummy; end # Change SP
|
||||
def command_313; command_dummy; end # Change State
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Recover All
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_314
|
||||
$Trainer.heal_party if @parameters[0] == 0
|
||||
if @parameters[0] == 0
|
||||
if Settings::HEAL_STORED_POKEMON # No need to heal stored Pokémon
|
||||
$player.heal_party
|
||||
else
|
||||
pbEachPokemon { |pkmn, box| pkmn.heal } # Includes party Pokémon
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -977,6 +1139,7 @@ class Interpreter
|
||||
def command_338; command_dummy; end # Deal Damage
|
||||
def command_339; command_dummy; end # Force Action
|
||||
def command_340; command_dummy; end # Abort Battle
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Call Menu Screen
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -985,15 +1148,15 @@ class Interpreter
|
||||
@index += 1
|
||||
return false
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Call Save Screen
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_352
|
||||
scene = PokemonSave_Scene.new
|
||||
screen = PokemonSaveScreen.new(scene)
|
||||
screen.pbSaveScreen
|
||||
pbFadeOutIn { UI::Save.new.main }
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Game Over
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -1002,13 +1165,15 @@ class Interpreter
|
||||
pbBGSFade(1.0)
|
||||
pbFadeOutIn { pbStartOver(true) }
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Return to Title Screen
|
||||
#-----------------------------------------------------------------------------
|
||||
def command_354
|
||||
$game_temp.to_title = true
|
||||
$game_temp.title_screen_calling = true
|
||||
return false
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Script
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -1017,7 +1182,7 @@ class Interpreter
|
||||
# Look for more script commands or a continuation of one, and add them to script
|
||||
loop do
|
||||
break if ![355, 655].include?(@list[@index + 1].code)
|
||||
script += @list[@index+1].parameters[0] + "\n"
|
||||
script += @list[@index + 1].parameters[0] + "\n"
|
||||
@index += 1
|
||||
end
|
||||
# Run the script
|
||||
|
||||
@@ -13,21 +13,15 @@ class Event
|
||||
end
|
||||
|
||||
# Removes an event handler procedure from the event.
|
||||
def -(method)
|
||||
for i in 0...@callbacks.length
|
||||
next if @callbacks[i]!=method
|
||||
@callbacks.delete_at(i)
|
||||
break
|
||||
end
|
||||
def -(other)
|
||||
@callbacks.delete(other)
|
||||
return self
|
||||
end
|
||||
|
||||
# Adds an event handler procedure from the event.
|
||||
def +(method)
|
||||
for i in 0...@callbacks.length
|
||||
return self if @callbacks[i]==method
|
||||
end
|
||||
@callbacks.push(method)
|
||||
def +(other)
|
||||
return self if @callbacks.include?(other)
|
||||
@callbacks.push(other)
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -44,13 +38,13 @@ class Event
|
||||
# proc { |sender,params| } where params is an array of the other parameters, and
|
||||
# proc { |sender,arg0,arg1,...| }
|
||||
def trigger(*arg)
|
||||
arglist = arg[1,arg.length]
|
||||
for callback in @callbacks
|
||||
if callback.arity>2 && arg.length==callback.arity
|
||||
arglist = arg[1, arg.length]
|
||||
@callbacks.each do |callback|
|
||||
if callback.arity > 2 && arg.length == callback.arity
|
||||
# Retrofitted for callbacks that take three or more arguments
|
||||
callback.call(*arg)
|
||||
else
|
||||
callback.call(arg[0],arglist)
|
||||
callback.call(arg[0], arglist)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -59,16 +53,164 @@ class Event
|
||||
# by the code where the event occurred. The first argument is the sender of
|
||||
# the event, the other arguments are the event's parameters.
|
||||
def trigger2(*arg)
|
||||
for callback in @callbacks
|
||||
@callbacks.each do |callback|
|
||||
callback.call(*arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
# Same as class Event, but each registered proc has a name (a symbol) so it can
|
||||
# be referenced individually.
|
||||
#===============================================================================
|
||||
class NamedEvent
|
||||
def initialize
|
||||
@callbacks = {}
|
||||
end
|
||||
|
||||
# Adds an event handler procedure from the event.
|
||||
def add(key, proc)
|
||||
@callbacks[key] = proc
|
||||
end
|
||||
|
||||
# Removes an event handler procedure from the event.
|
||||
def remove(key)
|
||||
@callbacks.delete(key)
|
||||
end
|
||||
|
||||
# Clears the event of event handlers.
|
||||
def clear
|
||||
@callbacks.clear
|
||||
end
|
||||
|
||||
# Triggers the event and calls all its event handlers. Normally called only
|
||||
# by the code where the event occurred.
|
||||
def trigger(*args)
|
||||
@callbacks.each_value { |callback| callback.call(*args) }
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# A class that stores code that can be triggered. Each piece of code has an
|
||||
# associated ID, which can be anything that can be used as a key in a hash.
|
||||
#===============================================================================
|
||||
class HandlerHash
|
||||
def initialize
|
||||
@hash = {}
|
||||
end
|
||||
|
||||
def [](id)
|
||||
return @hash[id] if id && @hash[id]
|
||||
return nil
|
||||
end
|
||||
|
||||
def keys
|
||||
return @hash.keys
|
||||
end
|
||||
|
||||
def add(id, handler = nil, &handlerBlock)
|
||||
if ![Proc, Hash].include?(handler.class) && !block_given?
|
||||
raise ArgumentError, "#{self.class.name} for #{id.inspect} has no valid handler (#{handler.inspect} was given)"
|
||||
end
|
||||
@hash[id] = handler || handlerBlock if id && !id.empty?
|
||||
end
|
||||
|
||||
def copy(src, *dests)
|
||||
handler = self[src]
|
||||
return if !handler
|
||||
dests.each { |dest| add(dest, handler) }
|
||||
end
|
||||
|
||||
def remove(key)
|
||||
@hash.delete(key)
|
||||
end
|
||||
|
||||
def clear
|
||||
@hash.clear
|
||||
end
|
||||
|
||||
def each
|
||||
@hash.each_pair { |key, value| yield key, value }
|
||||
end
|
||||
|
||||
def keys
|
||||
return @hash.keys.clone
|
||||
end
|
||||
|
||||
# NOTE: The call does not pass id as a parameter to the proc/block.
|
||||
def trigger(id, *args)
|
||||
handler = self[id]
|
||||
return handler&.call(*args)
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# A stripped-down version of class HandlerHash which only deals with IDs that
|
||||
# are symbols. Also contains an add_ifs hash for code that applies to multiple
|
||||
# IDs (determined by its condition proc).
|
||||
#===============================================================================
|
||||
class HandlerHashSymbol
|
||||
def initialize
|
||||
@hash = {}
|
||||
@add_ifs = {}
|
||||
end
|
||||
|
||||
def [](sym)
|
||||
sym = sym.id if !sym.is_a?(Symbol) && sym.respond_to?("id")
|
||||
return @hash[sym] if sym && @hash[sym]
|
||||
@add_ifs.each_value do |add_if|
|
||||
return add_if[1] if add_if[0].call(sym)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def keys
|
||||
return @hash.keys
|
||||
end
|
||||
|
||||
def add(sym, handler = nil, &handlerBlock)
|
||||
if ![Proc, Hash].include?(handler.class) && !block_given?
|
||||
raise ArgumentError, "#{self.class.name} for #{sym.inspect} has no valid handler (#{handler.inspect} was given)"
|
||||
end
|
||||
@hash[sym] = handler || handlerBlock if sym
|
||||
end
|
||||
|
||||
def addIf(sym, conditionProc, handler = nil, &handlerBlock)
|
||||
if ![Proc, Hash].include?(handler.class) && !block_given?
|
||||
raise ArgumentError, "addIf call for #{sym} in #{self.class.name} has no valid handler (#{handler.inspect} was given)"
|
||||
end
|
||||
@add_ifs[sym] = [conditionProc, handler || handlerBlock]
|
||||
end
|
||||
|
||||
def copy(src, *dests)
|
||||
handler = self[src]
|
||||
return if !handler
|
||||
dests.each { |dest| add(dest, handler) }
|
||||
end
|
||||
|
||||
def remove(key)
|
||||
@hash.delete(key)
|
||||
end
|
||||
|
||||
def clear
|
||||
@hash.clear
|
||||
@add_ifs.clear
|
||||
end
|
||||
|
||||
def trigger(sym, *args)
|
||||
sym = sym.id if !sym.is_a?(Symbol) && sym.respond_to?("id")
|
||||
handler = self[sym]
|
||||
return handler&.call(sym, *args)
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# A specialised version of class HandlerHash which only deals with IDs that are
|
||||
# constants in a particular class or module. That class or module must be
|
||||
# defined when creating an instance of this class.
|
||||
# Unused.
|
||||
#===============================================================================
|
||||
class HandlerHashEnum
|
||||
def initialize(mod)
|
||||
@mod = mod
|
||||
@hash = {}
|
||||
@@ -76,6 +218,25 @@ class HandlerHash
|
||||
@symbolCache = {}
|
||||
end
|
||||
|
||||
# 'sym' can be an ID or symbol.
|
||||
def [](sym)
|
||||
id = fromSymbol(sym)
|
||||
ret = nil
|
||||
ret = @hash[id] if id && @hash[id] # Real ID from the item
|
||||
symbol = toSymbol(sym)
|
||||
ret = @hash[symbol] if symbol && @hash[symbol] # Symbol or string
|
||||
unless ret
|
||||
@addIfs.each do |addif|
|
||||
return addif[1] if addif[0].call(id)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def keys
|
||||
return @hash.keys
|
||||
end
|
||||
|
||||
def fromSymbol(sym)
|
||||
return sym unless sym.is_a?(Symbol) || sym.is_a?(String)
|
||||
mod = Object.const_get(@mod) rescue nil
|
||||
@@ -89,8 +250,8 @@ class HandlerHash
|
||||
return ret if ret
|
||||
mod = Object.const_get(@mod) rescue nil
|
||||
return nil if !mod
|
||||
for key in mod.constants
|
||||
next if mod.const_get(key)!=sym
|
||||
mod.constants.each do |key|
|
||||
next if mod.const_get(key) != sym
|
||||
ret = key.to_sym
|
||||
@symbolCache[sym] = ret
|
||||
break
|
||||
@@ -98,15 +259,9 @@ class HandlerHash
|
||||
return ret
|
||||
end
|
||||
|
||||
def addIf(conditionProc,handler=nil,&handlerBlock)
|
||||
if ![Proc,Hash].include?(handler.class) && !block_given?
|
||||
raise ArgumentError, "addIf call for #{self.class.name} has no valid handler (#{handler.inspect} was given)"
|
||||
end
|
||||
@addIfs.push([conditionProc,handler || handlerBlock])
|
||||
end
|
||||
|
||||
def add(sym,handler=nil,&handlerBlock) # 'sym' can be an ID or symbol
|
||||
if ![Proc,Hash].include?(handler.class) && !block_given?
|
||||
# 'sym' can be an ID or symbol.
|
||||
def add(sym, handler = nil, &handlerBlock)
|
||||
if ![Proc, Hash].include?(handler.class) && !block_given?
|
||||
raise ArgumentError, "#{self.class.name} for #{sym.inspect} has no valid handler (#{handler.inspect} was given)"
|
||||
end
|
||||
id = fromSymbol(sym)
|
||||
@@ -115,126 +270,6 @@ class HandlerHash
|
||||
@hash[symbol] = handler || handlerBlock if symbol
|
||||
end
|
||||
|
||||
def copy(src,*dests)
|
||||
handler = self[src]
|
||||
if handler
|
||||
for dest in dests
|
||||
self.add(dest,handler)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def [](sym) # 'sym' can be an ID or symbol
|
||||
id = fromSymbol(sym)
|
||||
ret = nil
|
||||
ret = @hash[id] if id && @hash[id] # Real ID from the item
|
||||
symbol = toSymbol(sym)
|
||||
ret = @hash[symbol] if symbol && @hash[symbol] # Symbol or string
|
||||
unless ret
|
||||
for addif in @addIfs
|
||||
return addif[1] if addif[0].call(id)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def trigger(sym,*args)
|
||||
handler = self[sym]
|
||||
return (handler) ? handler.call(fromSymbol(sym),*args) : nil
|
||||
end
|
||||
|
||||
def clear
|
||||
@hash.clear
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# A stripped-down version of class HandlerHash which only deals with symbols and
|
||||
# doesn't care about whether those symbols actually relate to a defined thing.
|
||||
#===============================================================================
|
||||
class HandlerHash2
|
||||
def initialize
|
||||
@hash = {}
|
||||
@add_ifs = []
|
||||
end
|
||||
|
||||
def [](sym)
|
||||
sym = sym.id if !sym.is_a?(Symbol) && sym.respond_to?("id")
|
||||
return @hash[sym] if sym && @hash[sym]
|
||||
for add_if in @add_ifs
|
||||
return add_if[1] if add_if[0].call(sym)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def addIf(conditionProc, handler = nil, &handlerBlock)
|
||||
if ![Proc, Hash].include?(handler.class) && !block_given?
|
||||
raise ArgumentError, "addIf call for #{self.class.name} has no valid handler (#{handler.inspect} was given)"
|
||||
end
|
||||
@add_ifs.push([conditionProc, handler || handlerBlock])
|
||||
end
|
||||
|
||||
def add(sym, handler = nil, &handlerBlock)
|
||||
if ![Proc, Hash].include?(handler.class) && !block_given?
|
||||
raise ArgumentError, "#{self.class.name} for #{sym.inspect} has no valid handler (#{handler.inspect} was given)"
|
||||
end
|
||||
@hash[sym] = handler || handlerBlock if sym
|
||||
end
|
||||
|
||||
def copy(src, *dests)
|
||||
handler = self[src]
|
||||
return if !handler
|
||||
for dest in dests
|
||||
self.add(dest, handler)
|
||||
end
|
||||
end
|
||||
|
||||
def clear
|
||||
@hash.clear
|
||||
end
|
||||
|
||||
def trigger(sym, *args)
|
||||
sym = sym.id if !sym.is_a?(Symbol) && sym.respond_to?("id")
|
||||
handler = self[sym]
|
||||
return (handler) ? handler.call(sym, *args) : nil
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# An even more stripped down version of class HandlerHash which just takes
|
||||
# hashes with keys, no matter what the keys are.
|
||||
#===============================================================================
|
||||
class HandlerHashBasic
|
||||
def initialize
|
||||
@ordered_keys = []
|
||||
@hash = {}
|
||||
@addIfs = []
|
||||
end
|
||||
|
||||
def [](entry)
|
||||
ret = nil
|
||||
ret = @hash[entry] if entry && @hash[entry]
|
||||
unless ret
|
||||
for addif in @addIfs
|
||||
return addif[1] if addif[0].call(entry)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def each
|
||||
@ordered_keys.each { |key| yield key, @hash[key] }
|
||||
end
|
||||
|
||||
def add(entry, handler = nil, &handlerBlock)
|
||||
if ![Proc,Hash].include?(handler.class) && !block_given?
|
||||
raise ArgumentError, "#{self.class.name} for #{entry.inspect} has no valid handler (#{handler.inspect} was given)"
|
||||
end
|
||||
return if !entry || entry.empty?
|
||||
@ordered_keys.push(entry) if !@ordered_keys.include?(entry)
|
||||
@hash[entry] = handler || handlerBlock
|
||||
end
|
||||
|
||||
def addIf(conditionProc, handler = nil, &handlerBlock)
|
||||
if ![Proc, Hash].include?(handler.class) && !block_given?
|
||||
raise ArgumentError, "addIf call for #{self.class.name} has no valid handler (#{handler.inspect} was given)"
|
||||
@@ -250,26 +285,26 @@ class HandlerHashBasic
|
||||
|
||||
def clear
|
||||
@hash.clear
|
||||
@ordered_keys.clear
|
||||
@addIfs.clear
|
||||
end
|
||||
|
||||
def trigger(entry, *args)
|
||||
handler = self[entry]
|
||||
return (handler) ? handler.call(*args) : nil
|
||||
def trigger(sym, *args)
|
||||
handler = self[sym]
|
||||
return (handler) ? handler.call(fromSymbol(sym), *args) : nil
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class SpeciesHandlerHash < HandlerHash2
|
||||
class SpeciesHandlerHash < HandlerHashSymbol
|
||||
end
|
||||
|
||||
class AbilityHandlerHash < HandlerHash2
|
||||
class AbilityHandlerHash < HandlerHashSymbol
|
||||
end
|
||||
|
||||
class ItemHandlerHash < HandlerHash2
|
||||
class ItemHandlerHash < HandlerHashSymbol
|
||||
end
|
||||
|
||||
class MoveHandlerHash < HandlerHash2
|
||||
class MoveHandlerHash < HandlerHashSymbol
|
||||
end
|
||||
|
||||
173
Data/Scripts/003_Game processing/006_Event_HandlerCollections.rb
Normal file
173
Data/Scripts/003_Game processing/006_Event_HandlerCollections.rb
Normal file
@@ -0,0 +1,173 @@
|
||||
#===============================================================================
|
||||
# This module stores events that can happen during the game. A procedure can
|
||||
# subscribe to an event by adding itself to the event. It will then be called
|
||||
# whenever the event occurs. Existing events are:
|
||||
#-------------------------------------------------------------------------------
|
||||
# :on_game_map_setup - When a Game_Map is set up. Typically changes map data.
|
||||
# :on_new_spriteset_map - When a Spriteset_Map is created. Adds more things to
|
||||
# show in the overworld.
|
||||
# :on_frame_update - Once per frame. Various frame/time counters.
|
||||
# :on_leave_map - When leaving a map. End weather/expired effects.
|
||||
# :on_enter_map - Upon entering a new map. Set up new effects, end expired
|
||||
# effects.
|
||||
# :on_map_or_spriteset_change - Upon entering a new map or when spriteset was
|
||||
# made. Show things on-screen.
|
||||
#-------------------------------------------------------------------------------
|
||||
# :on_player_change_direction - When the player turns in a different direction.
|
||||
# :on_leave_tile - When any event or the player starts to move from a tile.
|
||||
# :on_step_taken - When any event or the player finishes a step.
|
||||
# :on_player_step_taken - When the player finishes a step/ends surfing, except
|
||||
# as part of a move route. Step-based counters.
|
||||
# :on_player_step_taken_can_transfer - When the player finishes a step/ends
|
||||
# surfing, except as part of a move route. Step-based effects that can
|
||||
# transfer the player elsewhere.
|
||||
# :on_player_interact - When the player presses the Use button in the
|
||||
# overworld.
|
||||
#-------------------------------------------------------------------------------
|
||||
# :on_trainer_load - When an NPCTrainer is generated (to battle against or as
|
||||
# a registered partner). Various modifications to that trainer and their
|
||||
# Pokémon.
|
||||
# :on_wild_species_chosen - When a species/level have been chosen for a wild
|
||||
# encounter. Changes the species/level (e.g. roamer, Poké Radar chain).
|
||||
# :on_wild_pokemon_created - When a Pokemon object has been created for a wild
|
||||
# encounter. Various modifications to that Pokémon.
|
||||
# :on_calling_wild_battle - When a wild battle is called. Prevents that wild
|
||||
# battle and instead starts a different kind of battle (e.g. Safari Zone).
|
||||
# :on_start_battle - Just before a battle starts. Memorize/reset information
|
||||
# about party Pokémon, which is used after battle for evolution checks.
|
||||
# :on_end_battle - Just after a battle ends. Evolution checks, Pickup/Honey
|
||||
# Gather, blacking out.
|
||||
# :on_wild_battle_end - After a wild battle. Updates Poké Radar chain info.
|
||||
#===============================================================================
|
||||
module EventHandlers
|
||||
@@events = {}
|
||||
|
||||
module_function
|
||||
|
||||
# Add a named callback for the given event.
|
||||
def add(event, key, proc)
|
||||
@@events[event] = NamedEvent.new if !@@events.has_key?(event)
|
||||
@@events[event].add(key, proc)
|
||||
end
|
||||
|
||||
# Remove a named callback from the given event.
|
||||
def remove(event, key)
|
||||
@@events[event]&.remove(key)
|
||||
end
|
||||
|
||||
# Clear all callbacks for the given event.
|
||||
def clear(key)
|
||||
@@events[key]&.clear
|
||||
end
|
||||
|
||||
# Trigger all callbacks from an Event if it has been defined.
|
||||
def trigger(event, *args)
|
||||
return @@events[event]&.trigger(*args)
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# This module stores the contents of various menus. Each command in a menu is a
|
||||
# hash of data (containing its name, relative order, code to run when chosen,
|
||||
# etc.).
|
||||
# Menus that use this module are:
|
||||
#-------------------------------------------------------------------------------
|
||||
# Pause menu
|
||||
# Party screen main interact menu
|
||||
# Pokégear main menu
|
||||
# Options screen
|
||||
# PC main menu
|
||||
# Various debug menus (main, Pokémon, battle, battle Pokémon)
|
||||
#===============================================================================
|
||||
module MenuHandlers
|
||||
@@handlers = {}
|
||||
|
||||
module_function
|
||||
|
||||
def add(menu, option, hash)
|
||||
@@handlers[menu] = HandlerHash.new if !@@handlers.has_key?(menu)
|
||||
@@handlers[menu].add(option, hash)
|
||||
end
|
||||
|
||||
def remove(menu, option)
|
||||
@@handlers[menu]&.remove(option)
|
||||
end
|
||||
|
||||
def clear(menu)
|
||||
@@handlers[menu]&.clear
|
||||
end
|
||||
|
||||
def get(menu, option)
|
||||
return @@handlers[menu][option]
|
||||
end
|
||||
|
||||
def each(menu)
|
||||
return if !@@handlers.has_key?(menu)
|
||||
@@handlers[menu].each { |option, hash| yield option, hash }
|
||||
end
|
||||
|
||||
def each_available(menu, *args)
|
||||
return if !@@handlers.has_key?(menu)
|
||||
options = @@handlers[menu]
|
||||
keys = options.keys
|
||||
sorted_keys = keys.sort_by { |option| options[option]["order"] || keys.index(option) }
|
||||
sorted_keys.each do |option|
|
||||
hash = options[option]
|
||||
next if hash["condition"] && !hash["condition"].call(*args)
|
||||
if hash["multi_options"]
|
||||
extra_options = hash["multi_options"].call(*args)
|
||||
if extra_options && extra_options.length > 0
|
||||
if extra_options[0].is_a?(Array)
|
||||
extra_options.each { |opt| yield *opt }
|
||||
else
|
||||
yield *extra_options
|
||||
end
|
||||
end
|
||||
next
|
||||
end
|
||||
if hash["name"].is_a?(Proc)
|
||||
name = hash["name"].call(*args)
|
||||
else
|
||||
name = _INTL(hash["name"])
|
||||
end
|
||||
yield option, hash, name
|
||||
end
|
||||
end
|
||||
|
||||
def call(menu, option, function, *args)
|
||||
option_hash = @@handlers[menu][option]
|
||||
return nil if !option_hash || !option_hash[function]
|
||||
return option_hash[function].call(*args)
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module UIActionHandlers
|
||||
@@handlers = {}
|
||||
|
||||
module_function
|
||||
|
||||
def add(menu, action, hash)
|
||||
@@handlers[menu] = HandlerHash.new if !@@handlers.has_key?(menu)
|
||||
@@handlers[menu].add(action, hash)
|
||||
end
|
||||
|
||||
def remove(menu, action)
|
||||
@@handlers[menu]&.remove(action)
|
||||
end
|
||||
|
||||
def clear(menu)
|
||||
@@handlers[menu]&.clear
|
||||
end
|
||||
|
||||
def get(menu, action)
|
||||
return @@handlers[menu][action]
|
||||
end
|
||||
|
||||
def each(menu)
|
||||
return if !@@handlers.has_key?(menu)
|
||||
@@handlers[menu].each { |action, hash| yield action, hash }
|
||||
end
|
||||
end
|
||||
@@ -1,172 +0,0 @@
|
||||
#===============================================================================
|
||||
# This module stores events that can happen during the game. A procedure can
|
||||
# subscribe to an event by adding itself to the event. It will then be called
|
||||
# whenever the event occurs.
|
||||
#===============================================================================
|
||||
module Events
|
||||
@@OnMapCreate = Event.new
|
||||
@@OnMapUpdate = Event.new
|
||||
@@OnMapChange = Event.new
|
||||
@@OnMapChanging = Event.new
|
||||
@@OnMapSceneChange = Event.new
|
||||
@@OnSpritesetCreate = Event.new
|
||||
@@OnAction = Event.new
|
||||
@@OnStepTaken = Event.new
|
||||
@@OnLeaveTile = Event.new
|
||||
@@OnStepTakenFieldMovement = Event.new
|
||||
@@OnStepTakenTransferPossible = Event.new
|
||||
@@OnStartBattle = Event.new
|
||||
@@OnEndBattle = Event.new
|
||||
@@OnWildPokemonCreate = Event.new
|
||||
@@OnWildBattleOverride = Event.new
|
||||
@@OnWildBattleEnd = Event.new
|
||||
@@OnTrainerPartyLoad = Event.new
|
||||
@@OnChangeDirection = Event.new
|
||||
|
||||
# Fires whenever a map is created. Event handler receives two parameters: the
|
||||
# map (RPG::Map) and the tileset (RPG::Tileset)
|
||||
def self.onMapCreate; @@OnMapCreate; end
|
||||
def self.onMapCreate=(v); @@OnMapCreate = v; end
|
||||
|
||||
# Fires each frame during a map update.
|
||||
def self.onMapUpdate; @@OnMapUpdate; end
|
||||
def self.onMapUpdate=(v); @@OnMapUpdate = v; end
|
||||
|
||||
# Fires whenever one map is about to change to a different one. Event handler
|
||||
# receives the new map ID and the Game_Map object representing the new map.
|
||||
# When the event handler is called, $game_map still refers to the old map.
|
||||
def self.onMapChanging; @@OnMapChanging; end
|
||||
def self.onMapChanging=(v); @@OnMapChanging = v; end
|
||||
|
||||
# Fires whenever the player moves to a new map. Event handler receives the old
|
||||
# map ID or 0 if none. Also fires when the first map of the game is loaded
|
||||
def self.onMapChange; @@OnMapChange; end
|
||||
def self.onMapChange=(v); @@OnMapChange = v; end
|
||||
|
||||
# Fires whenever the map scene is regenerated and soon after the player moves
|
||||
# to a new map.
|
||||
# Parameters:
|
||||
# e[0] - Scene_Map object.
|
||||
# e[1] - Whether the player just moved to a new map (either true or false). If
|
||||
# false, some other code had called $scene.createSpritesets to
|
||||
# regenerate the map scene without transferring the player elsewhere
|
||||
def self.onMapSceneChange; @@OnMapSceneChange; end
|
||||
def self.onMapSceneChange=(v); @@OnMapSceneChange = v; end
|
||||
|
||||
# Fires whenever a spriteset is created.
|
||||
# Parameters:
|
||||
# e[0] - Spriteset being created. e[0].map is the map associated with the
|
||||
# spriteset (not necessarily the current map).
|
||||
# e[1] - Viewport used for tilemap and characters
|
||||
def self.onSpritesetCreate; @@OnSpritesetCreate; end
|
||||
def self.onSpritesetCreate=(v); @@OnSpritesetCreate = v; end
|
||||
|
||||
# Triggers when the player presses the Action button on the map.
|
||||
def self.onAction; @@OnAction; end
|
||||
def self.onAction=(v); @@OnAction = v; end
|
||||
|
||||
# Fires whenever the player takes a step.
|
||||
def self.onStepTaken; @@OnStepTaken; end
|
||||
def self.onStepTaken=(v); @@OnStepTaken = v; end
|
||||
|
||||
# Fires whenever the player or another event leaves a tile.
|
||||
# Parameters:
|
||||
# e[0] - Event that just left the tile.
|
||||
# e[1] - Map ID where the tile is located (not necessarily
|
||||
# the current map). Use "$MapFactory.getMap(e[1])" to
|
||||
# get the Game_Map object corresponding to that map.
|
||||
# e[2] - X-coordinate of the tile
|
||||
# e[3] - Y-coordinate of the tile
|
||||
def self.onLeaveTile; @@OnLeaveTile; end
|
||||
def self.onLeaveTile=(v); @@OnLeaveTile = v; end
|
||||
|
||||
# Fires whenever the player or another event enters a tile.
|
||||
# Parameters:
|
||||
# e[0] - Event that just entered a tile.
|
||||
def self.onStepTakenFieldMovement; @@OnStepTakenFieldMovement; end
|
||||
def self.onStepTakenFieldMovement=(v); @@OnStepTakenFieldMovement = v; end
|
||||
|
||||
# Fires whenever the player takes a step. The event handler may possibly move
|
||||
# the player elsewhere.
|
||||
# Parameters:
|
||||
# e[0] - Array that contains a single boolean value. If an event handler moves
|
||||
# the player to a new map, it should set this value to true. Other
|
||||
# event handlers should check this parameter's value.
|
||||
def self.onStepTakenTransferPossible; @@OnStepTakenTransferPossible; end
|
||||
def self.onStepTakenTransferPossible=(v); @@OnStepTakenTransferPossible = v; end
|
||||
|
||||
def self.onStartBattle; @@OnStartBattle; end
|
||||
def self.onStartBattle=(v); @@OnStartBattle = v; end
|
||||
|
||||
def self.onEndBattle; @@OnEndBattle; end
|
||||
def self.onEndBattle=(v); @@OnEndBattle = v; end
|
||||
|
||||
# Triggers whenever a wild Pokémon is created
|
||||
# Parameters:
|
||||
# e[0] - Pokémon being created
|
||||
def self.onWildPokemonCreate; @@OnWildPokemonCreate; end
|
||||
def self.onWildPokemonCreate=(v); @@OnWildPokemonCreate = v; end
|
||||
|
||||
# Triggers at the start of a wild battle. Event handlers can provide their
|
||||
# own wild battle routines to override the default behavior.
|
||||
def self.onWildBattleOverride; @@OnWildBattleOverride; end
|
||||
def self.onWildBattleOverride=(v); @@OnWildBattleOverride = v; end
|
||||
|
||||
# Triggers whenever a wild Pokémon battle ends
|
||||
# Parameters:
|
||||
# e[0] - Pokémon species
|
||||
# e[1] - Pokémon level
|
||||
# e[2] - Battle result (1-win, 2-loss, 3-escaped, 4-caught, 5-draw)
|
||||
def self.onWildBattleEnd; @@OnWildBattleEnd; end
|
||||
def self.onWildBattleEnd=(v); @@OnWildBattleEnd = v; end
|
||||
|
||||
# Triggers whenever an NPC trainer's Pokémon party is loaded
|
||||
# Parameters:
|
||||
# e[0] - Trainer
|
||||
# e[1] - Items possessed by the trainer
|
||||
# e[2] - Party
|
||||
def self.onTrainerPartyLoad; @@OnTrainerPartyLoad; end
|
||||
def self.onTrainerPartyLoad=(v); @@OnTrainerPartyLoad = v; end
|
||||
|
||||
# Fires whenever the player changes direction.
|
||||
def self.onChangeDirection; @@OnChangeDirection; end
|
||||
def self.onChangeDirection=(v); @@OnChangeDirection = v; end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
def pbOnSpritesetCreate(spriteset,viewport)
|
||||
Events.onSpritesetCreate.trigger(nil,spriteset,viewport)
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# This module stores encounter-modifying events that can happen during the game.
|
||||
# A procedure can subscribe to an event by adding itself to the event. It will
|
||||
# then be called whenever the event occurs.
|
||||
#===============================================================================
|
||||
module EncounterModifier
|
||||
@@procs = []
|
||||
@@procsEnd = []
|
||||
|
||||
def self.register(p)
|
||||
@@procs.push(p)
|
||||
end
|
||||
|
||||
def self.registerEncounterEnd(p)
|
||||
@@procsEnd.push(p)
|
||||
end
|
||||
|
||||
def self.trigger(encounter)
|
||||
for prc in @@procs
|
||||
encounter = prc.call(encounter)
|
||||
end
|
||||
return encounter
|
||||
end
|
||||
|
||||
def self.triggerEncounterEnd()
|
||||
for prc in @@procsEnd
|
||||
prc.call()
|
||||
end
|
||||
end
|
||||
end
|
||||
62
Data/Scripts/003_New_UI_Settings.rb
Normal file
62
Data/Scripts/003_New_UI_Settings.rb
Normal file
@@ -0,0 +1,62 @@
|
||||
#===============================================================================
|
||||
# NOTE: Some Settings in here will be moved elsewhere eventually. They're all
|
||||
# just gathered here while the new UI is being written.
|
||||
#===============================================================================
|
||||
module Settings
|
||||
# :one, :adventure, :multiple
|
||||
SAVE_SLOTS = :multiple
|
||||
|
||||
# Whether the main color of a move's name in the Fight menu in battle matches
|
||||
# the pixel at coordinate (10,34) in cursor_fight.png for that move's type
|
||||
# (true), or whether the move name's color is the default black (false).
|
||||
BATTLE_MOVE_NAME_COLOR_FROM_GRAPHIC = true
|
||||
|
||||
# Whether "Town Map" will show as an option in the pause menu if the player
|
||||
# has that item in the Bag and doesn't have a Pokégear.
|
||||
SHOW_TOWN_MAP_IN_PAUSE_MENU = true
|
||||
|
||||
# The filename of a location sign graphic to be used if the map metadata for a
|
||||
# map doesn't define one. Make this nil to use the default menu windowskin.
|
||||
DEFAULT_LOCATION_SIGN_GRAPHIC = "Pt default"
|
||||
# Assigns location sign graphics to text styles (numbers). These are used in
|
||||
# class LocationWindow to display the text appropriately for the graphic being
|
||||
# used. Style :none is reserved for the "no graphic" style. A filename may
|
||||
# instead be an array of [filename, text base color, text shadow color].
|
||||
LOCATION_SIGN_GRAPHIC_STYLES = {
|
||||
:dp => [["DP", Color.new(72, 80, 72), Color.new(144, 160, 160)]],
|
||||
:hgss => [["HGSS cave", Color.new(232, 232, 232), Color.new(120, 144, 160)],
|
||||
["HGSS city", Color.new(56, 64, 72), Color.new(152, 152, 144)],
|
||||
["HGSS default", Color.new(48, 64, 72), Color.new(144, 144, 96)],
|
||||
["HGSS forest", Color.new(232, 232, 232), Color.new(120, 176, 144)],
|
||||
["HGSS lake", Color.new(40, 48, 56), Color.new(104, 144, 192)],
|
||||
["HGSS park", Color.new(40, 48, 56), Color.new(120, 136, 152)],
|
||||
["HGSS route", Color.new(48, 64, 72), Color.new(136, 136, 104)],
|
||||
["HGSS sea", Color.new(216, 240, 248), Color.new(24, 96, 144)],
|
||||
["HGSS town", Color.new(48, 56, 64), Color.new(144, 120, 80)]],
|
||||
:platinum => ["Pt cave", "Pt city", "Pt default", "Pt forest", "Pt lake",
|
||||
"Pt park", "Pt route", "Pt sea", "Pt town"]
|
||||
}
|
||||
|
||||
# Whether a move's power/type/category/etc. as shown in battle, the summary
|
||||
# screen and the Move Reminder screen will appear as their calculated values
|
||||
# (true) or their values from the PBS file moves.txt (false). For example, if
|
||||
# this is true, Judgment's displayed type will depend on the Plate being held
|
||||
# by the Pokémon that knows it.
|
||||
SHOW_MODIFIED_MOVE_PROPERTIES = false
|
||||
|
||||
# Whether pressing Use in the Town Map will zoom it in to 200% and show a text
|
||||
# pane on the right showing the selected point's description. The cursor can
|
||||
# still be moved while zoomed in.
|
||||
ENABLE_TOWN_MAP_ZOOM_IN_FOR_DETAILS = true
|
||||
# Whether points in the Town Map can be marked.
|
||||
ENABLE_TOWN_MAP_MARKING = true
|
||||
|
||||
# TODO: Allow renaming a Pokémon from the party screen/summary screen (not
|
||||
# sure which). Gen 9 feature.
|
||||
# TODO: Allow forgetting/remembering moves from the summary screen. Gen 9
|
||||
# feature.
|
||||
# TODO: Show usability party balls in the Bag. Maybe?
|
||||
# TODO: Replace Run with Call in battle; don't have this depend on the Shadow
|
||||
# type existing?
|
||||
# TODO: Whether new items go at the top or bottom of its Bag pocket?
|
||||
end
|
||||
@@ -4,11 +4,7 @@
|
||||
# This class handles screen maintenance data, such as change in color tone,
|
||||
# flashing, etc. Refer to "$game_screen" for the instance of this class.
|
||||
#===============================================================================
|
||||
|
||||
class Game_Screen
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Public Instance Variables
|
||||
#-----------------------------------------------------------------------------
|
||||
attr_reader :brightness # brightness
|
||||
attr_reader :tone # color tone
|
||||
attr_reader :flash_color # flash color
|
||||
@@ -17,120 +13,106 @@ class Game_Screen
|
||||
attr_reader :weather_type # weather type
|
||||
attr_reader :weather_max # max number of weather sprites
|
||||
attr_accessor :weather_duration # ticks in which the weather should fade in
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Object Initialization
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def initialize
|
||||
@brightness = 255
|
||||
@fadeout_duration = 0
|
||||
@fadein_duration = 0
|
||||
@tone = Tone.new(0, 0, 0, 0)
|
||||
@tone_target = Tone.new(0, 0, 0, 0)
|
||||
@tone_duration = 0
|
||||
@flash_color = Color.new(0, 0, 0, 0)
|
||||
@flash_duration = 0
|
||||
@shake_power = 0
|
||||
@shake_speed = 0
|
||||
@shake_duration = 0
|
||||
@shake_direction = 1
|
||||
@shake = 0
|
||||
@pictures = [nil]
|
||||
for i in 1..100
|
||||
@pictures.push(Game_Picture.new(i))
|
||||
end
|
||||
@weather_type = 0
|
||||
@weather_max = 0.0
|
||||
@weather_duration = 0
|
||||
@brightness = 255
|
||||
@tone = Tone.new(0, 0, 0, 0)
|
||||
@tone_target = Tone.new(0, 0, 0, 0)
|
||||
@tone_duration = 0
|
||||
@tone_timer_start = nil
|
||||
@flash_color = Color.new(0, 0, 0, 0)
|
||||
@flash_duration = 0
|
||||
@flash_timer_start = nil
|
||||
@shake_power = 0
|
||||
@shake_speed = 0
|
||||
@shake_duration = 0
|
||||
@shake = 0
|
||||
@pictures = [nil]
|
||||
(1..100).each { |i| @pictures.push(Game_Picture.new(i)) }
|
||||
@weather_type = :None
|
||||
@weather_max = 0.0
|
||||
@weather_duration = 0
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Start Changing Color Tone
|
||||
# tone : color tone
|
||||
# duration : time
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# duration is time in 1/20ths of a second.
|
||||
def start_tone_change(tone, duration)
|
||||
@tone_target = tone.clone
|
||||
@tone_duration = duration
|
||||
if @tone_duration == 0
|
||||
@tone = @tone_target.clone
|
||||
if duration == 0
|
||||
@tone = tone.clone
|
||||
return
|
||||
end
|
||||
@tone_initial = @tone.clone
|
||||
@tone_target = tone.clone
|
||||
@tone_duration = duration / 20.0
|
||||
@tone_timer_start = $stats.play_time
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Start Flashing
|
||||
# color : color
|
||||
# duration : time
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# duration is time in 1/20ths of a second.
|
||||
def start_flash(color, duration)
|
||||
@flash_color = color.clone
|
||||
@flash_duration = duration
|
||||
@flash_color = color.clone
|
||||
@flash_initial_alpha = @flash_color.alpha
|
||||
@flash_duration = duration / 20.0
|
||||
@flash_timer_start = $stats.play_time
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Start Shaking
|
||||
# power : strength
|
||||
# speed : speed
|
||||
# duration : time
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# duration is time in 1/20ths of a second.
|
||||
def start_shake(power, speed, duration)
|
||||
@shake_power = power
|
||||
@shake_speed = speed
|
||||
@shake_duration = duration
|
||||
@shake_power = power
|
||||
@shake_speed = speed
|
||||
@shake_duration = duration / 20.0
|
||||
@shake_timer_start = $stats.play_time
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Set Weather
|
||||
# type : type
|
||||
# power : strength
|
||||
# duration : time
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# duration is time in 1/20ths of a second.
|
||||
def weather(type, power, duration)
|
||||
@weather_type = GameData::Weather.get(type).id
|
||||
@weather_max = (power + 1) * RPG::Weather::MAX_SPRITES / 10
|
||||
@weather_duration = duration # In 1/20ths of a seconds
|
||||
@weather_duration = duration
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Frame Update
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def update
|
||||
if @fadeout_duration && @fadeout_duration>=1
|
||||
d = @fadeout_duration
|
||||
@brightness = (@brightness*(d-1))/d
|
||||
@fadeout_duration -= 1
|
||||
end
|
||||
if @fadein_duration && @fadein_duration>=1
|
||||
d = @fadein_duration
|
||||
@brightness = (@brightness*(d-1)+255)/d
|
||||
@fadein_duration -= 1
|
||||
end
|
||||
if @tone_duration>=1
|
||||
d = @tone_duration
|
||||
@tone.red = (@tone.red*(d-1)+@tone_target.red)/d
|
||||
@tone.green = (@tone.green*(d-1)+@tone_target.green)/d
|
||||
@tone.blue = (@tone.blue*(d-1)+@tone_target.blue)/d
|
||||
@tone.gray = (@tone.gray*(d-1)+@tone_target.gray)/d
|
||||
@tone_duration -= 1
|
||||
end
|
||||
if @flash_duration>=1
|
||||
d = @flash_duration
|
||||
@flash_color.alpha = @flash_color.alpha*(d-1)/d
|
||||
@flash_duration -= 1
|
||||
end
|
||||
if @shake_duration>=1 || @shake!=0
|
||||
delta = (@shake_power*@shake_speed*@shake_direction)/10.0
|
||||
if @shake_duration<=1 && @shake*(@shake+delta)<0
|
||||
@shake = 0
|
||||
else
|
||||
@shake += delta
|
||||
now = $stats.play_time
|
||||
if @tone_timer_start
|
||||
@tone.red = lerp(@tone_initial.red, @tone_target.red, @tone_duration, @tone_timer_start, now)
|
||||
@tone.green = lerp(@tone_initial.green, @tone_target.green, @tone_duration, @tone_timer_start, now)
|
||||
@tone.blue = lerp(@tone_initial.blue, @tone_target.blue, @tone_duration, @tone_timer_start, now)
|
||||
@tone.gray = lerp(@tone_initial.gray, @tone_target.gray, @tone_duration, @tone_timer_start, now)
|
||||
if now - @tone_timer_start >= @tone_duration
|
||||
@tone_initial = nil
|
||||
@tone_timer_start = nil
|
||||
end
|
||||
end
|
||||
if @flash_timer_start
|
||||
@flash_color.alpha = lerp(@flash_initial_alpha, 0, @flash_duration, @flash_timer_start, now)
|
||||
if now - @flash_timer_start >= @flash_duration
|
||||
@flash_initial_alpha = nil
|
||||
@flash_timer_start = nil
|
||||
end
|
||||
end
|
||||
if @shake_timer_start
|
||||
delta_t = now - @shake_timer_start
|
||||
movement_per_second = @shake_power * @shake_speed * 4
|
||||
limit = @shake_power * 2.5 # Maximum pixel displacement
|
||||
phase = (delta_t * movement_per_second / limit).to_i % 4
|
||||
case phase
|
||||
when 0, 2
|
||||
@shake = (movement_per_second * delta_t) % limit
|
||||
@shake *= -1 if phase == 2
|
||||
else
|
||||
@shake = limit - ((movement_per_second * delta_t) % limit)
|
||||
@shake *= -1 if phase == 3
|
||||
end
|
||||
if delta_t >= @shake_duration
|
||||
@shake_phase = phase if !@shake_phase || phase == 1 || phase == 3
|
||||
if phase != @shake_phase || @shake < 2
|
||||
@shake_timer_start = nil
|
||||
@shake = 0
|
||||
end
|
||||
end
|
||||
@shake_direction = -1 if @shake>@shake_power*2
|
||||
@shake_direction = 1 if @shake<-@shake_power*2
|
||||
@shake_duration -= 1 if @shake_duration>=1
|
||||
end
|
||||
if $game_temp.in_battle
|
||||
for i in 51..100
|
||||
@pictures[i].update
|
||||
end
|
||||
(51..100).each { |i| @pictures[i].update }
|
||||
else
|
||||
for i in 1..50
|
||||
@pictures[i].update
|
||||
end
|
||||
(1..50).each { |i| @pictures[i].update }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -138,17 +120,15 @@ end
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
def pbToneChangeAll(tone,duration)
|
||||
$game_screen.start_tone_change(tone,duration*Graphics.frame_rate/20)
|
||||
for picture in $game_screen.pictures
|
||||
picture.start_tone_change(tone,duration*Graphics.frame_rate/20) if picture
|
||||
end
|
||||
def pbToneChangeAll(tone, duration)
|
||||
$game_screen.start_tone_change(tone, duration)
|
||||
$game_screen.pictures.each { |picture| picture&.start_tone_change(tone, duration) }
|
||||
end
|
||||
|
||||
def pbShake(power,speed,frames)
|
||||
$game_screen.start_shake(power,speed,frames*Graphics.frame_rate/20)
|
||||
def pbFlash(color, frames)
|
||||
$game_screen.start_flash(color, frames)
|
||||
end
|
||||
|
||||
def pbFlash(color,frames)
|
||||
$game_screen.start_flash(color,frames*Graphics.frame_rate/20)
|
||||
def pbShake(power, speed, frames)
|
||||
$game_screen.start_shake(power, speed, frames)
|
||||
end
|
||||
|
||||
@@ -5,51 +5,83 @@
|
||||
# Refer to "$game_temp" for the instance of this class.
|
||||
#===============================================================================
|
||||
class Game_Temp
|
||||
attr_accessor :message_window_showing # message window showing
|
||||
attr_accessor :common_event_id # common event ID
|
||||
attr_accessor :in_battle # in-battle flag
|
||||
attr_accessor :battle_abort # battle flag: interrupt
|
||||
attr_accessor :battleback_name # battleback file name
|
||||
attr_accessor :in_menu # menu is open
|
||||
attr_accessor :menu_beep # menu: play sound effect flag
|
||||
# Flags requesting something to happen
|
||||
attr_accessor :menu_calling # menu calling flag
|
||||
attr_accessor :ready_menu_calling # ready menu calling flag
|
||||
attr_accessor :debug_calling # debug calling flag
|
||||
attr_accessor :interact_calling # EventHandlers.trigger(:on_player_interact) flag
|
||||
attr_accessor :battle_abort # battle flag: interrupt (unused)
|
||||
attr_accessor :title_screen_calling # return to title screen flag
|
||||
attr_accessor :common_event_id # common event ID to start
|
||||
attr_accessor :field_move_to_use
|
||||
attr_accessor :field_move_user
|
||||
# Flags indicating something is happening
|
||||
attr_accessor :in_menu # menu is open
|
||||
attr_accessor :in_storage # in-Pokémon storage flag
|
||||
attr_accessor :in_battle # in-battle flag
|
||||
attr_accessor :message_window_showing # message window showing
|
||||
attr_accessor :ending_surf # jumping off surf base flag
|
||||
attr_accessor :surf_base_coords # [x, y] while jumping on/off, or nil
|
||||
attr_accessor :in_mini_update # performing mini update flag
|
||||
# Battle
|
||||
attr_accessor :battleback_name # battleback file name
|
||||
attr_accessor :force_single_battle # force next battle to be 1v1 flag
|
||||
attr_accessor :waiting_trainer # [trainer, event ID] or nil
|
||||
attr_accessor :last_battle_record # record of actions in last recorded battle
|
||||
# Overrides transfers
|
||||
attr_accessor :player_transferring # player place movement flag
|
||||
attr_accessor :player_new_map_id # player destination: map ID
|
||||
attr_accessor :player_new_x # player destination: x-coordinate
|
||||
attr_accessor :player_new_y # player destination: y-coordinate
|
||||
attr_accessor :player_new_direction # player destination: direction
|
||||
attr_accessor :fly_destination # [map ID, x, y] or nil
|
||||
# Transitions
|
||||
attr_accessor :transition_processing # transition processing flag
|
||||
attr_accessor :transition_name # transition file name
|
||||
attr_accessor :to_title # return to title screen flag
|
||||
attr_accessor :fadestate # for sprite hashes
|
||||
attr_accessor :background_bitmap
|
||||
attr_accessor :fadestate # for sprite hashes
|
||||
# Other
|
||||
attr_accessor :menu_beep # menu: play sound effect flag
|
||||
attr_accessor :menu_last_choice # pause menu: index of last selection
|
||||
attr_accessor :memorized_bgm # set when trainer intro BGM is played
|
||||
attr_accessor :memorized_bgm_position # set when trainer intro BGM is played
|
||||
attr_accessor :darkness_sprite # DarknessSprite or nil
|
||||
attr_accessor :mart_prices
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Object Initialization
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def initialize
|
||||
@message_window_showing = false
|
||||
@common_event_id = 0
|
||||
@in_battle = false
|
||||
@battle_abort = false
|
||||
@battleback_name = ''
|
||||
@in_menu = false
|
||||
@menu_beep = false
|
||||
# Flags requesting something to happen
|
||||
@menu_calling = false
|
||||
@ready_menu_calling = false
|
||||
@debug_calling = false
|
||||
@interact_calling = false
|
||||
@battle_abort = false
|
||||
@title_screen_calling = false
|
||||
@common_event_id = 0
|
||||
# Flags indicating something is happening
|
||||
@in_menu = false
|
||||
@in_storage = false
|
||||
@in_battle = false
|
||||
@message_window_showing = false
|
||||
@ending_surf = false
|
||||
@in_mini_update = false
|
||||
# Battle
|
||||
@battleback_name = ""
|
||||
@force_single_battle = false
|
||||
# Overrides transfers
|
||||
@player_transferring = false
|
||||
@player_new_map_id = 0
|
||||
@player_new_x = 0
|
||||
@player_new_y = 0
|
||||
@player_new_direction = 0
|
||||
# Transitions
|
||||
@transition_processing = false
|
||||
@transition_name = ""
|
||||
@to_title = false
|
||||
@fadestate = 0
|
||||
@background_bitmap = nil
|
||||
@message_window_showing = false
|
||||
@transition_processing = false
|
||||
# Other
|
||||
@menu_beep = false
|
||||
@memorized_bgm = nil
|
||||
@memorized_bgm_position = 0
|
||||
@menu_last_choice = 0
|
||||
@mart_prices = {}
|
||||
end
|
||||
|
||||
|
||||
@@ -5,25 +5,20 @@
|
||||
# Refer to "$game_switches" for the instance of this class.
|
||||
#===============================================================================
|
||||
class Game_Switches
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Object Initialization
|
||||
#-----------------------------------------------------------------------------
|
||||
def initialize
|
||||
@data = []
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Get Switch
|
||||
|
||||
# Get Switch
|
||||
# switch_id : switch ID
|
||||
#-----------------------------------------------------------------------------
|
||||
def [](switch_id)
|
||||
return @data[switch_id] if switch_id <= 5000 && @data[switch_id] != nil
|
||||
return @data[switch_id] if switch_id <= 5000 && @data[switch_id]
|
||||
return false
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Set Switch
|
||||
|
||||
# Set Switch
|
||||
# switch_id : switch ID
|
||||
# value : ON (true) / OFF (false)
|
||||
#-----------------------------------------------------------------------------
|
||||
def []=(switch_id, value)
|
||||
@data[switch_id] = value if switch_id <= 5000
|
||||
end
|
||||
|
||||
@@ -5,25 +5,20 @@
|
||||
# Refer to "$game_variables" for the instance of this class.
|
||||
#===============================================================================
|
||||
class Game_Variables
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Object Initialization
|
||||
#-----------------------------------------------------------------------------
|
||||
def initialize
|
||||
@data = []
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Get Variable
|
||||
|
||||
# Get Variable
|
||||
# variable_id : variable ID
|
||||
#-----------------------------------------------------------------------------
|
||||
def [](variable_id)
|
||||
return @data[variable_id] if variable_id <= 5000 && !@data[variable_id].nil?
|
||||
return 0
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Set Variable
|
||||
|
||||
# Set Variable
|
||||
# variable_id : variable ID
|
||||
# value : the variable's value
|
||||
#-----------------------------------------------------------------------------
|
||||
def []=(variable_id, value)
|
||||
@data[variable_id] = value if variable_id <= 5000
|
||||
end
|
||||
|
||||
@@ -5,24 +5,19 @@
|
||||
# "Hash." Refer to "$game_self_switches" for the instance of this class.
|
||||
#===============================================================================
|
||||
class Game_SelfSwitches
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Object Initialization
|
||||
#-----------------------------------------------------------------------------
|
||||
def initialize
|
||||
@data = {}
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Get Self Switch
|
||||
|
||||
# Get Self Switch
|
||||
# key : key
|
||||
#-----------------------------------------------------------------------------
|
||||
def [](key)
|
||||
return (@data[key]==true) ? true : false
|
||||
return @data[key] == true
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Set Self Switch
|
||||
|
||||
# Set Self Switch
|
||||
# key : key
|
||||
# value : ON (true) / OFF (false)
|
||||
#-----------------------------------------------------------------------------
|
||||
def []=(key, value)
|
||||
@data[key] = value
|
||||
end
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
#==============================================================================
|
||||
#===============================================================================
|
||||
# ** Game_System
|
||||
#------------------------------------------------------------------------------
|
||||
# This class handles data surrounding the system. Backround music, etc.
|
||||
# is managed here as well. Refer to "$game_system" for the instance of
|
||||
# this class.
|
||||
#==============================================================================
|
||||
#===============================================================================
|
||||
class Game_System
|
||||
attr_reader :map_interpreter # map event interpreter
|
||||
attr_reader :battle_interpreter # battle event interpreter
|
||||
attr_accessor :timer # timer
|
||||
attr_accessor :timer_working # timer working flag
|
||||
attr_accessor :timer_start # $stats.play_time when timer was started, or nil
|
||||
attr_accessor :timer_duration # Time (in seconds) the timer is initially set to
|
||||
attr_accessor :save_disabled # save forbidden
|
||||
attr_accessor :menu_disabled # menu forbidden
|
||||
attr_accessor :encounter_disabled # encounter forbidden
|
||||
@@ -22,66 +22,99 @@ class Game_System
|
||||
attr_accessor :bgm_position
|
||||
|
||||
def initialize
|
||||
@map_interpreter = Interpreter.new(0, true)
|
||||
@battle_interpreter = Interpreter.new(0, false)
|
||||
@timer = 0
|
||||
@timer_working = false
|
||||
@save_disabled = false
|
||||
@menu_disabled = false
|
||||
@encounter_disabled = false
|
||||
@message_position = 2
|
||||
@message_frame = 0
|
||||
@save_count = 0
|
||||
@magic_number = 0
|
||||
@autoscroll_x_speed = 0
|
||||
@autoscroll_y_speed = 0
|
||||
@bgm_position = 0
|
||||
@bgs_position = 0
|
||||
@map_interpreter = Interpreter.new(0, true)
|
||||
@battle_interpreter = Interpreter.new(0, false)
|
||||
@timer_start = nil
|
||||
@timer_duration = 0
|
||||
@save_disabled = false
|
||||
@menu_disabled = false
|
||||
@encounter_disabled = false
|
||||
@message_position = 2
|
||||
@message_frame = 0
|
||||
@save_count = 0
|
||||
@magic_number = 0
|
||||
@adventure_magic_number = rand(2**32)
|
||||
@autoscroll_x_speed = 0
|
||||
@autoscroll_y_speed = 0
|
||||
@bgm_position = 0
|
||||
@bgs_position = 0
|
||||
end
|
||||
|
||||
################################################################################
|
||||
def adventure_magic_number
|
||||
@adventure_magic_number ||= rand(2**32)
|
||||
return @adventure_magic_number
|
||||
end
|
||||
|
||||
def bgm_play(bgm)
|
||||
def battle_bgm
|
||||
return (@battle_bgm) ? @battle_bgm : $data_system.battle_bgm
|
||||
end
|
||||
|
||||
attr_writer :battle_bgm
|
||||
|
||||
def battle_end_me
|
||||
return (@battle_end_me) ? @battle_end_me : $data_system.battle_end_me
|
||||
end
|
||||
|
||||
attr_writer :battle_end_me
|
||||
|
||||
def windowskin_name
|
||||
return $data_system.windowskin_name if @windowskin_name.nil?
|
||||
return @windowskin_name
|
||||
end
|
||||
|
||||
attr_writer :windowskin_name
|
||||
|
||||
def timer
|
||||
return 0 if !@timer_start || !$stats
|
||||
return @timer_duration - $stats.play_time + @timer_start
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def bgm_play(bgm, track = nil)
|
||||
old_pos = @bgm_position
|
||||
@bgm_position = 0
|
||||
bgm_play_internal(bgm,0)
|
||||
bgm_play_internal(bgm, 0, track)
|
||||
@bgm_position = old_pos
|
||||
end
|
||||
|
||||
def bgm_play_internal2(name,volume,pitch,position) # :nodoc:
|
||||
def bgm_play_internal2(name, volume, pitch, position, track = nil) # :nodoc:
|
||||
vol = volume
|
||||
vol *= $PokemonSystem.bgmvolume/100.0
|
||||
vol *= $PokemonSystem.bgmvolume / 100.0
|
||||
vol = vol.to_i
|
||||
begin
|
||||
Audio.bgm_play(name,vol,pitch,position)
|
||||
Audio.bgm_play(name, vol, pitch, position, track)
|
||||
rescue ArgumentError
|
||||
Audio.bgm_play(name,vol,pitch)
|
||||
Audio.bgm_play(name, vol, pitch, 0, track)
|
||||
end
|
||||
end
|
||||
|
||||
def bgm_play_internal(bgm,position) # :nodoc:
|
||||
@bgm_position = position if !@bgm_paused
|
||||
@playing_bgm = (bgm==nil) ? nil : bgm.clone
|
||||
if bgm!=nil && bgm.name!=""
|
||||
if FileTest.audio_exist?("Audio/BGM/"+bgm.name)
|
||||
bgm_play_internal2("Audio/BGM/"+bgm.name,
|
||||
bgm.volume,bgm.pitch,@bgm_position) if !@defaultBGM
|
||||
def bgm_play_internal(bgm, position, track = nil) # :nodoc:
|
||||
if !track || track == 0
|
||||
@bgm_position = position if !@bgm_paused
|
||||
@playing_bgm = bgm&.clone
|
||||
end
|
||||
if bgm && bgm.name != ""
|
||||
if !@defaultBGM && FileTest.audio_exist?("Audio/BGM/" + bgm.name)
|
||||
bgm_play_internal2("Audio/BGM/" + bgm.name, bgm.volume, bgm.pitch, @bgm_position, track)
|
||||
end
|
||||
else
|
||||
@bgm_position = position if !@bgm_paused
|
||||
@playing_bgm = nil
|
||||
Audio.bgm_stop if !@defaultBGM
|
||||
if !track || track == 0
|
||||
@bgm_position = position if !@bgm_paused
|
||||
@playing_bgm = nil
|
||||
end
|
||||
Audio.bgm_stop(track) if !@defaultBGM
|
||||
end
|
||||
if @defaultBGM
|
||||
bgm_play_internal2("Audio/BGM/"+@defaultBGM.name,
|
||||
@defaultBGM.volume,@defaultBGM.pitch,@bgm_position)
|
||||
bgm_play_internal2("Audio/BGM/" + @defaultBGM.name,
|
||||
@defaultBGM.volume, @defaultBGM.pitch, @bgm_position, track)
|
||||
end
|
||||
Graphics.frame_reset
|
||||
end
|
||||
|
||||
def bgm_pause(fadetime=0.0) # :nodoc:
|
||||
def bgm_pause(fadetime = 0.0) # :nodoc:
|
||||
pos = Audio.bgm_pos rescue 0
|
||||
self.bgm_fade(fadetime) if fadetime>0.0
|
||||
self.bgm_fade(fadetime) if fadetime > 0.0
|
||||
@bgm_position = pos
|
||||
@bgm_paused = true
|
||||
end
|
||||
@@ -93,22 +126,26 @@ class Game_System
|
||||
|
||||
def bgm_resume(bgm) # :nodoc:
|
||||
if @bgm_paused
|
||||
self.bgm_play_internal(bgm,@bgm_position)
|
||||
self.bgm_play_internal(bgm, @bgm_position)
|
||||
@bgm_position = 0
|
||||
@bgm_paused = false
|
||||
end
|
||||
end
|
||||
|
||||
def bgm_stop # :nodoc:
|
||||
@bgm_position = 0 if !@bgm_paused
|
||||
@playing_bgm = nil
|
||||
Audio.bgm_stop if !@defaultBGM
|
||||
def bgm_stop(track = nil) # :nodoc:
|
||||
if !track || track == 0
|
||||
@bgm_position = 0 if !@bgm_paused
|
||||
@playing_bgm = nil
|
||||
end
|
||||
Audio.bgm_stop(track) if !@defaultBGM
|
||||
end
|
||||
|
||||
def bgm_fade(time) # :nodoc:
|
||||
@bgm_position = 0 if !@bgm_paused
|
||||
@playing_bgm = nil
|
||||
Audio.bgm_fade((time*1000).floor) if !@defaultBGM
|
||||
def bgm_fade(time, track = nil) # :nodoc:
|
||||
if !track || track == 0
|
||||
@bgm_position = 0 if !@bgm_paused
|
||||
@playing_bgm = nil
|
||||
end
|
||||
Audio.bgm_fade((time * 1000).floor, track) if !@defaultBGM
|
||||
end
|
||||
|
||||
def playing_bgm
|
||||
@@ -130,28 +167,27 @@ class Game_System
|
||||
return (@playing_bgm) ? @playing_bgm.clone : nil
|
||||
end
|
||||
|
||||
def setDefaultBGM(bgm,volume=80,pitch=100)
|
||||
bgm = RPG::AudioFile.new(bgm,volume,pitch) if bgm.is_a?(String)
|
||||
if bgm!=nil && bgm.name!=""
|
||||
@defaultBGM = nil
|
||||
def setDefaultBGM(bgm, volume = 80, pitch = 100)
|
||||
bgm = RPG::AudioFile.new(bgm, volume, pitch) if bgm.is_a?(String)
|
||||
@defaultBGM = nil
|
||||
if bgm && bgm.name != ""
|
||||
self.bgm_play(bgm)
|
||||
@defaultBGM = bgm.clone
|
||||
else
|
||||
@defaultBGM = nil
|
||||
self.bgm_play(@playing_bgm)
|
||||
end
|
||||
end
|
||||
|
||||
################################################################################
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def me_play(me)
|
||||
me = RPG::AudioFile.new(me) if me.is_a?(String)
|
||||
if me!=nil && me.name!=""
|
||||
if FileTest.audio_exist?("Audio/ME/"+me.name)
|
||||
if me && me.name != ""
|
||||
if FileTest.audio_exist?("Audio/ME/" + me.name)
|
||||
vol = me.volume
|
||||
vol *= $PokemonSystem.bgmvolume/100.0
|
||||
vol *= $PokemonSystem.bgmvolume / 100.0
|
||||
vol = vol.to_i
|
||||
Audio.me_play("Audio/ME/"+me.name,vol,me.pitch)
|
||||
Audio.me_play("Audio/ME/" + me.name, vol, me.pitch)
|
||||
end
|
||||
else
|
||||
Audio.me_stop
|
||||
@@ -159,16 +195,16 @@ class Game_System
|
||||
Graphics.frame_reset
|
||||
end
|
||||
|
||||
################################################################################
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def bgs_play(bgs)
|
||||
@playing_bgs = (bgs==nil) ? nil : bgs.clone
|
||||
if bgs!=nil && bgs.name!=""
|
||||
if FileTest.audio_exist?("Audio/BGS/"+bgs.name)
|
||||
@playing_bgs = (bgs.nil?) ? nil : bgs.clone
|
||||
if bgs && bgs.name != ""
|
||||
if FileTest.audio_exist?("Audio/BGS/" + bgs.name)
|
||||
vol = bgs.volume
|
||||
vol *= $PokemonSystem.sevolume/100.0
|
||||
vol *= $PokemonSystem.sevolume / 100.0
|
||||
vol = vol.to_i
|
||||
Audio.bgs_play("Audio/BGS/"+bgs.name,vol,bgs.pitch)
|
||||
Audio.bgs_play("Audio/BGS/" + bgs.name, vol, bgs.pitch)
|
||||
end
|
||||
else
|
||||
@bgs_position = 0
|
||||
@@ -178,8 +214,8 @@ class Game_System
|
||||
Graphics.frame_reset
|
||||
end
|
||||
|
||||
def bgs_pause(fadetime=0.0) # :nodoc:
|
||||
if fadetime>0.0
|
||||
def bgs_pause(fadetime = 0.0) # :nodoc:
|
||||
if fadetime > 0.0
|
||||
self.bgs_fade(fadetime)
|
||||
else
|
||||
self.bgs_stop
|
||||
@@ -207,7 +243,7 @@ class Game_System
|
||||
def bgs_fade(time)
|
||||
@bgs_position = 0
|
||||
@playing_bgs = nil
|
||||
Audio.bgs_fade((time*1000).floor)
|
||||
Audio.bgs_fade((time * 1000).floor)
|
||||
end
|
||||
|
||||
def playing_bgs
|
||||
@@ -226,15 +262,15 @@ class Game_System
|
||||
return (@playing_bgs) ? @playing_bgs.clone : nil
|
||||
end
|
||||
|
||||
################################################################################
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def se_play(se)
|
||||
se = RPG::AudioFile.new(se) if se.is_a?(String)
|
||||
if se!=nil && se.name!="" && FileTest.audio_exist?("Audio/SE/"+se.name)
|
||||
if se && se.name != "" && FileTest.audio_exist?("Audio/SE/" + se.name)
|
||||
vol = se.volume
|
||||
vol *= $PokemonSystem.sevolume/100.0
|
||||
vol *= $PokemonSystem.sevolume / 100.0
|
||||
vol = vol.to_i
|
||||
Audio.se_play("Audio/SE/"+se.name,vol,se.pitch)
|
||||
Audio.se_play("Audio/SE/" + se.name, vol, se.pitch)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -242,43 +278,12 @@ class Game_System
|
||||
Audio.se_stop
|
||||
end
|
||||
|
||||
################################################################################
|
||||
|
||||
def battle_bgm
|
||||
return (@battle_bgm) ? @battle_bgm : $data_system.battle_bgm
|
||||
end
|
||||
|
||||
def battle_bgm=(battle_bgm)
|
||||
@battle_bgm = battle_bgm
|
||||
end
|
||||
|
||||
def battle_end_me
|
||||
return (@battle_end_me) ? @battle_end_me : $data_system.battle_end_me
|
||||
end
|
||||
|
||||
def battle_end_me=(battle_end_me)
|
||||
@battle_end_me = battle_end_me
|
||||
end
|
||||
|
||||
################################################################################
|
||||
|
||||
def windowskin_name
|
||||
if @windowskin_name==nil
|
||||
return $data_system.windowskin_name
|
||||
else
|
||||
return @windowskin_name
|
||||
end
|
||||
end
|
||||
|
||||
def windowskin_name=(windowskin_name)
|
||||
@windowskin_name = windowskin_name
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def update
|
||||
@timer -= 1 if @timer_working && @timer>0
|
||||
if Input.trigger?(Input::SPECIAL) && pbCurrentEventCommentInput(1,"Cut Scene")
|
||||
event = @map_interpreter.get_character(0)
|
||||
@map_interpreter.pbSetSelfSwitch(event.id,"A",true)
|
||||
if Input.trigger?(Input::SPECIAL) && pbCurrentEventCommentInput(1, "Cut Scene")
|
||||
event = @map_interpreter.get_self
|
||||
@map_interpreter.pbSetSelfSwitch(event.id, "A", true)
|
||||
@map_interpreter.command_end
|
||||
event.start
|
||||
end
|
||||
|
||||
@@ -4,11 +4,7 @@
|
||||
# This class handles the picture. It's used within the Game_Screen class
|
||||
# ($game_screen).
|
||||
#===============================================================================
|
||||
|
||||
class Game_Picture
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Public Instance Variables
|
||||
#-----------------------------------------------------------------------------
|
||||
attr_reader :number # picture number
|
||||
attr_reader :name # file name
|
||||
attr_reader :origin # starting point
|
||||
@@ -20,10 +16,7 @@ class Game_Picture
|
||||
attr_reader :blend_type # blend method
|
||||
attr_reader :tone # color tone
|
||||
attr_reader :angle # rotation angle
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Object Initialization
|
||||
# number : picture number
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def initialize(number)
|
||||
@number = number
|
||||
@name = ""
|
||||
@@ -35,6 +28,7 @@ class Game_Picture
|
||||
@opacity = 255.0
|
||||
@blend_type = 1
|
||||
@duration = 0
|
||||
@move_timer_start = nil
|
||||
@target_x = @x
|
||||
@target_y = @y
|
||||
@target_zoom_x = @zoom_x
|
||||
@@ -43,11 +37,12 @@ class Game_Picture
|
||||
@tone = Tone.new(0, 0, 0, 0)
|
||||
@tone_target = Tone.new(0, 0, 0, 0)
|
||||
@tone_duration = 0
|
||||
@tone_timer_start = nil
|
||||
@angle = 0
|
||||
@rotate_speed = 0
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Show Picture
|
||||
|
||||
# Show Picture
|
||||
# name : file name
|
||||
# origin : starting point
|
||||
# x : x-coordinate
|
||||
@@ -56,7 +51,6 @@ class Game_Picture
|
||||
# zoom_y : y directional zoom rate
|
||||
# opacity : opacity level
|
||||
# blend_type : blend method
|
||||
#-----------------------------------------------------------------------------
|
||||
def show(name, origin, x, y, zoom_x, zoom_y, opacity, blend_type)
|
||||
@name = name
|
||||
@origin = origin
|
||||
@@ -65,7 +59,7 @@ class Game_Picture
|
||||
@zoom_x = zoom_x.to_f
|
||||
@zoom_y = zoom_y.to_f
|
||||
@opacity = opacity.to_f
|
||||
@blend_type = blend_type ? blend_type : 0
|
||||
@blend_type = blend_type || 0
|
||||
@duration = 0
|
||||
@target_x = @x
|
||||
@target_y = @y
|
||||
@@ -75,12 +69,13 @@ class Game_Picture
|
||||
@tone = Tone.new(0, 0, 0, 0)
|
||||
@tone_target = Tone.new(0, 0, 0, 0)
|
||||
@tone_duration = 0
|
||||
@tone_timer_start = nil
|
||||
@angle = 0
|
||||
@rotate_speed = 0
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Move Picture
|
||||
# duration : time
|
||||
|
||||
# Move Picture
|
||||
# duration : time in 1/20ths of a second
|
||||
# origin : starting point
|
||||
# x : x-coordinate
|
||||
# y : y-coordinate
|
||||
@@ -88,65 +83,80 @@ class Game_Picture
|
||||
# zoom_y : y directional zoom rate
|
||||
# opacity : opacity level
|
||||
# blend_type : blend method
|
||||
#-----------------------------------------------------------------------------
|
||||
def move(duration, origin, x, y, zoom_x, zoom_y, opacity, blend_type)
|
||||
@duration = duration
|
||||
@origin = origin
|
||||
@target_x = x.to_f
|
||||
@target_y = y.to_f
|
||||
@target_zoom_x = zoom_x.to_f
|
||||
@target_zoom_y = zoom_y.to_f
|
||||
@target_opacity = opacity.to_f
|
||||
@blend_type = blend_type ? blend_type : 0
|
||||
@duration = duration / 20.0
|
||||
@origin = origin
|
||||
@initial_x = @x
|
||||
@initial_y = @y
|
||||
@target_x = x.to_f
|
||||
@target_y = y.to_f
|
||||
@initial_zoom_x = @zoom_x
|
||||
@initial_zoom_y = @zoom_y
|
||||
@target_zoom_x = zoom_x.to_f
|
||||
@target_zoom_y = zoom_y.to_f
|
||||
@initial_opacity = @opacity
|
||||
@target_opacity = opacity.to_f
|
||||
@blend_type = blend_type || 0
|
||||
@move_timer_start = $stats.play_time
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Change Rotation Speed
|
||||
# speed : rotation speed
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Change Rotation Speed
|
||||
# speed : rotation speed (degrees to change per 1/20th of a second)
|
||||
def rotate(speed)
|
||||
@rotate_timer = (speed == 0) ? nil : System.uptime # Time since last frame
|
||||
@rotate_speed = speed
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Start Change of Color Tone
|
||||
|
||||
# Start Change of Color Tone
|
||||
# tone : color tone
|
||||
# duration : time
|
||||
#-----------------------------------------------------------------------------
|
||||
# duration : time in 1/20ths of a second
|
||||
def start_tone_change(tone, duration)
|
||||
@tone_target = tone.clone
|
||||
@tone_duration = duration
|
||||
if @tone_duration == 0
|
||||
@tone = @tone_target.clone
|
||||
if duration == 0
|
||||
@tone = tone.clone
|
||||
return
|
||||
end
|
||||
@tone_initial = @tone.clone
|
||||
@tone_target = tone.clone
|
||||
@tone_duration = duration / 20.0
|
||||
@tone_timer_start = $stats.play_time
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Erase Picture
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def erase
|
||||
@name = ""
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Frame Update
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def update
|
||||
if @duration >= 1
|
||||
d = @duration
|
||||
@x = (@x * (d - 1) + @target_x) / d
|
||||
@y = (@y * (d - 1) + @target_y) / d
|
||||
@zoom_x = (@zoom_x * (d - 1) + @target_zoom_x) / d
|
||||
@zoom_y = (@zoom_y * (d - 1) + @target_zoom_y) / d
|
||||
@opacity = (@opacity * (d - 1) + @target_opacity) / d
|
||||
@duration -= 1
|
||||
return if @name == ""
|
||||
now = $stats.play_time
|
||||
if @move_timer_start
|
||||
@x = lerp(@initial_x, @target_x, @duration, @move_timer_start, now)
|
||||
@y = lerp(@initial_y, @target_y, @duration, @move_timer_start, now)
|
||||
@zoom_x = lerp(@initial_zoom_x, @target_zoom_x, @duration, @move_timer_start, now)
|
||||
@zoom_y = lerp(@initial_zoom_y, @target_zoom_y, @duration, @move_timer_start, now)
|
||||
@opacity = lerp(@initial_opacity, @target_opacity, @duration, @move_timer_start, now)
|
||||
if now - @move_timer_start >= @duration
|
||||
@initial_x = nil
|
||||
@initial_y = nil
|
||||
@initial_zoom_x = nil
|
||||
@initial_zoom_y = nil
|
||||
@initial_opacity = nil
|
||||
@move_timer_start = nil
|
||||
end
|
||||
end
|
||||
if @tone_duration >= 1
|
||||
d = @tone_duration
|
||||
@tone.red = (@tone.red * (d - 1) + @tone_target.red) / d
|
||||
@tone.green = (@tone.green * (d - 1) + @tone_target.green) / d
|
||||
@tone.blue = (@tone.blue * (d - 1) + @tone_target.blue) / d
|
||||
@tone.gray = (@tone.gray * (d - 1) + @tone_target.gray) / d
|
||||
@tone_duration -= 1
|
||||
if @tone_timer_start
|
||||
@tone.red = lerp(@tone_initial.red, @tone_target.red, @tone_duration, @tone_timer_start, now)
|
||||
@tone.green = lerp(@tone_initial.green, @tone_target.green, @tone_duration, @tone_timer_start, now)
|
||||
@tone.blue = lerp(@tone_initial.blue, @tone_target.blue, @tone_duration, @tone_timer_start, now)
|
||||
@tone.gray = lerp(@tone_initial.gray, @tone_target.gray, @tone_duration, @tone_timer_start, now)
|
||||
if now - @tone_timer_start >= @tone_duration
|
||||
@tone_initial = nil
|
||||
@tone_timer_start = nil
|
||||
end
|
||||
end
|
||||
if @rotate_speed != 0
|
||||
@angle += @rotate_speed / 2.0
|
||||
@rotate_timer = System.uptime if !@rotate_timer
|
||||
@angle += @rotate_speed * (System.uptime - @rotate_timer) * 20.0
|
||||
@rotate_timer = System.uptime
|
||||
while @angle < 0
|
||||
@angle += 360
|
||||
end
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#==============================================================================
|
||||
#===============================================================================
|
||||
# ** Game_Map
|
||||
#------------------------------------------------------------------------------
|
||||
# This class handles the map. It includes scrolling and passable determining
|
||||
# functions. Refer to "$game_map" for the instance of this class.
|
||||
#==============================================================================
|
||||
#===============================================================================
|
||||
class Game_Map
|
||||
attr_accessor :map_id
|
||||
attr_accessor :tileset_name # tileset file name
|
||||
@@ -43,32 +43,34 @@ class Game_Map
|
||||
end
|
||||
|
||||
def setup(map_id)
|
||||
@map_id = map_id
|
||||
@map = load_data(sprintf("Data/Map%03d.rxdata",map_id))
|
||||
@map_id = map_id
|
||||
@map = load_data(sprintf("Data/Map%03d.rxdata", map_id))
|
||||
tileset = $data_tilesets[@map.tileset_id]
|
||||
updateTileset
|
||||
@fog_ox = 0
|
||||
@fog_oy = 0
|
||||
@fog_tone = Tone.new(0, 0, 0, 0)
|
||||
@fog_tone_target = Tone.new(0, 0, 0, 0)
|
||||
@fog_tone_duration = 0
|
||||
@fog_opacity_duration = 0
|
||||
@fog_opacity_target = 0
|
||||
self.display_x = 0
|
||||
self.display_y = 0
|
||||
@need_refresh = false
|
||||
Events.onMapCreate.trigger(self,map_id,@map,tileset)
|
||||
@events = {}
|
||||
for i in @map.events.keys
|
||||
@events[i] = Game_Event.new(@map_id, @map.events[i],self)
|
||||
@fog_ox = 0
|
||||
@fog_oy = 0
|
||||
@fog_tone = Tone.new(0, 0, 0, 0)
|
||||
@fog_tone_target = Tone.new(0, 0, 0, 0)
|
||||
@fog_tone_duration = 0
|
||||
@fog_tone_timer_start = nil
|
||||
@fog_opacity_duration = 0
|
||||
@fog_opacity_target = 0
|
||||
@fog_opacity_timer_start = nil
|
||||
self.display_x = 0
|
||||
self.display_y = 0
|
||||
@need_refresh = false
|
||||
EventHandlers.trigger(:on_game_map_setup, map_id, @map, tileset)
|
||||
@events = {}
|
||||
@map.events.each_key do |i|
|
||||
@events[i] = Game_Event.new(@map_id, @map.events[i], self)
|
||||
end
|
||||
@common_events = {}
|
||||
for i in 1...$data_common_events.size
|
||||
@common_events[i] = Game_CommonEvent.new(i)
|
||||
@common_events = {}
|
||||
(1...$data_common_events.size).each do |i|
|
||||
@common_events[i] = Game_CommonEvent.new(i)
|
||||
end
|
||||
@scroll_direction = 2
|
||||
@scroll_rest = 0
|
||||
@scroll_speed = 4
|
||||
@scroll_distance_x = 0
|
||||
@scroll_distance_y = 0
|
||||
@scroll_speed = 4
|
||||
end
|
||||
|
||||
def updateTileset
|
||||
@@ -95,57 +97,52 @@ class Game_Map
|
||||
def encounter_list; return @map.encounter_list; end
|
||||
def encounter_step; return @map.encounter_step; end
|
||||
def data; return @map.data; end
|
||||
def tileset_id; return @map.tileset_id; end
|
||||
def bgm; return @map.bgm; end
|
||||
|
||||
def name
|
||||
ret = pbGetMessage(MessageTypes::MapNames,@map_id)
|
||||
ret.gsub!(/\\PN/,$Trainer.name) if $Trainer
|
||||
return ret
|
||||
return pbGetMapNameFromId(@map_id)
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Autoplays background music
|
||||
# Plays music called "[normal BGM]_n" if it's night time and it exists
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def metadata
|
||||
return GameData::MapMetadata.try_get(@map_id)
|
||||
end
|
||||
|
||||
# Returns the name of this map's BGM. If it's night time, returns the night
|
||||
# version of the BGM (if it exists).
|
||||
def bgm_name
|
||||
if PBDayNight.isNight? && FileTest.audio_exist?("Audio/BGM/" + @map.bgm.name + "_n")
|
||||
return @map.bgm.name + "_n"
|
||||
end
|
||||
return @map.bgm.name
|
||||
end
|
||||
|
||||
# Autoplays background music
|
||||
# Plays music called "[normal BGM]_n" if it's night time and it exists
|
||||
def autoplayAsCue
|
||||
if @map.autoplay_bgm
|
||||
if PBDayNight.isNight? && FileTest.audio_exist?("Audio/BGM/"+ @map.bgm.name+ "_n")
|
||||
pbCueBGM(@map.bgm.name+"_n",1.0,@map.bgm.volume,@map.bgm.pitch)
|
||||
else
|
||||
pbCueBGM(@map.bgm,1.0)
|
||||
end
|
||||
end
|
||||
if @map.autoplay_bgs
|
||||
pbBGSPlay(@map.bgs)
|
||||
end
|
||||
pbCueBGM(bgm_name, 1.0, @map.bgm.volume, @map.bgm.pitch) if @map.autoplay_bgm
|
||||
pbBGSPlay(@map.bgs) if @map.autoplay_bgs
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Plays background music
|
||||
# Plays music called "[normal BGM]_n" if it's night time and it exists
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# Plays background music
|
||||
# Plays music called "[normal BGM]_n" if it's night time and it exists
|
||||
def autoplay
|
||||
if @map.autoplay_bgm
|
||||
if PBDayNight.isNight? && FileTest.audio_exist?("Audio/BGM/"+ @map.bgm.name+ "_n")
|
||||
pbBGMPlay(@map.bgm.name+"_n",@map.bgm.volume,@map.bgm.pitch)
|
||||
else
|
||||
pbBGMPlay(@map.bgm)
|
||||
end
|
||||
end
|
||||
if @map.autoplay_bgs
|
||||
pbBGSPlay(@map.bgs)
|
||||
end
|
||||
pbBGMPlay(bgm_name, @map.bgm.volume, @map.bgm.pitch) if @map.autoplay_bgm
|
||||
pbBGSPlay(@map.bgs) if @map.autoplay_bgs
|
||||
end
|
||||
|
||||
def valid?(x, y)
|
||||
return x>=0 && x<width && y>=0 && y<height
|
||||
return x >= 0 && x < width && y >= 0 && y < height
|
||||
end
|
||||
|
||||
def validLax?(x, y)
|
||||
return x>=-10 && x<=width+10 && y>=-10 && y<=height+10
|
||||
return x >= -10 && x <= width + 10 && y >= -10 && y <= height + 10
|
||||
end
|
||||
|
||||
def passable?(x, y, d, self_event = nil)
|
||||
def passable?(x, y, dir, self_event = nil)
|
||||
return false if !valid?(x, y)
|
||||
bit = (1 << (d / 2 - 1)) & 0x0f
|
||||
for event in events.values
|
||||
bit = (1 << ((dir / 2) - 1)) & 0x0f
|
||||
events.each_value do |event|
|
||||
next if event.tile_id <= 0
|
||||
next if event == self_event
|
||||
next if !event.at_coordinate?(x, y)
|
||||
@@ -156,11 +153,11 @@ class Game_Map
|
||||
return false if passage & 0x0f == 0x0f
|
||||
return true if @priorities[event.tile_id] == 0
|
||||
end
|
||||
return playerPassable?(x, y, d, self_event) if self_event==$game_player
|
||||
return playerPassable?(x, y, dir, self_event) if self_event == $game_player
|
||||
# All other events
|
||||
newx = x
|
||||
newy = y
|
||||
case d
|
||||
case dir
|
||||
when 1
|
||||
newx -= 1
|
||||
newy += 1
|
||||
@@ -183,14 +180,15 @@ class Game_Map
|
||||
newy -= 1
|
||||
end
|
||||
return false if !valid?(newx, newy)
|
||||
for i in [2, 1, 0]
|
||||
[2, 1, 0].each do |i|
|
||||
tile_id = data[x, y, i]
|
||||
terrain = GameData::TerrainTag.try_get(@terrain_tags[tile_id])
|
||||
# If already on water, only allow movement to another water tile
|
||||
if self_event != nil && terrain.can_surf_freely
|
||||
for j in [2, 1, 0]
|
||||
if self_event && terrain.can_surf_freely
|
||||
[2, 1, 0].each do |j|
|
||||
facing_tile_id = data[newx, newy, j]
|
||||
return false if facing_tile_id == nil
|
||||
next if facing_tile_id == 0
|
||||
return false if facing_tile_id.nil?
|
||||
facing_terrain = GameData::TerrainTag.try_get(@terrain_tags[facing_tile_id])
|
||||
if facing_terrain.id != :None && !facing_terrain.ignore_passability
|
||||
return facing_terrain.can_surf_freely
|
||||
@@ -200,30 +198,32 @@ class Game_Map
|
||||
# Can't walk onto ice
|
||||
elsif terrain.ice
|
||||
return false
|
||||
elsif self_event != nil && self_event.x == x && self_event.y == y
|
||||
elsif self_event && self_event.x == x && self_event.y == y
|
||||
# Can't walk onto ledges
|
||||
for j in [2, 1, 0]
|
||||
[2, 1, 0].each do |j|
|
||||
facing_tile_id = data[newx, newy, j]
|
||||
return false if facing_tile_id == nil
|
||||
next if facing_tile_id == 0
|
||||
return false if facing_tile_id.nil?
|
||||
facing_terrain = GameData::TerrainTag.try_get(@terrain_tags[facing_tile_id])
|
||||
return false if facing_terrain.ledge
|
||||
break if facing_terrain.id != :None && !facing_terrain.ignore_passability
|
||||
end
|
||||
end
|
||||
next if terrain&.ignore_passability
|
||||
next if tile_id == 0
|
||||
# Regular passability checks
|
||||
if !terrain || !terrain.ignore_passability
|
||||
passage = @passages[tile_id]
|
||||
return false if passage & bit != 0 || passage & 0x0f == 0x0f
|
||||
return true if @priorities[tile_id] == 0
|
||||
end
|
||||
passage = @passages[tile_id]
|
||||
return false if passage & bit != 0 || passage & 0x0f == 0x0f
|
||||
return true if @priorities[tile_id] == 0
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def playerPassable?(x, y, d, self_event = nil)
|
||||
bit = (1 << (d / 2 - 1)) & 0x0f
|
||||
for i in [2, 1, 0]
|
||||
def playerPassable?(x, y, dir, self_event = nil)
|
||||
bit = (1 << ((dir / 2) - 1)) & 0x0f
|
||||
[2, 1, 0].each do |i|
|
||||
tile_id = data[x, y, i]
|
||||
next if tile_id == 0
|
||||
terrain = GameData::TerrainTag.try_get(@terrain_tags[tile_id])
|
||||
passage = @passages[tile_id]
|
||||
if terrain
|
||||
@@ -232,34 +232,34 @@ class Game_Map
|
||||
# Make water tiles passable if player is surfing
|
||||
return true if $PokemonGlobal.surfing && terrain.can_surf && !terrain.waterfall
|
||||
# Prevent cycling in really tall grass/on ice
|
||||
return false if $PokemonGlobal.bicycle && terrain.must_walk
|
||||
return false if $PokemonGlobal.bicycle && (terrain.must_walk || terrain.must_walk_or_run)
|
||||
# Depend on passability of bridge tile if on bridge
|
||||
if terrain.bridge && $PokemonGlobal.bridge > 0
|
||||
return (passage & bit == 0 && passage & 0x0f != 0x0f)
|
||||
end
|
||||
end
|
||||
next if terrain&.ignore_passability
|
||||
# Regular passability checks
|
||||
if !terrain || !terrain.ignore_passability
|
||||
return false if passage & bit != 0 || passage & 0x0f == 0x0f
|
||||
return true if @priorities[tile_id] == 0
|
||||
end
|
||||
return false if passage & bit != 0 || passage & 0x0f == 0x0f
|
||||
return true if @priorities[tile_id] == 0
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
# Returns whether the position x,y is fully passable (there is no blocking
|
||||
# event there, and the tile is fully passable in all directions)
|
||||
# event there, and the tile is fully passable in all directions).
|
||||
def passableStrict?(x, y, d, self_event = nil)
|
||||
return false if !valid?(x, y)
|
||||
for event in events.values
|
||||
events.each_value do |event|
|
||||
next if event == self_event || event.tile_id < 0 || event.through
|
||||
next if !event.at_coordinate?(x, y)
|
||||
next if GameData::TerrainTag.try_get(@terrain_tags[event.tile_id]).ignore_passability
|
||||
return false if @passages[event.tile_id] & 0x0f != 0
|
||||
return true if @priorities[event.tile_id] == 0
|
||||
end
|
||||
for i in [2, 1, 0]
|
||||
[2, 1, 0].each do |i|
|
||||
tile_id = data[x, y, i]
|
||||
next if tile_id == 0
|
||||
next if GameData::TerrainTag.try_get(@terrain_tags[tile_id]).ignore_passability
|
||||
return false if @passages[tile_id] & 0x0f != 0
|
||||
return true if @priorities[tile_id] == 0
|
||||
@@ -267,9 +267,10 @@ class Game_Map
|
||||
return true
|
||||
end
|
||||
|
||||
def bush?(x,y)
|
||||
for i in [2, 1, 0]
|
||||
def bush?(x, y)
|
||||
[2, 1, 0].each do |i|
|
||||
tile_id = data[x, y, i]
|
||||
next if tile_id == 0
|
||||
return false if GameData::TerrainTag.try_get(@terrain_tags[tile_id]).bridge &&
|
||||
$PokemonGlobal.bridge > 0
|
||||
return true if @passages[tile_id] & 0x40 == 0x40
|
||||
@@ -277,9 +278,10 @@ class Game_Map
|
||||
return false
|
||||
end
|
||||
|
||||
def deepBush?(x,y)
|
||||
for i in [2, 1, 0]
|
||||
def deepBush?(x, y)
|
||||
[2, 1, 0].each do |i|
|
||||
tile_id = data[x, y, i]
|
||||
next if tile_id == 0
|
||||
terrain = GameData::TerrainTag.try_get(@terrain_tags[tile_id])
|
||||
return false if terrain.bridge && $PokemonGlobal.bridge > 0
|
||||
return true if terrain.deep_bush && @passages[tile_id] & 0x40 == 0x40
|
||||
@@ -287,19 +289,21 @@ class Game_Map
|
||||
return false
|
||||
end
|
||||
|
||||
def counter?(x,y)
|
||||
for i in [2, 1, 0]
|
||||
def counter?(x, y)
|
||||
[2, 1, 0].each do |i|
|
||||
tile_id = data[x, y, i]
|
||||
next if tile_id == 0
|
||||
passage = @passages[tile_id]
|
||||
return true if passage & 0x80 == 0x80
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def terrain_tag(x,y,countBridge=false)
|
||||
def terrain_tag(x, y, countBridge = false)
|
||||
if valid?(x, y)
|
||||
for i in [2, 1, 0]
|
||||
[2, 1, 0].each do |i|
|
||||
tile_id = data[x, y, i]
|
||||
next if tile_id == 0
|
||||
terrain = GameData::TerrainTag.try_get(@terrain_tags[tile_id])
|
||||
next if terrain.id == :None || terrain.ignore_passability
|
||||
next if !countBridge && terrain.bridge && $PokemonGlobal.bridge == 0
|
||||
@@ -310,8 +314,8 @@ class Game_Map
|
||||
end
|
||||
|
||||
# Unused.
|
||||
def check_event(x,y)
|
||||
for event in self.events.values
|
||||
def check_event(x, y)
|
||||
self.events.each_value do |event|
|
||||
return event.id if event.at_coordinate?(x, y)
|
||||
end
|
||||
end
|
||||
@@ -319,21 +323,21 @@ class Game_Map
|
||||
def display_x=(value)
|
||||
return if @display_x == value
|
||||
@display_x = value
|
||||
if GameData::MapMetadata.exists?(self.map_id) && GameData::MapMetadata.get(self.map_id).snap_edges
|
||||
max_x = (self.width - Graphics.width*1.0/TILE_WIDTH) * REAL_RES_X
|
||||
if metadata&.snap_edges
|
||||
max_x = (self.width - (Graphics.width.to_f / TILE_WIDTH)) * REAL_RES_X
|
||||
@display_x = [0, [@display_x, max_x].min].max
|
||||
end
|
||||
$MapFactory.setMapsInRange if $MapFactory
|
||||
$map_factory&.setMapsInRange
|
||||
end
|
||||
|
||||
def display_y=(value)
|
||||
return if @display_y == value
|
||||
@display_y = value
|
||||
if GameData::MapMetadata.exists?(self.map_id) && GameData::MapMetadata.get(self.map_id).snap_edges
|
||||
max_y = (self.height - Graphics.height*1.0/TILE_HEIGHT) * REAL_RES_Y
|
||||
if metadata&.snap_edges
|
||||
max_y = (self.height - (Graphics.height.to_f / TILE_HEIGHT)) * REAL_RES_Y
|
||||
@display_y = [0, [@display_y, max_y].min].max
|
||||
end
|
||||
$MapFactory.setMapsInRange if $MapFactory
|
||||
$map_factory&.setMapsInRange
|
||||
end
|
||||
|
||||
def scroll_up(distance)
|
||||
@@ -352,90 +356,135 @@ class Game_Map
|
||||
self.display_x += distance
|
||||
end
|
||||
|
||||
def start_scroll(direction, distance, speed)
|
||||
@scroll_direction = direction
|
||||
if direction==2 || direction==8 # down or up
|
||||
@scroll_rest = distance * REAL_RES_Y
|
||||
else
|
||||
@scroll_rest = distance * REAL_RES_X
|
||||
# speed is:
|
||||
# 1: moves 1 tile in 1.6 seconds
|
||||
# 2: moves 1 tile in 0.8 seconds
|
||||
# 3: moves 1 tile in 0.4 seconds
|
||||
# 4: moves 1 tile in 0.2 seconds
|
||||
# 5: moves 1 tile in 0.1 seconds
|
||||
# 6: moves 1 tile in 0.05 seconds
|
||||
def start_scroll(direction, distance, speed = 4)
|
||||
return if direction <= 0 || direction == 5 || direction >= 10
|
||||
if [1, 3, 4, 6, 7, 9].include?(direction) # horizontal
|
||||
@scroll_distance_x = distance
|
||||
@scroll_distance_x *= -1 if [1, 4, 7].include?(direction)
|
||||
end
|
||||
if [1, 2, 3, 7, 8, 9].include?(direction) # vertical
|
||||
@scroll_distance_y = distance
|
||||
@scroll_distance_y *= -1 if [7, 8, 9].include?(direction)
|
||||
end
|
||||
@scroll_speed = speed
|
||||
@scroll_start_x = display_x
|
||||
@scroll_start_y = display_y
|
||||
@scroll_timer_start = System.uptime
|
||||
end
|
||||
|
||||
# The two distances can be positive or negative.
|
||||
def start_scroll_custom(distance_x, distance_y, speed = 4)
|
||||
return if distance_x == 0 && distance_y == 0
|
||||
@scroll_distance_x = distance_x
|
||||
@scroll_distance_y = distance_y
|
||||
@scroll_speed = speed
|
||||
@scroll_start_x = display_x
|
||||
@scroll_start_y = display_y
|
||||
@scroll_timer_start = System.uptime
|
||||
end
|
||||
|
||||
def scrolling?
|
||||
return @scroll_rest > 0
|
||||
return (@scroll_distance_x || 0) != 0 || (@scroll_distance_y || 0) != 0
|
||||
end
|
||||
|
||||
def start_fog_tone_change(tone,duration)
|
||||
# duration is time in 1/20ths of a second.
|
||||
def start_fog_tone_change(tone, duration)
|
||||
if duration == 0
|
||||
@fog_tone = tone.clone
|
||||
return
|
||||
end
|
||||
@fog_tone_initial = @fog_tone.clone
|
||||
@fog_tone_target = tone.clone
|
||||
@fog_tone_duration = duration
|
||||
if @fog_tone_duration == 0
|
||||
@fog_tone = @fog_tone_target.clone
|
||||
end
|
||||
@fog_tone_duration = duration / 20.0
|
||||
@fog_tone_timer_start = $stats.play_time
|
||||
end
|
||||
|
||||
def start_fog_opacity_change(opacity,duration)
|
||||
@fog_opacity_target = opacity*1.0
|
||||
@fog_opacity_duration = duration
|
||||
if @fog_opacity_duration==0
|
||||
@fog_opacity = @fog_opacity_target
|
||||
# duration is time in 1/20ths of a second.
|
||||
def start_fog_opacity_change(opacity, duration)
|
||||
if duration == 0
|
||||
@fog_opacity = opacity.to_f
|
||||
return
|
||||
end
|
||||
@fog_opacity_initial = @fog_opacity
|
||||
@fog_opacity_target = opacity.to_f
|
||||
@fog_opacity_duration = duration / 20.0
|
||||
@fog_opacity_timer_start = $stats.play_time
|
||||
end
|
||||
|
||||
def set_tile(x, y, layer, id = 0)
|
||||
self.data[x, y, layer] = id
|
||||
end
|
||||
|
||||
def erase_tile(x, y, layer)
|
||||
set_tile(x, y, layer, 0)
|
||||
end
|
||||
|
||||
def refresh
|
||||
for event in @events.values
|
||||
@events.each_value do |event|
|
||||
event.refresh
|
||||
end
|
||||
for common_event in @common_events.values
|
||||
@common_events.each_value do |common_event|
|
||||
common_event.refresh
|
||||
end
|
||||
@need_refresh = false
|
||||
end
|
||||
|
||||
def update
|
||||
# refresh maps if necessary
|
||||
if $MapFactory
|
||||
for i in $MapFactory.maps
|
||||
i.refresh if i.need_refresh
|
||||
end
|
||||
$MapFactory.setCurrentMap
|
||||
uptime_now = System.uptime
|
||||
play_now = $stats.play_time
|
||||
# Refresh maps if necessary
|
||||
if $map_factory
|
||||
$map_factory.maps.each { |i| i.refresh if i.need_refresh }
|
||||
$map_factory.setCurrentMap
|
||||
end
|
||||
# If scrolling
|
||||
if @scroll_rest>0
|
||||
distance = (1<<@scroll_speed)*40.0/Graphics.frame_rate
|
||||
distance = @scroll_rest if distance>@scroll_rest
|
||||
case @scroll_direction
|
||||
when 2 then scroll_down(distance)
|
||||
when 4 then scroll_left(distance)
|
||||
when 6 then scroll_right(distance)
|
||||
when 8 then scroll_up(distance)
|
||||
end
|
||||
@scroll_rest -= distance
|
||||
if (@scroll_distance_x || 0) != 0
|
||||
duration = @scroll_distance_x.abs * TILE_WIDTH.to_f / (10 * (2**@scroll_speed))
|
||||
scroll_offset = lerp(0, @scroll_distance_x, duration, @scroll_timer_start, uptime_now)
|
||||
self.display_x = @scroll_start_x + (scroll_offset * REAL_RES_X)
|
||||
@scroll_distance_x = 0 if scroll_offset == @scroll_distance_x
|
||||
end
|
||||
if (@scroll_distance_y || 0) != 0
|
||||
duration = @scroll_distance_y.abs * TILE_HEIGHT.to_f / (10 * (2**@scroll_speed))
|
||||
scroll_offset = lerp(0, @scroll_distance_y, duration, @scroll_timer_start, uptime_now)
|
||||
self.display_y = @scroll_start_y + (scroll_offset * REAL_RES_Y)
|
||||
@scroll_distance_y = 0 if scroll_offset == @scroll_distance_y
|
||||
end
|
||||
# Only update events that are on-screen
|
||||
for event in @events.values
|
||||
event.update
|
||||
if !$game_temp.in_menu
|
||||
@events.each_value { |event| event.update }
|
||||
end
|
||||
# Update common events
|
||||
for common_event in @common_events.values
|
||||
common_event.update
|
||||
end
|
||||
@common_events.each_value { |common_event| common_event.update }
|
||||
# Update fog
|
||||
@fog_ox -= @fog_sx/8.0
|
||||
@fog_oy -= @fog_sy/8.0
|
||||
if @fog_tone_duration>=1
|
||||
d = @fog_tone_duration
|
||||
target = @fog_tone_target
|
||||
@fog_tone.red = (@fog_tone.red * (d - 1) + target.red) / d
|
||||
@fog_tone.green = (@fog_tone.green * (d - 1) + target.green) / d
|
||||
@fog_tone.blue = (@fog_tone.blue * (d - 1) + target.blue) / d
|
||||
@fog_tone.gray = (@fog_tone.gray * (d - 1) + target.gray) / d
|
||||
@fog_tone_duration -= 1
|
||||
@fog_scroll_last_update_timer = uptime_now if !@fog_scroll_last_update_timer
|
||||
scroll_mult = (uptime_now - @fog_scroll_last_update_timer) * 5
|
||||
@fog_ox -= @fog_sx * scroll_mult
|
||||
@fog_oy -= @fog_sy * scroll_mult
|
||||
@fog_scroll_last_update_timer = uptime_now
|
||||
if @fog_tone_timer_start
|
||||
@fog_tone.red = lerp(@fog_tone_initial.red, @fog_tone_target.red, @fog_tone_duration, @fog_tone_timer_start, play_now)
|
||||
@fog_tone.green = lerp(@fog_tone_initial.green, @fog_tone_target.green, @fog_tone_duration, @fog_tone_timer_start, play_now)
|
||||
@fog_tone.blue = lerp(@fog_tone_initial.blue, @fog_tone_target.blue, @fog_tone_duration, @fog_tone_timer_start, play_now)
|
||||
@fog_tone.gray = lerp(@fog_tone_initial.gray, @fog_tone_target.gray, @fog_tone_duration, @fog_tone_timer_start, play_now)
|
||||
if play_now - @fog_tone_timer_start >= @fog_tone_duration
|
||||
@fog_tone_initial = nil
|
||||
@fog_tone_timer_start = nil
|
||||
end
|
||||
end
|
||||
if @fog_opacity_duration >= 1
|
||||
d = @fog_opacity_duration
|
||||
@fog_opacity = (@fog_opacity * (d - 1) + @fog_opacity_target) / d
|
||||
@fog_opacity_duration -= 1
|
||||
if @fog_opacity_timer_start
|
||||
@fog_opacity = lerp(@fog_opacity_initial, @fog_opacity_target, @fog_opacity_duration, @fog_opacity_timer_start, play_now)
|
||||
if play_now - @fog_opacity_timer_start >= @fog_opacity_duration
|
||||
@fog_opacity_initial = nil
|
||||
@fog_opacity_timer_start = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -443,26 +492,74 @@ end
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
def pbScrollMap(direction,distance,speed)
|
||||
if speed==0
|
||||
case direction
|
||||
when 2 then $game_map.scroll_down(distance * Game_Map::REAL_RES_Y)
|
||||
when 4 then $game_map.scroll_left(distance * Game_Map::REAL_RES_X)
|
||||
when 6 then $game_map.scroll_right(distance * Game_Map::REAL_RES_X)
|
||||
when 8 then $game_map.scroll_up(distance * Game_Map::REAL_RES_Y)
|
||||
# Scroll the map in the given direction by the given distance at the (optional)
|
||||
# given speed.
|
||||
def pbScrollMap(direction, distance, speed = 4)
|
||||
if speed == 0
|
||||
if [1, 2, 3].include?(direction)
|
||||
$game_map.scroll_down(distance * Game_Map::REAL_RES_Y)
|
||||
elsif [7, 8, 9].include?(direction)
|
||||
$game_map.scroll_up(distance * Game_Map::REAL_RES_Y)
|
||||
end
|
||||
if [3, 6, 9].include?(direction)
|
||||
$game_map.scroll_right(distance * Game_Map::REAL_RES_X)
|
||||
elsif [1, 4, 7].include?(direction)
|
||||
$game_map.scroll_left(distance * Game_Map::REAL_RES_X)
|
||||
end
|
||||
else
|
||||
$game_map.start_scroll(direction, distance, speed)
|
||||
oldx = $game_map.display_x
|
||||
oldy = $game_map.display_y
|
||||
loop do
|
||||
Graphics.update
|
||||
Input.update
|
||||
break if !$game_map.scrolling?
|
||||
pbUpdateSceneMap
|
||||
break if $game_map.display_x==oldx && $game_map.display_y==oldy
|
||||
oldx = $game_map.display_x
|
||||
oldy = $game_map.display_y
|
||||
break if !$game_map.scrolling?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Scroll the map to center on the given coordinates at the (optional) given
|
||||
# speed. The scroll can happen in up to two parts, depending on where the target
|
||||
# is relative to the current location: an initial diagonal movement and a
|
||||
# following cardinal (vertical/horizontal) movement.
|
||||
def pbScrollMapTo(x, y, speed = 4)
|
||||
if !$game_map.valid?(x, y)
|
||||
print "pbScrollMapTo: given x,y is invalid"
|
||||
return
|
||||
elsif !(0..6).include?(speed)
|
||||
print "pbScrollMapTo: invalid speed (0-6 only)"
|
||||
return
|
||||
end
|
||||
# Get tile coordinates that the screen is currently scrolled to
|
||||
screen_offset_x = (Graphics.width - Game_Map::TILE_WIDTH) * Game_Map::X_SUBPIXELS / 2
|
||||
screen_offset_y = (Graphics.height - Game_Map::TILE_HEIGHT) * Game_Map::Y_SUBPIXELS / 2
|
||||
current_tile_x = ($game_map.display_x + screen_offset_x) / Game_Map::REAL_RES_X
|
||||
current_tile_y = ($game_map.display_y + screen_offset_y) / Game_Map::REAL_RES_Y
|
||||
offset_x = x - current_tile_x
|
||||
offset_y = y - current_tile_y
|
||||
return if offset_x == 0 && offset_y == 0
|
||||
if speed == 0
|
||||
if offset_y > 0
|
||||
$game_map.scroll_down(offset_y.abs * Game_Map::REAL_RES_Y)
|
||||
elsif offset_y < 0
|
||||
$game_map.scroll_up(offset_y.abs * Game_Map::REAL_RES_Y)
|
||||
end
|
||||
if offset_x > 0
|
||||
$game_map.scroll_right(offset_x.abs * Game_Map::REAL_RES_X)
|
||||
elsif offset_x < 0
|
||||
$game_map.scroll_left(offset_x.abs * Game_Map::REAL_RES_X)
|
||||
end
|
||||
else
|
||||
$game_map.start_scroll_custom(offset_x, offset_y, speed)
|
||||
loop do
|
||||
Graphics.update
|
||||
Input.update
|
||||
pbUpdateSceneMap
|
||||
break if !$game_map.scrolling?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Scroll the map to center on the player at the (optional) given speed.
|
||||
def pbScrollMapToPlayer(speed = 4)
|
||||
pbScrollMapTo($game_player.x, $game_player.y, speed)
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#===============================================================================
|
||||
# Map Factory (allows multiple maps to be loaded at once and connected)
|
||||
# Map Factory (allows multiple maps to be loaded at once and connected).
|
||||
#===============================================================================
|
||||
class PokemonMapFactory
|
||||
attr_reader :maps
|
||||
@@ -19,7 +19,7 @@ class PokemonMapFactory
|
||||
@maps[0] = Game_Map.new
|
||||
@mapIndex = 0
|
||||
oldID = ($game_map) ? $game_map.map_id : 0
|
||||
setMapChanging(id,@maps[0]) if oldID!=0 && oldID!=@maps[0].map_id
|
||||
setMapChanging(id, @maps[0]) if oldID != 0 && oldID != @maps[0].map_id
|
||||
$game_map = @maps[0]
|
||||
@maps[0].setup(id)
|
||||
setMapsInRange
|
||||
@@ -27,33 +27,33 @@ class PokemonMapFactory
|
||||
end
|
||||
|
||||
def map
|
||||
@mapIndex = 0 if !@mapIndex || @mapIndex<0
|
||||
@mapIndex = 0 if !@mapIndex || @mapIndex < 0
|
||||
return @maps[@mapIndex] if @maps[@mapIndex]
|
||||
raise "No maps in save file... (mapIndex=#{@mapIndex})" if @maps.length==0
|
||||
raise "No maps in save file... (mapIndex=#{@mapIndex})" if @maps.length == 0
|
||||
if @maps[0]
|
||||
echoln("Using next map, may be incorrect (mapIndex=#{@mapIndex}, length=#{@maps.length})")
|
||||
echoln "Using next map, may be incorrect (mapIndex=#{@mapIndex}, length=#{@maps.length})"
|
||||
return @maps[0]
|
||||
end
|
||||
raise "No maps in save file... (all maps empty; mapIndex=#{@mapIndex})"
|
||||
end
|
||||
|
||||
def hasMap?(id)
|
||||
for map in @maps
|
||||
return true if map.map_id==id
|
||||
@maps.each do |map|
|
||||
return true if map.map_id == id
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def getMapIndex(id)
|
||||
for i in 0...@maps.length
|
||||
return i if @maps[i].map_id==id
|
||||
@maps.length.times do |i|
|
||||
return i if @maps[i].map_id == id
|
||||
end
|
||||
return -1
|
||||
end
|
||||
|
||||
def getMap(id,add=true)
|
||||
for map in @maps
|
||||
return map if map.map_id==id
|
||||
def getMap(id, add = true)
|
||||
@maps.each do |map|
|
||||
return map if map.map_id == id
|
||||
end
|
||||
map = Game_Map.new
|
||||
map.setup(id)
|
||||
@@ -62,31 +62,29 @@ class PokemonMapFactory
|
||||
end
|
||||
|
||||
def getMapNoAdd(id)
|
||||
return getMap(id,false)
|
||||
return getMap(id, false)
|
||||
end
|
||||
|
||||
def getNewMap(playerX,playerY)
|
||||
id = $game_map.map_id
|
||||
conns = MapFactoryHelper.getMapConnections
|
||||
if conns[id]
|
||||
for conn in conns[id]
|
||||
mapidB = nil
|
||||
newx = 0
|
||||
newy = 0
|
||||
if conn[0] == id
|
||||
mapidB = conn[3]
|
||||
mapB = MapFactoryHelper.getMapDims(conn[3])
|
||||
newx = conn[4] - conn[1] + playerX
|
||||
newy = conn[5] - conn[2] + playerY
|
||||
else
|
||||
mapidB = conn[0]
|
||||
mapB = MapFactoryHelper.getMapDims(conn[0])
|
||||
newx = conn[1] - conn[4] + playerX
|
||||
newy = conn[2] - conn[5] + playerY
|
||||
end
|
||||
if newx >= 0 && newx < mapB[0] && newy >= 0 && newy < mapB[1]
|
||||
return [getMap(mapidB), newx, newy]
|
||||
end
|
||||
def getNewMap(playerX, playerY, map_id = nil)
|
||||
id = map_id || $game_map.map_id
|
||||
MapFactoryHelper.eachConnectionForMap(id) do |conn|
|
||||
mapidB = nil
|
||||
newx = 0
|
||||
newy = 0
|
||||
if conn[0] == id
|
||||
mapidB = conn[3]
|
||||
mapB = MapFactoryHelper.getMapDims(conn[3])
|
||||
newx = conn[4] - conn[1] + playerX
|
||||
newy = conn[5] - conn[2] + playerY
|
||||
else
|
||||
mapidB = conn[0]
|
||||
mapB = MapFactoryHelper.getMapDims(conn[0])
|
||||
newx = conn[1] - conn[4] + playerX
|
||||
newy = conn[2] - conn[5] + playerY
|
||||
end
|
||||
if newx >= 0 && newx < mapB[0] && newy >= 0 && newy < mapB[1]
|
||||
return [getMapNoAdd(mapidB), newx, newy] if map_id
|
||||
return [getMap(mapidB), newx, newy]
|
||||
end
|
||||
end
|
||||
return nil
|
||||
@@ -95,17 +93,17 @@ class PokemonMapFactory
|
||||
# Detects whether the player has moved onto a connected map, and if so, causes
|
||||
# their transfer to that map.
|
||||
def setCurrentMap
|
||||
return if $game_player.moving?
|
||||
return if $game_map.valid?($game_player.x,$game_player.y)
|
||||
newmap = getNewMap($game_player.x,$game_player.y)
|
||||
return if $game_player.moving? || $game_player.jumping?
|
||||
return if $game_map.valid?($game_player.x, $game_player.y)
|
||||
newmap = getNewMap($game_player.x, $game_player.y)
|
||||
return if !newmap
|
||||
oldmap=$game_map.map_id
|
||||
if oldmap!=0 && oldmap!=newmap[0].map_id
|
||||
setMapChanging(newmap[0].map_id,newmap[0])
|
||||
oldmap = $game_map.map_id
|
||||
if oldmap != 0 && oldmap != newmap[0].map_id
|
||||
setMapChanging(newmap[0].map_id, newmap[0])
|
||||
end
|
||||
$game_map = newmap[0]
|
||||
@mapIndex = getMapIndex($game_map.map_id)
|
||||
$game_player.moveto(newmap[1],newmap[2])
|
||||
$game_player.moveto(newmap[1], newmap[2])
|
||||
$game_map.update
|
||||
pbAutoplayOnTransition
|
||||
$game_map.refresh
|
||||
@@ -117,148 +115,128 @@ class PokemonMapFactory
|
||||
return if @fixup
|
||||
@fixup = true
|
||||
id = $game_map.map_id
|
||||
conns = MapFactoryHelper.getMapConnections
|
||||
if conns[id]
|
||||
for conn in conns[id]
|
||||
if conn[0] == id
|
||||
mapA = getMap(conn[0])
|
||||
newdispx = (conn[4] - conn[1]) * Game_Map::REAL_RES_X + mapA.display_x
|
||||
newdispy = (conn[5] - conn[2]) * Game_Map::REAL_RES_Y + mapA.display_y
|
||||
if hasMap?(conn[3]) || MapFactoryHelper.mapInRangeById?(conn[3], newdispx, newdispy)
|
||||
mapB = getMap(conn[3])
|
||||
mapB.display_x = newdispx if mapB.display_x != newdispx
|
||||
mapB.display_y = newdispy if mapB.display_y != newdispy
|
||||
end
|
||||
else
|
||||
mapA = getMap(conn[3])
|
||||
newdispx = (conn[1] - conn[4]) * Game_Map::REAL_RES_X + mapA.display_x
|
||||
newdispy = (conn[2] - conn[5]) * Game_Map::REAL_RES_Y + mapA.display_y
|
||||
if hasMap?(conn[0]) || MapFactoryHelper.mapInRangeById?(conn[0], newdispx, newdispy)
|
||||
mapB = getMap(conn[0])
|
||||
mapB.display_x = newdispx if mapB.display_x != newdispx
|
||||
mapB.display_y = newdispy if mapB.display_y != newdispy
|
||||
end
|
||||
MapFactoryHelper.eachConnectionForMap(id) do |conn|
|
||||
if conn[0] == id
|
||||
mapA = getMap(conn[0])
|
||||
newdispx = ((conn[4] - conn[1]) * Game_Map::REAL_RES_X) + mapA.display_x
|
||||
newdispy = ((conn[5] - conn[2]) * Game_Map::REAL_RES_Y) + mapA.display_y
|
||||
if hasMap?(conn[3]) || MapFactoryHelper.mapInRangeById?(conn[3], newdispx, newdispy)
|
||||
mapB = getMap(conn[3])
|
||||
mapB.display_x = newdispx if mapB.display_x != newdispx
|
||||
mapB.display_y = newdispy if mapB.display_y != newdispy
|
||||
end
|
||||
else
|
||||
mapA = getMap(conn[3])
|
||||
newdispx = ((conn[1] - conn[4]) * Game_Map::REAL_RES_X) + mapA.display_x
|
||||
newdispy = ((conn[2] - conn[5]) * Game_Map::REAL_RES_Y) + mapA.display_y
|
||||
if hasMap?(conn[0]) || MapFactoryHelper.mapInRangeById?(conn[0], newdispx, newdispy)
|
||||
mapB = getMap(conn[0])
|
||||
mapB.display_x = newdispx if mapB.display_x != newdispx
|
||||
mapB.display_y = newdispy if mapB.display_y != newdispy
|
||||
end
|
||||
end
|
||||
end
|
||||
@fixup = false
|
||||
end
|
||||
|
||||
def setMapChanging(newID,newMap)
|
||||
Events.onMapChanging.trigger(self,newID,newMap)
|
||||
def setMapChanging(newID, newMap)
|
||||
EventHandlers.trigger(:on_leave_map, newID, newMap)
|
||||
end
|
||||
|
||||
def setMapChanged(prevMap)
|
||||
Events.onMapChange.trigger(self,prevMap)
|
||||
EventHandlers.trigger(:on_enter_map, prevMap)
|
||||
@mapChanged = true
|
||||
end
|
||||
|
||||
def setSceneStarted(scene)
|
||||
Events.onMapSceneChange.trigger(self,scene,@mapChanged)
|
||||
EventHandlers.trigger(:on_map_or_spriteset_change, scene, @mapChanged)
|
||||
@mapChanged = false
|
||||
end
|
||||
|
||||
# Similar to Game_Player#passable?, but supports map connections
|
||||
def isPassableFromEdge?(x, y)
|
||||
def isPassableFromEdge?(x, y, dir = 0)
|
||||
return true if $game_map.valid?(x, y)
|
||||
newmap = getNewMap(x, y)
|
||||
newmap = getNewMap(x, y, $game_map.map_id)
|
||||
return false if !newmap
|
||||
return isPassable?(newmap[0].map_id, newmap[1], newmap[2])
|
||||
return isPassable?(newmap[0].map_id, newmap[1], newmap[2], dir)
|
||||
end
|
||||
|
||||
def isPassable?(mapID, x, y, thisEvent = nil)
|
||||
def isPassable?(mapID, x, y, dir = 0, thisEvent = nil)
|
||||
thisEvent = $game_player if !thisEvent
|
||||
map = getMapNoAdd(mapID)
|
||||
return false if !map
|
||||
return false if !map.valid?(x, y)
|
||||
return true if thisEvent.through
|
||||
# Check passability of tile
|
||||
if thisEvent.is_a?(Game_Player)
|
||||
return false unless ($DEBUG && Input.press?(Input::CTRL)) ||
|
||||
map.passable?(x, y, 0, thisEvent)
|
||||
else
|
||||
return false unless map.passable?(x, y, 0, thisEvent)
|
||||
end
|
||||
return true if $DEBUG && Input.press?(Input::CTRL) && thisEvent.is_a?(Game_Player)
|
||||
return false if !map.passable?(x, y, dir, thisEvent)
|
||||
# Check passability of event(s) in that spot
|
||||
for event in map.events.values
|
||||
map.events.each_value do |event|
|
||||
next if event == thisEvent || !event.at_coordinate?(x, y)
|
||||
return false if !event.through && event.character_name != ""
|
||||
end
|
||||
# Check passability of player
|
||||
if !thisEvent.is_a?(Game_Player)
|
||||
if $game_map.map_id == mapID && $game_player.x == x && $game_player.y == y
|
||||
return false if !$game_player.through && $game_player.character_name != ""
|
||||
end
|
||||
if !thisEvent.is_a?(Game_Player) &&
|
||||
$game_map.map_id == mapID && $game_player.x == x && $game_player.y == y &&
|
||||
!$game_player.through && $game_player.character_name != ""
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
# Only used by dependent events
|
||||
def isPassableStrict?(mapID,x,y,thisEvent=nil)
|
||||
# Only used by follower events
|
||||
def isPassableStrict?(mapID, x, y, thisEvent = nil)
|
||||
thisEvent = $game_player if !thisEvent
|
||||
map = getMapNoAdd(mapID)
|
||||
return false if !map
|
||||
return false if !map.valid?(x,y)
|
||||
return false if !map.valid?(x, y)
|
||||
return true if thisEvent.through
|
||||
if thisEvent==$game_player
|
||||
if !($DEBUG && Input.press?(Input::CTRL))
|
||||
return false if !map.passableStrict?(x,y,0,thisEvent)
|
||||
end
|
||||
else
|
||||
return false if !map.passableStrict?(x,y,0,thisEvent)
|
||||
end
|
||||
for event in map.events.values
|
||||
return true if $DEBUG && Input.press?(Input::CTRL) && thisEvent.is_a?(Game_Player)
|
||||
return false if !map.passableStrict?(x, y, 0, thisEvent)
|
||||
map.events.each_value do |event|
|
||||
next if event == thisEvent || !event.at_coordinate?(x, y)
|
||||
return false if !event.through && event.character_name!=""
|
||||
return false if !event.through && event.character_name != ""
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def getTerrainTag(mapid,x,y,countBridge=false)
|
||||
def getTerrainTag(mapid, x, y, countBridge = false)
|
||||
map = getMapNoAdd(mapid)
|
||||
return map.terrain_tag(x,y,countBridge)
|
||||
return map.terrain_tag(x, y, countBridge)
|
||||
end
|
||||
|
||||
# NOTE: Assumes the event is 1x1 tile in size. Only returns one terrain tag.
|
||||
def getFacingTerrainTag(dir=nil,event=nil)
|
||||
tile = getFacingTile(dir,event)
|
||||
def getFacingTerrainTag(dir = nil, event = nil)
|
||||
tile = getFacingTile(dir, event)
|
||||
return GameData::TerrainTag.get(:None) if !tile
|
||||
return getTerrainTag(tile[0],tile[1],tile[2])
|
||||
return getTerrainTag(tile[0], tile[1], tile[2])
|
||||
end
|
||||
|
||||
def getTerrainTagFromCoords(mapid,x,y,countBridge=false)
|
||||
tile = getRealTilePos(mapid,x,y)
|
||||
def getTerrainTagFromCoords(mapid, x, y, countBridge = false)
|
||||
tile = getRealTilePos(mapid, x, y)
|
||||
return GameData::TerrainTag.get(:None) if !tile
|
||||
return getTerrainTag(tile[0],tile[1],tile[2])
|
||||
return getTerrainTag(tile[0], tile[1], tile[2])
|
||||
end
|
||||
|
||||
def areConnected?(mapID1, mapID2)
|
||||
return true if mapID1 == mapID2
|
||||
conns = MapFactoryHelper.getMapConnections
|
||||
if conns[mapID1]
|
||||
for conn in conns[mapID1]
|
||||
return true if conn[0] == mapID2 || conn[3] == mapID2
|
||||
end
|
||||
end
|
||||
return false
|
||||
return MapFactoryHelper.mapsConnected?(mapID1, mapID2)
|
||||
end
|
||||
|
||||
# Returns the coordinate change to go from this position to other position
|
||||
def getRelativePos(thisMapID, thisX, thisY, otherMapID, otherX, otherY)
|
||||
if thisMapID == otherMapID # Both events share the same map
|
||||
return [otherX - thisX, otherY - thisY]
|
||||
end
|
||||
conns = MapFactoryHelper.getMapConnections
|
||||
if conns[thisMapID]
|
||||
for conn in conns[thisMapID]
|
||||
if conn[0] == otherMapID
|
||||
posX = thisX + conn[1] - conn[4] + otherX
|
||||
posY = thisY + conn[2] - conn[5] + otherY
|
||||
return [posX, posY]
|
||||
elsif conn[1] == otherMapID
|
||||
posX = thisX + conn[4] - conn[1] + otherX
|
||||
posY = thisY + conn[5] - conn[2] + otherY
|
||||
return [posX, posY]
|
||||
end
|
||||
MapFactoryHelper.eachConnectionForMap(thisMapID) do |conn|
|
||||
if conn[0] == otherMapID
|
||||
posX = conn[4] - conn[1] + otherX - thisX
|
||||
posY = conn[5] - conn[2] + otherY - thisY
|
||||
return [posX, posY]
|
||||
elsif conn[3] == otherMapID
|
||||
posX = conn[1] - conn[4] + otherX - thisX
|
||||
posY = conn[2] - conn[5] + otherY - thisY
|
||||
return [posX, posY]
|
||||
end
|
||||
end
|
||||
return [0, 0]
|
||||
@@ -267,38 +245,37 @@ class PokemonMapFactory
|
||||
# Gets the distance from this event to another event. Example: If this event's
|
||||
# coordinates are (2,5) and the other event's coordinates are (5,1), returns
|
||||
# the array (3,-4), because (5-2=3) and (1-5=-4).
|
||||
def getThisAndOtherEventRelativePos(thisEvent,otherEvent)
|
||||
return [0,0] if !thisEvent || !otherEvent
|
||||
return getRelativePos(
|
||||
thisEvent.map.map_id,thisEvent.x,thisEvent.y,
|
||||
otherEvent.map.map_id,otherEvent.x,otherEvent.y)
|
||||
def getThisAndOtherEventRelativePos(thisEvent, otherEvent)
|
||||
return [0, 0] if !thisEvent || !otherEvent
|
||||
return getRelativePos(thisEvent.map.map_id, thisEvent.x, thisEvent.y,
|
||||
otherEvent.map.map_id, otherEvent.x, otherEvent.y)
|
||||
end
|
||||
|
||||
def getThisAndOtherPosRelativePos(thisEvent,otherMapID,otherX,otherY)
|
||||
return [0,0] if !thisEvent
|
||||
return getRelativePos(
|
||||
thisEvent.map.map_id,thisEvent.x,thisEvent.y,otherMapID,otherX,otherY)
|
||||
def getThisAndOtherPosRelativePos(thisEvent, otherMapID, otherX, otherY)
|
||||
return [0, 0] if !thisEvent
|
||||
return getRelativePos(thisEvent.map.map_id, thisEvent.x, thisEvent.y,
|
||||
otherMapID, otherX, otherY)
|
||||
end
|
||||
|
||||
# Unused
|
||||
def getOffsetEventPos(event,xOffset,yOffset)
|
||||
def getOffsetEventPos(event, xOffset, yOffset)
|
||||
event = $game_player if !event
|
||||
return nil if !event
|
||||
return getRealTilePos(event.map.map_id,event.x+xOffset,event.y+yOffset)
|
||||
return getRealTilePos(event.map.map_id, event.x + xOffset, event.y + yOffset)
|
||||
end
|
||||
|
||||
# NOTE: Assumes the event is 1x1 tile in size. Only returns one tile.
|
||||
def getFacingTile(direction=nil,event=nil,steps=1)
|
||||
event = $game_player if event==nil
|
||||
return [0,0,0] if !event
|
||||
def getFacingTile(direction = nil, event = nil, steps = 1)
|
||||
event = $game_player if event.nil?
|
||||
return [0, 0, 0] if !event
|
||||
x = event.x
|
||||
y = event.y
|
||||
id = event.map.map_id
|
||||
direction = event.direction if direction==nil
|
||||
return getFacingTileFromPos(id,x,y,direction,steps)
|
||||
direction = event.direction if direction.nil?
|
||||
return getFacingTileFromPos(id, x, y, direction, steps)
|
||||
end
|
||||
|
||||
def getFacingTileFromPos(mapID,x,y,direction=0,steps=1)
|
||||
def getFacingTileFromPos(mapID, x, y, direction = 0, steps = 1)
|
||||
id = mapID
|
||||
case direction
|
||||
when 1
|
||||
@@ -322,38 +299,35 @@ class PokemonMapFactory
|
||||
x += steps
|
||||
y -= steps
|
||||
else
|
||||
return [id,x,y]
|
||||
return [id, x, y]
|
||||
end
|
||||
return getRealTilePos(mapID,x,y)
|
||||
return getRealTilePos(mapID, x, y)
|
||||
end
|
||||
|
||||
def getRealTilePos(mapID, x, y)
|
||||
id = mapID
|
||||
return [id, x, y] if getMapNoAdd(id).valid?(x, y)
|
||||
conns = MapFactoryHelper.getMapConnections
|
||||
if conns[id]
|
||||
for conn in conns[id]
|
||||
if conn[0] == id
|
||||
newX = x + conn[4] - conn[1]
|
||||
newY = y + conn[5] - conn[2]
|
||||
next if newX < 0 || newY < 0
|
||||
dims = MapFactoryHelper.getMapDims(conn[3])
|
||||
next if newX >= dims[0] || newY >= dims[1]
|
||||
return [conn[3], newX, newY]
|
||||
else
|
||||
newX = x + conn[1] - conn[4]
|
||||
newY = y + conn[2] - conn[5]
|
||||
next if newX < 0 || newY < 0
|
||||
dims = MapFactoryHelper.getMapDims(conn[0])
|
||||
next if newX >= dims[0] || newY >= dims[1]
|
||||
return [conn[0], newX, newY]
|
||||
end
|
||||
MapFactoryHelper.eachConnectionForMap(id) do |conn|
|
||||
if conn[0] == id
|
||||
newX = x + conn[4] - conn[1]
|
||||
newY = y + conn[5] - conn[2]
|
||||
next if newX < 0 || newY < 0
|
||||
dims = MapFactoryHelper.getMapDims(conn[3])
|
||||
next if newX >= dims[0] || newY >= dims[1]
|
||||
return [conn[3], newX, newY]
|
||||
else
|
||||
newX = x + conn[1] - conn[4]
|
||||
newY = y + conn[2] - conn[5]
|
||||
next if newX < 0 || newY < 0
|
||||
dims = MapFactoryHelper.getMapDims(conn[0])
|
||||
next if newX >= dims[0] || newY >= dims[1]
|
||||
return [conn[0], newX, newY]
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def getFacingCoords(x,y,direction=0,steps=1)
|
||||
def getFacingCoords(x, y, direction = 0, steps = 1)
|
||||
case direction
|
||||
when 1
|
||||
x -= steps
|
||||
@@ -376,36 +350,29 @@ class PokemonMapFactory
|
||||
x += steps
|
||||
y -= steps
|
||||
end
|
||||
return [x,y]
|
||||
return [x, y]
|
||||
end
|
||||
|
||||
def updateMaps(scene)
|
||||
updateMapsInternal
|
||||
$MapFactory.setSceneStarted(scene) if @mapChanged
|
||||
setSceneStarted(scene) if @mapChanged
|
||||
end
|
||||
|
||||
def updateMapsInternal
|
||||
return if $game_player.moving?
|
||||
if !MapFactoryHelper.hasConnections?($game_map.map_id)
|
||||
return if @maps.length==1
|
||||
for i in 0...@maps.length
|
||||
@maps[i] = nil if $game_map.map_id!=@maps[i].map_id
|
||||
end
|
||||
@maps.compact!
|
||||
return if @maps.length == 1
|
||||
@maps.delete_if { |map| map.map_id != $game_map.map_id }
|
||||
@mapIndex = getMapIndex($game_map.map_id)
|
||||
return
|
||||
end
|
||||
old_num_maps = @maps.length
|
||||
@maps.delete_if { |map| !MapFactoryHelper.mapsConnected?($game_map.map_id, map.map_id) }
|
||||
@mapIndex = getMapIndex($game_map.map_id) if @maps.length != old_num_maps
|
||||
setMapsInRange
|
||||
deleted = false
|
||||
for i in 0...@maps.length
|
||||
next if MapFactoryHelper.mapInRange?(@maps[i])
|
||||
@maps[i] = nil
|
||||
deleted = true
|
||||
end
|
||||
if deleted
|
||||
@maps.compact!
|
||||
@mapIndex = getMapIndex($game_map.map_id)
|
||||
end
|
||||
old_num_maps = @maps.length
|
||||
@maps.delete_if { |map| !MapFactoryHelper.mapInRange?(map) }
|
||||
@mapIndex = getMapIndex($game_map.map_id) if @maps.length != old_num_maps
|
||||
end
|
||||
end
|
||||
|
||||
@@ -417,12 +384,14 @@ module MapFactoryHelper
|
||||
@@MapConnections = nil
|
||||
@@MapDims = nil
|
||||
|
||||
def self.clear
|
||||
module_function
|
||||
|
||||
def clear
|
||||
@@MapConnections = nil
|
||||
@@MapDims = nil
|
||||
end
|
||||
|
||||
def self.getMapConnections
|
||||
def getMapConnections
|
||||
if !@@MapConnections
|
||||
@@MapConnections = []
|
||||
conns = load_data("Data/map_connections.dat")
|
||||
@@ -460,22 +429,35 @@ module MapFactoryHelper
|
||||
return @@MapConnections
|
||||
end
|
||||
|
||||
def self.hasConnections?(id)
|
||||
def hasConnections?(id)
|
||||
conns = MapFactoryHelper.getMapConnections
|
||||
return conns[id] ? true : false
|
||||
end
|
||||
|
||||
# Gets the height and width of the map with id
|
||||
def self.getMapDims(id)
|
||||
def mapsConnected?(id1, id2)
|
||||
MapFactoryHelper.eachConnectionForMap(id1) do |conn|
|
||||
return true if conn[0] == id2 || conn[3] == id2
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def eachConnectionForMap(id)
|
||||
conns = MapFactoryHelper.getMapConnections
|
||||
return if !conns[id]
|
||||
conns[id].each { |conn| yield conn }
|
||||
end
|
||||
|
||||
# Gets the height and width of the map with id.
|
||||
def getMapDims(id)
|
||||
# Create cache if doesn't exist
|
||||
@@MapDims = [] if !@@MapDims
|
||||
# Add map to cache if can't be found
|
||||
if !@@MapDims[id]
|
||||
begin
|
||||
map = load_data(sprintf("Data/Map%03d.rxdata", id))
|
||||
@@MapDims[id] = [map.width,map.height]
|
||||
@@MapDims[id] = [map.width, map.height]
|
||||
rescue
|
||||
@@MapDims[id] = [0,0]
|
||||
@@MapDims[id] = [0, 0]
|
||||
end
|
||||
end
|
||||
# Return map in cache
|
||||
@@ -484,32 +466,32 @@ module MapFactoryHelper
|
||||
|
||||
# Returns the X or Y coordinate of an edge on the map with id.
|
||||
# Considers the special strings "N","W","E","S"
|
||||
def self.getMapEdge(id,edge)
|
||||
return 0 if edge=="N" || edge=="W"
|
||||
def getMapEdge(id, edge)
|
||||
return 0 if ["N", "W"].include?(edge)
|
||||
dims = getMapDims(id) # Get dimensions
|
||||
return dims[0] if edge=="E"
|
||||
return dims[1] if edge=="S"
|
||||
return dims[0] if edge == "E"
|
||||
return dims[1] if edge == "S"
|
||||
return dims[0] # real dimension (use width)
|
||||
end
|
||||
|
||||
def self.mapInRange?(map)
|
||||
def mapInRange?(map)
|
||||
range = 6 # Number of tiles
|
||||
dispx = map.display_x
|
||||
dispy = map.display_y
|
||||
return false if dispx >= (map.width + range) * Game_Map::REAL_RES_X
|
||||
return false if dispy >= (map.height + range) * Game_Map::REAL_RES_Y
|
||||
return false if dispx <= -(Graphics.width + range * Game_Map::TILE_WIDTH) * Game_Map::X_SUBPIXELS
|
||||
return false if dispy <= -(Graphics.height + range * Game_Map::TILE_HEIGHT) * Game_Map::Y_SUBPIXELS
|
||||
return false if dispx <= -(Graphics.width + (range * Game_Map::TILE_WIDTH)) * Game_Map::X_SUBPIXELS
|
||||
return false if dispy <= -(Graphics.height + (range * Game_Map::TILE_HEIGHT)) * Game_Map::Y_SUBPIXELS
|
||||
return true
|
||||
end
|
||||
|
||||
def self.mapInRangeById?(id,dispx,dispy)
|
||||
def mapInRangeById?(id, dispx, dispy)
|
||||
range = 6 # Number of tiles
|
||||
dims = MapFactoryHelper.getMapDims(id)
|
||||
return false if dispx >= (dims[0] + range) * Game_Map::REAL_RES_X
|
||||
return false if dispy >= (dims[1] + range) * Game_Map::REAL_RES_Y
|
||||
return false if dispx <= -(Graphics.width + range * Game_Map::TILE_WIDTH) * Game_Map::X_SUBPIXELS
|
||||
return false if dispy <= -(Graphics.height + range * Game_Map::TILE_HEIGHT) * Game_Map::Y_SUBPIXELS
|
||||
return false if dispx <= -(Graphics.width + (range * Game_Map::TILE_WIDTH)) * Game_Map::X_SUBPIXELS
|
||||
return false if dispy <= -(Graphics.height + (range * Game_Map::TILE_HEIGHT)) * Game_Map::Y_SUBPIXELS
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -519,8 +501,8 @@ end
|
||||
#===============================================================================
|
||||
# Unused
|
||||
def updateTilesets
|
||||
maps = $MapFactory.maps
|
||||
for map in maps
|
||||
map.updateTileset if map
|
||||
maps = $map_factory.maps
|
||||
maps.each do |map|
|
||||
map&.updateTileset
|
||||
end
|
||||
end
|
||||
@@ -1,194 +0,0 @@
|
||||
#===============================================================================
|
||||
# ** Map Autoscroll
|
||||
#-------------------------------------------------------------------------------
|
||||
# Wachunga
|
||||
# Version 1.02
|
||||
# 2005-12-18
|
||||
#===============================================================================
|
||||
=begin
|
||||
|
||||
This script supplements the built-in "Scroll Map" event command with the
|
||||
aim of simplifying cutscenes (and map scrolling in general). Whereas the
|
||||
normal event command requires a direction and number of tiles to scroll,
|
||||
Map Autoscroll scrolls the map to center on the tile whose x and y
|
||||
coordinates are given.
|
||||
|
||||
FEATURES
|
||||
- automatic map scrolling to given x,y coordinate (or player)
|
||||
- destination is fixed, so it's possible to scroll to same place even if
|
||||
origin is variable (e.g. moving NPC)
|
||||
- variable speed (just like "Scroll Map" event command)
|
||||
- diagonal scrolling supported
|
||||
|
||||
SETUP
|
||||
Instead of a "Scroll Map" event command, use the "Call Script" command
|
||||
and enter on the following on the first line:
|
||||
|
||||
autoscroll(x,y)
|
||||
|
||||
(replacing "x" and "y" with the x and y coordinates of the tile to scroll to)
|
||||
|
||||
To specify a scroll speed other than the default (4), use:
|
||||
|
||||
autoscroll(x,y,speed)
|
||||
|
||||
(now also replacing "speed" with the scroll speed from 1-6)
|
||||
|
||||
Diagonal scrolling happens automatically when the destination is diagonal
|
||||
relative to the starting point (i.e., not directly up, down, left or right).
|
||||
|
||||
To scroll to the player, instead use the following:
|
||||
|
||||
autoscroll_player(speed)
|
||||
|
||||
Note: because of how the interpreter and the "Call Script" event command
|
||||
are setup, the call to autoscroll(...) can only be on the first line of
|
||||
the "Call Script" event command (and not flowing down to subsequent lines).
|
||||
|
||||
For example, the following call may not work as expected:
|
||||
|
||||
autoscroll($game_variables[1],
|
||||
$game_variables[2])
|
||||
|
||||
(since the long argument names require dropping down to a second line)
|
||||
A work-around is to setup new variables with shorter names in a preceding
|
||||
(separate) "Call Script" event command:
|
||||
|
||||
@x = $game_variables[1]
|
||||
@y = $game_variables[2]
|
||||
|
||||
and then use those as arguments:
|
||||
|
||||
autoscroll(@x,@y)
|
||||
|
||||
The renaming must be in a separate "Call Script" because otherwise
|
||||
the call to autoscroll(...) isn't on the first line.
|
||||
|
||||
Originally requested by militantmilo80:
|
||||
http://www.rmxp.net/forums/index.php?showtopic=29519
|
||||
|
||||
=end
|
||||
|
||||
class Interpreter
|
||||
SCROLL_SPEED_DEFAULT = 4
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Map Autoscroll to Coordinates
|
||||
# x : x coordinate to scroll to and center on
|
||||
# y : y coordinate to scroll to and center on
|
||||
# speed : (optional) scroll speed (from 1-6, default being 4)
|
||||
#-----------------------------------------------------------------------------
|
||||
def autoscroll(x,y,speed=SCROLL_SPEED_DEFAULT)
|
||||
if $game_map.scrolling?
|
||||
return false
|
||||
elsif !$game_map.valid?(x,y)
|
||||
print 'Map Autoscroll: given x,y is invalid'
|
||||
return command_skip
|
||||
elsif !(1..6).include?(speed)
|
||||
print 'Map Autoscroll: invalid speed (1-6 only)'
|
||||
return command_skip
|
||||
end
|
||||
center_x = (Graphics.width/2 - Game_Map::TILE_WIDTH/2) * 4 # X coordinate in the center of the screen
|
||||
center_y = (Graphics.height/2 - Game_Map::TILE_HEIGHT/2) * 4 # Y coordinate in the center of the screen
|
||||
max_x = ($game_map.width - Graphics.width*1.0/Game_Map::TILE_WIDTH) * 4 * Game_Map::TILE_WIDTH
|
||||
max_y = ($game_map.height - Graphics.height*1.0/Game_Map::TILE_HEIGHT) * 4 * Game_Map::TILE_HEIGHT
|
||||
count_x = ($game_map.display_x - [0,[x*Game_Map::REAL_RES_X-center_x,max_x].min].max)/Game_Map::REAL_RES_X
|
||||
count_y = ($game_map.display_y - [0,[y*Game_Map::REAL_RES_Y-center_y,max_y].min].max)/Game_Map::REAL_RES_Y
|
||||
if !@diag
|
||||
@diag = true
|
||||
dir = nil
|
||||
if count_x > 0
|
||||
if count_y > 0
|
||||
dir = 7
|
||||
elsif count_y < 0
|
||||
dir = 1
|
||||
end
|
||||
elsif count_x < 0
|
||||
if count_y > 0
|
||||
dir = 9
|
||||
elsif count_y < 0
|
||||
dir = 3
|
||||
end
|
||||
end
|
||||
count = [count_x.abs,count_y.abs].min
|
||||
else
|
||||
@diag = false
|
||||
dir = nil
|
||||
if count_x != 0 && count_y != 0
|
||||
return false
|
||||
elsif count_x > 0
|
||||
dir = 4
|
||||
elsif count_x < 0
|
||||
dir = 6
|
||||
elsif count_y > 0
|
||||
dir = 8
|
||||
elsif count_y < 0
|
||||
dir = 2
|
||||
end
|
||||
count = count_x != 0 ? count_x.abs : count_y.abs
|
||||
end
|
||||
$game_map.start_scroll(dir, count, speed) if dir != nil
|
||||
if @diag
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Map Autoscroll (to Player)
|
||||
# speed : (optional) scroll speed (from 1-6, default being 4)
|
||||
#-----------------------------------------------------------------------------
|
||||
def autoscroll_player(speed=SCROLL_SPEED_DEFAULT)
|
||||
autoscroll($game_player.x,$game_player.y,speed)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Game_Map
|
||||
def scroll_downright(distance)
|
||||
@display_x = [@display_x + distance,
|
||||
(self.width - Graphics.width*1.0/TILE_WIDTH) * REAL_RES_X].min
|
||||
@display_y = [@display_y + distance,
|
||||
(self.height - Graphics.height*1.0/TILE_HEIGHT) * REAL_RES_Y].min
|
||||
end
|
||||
|
||||
def scroll_downleft(distance)
|
||||
@display_x = [@display_x - distance, 0].max
|
||||
@display_y = [@display_y + distance,
|
||||
(self.height - Graphics.height*1.0/TILE_HEIGHT) * REAL_RES_Y].min
|
||||
end
|
||||
|
||||
def scroll_upright(distance)
|
||||
@display_x = [@display_x + distance,
|
||||
(self.width - Graphics.width*1.0/TILE_WIDTH) * REAL_RES_X].min
|
||||
@display_y = [@display_y - distance, 0].max
|
||||
end
|
||||
|
||||
def scroll_upleft(distance)
|
||||
@display_x = [@display_x - distance, 0].max
|
||||
@display_y = [@display_y - distance, 0].max
|
||||
end
|
||||
|
||||
def update_scrolling
|
||||
# If scrolling
|
||||
if @scroll_rest > 0
|
||||
# Change from scroll speed to distance in map coordinates
|
||||
distance = (1<<@scroll_speed)*40/Graphics.frame_rate
|
||||
distance = @scroll_rest if distance>@scroll_rest
|
||||
# Execute scrolling
|
||||
case @scroll_direction
|
||||
when 1 then scroll_downleft(distance)
|
||||
when 2 then scroll_down(distance)
|
||||
when 3 then scroll_downright(distance)
|
||||
when 4 then scroll_left(distance)
|
||||
when 6 then scroll_right(distance)
|
||||
when 7 then scroll_upleft(distance)
|
||||
when 8 then scroll_up(distance)
|
||||
when 9 then scroll_upright(distance)
|
||||
end
|
||||
# Subtract distance scrolled
|
||||
@scroll_rest -= distance
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,3 +1,6 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Game_Character
|
||||
attr_reader :id
|
||||
attr_reader :original_x
|
||||
@@ -6,13 +9,15 @@ class Game_Character
|
||||
attr_reader :y
|
||||
attr_reader :real_x
|
||||
attr_reader :real_y
|
||||
attr_writer :x_offset # In pixels, positive shifts sprite to the right
|
||||
attr_writer :y_offset # In pixels, positive shifts sprite down
|
||||
attr_accessor :width
|
||||
attr_accessor :height
|
||||
attr_accessor :sprite_size
|
||||
attr_reader :tile_id
|
||||
attr_accessor :character_name
|
||||
attr_accessor :character_hue
|
||||
attr_reader :opacity
|
||||
attr_accessor :opacity
|
||||
attr_reader :blend_type
|
||||
attr_accessor :direction
|
||||
attr_accessor :pattern
|
||||
@@ -20,13 +25,16 @@ class Game_Character
|
||||
attr_accessor :lock_pattern
|
||||
attr_reader :move_route_forcing
|
||||
attr_accessor :through
|
||||
attr_accessor :animation_id
|
||||
attr_reader :animation_id
|
||||
attr_accessor :animation_height
|
||||
attr_accessor :animation_regular_tone
|
||||
attr_accessor :transparent
|
||||
attr_reader :move_speed
|
||||
attr_reader :jump_speed
|
||||
attr_accessor :walk_anime
|
||||
attr_writer :bob_height
|
||||
|
||||
def initialize(map=nil)
|
||||
def initialize(map = nil)
|
||||
@map = map
|
||||
@id = 0
|
||||
@original_x = 0
|
||||
@@ -35,6 +43,8 @@ class Game_Character
|
||||
@y = 0
|
||||
@real_x = 0
|
||||
@real_y = 0
|
||||
@x_offset = 0
|
||||
@y_offset = 0
|
||||
@width = 1
|
||||
@height = 1
|
||||
@sprite_size = [Game_Map::TILE_WIDTH, Game_Map::TILE_HEIGHT]
|
||||
@@ -49,13 +59,14 @@ class Game_Character
|
||||
@lock_pattern = false
|
||||
@move_route_forcing = false
|
||||
@through = false
|
||||
@animation_id = 0
|
||||
animation_id = 0
|
||||
@transparent = false
|
||||
@original_direction = 2
|
||||
@original_pattern = 0
|
||||
@move_type = 0
|
||||
self.move_speed = 3
|
||||
self.move_frequency = 6
|
||||
self.jump_speed = 3
|
||||
@move_route = nil
|
||||
@move_route_index = 0
|
||||
@original_move_route = nil
|
||||
@@ -64,19 +75,32 @@ class Game_Character
|
||||
@step_anime = false # Whether character should animate while still
|
||||
@direction_fix = false
|
||||
@always_on_top = false
|
||||
@anime_count = 0
|
||||
@stop_count = 0
|
||||
@anime_count = 0 # Time since pattern was last changed
|
||||
@stop_count = 0 # Time since character last finished moving
|
||||
@jump_peak = 0 # Max height while jumping
|
||||
@jump_distance = 0 # Total distance of jump
|
||||
@jump_distance_left = 0 # Distance left to travel
|
||||
@jump_count = 0 # Frames left in a stationary jump
|
||||
@jump_fraction = 0 # How far through a jump we currently are (0-1)
|
||||
@jumping_on_spot = false
|
||||
@bob_height = 0
|
||||
@wait_count = 0
|
||||
@wait_start = nil
|
||||
@moved_this_frame = false
|
||||
@moveto_happened = false
|
||||
@locked = false
|
||||
@prelock_direction = 0
|
||||
end
|
||||
|
||||
def animation_id=(value)
|
||||
@animation_id = value
|
||||
if value == 0
|
||||
@animation_height = 3
|
||||
@animation_regular_tone = false
|
||||
end
|
||||
end
|
||||
|
||||
def x_offset; return @x_offset || 0; end
|
||||
def y_offset; return @y_offset || 0; end
|
||||
|
||||
def at_coordinate?(check_x, check_y)
|
||||
return check_x >= @x && check_x < @x + @width &&
|
||||
check_y > @y - @height && check_y <= @y
|
||||
@@ -88,70 +112,61 @@ class Game_Character
|
||||
end
|
||||
|
||||
def each_occupied_tile
|
||||
for i in @x...(@x + @width)
|
||||
for j in (@y - @height + 1)..@y
|
||||
(@x...(@x + @width)).each do |i|
|
||||
((@y - @height + 1)..@y).each do |j|
|
||||
yield i, j
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def move_speed=(val)
|
||||
return if val==@move_speed
|
||||
@move_speed = val
|
||||
# @move_speed_real is the number of quarter-pixels to move each frame. There
|
||||
# are 128 quarter-pixels per tile. By default, it is calculated from
|
||||
# @move_speed and has these values (assuming 40 fps):
|
||||
# 1 => 3.2 # 40 frames per tile
|
||||
# 2 => 6.4 # 20 frames per tile
|
||||
# 3 => 12.8 # 10 frames per tile - walking speed
|
||||
# 4 => 25.6 # 5 frames per tile - running speed (2x walking speed)
|
||||
# 5 => 32 # 4 frames per tile - cycling speed (1.25x running speed)
|
||||
# 6 => 64 # 2 frames per tile
|
||||
self.move_speed_real = (val == 6) ? 64 : (val == 5) ? 32 : (2 ** (val + 1)) * 0.8
|
||||
# Time taken to traverse one tile (in seconds) for each speed:
|
||||
# 1 => 1.0
|
||||
# 2 => 0.5
|
||||
# 3 => 0.25 # Walking speed
|
||||
# 4 => 0.125 # Running speed (2x walking speed)
|
||||
# 5 => 0.1 # Cycling speed (1.25x running speed)
|
||||
# 6 => 0.05
|
||||
case val
|
||||
when 6 then @move_time = 0.05
|
||||
when 5 then @move_time = 0.1
|
||||
else @move_time = 2.0 / (2**val)
|
||||
end
|
||||
end
|
||||
|
||||
def move_speed_real
|
||||
self.move_speed = @move_speed if !@move_speed_real
|
||||
return @move_speed_real
|
||||
# Takes the same values as move_speed above.
|
||||
def jump_speed=(val)
|
||||
@jump_speed = val
|
||||
case val
|
||||
when 6 then @jump_time = 0.05
|
||||
when 5 then @jump_time = 0.1
|
||||
else @jump_time = 2.0 / (2**val)
|
||||
end
|
||||
end
|
||||
|
||||
def move_speed_real=(val)
|
||||
@move_speed_real = val * 40.0 / Graphics.frame_rate
|
||||
end
|
||||
|
||||
def jump_speed_real
|
||||
self.jump_speed_real = (2 ** (3 + 1)) * 0.8 if !@jump_speed_real # 3 is walking speed
|
||||
return @jump_speed_real
|
||||
end
|
||||
|
||||
def jump_speed_real=(val)
|
||||
@jump_speed_real = val * 40.0 / Graphics.frame_rate
|
||||
# Returns time in seconds for one full cycle (4 frames) of an animating
|
||||
# charset to show. Two frames are shown per movement across one tile.
|
||||
def pattern_update_speed
|
||||
return @jump_time * 2 if jumping?
|
||||
ret = @move_time * 2
|
||||
ret *= 2 if @move_speed >= 5 # Cycling speed or faster; slower animation
|
||||
return ret
|
||||
end
|
||||
|
||||
def move_frequency=(val)
|
||||
return if val==@move_frequency
|
||||
return if val == @move_frequency
|
||||
@move_frequency = val
|
||||
# @move_frequency_real is the number of frames to wait between each action
|
||||
# in a move route (not forced). Specifically, this is the number of frames
|
||||
# to wait after the character stops moving because of the previous action.
|
||||
# By default, it is calculated from @move_frequency and has these values
|
||||
# (assuming 40 fps):
|
||||
# 1 => 190 # 4.75 seconds
|
||||
# 2 => 144 # 3.6 seconds
|
||||
# 3 => 102 # 2.55 seconds
|
||||
# 4 => 64 # 1.6 seconds
|
||||
# 5 => 30 # 0.75 seconds
|
||||
# 6 => 0 # 0 seconds, i.e. continuous movement
|
||||
self.move_frequency_real = (40 - val * 2) * (6 - val)
|
||||
end
|
||||
|
||||
def move_frequency_real
|
||||
self.move_frequency = @move_frequency if !@move_frequency_real
|
||||
return @move_frequency_real
|
||||
end
|
||||
|
||||
def move_frequency_real=(val)
|
||||
@move_frequency_real = val * Graphics.frame_rate / 40.0
|
||||
# Time in seconds to wait between each action in a move route (not forced).
|
||||
# Specifically, this is the time to wait after the character stops moving
|
||||
# because of the previous action.
|
||||
# 1 => 4.75 seconds
|
||||
# 2 => 3.6 seconds
|
||||
# 3 => 2.55 seconds
|
||||
# 4 => 1.6 seconds
|
||||
# 5 => 0.75 seconds
|
||||
# 6 => 0 seconds, i.e. continuous movement
|
||||
@command_delay = (40 - (val * 2)) * (6 - val) / 40.0
|
||||
end
|
||||
|
||||
def bob_height
|
||||
@@ -181,9 +196,10 @@ class Game_Character
|
||||
@direction = @prelock_direction if !@direction_fix && @prelock_direction != 0
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Information from map data
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def map
|
||||
return (@map) ? @map : $game_map
|
||||
end
|
||||
@@ -193,48 +209,65 @@ class Game_Character
|
||||
end
|
||||
|
||||
def bush_depth
|
||||
return 0 if respond_to?("name") && name[/airborne/i]
|
||||
return @bush_depth || 0
|
||||
end
|
||||
|
||||
def calculate_bush_depth
|
||||
if @tile_id > 0 || @always_on_top || jumping?
|
||||
if @tile_id > 0 || @always_on_top || jumping? || (respond_to?("name") && name[/airborne/i])
|
||||
@bush_depth = 0
|
||||
else
|
||||
deep_bush = regular_bush = false
|
||||
return
|
||||
end
|
||||
this_map = (self.map.valid?(@x, @y)) ? [self.map, @x, @y] : $map_factory&.getNewMap(@x, @y, self.map.map_id)
|
||||
if this_map && this_map[0].deepBush?(this_map[1], this_map[2])
|
||||
xbehind = @x + (@direction == 4 ? 1 : @direction == 6 ? -1 : 0)
|
||||
ybehind = @y + (@direction == 8 ? 1 : @direction == 2 ? -1 : 0)
|
||||
this_map = (self.map.valid?(@x, @y)) ? [self.map, @x, @y] : $MapFactory.getNewMap(@x, @y)
|
||||
if this_map[0].deepBush?(this_map[1], this_map[2]) && self.map.deepBush?(xbehind, ybehind)
|
||||
@bush_depth = Game_Map::TILE_HEIGHT
|
||||
elsif !moving? && this_map[0].bush?(this_map[1], this_map[2])
|
||||
@bush_depth = 12
|
||||
if moving?
|
||||
behind_map = (self.map.valid?(xbehind, ybehind)) ? [self.map, xbehind, ybehind] : $map_factory&.getNewMap(xbehind, ybehind, self.map.map_id)
|
||||
@bush_depth = Game_Map::TILE_HEIGHT if behind_map[0].deepBush?(behind_map[1], behind_map[2])
|
||||
else
|
||||
@bush_depth = 0
|
||||
@bush_depth = Game_Map::TILE_HEIGHT
|
||||
end
|
||||
elsif this_map && this_map[0].bush?(this_map[1], this_map[2]) && !moving?
|
||||
@bush_depth = 12
|
||||
else
|
||||
@bush_depth = 0
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
def fullPattern
|
||||
case self.direction
|
||||
when 2 then return self.pattern
|
||||
when 4 then return self.pattern + 4
|
||||
when 6 then return self.pattern + 8
|
||||
when 8 then return self.pattern + 12
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Passability
|
||||
#=============================================================================
|
||||
def passable?(x, y, d, strict = false)
|
||||
new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
|
||||
new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def passable?(x, y, dir, strict = false)
|
||||
new_x = x + (dir == 6 ? 1 : dir == 4 ? -1 : 0)
|
||||
new_y = y + (dir == 2 ? 1 : dir == 8 ? -1 : 0)
|
||||
return false unless self.map.valid?(new_x, new_y)
|
||||
return true if @through
|
||||
if strict
|
||||
return false unless self.map.passableStrict?(x, y, d, self)
|
||||
return false unless self.map.passableStrict?(new_x, new_y, 10 - d, self)
|
||||
return false unless self.map.passableStrict?(x, y, dir, self)
|
||||
return false unless self.map.passableStrict?(new_x, new_y, 10 - dir, self)
|
||||
else
|
||||
return false unless self.map.passable?(x, y, d, self)
|
||||
return false unless self.map.passable?(new_x, new_y, 10 - d, self)
|
||||
return false unless self.map.passable?(x, y, dir, self)
|
||||
return false unless self.map.passable?(new_x, new_y, 10 - dir, self)
|
||||
end
|
||||
for event in self.map.events.values
|
||||
self.map.events.each_value do |event|
|
||||
next if self == event || !event.at_coordinate?(new_x, new_y) || event.through
|
||||
return false if self != $game_player || event.character_name != ""
|
||||
end
|
||||
if $game_player.x == new_x && $game_player.y == new_y
|
||||
return false if !$game_player.through && @character_name != ""
|
||||
if $game_player.x == new_x && $game_player.y == new_y &&
|
||||
!$game_player.through && @character_name != ""
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
@@ -243,24 +276,24 @@ class Game_Character
|
||||
case dir
|
||||
when 2, 8 # Down, up
|
||||
y_diff = (dir == 8) ? @height - 1 : 0
|
||||
for i in start_x...(start_x + @width)
|
||||
(start_x...(start_x + @width)).each do |i|
|
||||
return false if !passable?(i, start_y - y_diff, dir, strict)
|
||||
end
|
||||
return true
|
||||
when 4, 6 # Left, right
|
||||
x_diff = (dir == 6) ? @width - 1 : 0
|
||||
for i in (start_y - @height + 1)..start_y
|
||||
((start_y - @height + 1)..start_y).each do |i|
|
||||
return false if !passable?(start_x + x_diff, i, dir, strict)
|
||||
end
|
||||
return true
|
||||
when 1, 3 # Down diagonals
|
||||
# Treated as moving down first and then horizontally, because that
|
||||
# describes which tiles the character's feet touch
|
||||
for i in start_x...(start_x + @width)
|
||||
(start_x...(start_x + @width)).each do |i|
|
||||
return false if !passable?(i, start_y, 2, strict)
|
||||
end
|
||||
x_diff = (dir == 3) ? @width - 1 : 0
|
||||
for i in (start_y - @height + 1)..start_y
|
||||
((start_y - @height + 1)..start_y).each do |i|
|
||||
return false if !passable?(start_x + x_diff, i + 1, dir + 3, strict)
|
||||
end
|
||||
return true
|
||||
@@ -268,12 +301,12 @@ class Game_Character
|
||||
# Treated as moving horizontally first and then up, because that describes
|
||||
# which tiles the character's feet touch
|
||||
x_diff = (dir == 9) ? @width - 1 : 0
|
||||
for i in (start_y - @height + 1)..start_y
|
||||
((start_y - @height + 1)..start_y).each do |i|
|
||||
return false if !passable?(start_x + x_diff, i, dir - 3, strict)
|
||||
end
|
||||
x_offset = (dir == 9) ? 1 : -1
|
||||
for i in start_x...(start_x + @width)
|
||||
return false if !passable?(i + x_offset, start_y - @height + 1, 8, strict)
|
||||
x_tile_offset = (dir == 9) ? 1 : -1
|
||||
(start_x...(start_x + @width)).each do |i|
|
||||
return false if !passable?(i + x_tile_offset, start_y - @height + 1, 8, strict)
|
||||
end
|
||||
return true
|
||||
end
|
||||
@@ -284,17 +317,19 @@ class Game_Character
|
||||
return can_move_from_coordinate?(@x, @y, dir, strict)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Screen position of the character
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def screen_x
|
||||
ret = ((@real_x - self.map.display_x) / Game_Map::X_SUBPIXELS).round
|
||||
ret = ((@real_x.to_f - self.map.display_x) / Game_Map::X_SUBPIXELS).round
|
||||
ret += @width * Game_Map::TILE_WIDTH / 2
|
||||
ret += self.x_offset
|
||||
return ret
|
||||
end
|
||||
|
||||
def screen_y_ground
|
||||
ret = ((@real_y - self.map.display_y) / Game_Map::Y_SUBPIXELS).round
|
||||
ret = ((@real_y.to_f - self.map.display_y) / Game_Map::Y_SUBPIXELS).round
|
||||
ret += Game_Map::TILE_HEIGHT
|
||||
return ret
|
||||
end
|
||||
@@ -302,13 +337,10 @@ class Game_Character
|
||||
def screen_y
|
||||
ret = screen_y_ground
|
||||
if jumping?
|
||||
if @jump_count > 0
|
||||
jump_fraction = ((@jump_count * jump_speed_real / Game_Map::REAL_RES_X) - 0.5).abs # 0.5 to 0 to 0.5
|
||||
else
|
||||
jump_fraction = ((@jump_distance_left / @jump_distance) - 0.5).abs # 0.5 to 0 to 0.5
|
||||
end
|
||||
ret += @jump_peak * (4 * jump_fraction**2 - 1)
|
||||
jump_progress = (@jump_fraction - 0.5).abs # 0.5 to 0 to 0.5
|
||||
ret += @jump_peak * ((4 * (jump_progress**2)) - 1)
|
||||
end
|
||||
ret += self.y_offset
|
||||
return ret
|
||||
end
|
||||
|
||||
@@ -317,7 +349,7 @@ class Game_Character
|
||||
z = screen_y_ground
|
||||
if @tile_id > 0
|
||||
begin
|
||||
return z + self.map.priorities[@tile_id] * 32
|
||||
return z + (self.map.priorities[@tile_id] * 32)
|
||||
rescue
|
||||
raise "Event's graphic is an out-of-range tile (event #{@id}, map #{self.map.map_id})"
|
||||
end
|
||||
@@ -326,16 +358,16 @@ class Game_Character
|
||||
return z + ((height > Game_Map::TILE_HEIGHT) ? Game_Map::TILE_HEIGHT - 1 : 0)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Movement
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def moving?
|
||||
return @real_x != @x * Game_Map::REAL_RES_X ||
|
||||
@real_y != @y * Game_Map::REAL_RES_Y
|
||||
return !@move_timer.nil?
|
||||
end
|
||||
|
||||
def jumping?
|
||||
return (@jump_distance_left || 0) > 0 || @jump_count > 0
|
||||
return !@jump_timer.nil?
|
||||
end
|
||||
|
||||
def straighten
|
||||
@@ -345,7 +377,7 @@ class Game_Character
|
||||
end
|
||||
|
||||
def force_move_route(move_route)
|
||||
if @original_move_route == nil
|
||||
if @original_move_route.nil?
|
||||
@original_move_route = @move_route
|
||||
@original_move_route_index = @move_route_index
|
||||
end
|
||||
@@ -354,6 +386,7 @@ class Game_Character
|
||||
@move_route_forcing = true
|
||||
@prelock_direction = 0
|
||||
@wait_count = 0
|
||||
@wait_start = nil
|
||||
move_type_custom
|
||||
end
|
||||
|
||||
@@ -363,14 +396,15 @@ class Game_Character
|
||||
@real_x = @x * Game_Map::REAL_RES_X
|
||||
@real_y = @y * Game_Map::REAL_RES_Y
|
||||
@prelock_direction = 0
|
||||
@moveto_happened = true
|
||||
calculate_bush_depth
|
||||
triggerLeaveTile
|
||||
end
|
||||
|
||||
def triggerLeaveTile
|
||||
if @oldX && @oldY && @oldMap &&
|
||||
(@oldX!=self.x || @oldY!=self.y || @oldMap!=self.map.map_id)
|
||||
Events.onLeaveTile.trigger(self,self,@oldMap,@oldX,@oldY)
|
||||
(@oldX != self.x || @oldY != self.y || @oldMap != self.map.map_id)
|
||||
EventHandlers.trigger(:on_leave_tile, self, @oldMap, @oldX, @oldY)
|
||||
end
|
||||
@oldX = self.x
|
||||
@oldY = self.y
|
||||
@@ -382,9 +416,10 @@ class Game_Character
|
||||
triggerLeaveTile
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Movement commands
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def move_type_random
|
||||
case rand(6)
|
||||
when 0..3 then move_random
|
||||
@@ -394,8 +429,8 @@ class Game_Character
|
||||
end
|
||||
|
||||
def move_type_toward_player
|
||||
sx = @x + @width / 2.0 - ($game_player.x + $game_player.width / 2.0)
|
||||
sy = @y - @height / 2.0 - ($game_player.y - $game_player.height / 2.0)
|
||||
sx = @x + (@width / 2.0) - ($game_player.x + ($game_player.width / 2.0))
|
||||
sy = @y - (@height / 2.0) - ($game_player.y - ($game_player.height / 2.0))
|
||||
if sx.abs + sy.abs >= 20
|
||||
move_random
|
||||
return
|
||||
@@ -409,11 +444,14 @@ class Game_Character
|
||||
|
||||
def move_type_custom
|
||||
return if jumping? || moving?
|
||||
while @move_route_index < @move_route.list.size
|
||||
return if @move_route.list.size <= 1 # Empty move route
|
||||
start_index = @move_route_index
|
||||
(@move_route.list.size - 1).times do
|
||||
command = @move_route.list[@move_route_index]
|
||||
if command.code == 0
|
||||
if @move_route.repeat
|
||||
@move_route_index = 0
|
||||
command = @move_route.list[@move_route_index]
|
||||
else
|
||||
if @move_route_forcing
|
||||
@move_route_forcing = false
|
||||
@@ -422,9 +460,12 @@ class Game_Character
|
||||
@original_move_route = nil
|
||||
end
|
||||
@stop_count = 0
|
||||
return
|
||||
end
|
||||
return
|
||||
end
|
||||
done_one_command = true
|
||||
# The below move route commands wait for a frame (i.e. return) after
|
||||
# executing them
|
||||
if command.code <= 14
|
||||
case command.code
|
||||
when 1 then move_down
|
||||
@@ -445,13 +486,13 @@ class Game_Character
|
||||
@move_route_index += 1 if @move_route.skippable || moving? || jumping?
|
||||
return
|
||||
end
|
||||
if command.code == 15 # Wait
|
||||
@wait_count = (command.parameters[0] * Graphics.frame_rate / 20) - 1
|
||||
@move_route_index += 1
|
||||
return
|
||||
end
|
||||
if command.code >= 16 && command.code <= 26
|
||||
# The below move route commands wait for a frame (i.e. return) after
|
||||
# executing them
|
||||
if command.code >= 15 && command.code <= 26
|
||||
case command.code
|
||||
when 15 # Wait
|
||||
@wait_count = command.parameters[0] / 20.0
|
||||
@wait_start = System.uptime
|
||||
when 16 then turn_down
|
||||
when 17 then turn_left
|
||||
when 18 then turn_right
|
||||
@@ -467,6 +508,8 @@ class Game_Character
|
||||
@move_route_index += 1
|
||||
return
|
||||
end
|
||||
# The below move route commands don't wait for a frame (i.e. return) after
|
||||
# executing them
|
||||
if command.code >= 27
|
||||
case command.code
|
||||
when 27
|
||||
@@ -511,7 +554,14 @@ class Game_Character
|
||||
when 42 then @opacity = command.parameters[0]
|
||||
when 43 then @blend_type = command.parameters[0]
|
||||
when 44 then pbSEPlay(command.parameters[0])
|
||||
when 45 then eval(command.parameters[0])
|
||||
when 45
|
||||
eval(command.parameters[0])
|
||||
if command.parameters[0][/^move_random_range/] ||
|
||||
command.parameters[0][/^move_random_UD/] ||
|
||||
command.parameters[0][/^move_random_LR/]
|
||||
@move_route_index += 1
|
||||
return
|
||||
end
|
||||
end
|
||||
@move_route_index += 1
|
||||
end
|
||||
@@ -522,8 +572,11 @@ class Game_Character
|
||||
turn_generic(dir) if turn_enabled
|
||||
if can_move_in_direction?(dir)
|
||||
turn_generic(dir)
|
||||
@move_initial_x = @x
|
||||
@move_initial_y = @y
|
||||
@x += (dir == 4) ? -1 : (dir == 6) ? 1 : 0
|
||||
@y += (dir == 8) ? -1 : (dir == 2) ? 1 : 0
|
||||
@move_timer = 0.0
|
||||
increase_steps
|
||||
else
|
||||
check_event_trigger_touch(dir)
|
||||
@@ -551,8 +604,11 @@ class Game_Character
|
||||
@direction = (@direction == 6 ? 4 : @direction == 2 ? 8 : @direction)
|
||||
end
|
||||
if can_move_in_direction?(7)
|
||||
@move_initial_x = @x
|
||||
@move_initial_y = @y
|
||||
@x -= 1
|
||||
@y -= 1
|
||||
@move_timer = 0.0
|
||||
increase_steps
|
||||
end
|
||||
end
|
||||
@@ -562,8 +618,11 @@ class Game_Character
|
||||
@direction = (@direction == 4 ? 6 : @direction == 2 ? 8 : @direction)
|
||||
end
|
||||
if can_move_in_direction?(9)
|
||||
@move_initial_x = @x
|
||||
@move_initial_y = @y
|
||||
@x += 1
|
||||
@y -= 1
|
||||
@move_timer = 0.0
|
||||
increase_steps
|
||||
end
|
||||
end
|
||||
@@ -573,8 +632,11 @@ class Game_Character
|
||||
@direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction)
|
||||
end
|
||||
if can_move_in_direction?(1)
|
||||
@move_initial_x = @x
|
||||
@move_initial_y = @y
|
||||
@x -= 1
|
||||
@y += 1
|
||||
@move_timer = 0.0
|
||||
increase_steps
|
||||
end
|
||||
end
|
||||
@@ -584,13 +646,17 @@ class Game_Character
|
||||
@direction = (@direction == 4 ? 6 : @direction == 8 ? 2 : @direction)
|
||||
end
|
||||
if can_move_in_direction?(3)
|
||||
@move_initial_x = @x
|
||||
@move_initial_y = @y
|
||||
@x += 1
|
||||
@y += 1
|
||||
@move_timer = 0.0
|
||||
increase_steps
|
||||
end
|
||||
end
|
||||
|
||||
def moveLeft90 # anticlockwise
|
||||
# Anticlockwise.
|
||||
def moveLeft90
|
||||
case self.direction
|
||||
when 2 then move_right # down
|
||||
when 4 then move_down # left
|
||||
@@ -599,7 +665,8 @@ class Game_Character
|
||||
end
|
||||
end
|
||||
|
||||
def moveRight90 # clockwise
|
||||
# Clockwise.
|
||||
def moveRight90
|
||||
case self.direction
|
||||
when 2 then move_left # down
|
||||
when 4 then move_up # left
|
||||
@@ -617,21 +684,23 @@ class Game_Character
|
||||
end
|
||||
end
|
||||
|
||||
def move_random_range(xrange=-1,yrange=-1)
|
||||
def move_random_range(xrange = -1, yrange = -1)
|
||||
dirs = [] # 0=down, 1=left, 2=right, 3=up
|
||||
if xrange<0
|
||||
dirs.push(1); dirs.push(2)
|
||||
elsif xrange>0
|
||||
if xrange < 0
|
||||
dirs.push(1)
|
||||
dirs.push(2)
|
||||
elsif xrange > 0
|
||||
dirs.push(1) if @x > @original_x - xrange
|
||||
dirs.push(2) if @x < @original_x + xrange
|
||||
end
|
||||
if yrange<0
|
||||
dirs.push(0); dirs.push(3)
|
||||
elsif yrange>0
|
||||
if yrange < 0
|
||||
dirs.push(0)
|
||||
dirs.push(3)
|
||||
elsif yrange > 0
|
||||
dirs.push(0) if @y < @original_y + yrange
|
||||
dirs.push(3) if @y > @original_y - yrange
|
||||
end
|
||||
return if dirs.length==0
|
||||
return if dirs.length == 0
|
||||
case dirs[rand(dirs.length)]
|
||||
when 0 then move_down(false)
|
||||
when 1 then move_left(false)
|
||||
@@ -640,17 +709,17 @@ class Game_Character
|
||||
end
|
||||
end
|
||||
|
||||
def move_random_UD(range=-1)
|
||||
move_random_range(0,range)
|
||||
def move_random_UD(range = -1)
|
||||
move_random_range(0, range)
|
||||
end
|
||||
|
||||
def move_random_LR(range=-1)
|
||||
move_random_range(range,0)
|
||||
def move_random_LR(range = -1)
|
||||
move_random_range(range, 0)
|
||||
end
|
||||
|
||||
def move_toward_player
|
||||
sx = @x + @width / 2.0 - ($game_player.x + $game_player.width / 2.0)
|
||||
sy = @y - @height / 2.0 - ($game_player.y - $game_player.height / 2.0)
|
||||
sx = @x + (@width / 2.0) - ($game_player.x + ($game_player.width / 2.0))
|
||||
sy = @y - (@height / 2.0) - ($game_player.y - ($game_player.height / 2.0))
|
||||
return if sx == 0 && sy == 0
|
||||
abs_sx = sx.abs
|
||||
abs_sy = sy.abs
|
||||
@@ -658,21 +727,29 @@ class Game_Character
|
||||
(rand(2) == 0) ? abs_sx += 1 : abs_sy += 1
|
||||
end
|
||||
if abs_sx > abs_sy
|
||||
(sx > 0) ? move_left : move_right
|
||||
if abs_sx >= 1
|
||||
(sx > 0) ? move_left : move_right
|
||||
end
|
||||
if !moving? && sy != 0
|
||||
(sy > 0) ? move_up : move_down
|
||||
if abs_sy >= 1
|
||||
(sy > 0) ? move_up : move_down
|
||||
end
|
||||
end
|
||||
else
|
||||
(sy > 0) ? move_up : move_down
|
||||
if abs_sy >= 1
|
||||
(sy > 0) ? move_up : move_down
|
||||
end
|
||||
if !moving? && sx != 0
|
||||
(sx > 0) ? move_left : move_right
|
||||
if abs_sx >= 1
|
||||
(sx > 0) ? move_left : move_right
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def move_away_from_player
|
||||
sx = @x + @width / 2.0 - ($game_player.x + $game_player.width / 2.0)
|
||||
sy = @y - @height / 2.0 - ($game_player.y - $game_player.height / 2.0)
|
||||
sx = @x + (@width / 2.0) - ($game_player.x + ($game_player.width / 2.0))
|
||||
sy = @y - (@height / 2.0) - ($game_player.y - ($game_player.height / 2.0))
|
||||
return if sx == 0 && sy == 0
|
||||
abs_sx = sx.abs
|
||||
abs_sy = sy.abs
|
||||
@@ -722,42 +799,43 @@ class Game_Character
|
||||
end
|
||||
each_occupied_tile { |i, j| return if !passable?(i + x_plus, j + y_plus, 0) }
|
||||
end
|
||||
@x = @x + x_plus
|
||||
@y = @y + y_plus
|
||||
real_distance = Math::sqrt(x_plus * x_plus + y_plus * y_plus)
|
||||
@jump_initial_x = @x
|
||||
@jump_initial_y = @y
|
||||
@x += x_plus
|
||||
@y += y_plus
|
||||
@jump_timer = 0.0
|
||||
real_distance = Math.sqrt((x_plus**2) + (y_plus**2))
|
||||
distance = [1, real_distance].max
|
||||
@jump_peak = distance * Game_Map::TILE_HEIGHT * 3 / 8 # 3/4 of tile for ledge jumping
|
||||
@jump_distance = [x_plus.abs * Game_Map::REAL_RES_X, y_plus.abs * Game_Map::REAL_RES_Y].max
|
||||
@jump_distance_left = 1 # Just needs to be non-zero
|
||||
if real_distance > 0 # Jumping to somewhere else
|
||||
@jump_count = 0
|
||||
else # Jumping on the spot
|
||||
@jump_speed_real = nil # Reset jump speed
|
||||
@jump_count = Game_Map::REAL_RES_X / jump_speed_real # Number of frames to jump one tile
|
||||
end
|
||||
@stop_count = 0
|
||||
if self.is_a?(Game_Player)
|
||||
$PokemonTemp.dependentEvents.pbMoveDependentEvents
|
||||
end
|
||||
triggerLeaveTile
|
||||
@jumping_on_spot = (real_distance == 0)
|
||||
increase_steps
|
||||
end
|
||||
|
||||
def jumpForward
|
||||
def jumpForward(distance = 1)
|
||||
return false if distance == 0
|
||||
old_x = @x
|
||||
old_y = @y
|
||||
case self.direction
|
||||
when 2 then jump(0,1) # down
|
||||
when 4 then jump(-1,0) # left
|
||||
when 6 then jump(1,0) # right
|
||||
when 8 then jump(0,-1) # up
|
||||
when 2 then jump(0, distance) # down
|
||||
when 4 then jump(-distance, 0) # left
|
||||
when 6 then jump(distance, 0) # right
|
||||
when 8 then jump(0, -distance) # up
|
||||
end
|
||||
return @x != old_x || @y != old_y
|
||||
end
|
||||
|
||||
def jumpBackward
|
||||
def jumpBackward(distance = 1)
|
||||
return false if distance == 0
|
||||
old_x = @x
|
||||
old_y = @y
|
||||
case self.direction
|
||||
when 2 then jump(0,-1) # down
|
||||
when 4 then jump(1,0) # left
|
||||
when 6 then jump(-1,0) # right
|
||||
when 8 then jump(0,1) # up
|
||||
when 2 then jump(0, -distance) # down
|
||||
when 4 then jump(distance, 0) # left
|
||||
when 6 then jump(-distance, 0) # right
|
||||
when 8 then jump(0, distance) # up
|
||||
end
|
||||
return @x != old_x || @y != old_y
|
||||
end
|
||||
|
||||
def turn_generic(dir)
|
||||
@@ -765,7 +843,7 @@ class Game_Character
|
||||
oldDirection = @direction
|
||||
@direction = dir
|
||||
@stop_count = 0
|
||||
pbCheckEventTriggerAfterTurning if dir != oldDirection
|
||||
check_event_trigger_after_turning if dir != oldDirection
|
||||
end
|
||||
|
||||
def turn_down; turn_generic(2); end
|
||||
@@ -814,8 +892,8 @@ class Game_Character
|
||||
end
|
||||
|
||||
def turn_toward_player
|
||||
sx = @x + @width / 2.0 - ($game_player.x + $game_player.width / 2.0)
|
||||
sy = @y - @height / 2.0 - ($game_player.y - $game_player.height / 2.0)
|
||||
sx = @x + (@width / 2.0) - ($game_player.x + ($game_player.width / 2.0))
|
||||
sy = @y - (@height / 2.0) - ($game_player.y - ($game_player.height / 2.0))
|
||||
return if sx == 0 && sy == 0
|
||||
if sx.abs > sy.abs
|
||||
(sx > 0) ? turn_left : turn_right
|
||||
@@ -825,8 +903,8 @@ class Game_Character
|
||||
end
|
||||
|
||||
def turn_away_from_player
|
||||
sx = @x + @width / 2.0 - ($game_player.x + $game_player.width / 2.0)
|
||||
sy = @y - @height / 2.0 - ($game_player.y - $game_player.height / 2.0)
|
||||
sx = @x + (@width / 2.0) - ($game_player.x + ($game_player.width / 2.0))
|
||||
sy = @y - (@height / 2.0) - ($game_player.y - ($game_player.height / 2.0))
|
||||
return if sx == 0 && sy == 0
|
||||
if sx.abs > sy.abs
|
||||
(sx > 0) ? turn_right : turn_left
|
||||
@@ -835,26 +913,36 @@ class Game_Character
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
# Updating
|
||||
#=============================================================================
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def update
|
||||
return if $game_temp.in_menu
|
||||
time_now = System.uptime
|
||||
@last_update_time = time_now if !@last_update_time || @last_update_time > time_now
|
||||
@delta_t = time_now - @last_update_time
|
||||
@last_update_time = time_now
|
||||
return if @delta_t > 0.25 # Was in a menu; delay movement
|
||||
@moved_last_frame = @moved_this_frame
|
||||
@stopped_last_frame = @stopped_this_frame
|
||||
if !$game_temp.in_menu
|
||||
# Update command
|
||||
update_command
|
||||
# Update movement
|
||||
(moving? || jumping?) ? update_move : update_stop
|
||||
end
|
||||
@moved_this_frame = false
|
||||
@stopped_this_frame = false
|
||||
# Update command
|
||||
update_command
|
||||
# Update movement
|
||||
(moving? || jumping?) ? update_move : update_stop
|
||||
# Update animation
|
||||
update_pattern
|
||||
end
|
||||
|
||||
def update_command
|
||||
if @wait_count > 0
|
||||
@wait_count -= 1
|
||||
elsif @move_route_forcing
|
||||
return if System.uptime - @wait_start < @wait_count
|
||||
@wait_count = 0
|
||||
@wait_start = nil
|
||||
end
|
||||
if @move_route_forcing
|
||||
move_type_custom
|
||||
elsif !@starting && !lock? && !moving? && !jumping?
|
||||
update_command_new
|
||||
@@ -862,15 +950,7 @@ class Game_Character
|
||||
end
|
||||
|
||||
def update_command_new
|
||||
# @stop_count is the number of frames since the last movement finished.
|
||||
# @move_frequency has these values:
|
||||
# 1 => @stop_count > 190 # 4.75 seconds
|
||||
# 2 => @stop_count > 144 # 3.6 seconds
|
||||
# 3 => @stop_count > 102 # 2.55 seconds
|
||||
# 4 => @stop_count > 64 # 1.6 seconds
|
||||
# 5 => @stop_count > 30 # 0.75 seconds
|
||||
# 6 => @stop_count > 0 # 0 seconds
|
||||
if @stop_count >= self.move_frequency_real
|
||||
if @stop_count >= @command_delay
|
||||
case @move_type
|
||||
when 1 then move_type_random
|
||||
when 2 then move_type_toward_player
|
||||
@@ -880,53 +960,71 @@ class Game_Character
|
||||
end
|
||||
|
||||
def update_move
|
||||
# Move the character (the 0.1 catches rounding errors)
|
||||
distance = (jumping?) ? jump_speed_real : move_speed_real
|
||||
dest_x = @x * Game_Map::REAL_RES_X
|
||||
dest_y = @y * Game_Map::REAL_RES_Y
|
||||
if @real_x < dest_x
|
||||
@real_x += distance
|
||||
@real_x = dest_x if @real_x > dest_x - 0.1
|
||||
else
|
||||
@real_x -= distance
|
||||
@real_x = dest_x if @real_x < dest_x + 0.1
|
||||
if @move_timer
|
||||
@move_timer += @delta_t
|
||||
# Move horizontally
|
||||
if @x != @move_initial_x
|
||||
dist = (@move_initial_x - @x).abs
|
||||
@real_x = lerp(@move_initial_x, @x, @move_time * dist, @move_timer) * Game_Map::REAL_RES_X
|
||||
end
|
||||
# Move vertically
|
||||
if @y != @move_initial_y
|
||||
dist = (@move_initial_y - @y).abs
|
||||
@real_y = lerp(@move_initial_y, @y, @move_time * dist, @move_timer) * Game_Map::REAL_RES_Y
|
||||
end
|
||||
elsif @jump_timer
|
||||
self.jump_speed = 3 if !@jump_time
|
||||
@jump_timer += @delta_t
|
||||
dist = [(@x - @jump_initial_x).abs, (@y - @jump_initial_y).abs].max
|
||||
dist = 1 if dist == 0 # Jumping on spot
|
||||
# Move horizontally
|
||||
if @x != @jump_initial_x
|
||||
@real_x = lerp(@jump_initial_x, @x, @jump_time * dist, @jump_timer) * Game_Map::REAL_RES_X
|
||||
end
|
||||
# Move vertically
|
||||
if @y != @jump_initial_y
|
||||
@real_y = lerp(@jump_initial_y, @y, @jump_time * dist, @jump_timer) * Game_Map::REAL_RES_Y
|
||||
end
|
||||
# Calculate how far through the jump we are (from 0 to 1)
|
||||
@jump_fraction = @jump_timer / (@jump_time * dist)
|
||||
end
|
||||
if @real_y < dest_y
|
||||
@real_y += distance
|
||||
@real_y = dest_y if @real_y > dest_y - 0.1
|
||||
else
|
||||
@real_y -= distance
|
||||
@real_y = dest_y if @real_y < dest_y + 0.1
|
||||
# Snap to end position if close enough
|
||||
@real_x = @x * Game_Map::REAL_RES_X if (@real_x - (@x * Game_Map::REAL_RES_X)).abs < Game_Map::X_SUBPIXELS / 2
|
||||
@real_y = @y * Game_Map::REAL_RES_Y if (@real_y - (@y * Game_Map::REAL_RES_Y)).abs < Game_Map::Y_SUBPIXELS / 2
|
||||
# End of move
|
||||
if moving? && @move_timer >= @move_time &&
|
||||
@real_x == @x * Game_Map::REAL_RES_X && @real_y == @y * Game_Map::REAL_RES_Y
|
||||
@move_timer = nil
|
||||
end
|
||||
# Refresh how far is left to travel in a jump
|
||||
if jumping?
|
||||
@jump_count -= 1 if @jump_count > 0 # For stationary jumps only
|
||||
@jump_distance_left = [(dest_x - @real_x).abs, (dest_y - @real_y).abs].max
|
||||
# End of jump
|
||||
if jumping? && @jump_fraction >= 1
|
||||
@jump_timer = nil
|
||||
@jump_peak = 0
|
||||
@jump_distance = 0
|
||||
@jump_fraction = 0
|
||||
@jumping_on_spot = false
|
||||
end
|
||||
# End of a step, so perform events that happen at this time
|
||||
if !jumping? && !moving?
|
||||
Events.onStepTakenFieldMovement.trigger(self, self)
|
||||
EventHandlers.trigger(:on_step_taken, self)
|
||||
calculate_bush_depth
|
||||
@stopped_this_frame = true
|
||||
elsif !@moved_last_frame || @stopped_last_frame # Started a new step
|
||||
calculate_bush_depth
|
||||
@stopped_this_frame = false
|
||||
end
|
||||
# Increment animation counter
|
||||
@anime_count += 1 if @walk_anime || @step_anime
|
||||
@anime_count += @delta_t if @walk_anime || @step_anime
|
||||
@moved_this_frame = true
|
||||
end
|
||||
|
||||
def update_stop
|
||||
@anime_count += 1 if @step_anime
|
||||
@stop_count += 1 if !@starting && !lock?
|
||||
@moved_this_frame = false
|
||||
@stopped_this_frame = false
|
||||
@anime_count += @delta_t if @step_anime
|
||||
@stop_count += @delta_t if !@starting && !lock?
|
||||
end
|
||||
|
||||
def update_pattern
|
||||
return if @lock_pattern
|
||||
# return if @jump_count > 0 # Don't animate if jumping on the spot
|
||||
# return if @jumping_on_spot # Don't animate if jumping on the spot
|
||||
# Character has stopped moving, return to original pattern
|
||||
if @moved_last_frame && !@moved_this_frame && !@step_anime
|
||||
@pattern = @original_pattern
|
||||
@@ -942,12 +1040,10 @@ class Game_Character
|
||||
# Calculate how many frames each pattern should display for, i.e. the time
|
||||
# it takes to move half a tile (or a whole tile if cycling). We assume the
|
||||
# game uses square tiles.
|
||||
real_speed = (jumping?) ? jump_speed_real : move_speed_real
|
||||
frames_per_pattern = Game_Map::REAL_RES_X / (real_speed * 2.0)
|
||||
frames_per_pattern *= 2 if move_speed >= 5 # Cycling speed or faster
|
||||
return if @anime_count < frames_per_pattern
|
||||
pattern_time = pattern_update_speed / 4 # 4 frames per cycle in a charset
|
||||
return if @anime_count < pattern_time
|
||||
# Advance to the next animation frame
|
||||
@pattern = (@pattern + 1) % 4
|
||||
@anime_count -= frames_per_pattern
|
||||
@anime_count -= pattern_time
|
||||
end
|
||||
end
|
||||
@@ -1,3 +1,6 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Game_Event < Game_Character
|
||||
attr_reader :map_id
|
||||
attr_reader :trigger
|
||||
@@ -6,7 +9,7 @@ class Game_Event < Game_Character
|
||||
attr_reader :tempSwitches # Temporary self-switches
|
||||
attr_accessor :need_refresh
|
||||
|
||||
def initialize(map_id, event, map=nil)
|
||||
def initialize(map_id, event, map = nil)
|
||||
super(map)
|
||||
@map_id = map_id
|
||||
@event = event
|
||||
@@ -54,7 +57,7 @@ class Game_Event < Game_Character
|
||||
end
|
||||
|
||||
def tsOn?(c)
|
||||
return @tempSwitches && @tempSwitches[c]==true
|
||||
return @tempSwitches && @tempSwitches[c] == true
|
||||
end
|
||||
|
||||
def tsOff?(c)
|
||||
@@ -62,56 +65,62 @@ class Game_Event < Game_Character
|
||||
end
|
||||
|
||||
def setTempSwitchOn(c)
|
||||
@tempSwitches[c]=true
|
||||
@tempSwitches[c] = true
|
||||
refresh
|
||||
end
|
||||
|
||||
def setTempSwitchOff(c)
|
||||
@tempSwitches[c]=false
|
||||
@tempSwitches[c] = false
|
||||
refresh
|
||||
end
|
||||
|
||||
def isOff?(c)
|
||||
return !$game_self_switches[[@map_id,@event.id,c]]
|
||||
return !$game_self_switches[[@map_id, @event.id, c]]
|
||||
end
|
||||
|
||||
def switchIsOn?(id)
|
||||
switchname = $data_system.switches[id]
|
||||
return false if !switchname
|
||||
if switchname[/^s\:/]
|
||||
switch_name = $data_system.switches[id]
|
||||
if switch_name && switch_name[/^s\:/]
|
||||
return eval($~.post_match)
|
||||
else
|
||||
return $game_switches[id]
|
||||
end
|
||||
return $game_switches[id]
|
||||
end
|
||||
|
||||
def variableIsLessThan?(id, value)
|
||||
variable_name = $data_system.variables[id]
|
||||
if variable_name && variable_name[/^s\:/]
|
||||
return eval($~.post_match) < value
|
||||
end
|
||||
return $game_variables[id] < value
|
||||
end
|
||||
|
||||
def variable
|
||||
return nil if !$PokemonGlobal.eventvars
|
||||
return $PokemonGlobal.eventvars[[@map_id,@event.id]]
|
||||
return $PokemonGlobal.eventvars[[@map_id, @event.id]]
|
||||
end
|
||||
|
||||
def setVariable(variable)
|
||||
$PokemonGlobal.eventvars[[@map_id,@event.id]]=variable
|
||||
$PokemonGlobal.eventvars[[@map_id, @event.id]] = variable
|
||||
end
|
||||
|
||||
def varAsInt
|
||||
return 0 if !$PokemonGlobal.eventvars
|
||||
return $PokemonGlobal.eventvars[[@map_id,@event.id]].to_i
|
||||
return $PokemonGlobal.eventvars[[@map_id, @event.id]].to_i
|
||||
end
|
||||
|
||||
def expired?(secs=86400)
|
||||
ontime=self.variable
|
||||
time=pbGetTimeNow
|
||||
return ontime && (time.to_i>ontime+secs)
|
||||
def expired?(secs = 86_400)
|
||||
ontime = self.variable
|
||||
time = pbGetTimeNow
|
||||
return ontime && (time.to_i > ontime + secs)
|
||||
end
|
||||
|
||||
def expiredDays?(days=1)
|
||||
ontime=self.variable.to_i
|
||||
def expiredDays?(days = 1)
|
||||
ontime = self.variable.to_i
|
||||
return false if !ontime
|
||||
now=pbGetTimeNow
|
||||
elapsed=(now.to_i-ontime)/86400
|
||||
elapsed+=1 if (now.to_i-ontime)%86400>(now.hour*3600+now.min*60+now.sec)
|
||||
return elapsed>=days
|
||||
now = pbGetTimeNow
|
||||
elapsed = (now.to_i - ontime) / 86_400
|
||||
elapsed += 1 if (now.to_i - ontime) % 86_400 > ((now.hour * 3600) + (now.min * 60) + now.sec)
|
||||
return elapsed >= days
|
||||
end
|
||||
|
||||
def cooledDown?(seconds)
|
||||
@@ -127,10 +136,11 @@ class Game_Event < Game_Character
|
||||
end
|
||||
|
||||
def onEvent?
|
||||
return @map_id == $game_map.map_id && at_coordinate?($game_player.x, $game_player.y)
|
||||
return @map_id == $game_player.map_id && at_coordinate?($game_player.x, $game_player.y)
|
||||
end
|
||||
|
||||
def over_trigger?
|
||||
return false if @map_id != $game_player.map_id
|
||||
return false if @character_name != "" && !@through
|
||||
return false if @event.name[/hiddenitem/i]
|
||||
each_occupied_tile do |i, j|
|
||||
@@ -139,19 +149,10 @@ class Game_Event < Game_Character
|
||||
return false
|
||||
end
|
||||
|
||||
def pbCheckEventTriggerAfterTurning
|
||||
return if $game_system.map_interpreter.running? || @starting
|
||||
if @event.name[/trainer\((\d+)\)/i]
|
||||
distance = $~[1].to_i
|
||||
if @trigger==2 && pbEventCanReachPlayer?(self,$game_player,distance)
|
||||
start if !jumping? && !over_trigger?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def check_event_trigger_touch(dir)
|
||||
return if $game_system.map_interpreter.running?
|
||||
return if @map_id != $game_player.map_id
|
||||
return if @trigger != 2 # Event touch
|
||||
return if $game_system.map_interpreter.running?
|
||||
case dir
|
||||
when 2
|
||||
return if $game_player.y != @y + 1
|
||||
@@ -167,12 +168,41 @@ class Game_Event < Game_Character
|
||||
start
|
||||
end
|
||||
|
||||
def check_event_trigger_after_turning
|
||||
return if @map_id != $game_player.map_id
|
||||
return if @trigger != 2 # Not Event Touch
|
||||
return if $game_system.map_interpreter.running? || @starting
|
||||
return if !self.name[/(?:sight|trainer)\((\d+)\)/i]
|
||||
distance = $~[1].to_i
|
||||
return if !pbEventCanReachPlayer?(self, $game_player, distance)
|
||||
return if jumping? || over_trigger?
|
||||
start
|
||||
end
|
||||
|
||||
def check_event_trigger_after_moving
|
||||
return if @map_id != $game_player.map_id
|
||||
return if @trigger != 2 # Not Event Touch
|
||||
return if $game_system.map_interpreter.running? || @starting
|
||||
if self.name[/(?:sight|trainer)\((\d+)\)/i]
|
||||
distance = $~[1].to_i
|
||||
return if !pbEventCanReachPlayer?(self, $game_player, distance)
|
||||
elsif self.name[/counter\((\d+)\)/i]
|
||||
distance = $~[1].to_i
|
||||
return if !pbEventFacesPlayer?(self, $game_player, distance)
|
||||
else
|
||||
return
|
||||
end
|
||||
return if jumping? || over_trigger?
|
||||
start
|
||||
end
|
||||
|
||||
def check_event_trigger_auto
|
||||
if @trigger == 2 # Event touch
|
||||
if at_coordinate?($game_player.x, $game_player.y)
|
||||
start if !jumping? && over_trigger?
|
||||
case @trigger
|
||||
when 2 # Event touch
|
||||
if at_coordinate?($game_player.x, $game_player.y) && !jumping? && over_trigger?
|
||||
start
|
||||
end
|
||||
elsif @trigger == 3 # Autorun
|
||||
when 3 # Autorun
|
||||
start
|
||||
end
|
||||
end
|
||||
@@ -180,11 +210,11 @@ class Game_Event < Game_Character
|
||||
def refresh
|
||||
new_page = nil
|
||||
unless @erased
|
||||
for page in @event.pages.reverse
|
||||
@event.pages.reverse.each do |page|
|
||||
c = page.condition
|
||||
next if c.switch1_valid && !switchIsOn?(c.switch1_id)
|
||||
next if c.switch2_valid && !switchIsOn?(c.switch2_id)
|
||||
next if c.variable_valid && $game_variables[c.variable_id] < c.variable_value
|
||||
next if c.variable_valid && variableIsLessThan?(c.variable_id, c.variable_value)
|
||||
if c.self_switch_valid
|
||||
key = [@map_id, @event.id, c.self_switch_ch]
|
||||
next if $game_self_switches[key] != true
|
||||
@@ -196,7 +226,7 @@ class Game_Event < Game_Character
|
||||
return if new_page == @page
|
||||
@page = new_page
|
||||
clear_starting
|
||||
if @page == nil
|
||||
if @page.nil?
|
||||
@tile_id = 0
|
||||
@character_name = ""
|
||||
@character_hue = 0
|
||||
@@ -236,43 +266,50 @@ class Game_Event < Game_Character
|
||||
@trigger = @page.trigger
|
||||
@list = @page.list
|
||||
@interpreter = nil
|
||||
if @trigger == 4 # Parallel Process
|
||||
@interpreter = Interpreter.new
|
||||
end
|
||||
@interpreter = Interpreter.new if @trigger == 4 # Parallel Process
|
||||
check_event_trigger_auto
|
||||
end
|
||||
|
||||
def should_update?(recalc=false)
|
||||
def should_update?(recalc = false)
|
||||
return @to_update if !recalc
|
||||
return true if @updated_last_frame
|
||||
return true if @trigger && (@trigger == 3 || @trigger == 4)
|
||||
return true if @move_route_forcing
|
||||
return true if @move_route_forcing || @moveto_happened
|
||||
return true if @event.name[/update/i]
|
||||
range = 2 # Number of tiles
|
||||
return false if self.screen_x - @sprite_size[0]/2 > Graphics.width + range * Game_Map::TILE_WIDTH
|
||||
return false if self.screen_x + @sprite_size[0]/2 < -range * Game_Map::TILE_WIDTH
|
||||
return false if self.screen_y_ground - @sprite_size[1] > Graphics.height + range * Game_Map::TILE_HEIGHT
|
||||
return false if self.screen_x - (@sprite_size[0] / 2) > Graphics.width + (range * Game_Map::TILE_WIDTH)
|
||||
return false if self.screen_x + (@sprite_size[0] / 2) < -range * Game_Map::TILE_WIDTH
|
||||
return false if self.screen_y_ground - @sprite_size[1] > Graphics.height + (range * Game_Map::TILE_HEIGHT)
|
||||
return false if self.screen_y_ground < -range * Game_Map::TILE_HEIGHT
|
||||
return true
|
||||
end
|
||||
|
||||
def update
|
||||
@to_update = should_update?(true)
|
||||
@updated_last_frame = false
|
||||
return if !@to_update
|
||||
@updated_last_frame = true
|
||||
@moveto_happened = false
|
||||
last_moving = moving?
|
||||
super
|
||||
if !moving? && last_moving
|
||||
$game_player.pbCheckEventTriggerFromDistance([2])
|
||||
end
|
||||
check_event_trigger_after_moving if !moving? && last_moving
|
||||
if @need_refresh
|
||||
@need_refresh = false
|
||||
refresh
|
||||
end
|
||||
check_event_trigger_auto
|
||||
if @interpreter != nil
|
||||
unless @interpreter.running?
|
||||
@interpreter.setup(@list, @event.id, @map_id)
|
||||
end
|
||||
if @interpreter
|
||||
@interpreter.setup(@list, @event.id, @map_id) if !@interpreter.running?
|
||||
@interpreter.update
|
||||
end
|
||||
end
|
||||
|
||||
def update_move
|
||||
was_jumping = jumping?
|
||||
super
|
||||
if was_jumping && !jumping? && !@transparent && (@tile_id > 0 || @character_name != "")
|
||||
spriteset = $scene.spriteset(map_id)
|
||||
spriteset&.addUserAnimation(Settings::DUST_ANIMATION_ID, self.x, self.y, true, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
616
Data/Scripts/004_Game classes/008_Game_Player.rb
Normal file
616
Data/Scripts/004_Game classes/008_Game_Player.rb
Normal file
@@ -0,0 +1,616 @@
|
||||
#===============================================================================
|
||||
# ** Game_Player
|
||||
#-------------------------------------------------------------------------------
|
||||
# This class handles the player. Its functions include event starting
|
||||
# determinants and map scrolling. Refer to "$game_player" for the one
|
||||
# instance of this class.
|
||||
#===============================================================================
|
||||
class Game_Player < Game_Character
|
||||
attr_accessor :charsetData
|
||||
attr_accessor :encounter_count
|
||||
|
||||
SCREEN_CENTER_X = ((Settings::SCREEN_WIDTH / 2) - (Game_Map::TILE_WIDTH / 2)) * Game_Map::X_SUBPIXELS
|
||||
SCREEN_CENTER_Y = ((Settings::SCREEN_HEIGHT / 2) - (Game_Map::TILE_HEIGHT / 2)) * Game_Map::Y_SUBPIXELS
|
||||
# Time in seconds for one cycle of bobbing (playing 4 charset frames) while
|
||||
# surfing or diving.
|
||||
SURF_BOB_DURATION = 1.5
|
||||
|
||||
def initialize(*arg)
|
||||
super(*arg)
|
||||
@lastdir = 0
|
||||
@lastdirframe = 0
|
||||
end
|
||||
|
||||
def map
|
||||
@map = nil
|
||||
return $game_map
|
||||
end
|
||||
|
||||
def map_id
|
||||
return $game_map.map_id
|
||||
end
|
||||
|
||||
def screen_z(height = 0)
|
||||
ret = super
|
||||
return ret + 1
|
||||
end
|
||||
|
||||
def has_follower?
|
||||
return $PokemonGlobal.followers.length > 0
|
||||
end
|
||||
|
||||
def can_map_transfer_with_follower?
|
||||
return $PokemonGlobal.followers.length == 0
|
||||
end
|
||||
|
||||
def can_ride_vehicle_with_follower?
|
||||
return $PokemonGlobal.followers.length == 0
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def can_run?
|
||||
return @move_speed > 3 if @move_route_forcing
|
||||
return false if $game_temp.in_menu || $game_temp.in_battle ||
|
||||
$game_temp.message_window_showing || pbMapInterpreterRunning?
|
||||
return false if !$player.has_running_shoes && !$PokemonGlobal.diving &&
|
||||
!$PokemonGlobal.surfing && !$PokemonGlobal.bicycle
|
||||
return false if jumping?
|
||||
return false if pbTerrainTag.must_walk
|
||||
return ($PokemonSystem.runstyle == 1) ^ Input.press?(Input::BACK)
|
||||
end
|
||||
|
||||
def set_movement_type(type)
|
||||
meta = GameData::PlayerMetadata.get($player&.character_ID || 1)
|
||||
new_charset = nil
|
||||
case type
|
||||
when :fishing
|
||||
new_charset = pbGetPlayerCharset(meta.fish_charset)
|
||||
when :surf_fishing
|
||||
new_charset = pbGetPlayerCharset(meta.surf_fish_charset)
|
||||
when :diving, :diving_fast, :diving_jumping, :diving_stopped
|
||||
self.move_speed = 3 if !@move_route_forcing
|
||||
new_charset = pbGetPlayerCharset(meta.dive_charset)
|
||||
when :surfing, :surfing_fast, :surfing_jumping, :surfing_stopped
|
||||
if !@move_route_forcing
|
||||
self.move_speed = (type == :surfing_jumping) ? 3 : 4
|
||||
end
|
||||
new_charset = pbGetPlayerCharset(meta.surf_charset)
|
||||
when :descending_waterfall, :ascending_waterfall
|
||||
self.move_speed = 2 if !@move_route_forcing
|
||||
new_charset = pbGetPlayerCharset(meta.surf_charset)
|
||||
when :cycling, :cycling_fast, :cycling_jumping, :cycling_stopped
|
||||
if !@move_route_forcing
|
||||
self.move_speed = (type == :cycling_jumping) ? 3 : 5
|
||||
end
|
||||
new_charset = pbGetPlayerCharset(meta.cycle_charset)
|
||||
when :running
|
||||
self.move_speed = 4 if !@move_route_forcing
|
||||
new_charset = pbGetPlayerCharset(meta.run_charset)
|
||||
when :ice_sliding
|
||||
self.move_speed = 4 if !@move_route_forcing
|
||||
new_charset = pbGetPlayerCharset(meta.walk_charset)
|
||||
else # :walking, :jumping, :walking_stopped
|
||||
self.move_speed = 3 if !@move_route_forcing
|
||||
new_charset = pbGetPlayerCharset(meta.walk_charset)
|
||||
end
|
||||
@character_name = new_charset if new_charset
|
||||
end
|
||||
|
||||
# Called when the player's character or outfit changes. Assumes the player
|
||||
# isn't moving.
|
||||
def refresh_charset
|
||||
meta = GameData::PlayerMetadata.get($player&.character_ID || 1)
|
||||
new_charset = nil
|
||||
if $PokemonGlobal&.diving
|
||||
new_charset = pbGetPlayerCharset(meta.dive_charset)
|
||||
elsif $PokemonGlobal&.surfing
|
||||
new_charset = pbGetPlayerCharset(meta.surf_charset)
|
||||
elsif $PokemonGlobal&.bicycle
|
||||
new_charset = pbGetPlayerCharset(meta.cycle_charset)
|
||||
else
|
||||
new_charset = pbGetPlayerCharset(meta.walk_charset)
|
||||
end
|
||||
@character_name = new_charset if new_charset
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def bump_into_object
|
||||
return if @bump_time_start && (System.uptime - @bump_time_start < @move_time)
|
||||
pbSEPlay("Overrides bump") if !@move_route_forcing
|
||||
$stats.bump_count += 1
|
||||
@bump_time_start = System.uptime
|
||||
end
|
||||
|
||||
def add_move_distance_to_stats(distance = 1)
|
||||
if $PokemonGlobal&.diving || $PokemonGlobal&.surfing
|
||||
$stats.distance_surfed += distance
|
||||
elsif $PokemonGlobal&.bicycle
|
||||
$stats.distance_cycled += distance
|
||||
else
|
||||
$stats.distance_walked += distance
|
||||
end
|
||||
$stats.distance_slid_on_ice += distance if $PokemonGlobal.ice_sliding
|
||||
end
|
||||
|
||||
def move_generic(dir, turn_enabled = true)
|
||||
turn_generic(dir, true) if turn_enabled
|
||||
if !$game_temp.encounter_triggered
|
||||
if can_move_in_direction?(dir)
|
||||
x_offset = (dir == 4) ? -1 : (dir == 6) ? 1 : 0
|
||||
y_offset = (dir == 8) ? -1 : (dir == 2) ? 1 : 0
|
||||
# Jump over ledges
|
||||
if pbFacingTerrainTag.ledge
|
||||
if jumpForward(2)
|
||||
pbSEPlay("Overrides jump")
|
||||
increase_steps
|
||||
end
|
||||
return
|
||||
elsif pbFacingTerrainTag.waterfall_crest && dir == 2
|
||||
$PokemonGlobal.descending_waterfall = true
|
||||
$game_player.through = true
|
||||
$stats.waterfalls_descended += 1
|
||||
end
|
||||
# Jumping out of surfing back onto land
|
||||
return if pbEndSurf(x_offset, y_offset)
|
||||
# General movement
|
||||
turn_generic(dir, true)
|
||||
if !$game_temp.encounter_triggered
|
||||
@move_initial_x = @x
|
||||
@move_initial_y = @y
|
||||
@x += x_offset
|
||||
@y += y_offset
|
||||
@move_timer = 0.0
|
||||
add_move_distance_to_stats(x_offset.abs + y_offset.abs)
|
||||
increase_steps
|
||||
end
|
||||
elsif !check_event_trigger_touch(dir)
|
||||
bump_into_object
|
||||
end
|
||||
end
|
||||
$game_temp.encounter_triggered = false
|
||||
end
|
||||
|
||||
def turn_generic(dir, keep_enc_indicator = false)
|
||||
old_direction = @direction
|
||||
super(dir)
|
||||
if @direction != old_direction && !@move_route_forcing && !pbMapInterpreterRunning?
|
||||
EventHandlers.trigger(:on_player_change_direction)
|
||||
$game_temp.encounter_triggered = false if !keep_enc_indicator
|
||||
end
|
||||
end
|
||||
|
||||
def jump(x_plus, y_plus)
|
||||
old_x = @x
|
||||
old_y = @y
|
||||
super
|
||||
add_move_distance_to_stats(x_plus.abs + y_plus.abs) if @x != old_x || @y != old_y
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def pbTerrainTag(countBridge = false)
|
||||
return $map_factory.getTerrainTagFromCoords(self.map.map_id, @x, @y, countBridge) if $map_factory
|
||||
return $game_map.terrain_tag(@x, @y, countBridge)
|
||||
end
|
||||
|
||||
def pbFacingEvent(ignoreInterpreter = false)
|
||||
return nil if $game_system.map_interpreter.running? && !ignoreInterpreter
|
||||
# Check the tile in front of the player for events
|
||||
new_x = @x + (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
|
||||
new_y = @y + (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
|
||||
return nil if !$game_map.valid?(new_x, new_y)
|
||||
$game_map.events.each_value do |event|
|
||||
next if !event.at_coordinate?(new_x, new_y)
|
||||
next if event.jumping? || event.over_trigger?
|
||||
return event
|
||||
end
|
||||
# If the tile in front is a counter, check one tile beyond that for events
|
||||
if $game_map.counter?(new_x, new_y)
|
||||
new_x += (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
|
||||
new_y += (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
|
||||
$game_map.events.each_value do |event|
|
||||
next if !event.at_coordinate?(new_x, new_y)
|
||||
next if event.jumping? || event.over_trigger?
|
||||
return event
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def pbFacingTerrainTag(dir = nil)
|
||||
dir = self.direction if !dir
|
||||
return $map_factory.getFacingTerrainTag(dir, self) if $map_factory
|
||||
facing = pbFacingTile(dir, self)
|
||||
return $game_map.terrain_tag(facing[1], facing[2])
|
||||
end
|
||||
|
||||
# Passable Determinants
|
||||
# x : x-coordinate
|
||||
# y : y-coordinate
|
||||
# d : direction (0, 2, 4, 6, 8)
|
||||
# * 0 = Determines if all directions are impassable (for jumping)
|
||||
def passable?(x, y, dir, strict = false)
|
||||
# Get new coordinates
|
||||
new_x = x + (dir == 6 ? 1 : dir == 4 ? -1 : 0)
|
||||
new_y = y + (dir == 2 ? 1 : dir == 8 ? -1 : 0)
|
||||
# If coordinates are outside of map
|
||||
return false if !$game_map.validLax?(new_x, new_y)
|
||||
if !$game_map.valid?(new_x, new_y)
|
||||
return false if !$map_factory
|
||||
return $map_factory.isPassableFromEdge?(new_x, new_y, 10 - dir)
|
||||
end
|
||||
# If debug mode is ON and Ctrl key was pressed
|
||||
return true if $DEBUG && Input.press?(Input::CTRL)
|
||||
return super
|
||||
end
|
||||
|
||||
# Set Map Display Position to Center of Screen
|
||||
def center(x, y)
|
||||
self.map.display_x = (x * Game_Map::REAL_RES_X) - SCREEN_CENTER_X
|
||||
self.map.display_y = (y * Game_Map::REAL_RES_Y) - SCREEN_CENTER_Y
|
||||
end
|
||||
|
||||
# Move to Designated Position
|
||||
# x : x-coordinate
|
||||
# y : y-coordinate
|
||||
def moveto(x, y)
|
||||
super
|
||||
center(x, y)
|
||||
make_encounter_count
|
||||
end
|
||||
|
||||
# Make Encounter Count
|
||||
def make_encounter_count
|
||||
# Image of two dice rolling
|
||||
if $game_map.map_id != 0
|
||||
n = $game_map.encounter_step
|
||||
@encounter_count = rand(n) + rand(n) + 1
|
||||
end
|
||||
end
|
||||
|
||||
def refresh
|
||||
@opacity = 255
|
||||
@blend_type = 0
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def pbTriggeredTrainerEvents(triggers, checkIfRunning = true, trainer_only = false)
|
||||
result = []
|
||||
# If event is running
|
||||
return result if checkIfRunning && $game_system.map_interpreter.running?
|
||||
# All event loops
|
||||
$game_map.events.each_value do |event|
|
||||
next if !triggers.include?(event.trigger)
|
||||
next if !event.name[/trainer\((\d+)\)/i] && (trainer_only || !event.name[/sight\((\d+)\)/i])
|
||||
distance = $~[1].to_i
|
||||
next if !pbEventCanReachPlayer?(event, self, distance)
|
||||
next if event.jumping? || event.over_trigger?
|
||||
result.push(event)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
def pbTriggeredCounterEvents(triggers, checkIfRunning = true)
|
||||
result = []
|
||||
# If event is running
|
||||
return result if checkIfRunning && $game_system.map_interpreter.running?
|
||||
# All event loops
|
||||
$game_map.events.each_value do |event|
|
||||
next if !triggers.include?(event.trigger)
|
||||
next if !event.name[/counter\((\d+)\)/i]
|
||||
distance = $~[1].to_i
|
||||
next if !pbEventFacesPlayer?(event, self, distance)
|
||||
next if event.jumping? || event.over_trigger?
|
||||
result.push(event)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
def check_event_trigger_after_turning; end
|
||||
|
||||
def pbCheckEventTriggerFromDistance(triggers)
|
||||
events = pbTriggeredTrainerEvents(triggers)
|
||||
events.concat(pbTriggeredCounterEvents(triggers))
|
||||
return false if events.length == 0
|
||||
ret = false
|
||||
events.each do |event|
|
||||
event.start
|
||||
ret = true if event.starting
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
# Trigger event(s) at the same coordinates as self with the appropriate
|
||||
# trigger(s) that can be triggered
|
||||
def check_event_trigger_here(triggers)
|
||||
result = false
|
||||
# If event is running
|
||||
return result if $game_system.map_interpreter.running?
|
||||
# All event loops
|
||||
$game_map.events.each_value do |event|
|
||||
# If event coordinates and triggers are consistent
|
||||
next if !event.at_coordinate?(@x, @y)
|
||||
next if !triggers.include?(event.trigger)
|
||||
# If starting determinant is same position event (other than jumping)
|
||||
next if event.jumping? || !event.over_trigger?
|
||||
event.start
|
||||
result = true if event.starting
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
# Front Event Starting Determinant
|
||||
def check_event_trigger_there(triggers)
|
||||
result = false
|
||||
# If event is running
|
||||
return result if $game_system.map_interpreter.running?
|
||||
# Calculate front event coordinates
|
||||
new_x = @x + (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
|
||||
new_y = @y + (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
|
||||
return false if !$game_map.valid?(new_x, new_y)
|
||||
# All event loops
|
||||
$game_map.events.each_value do |event|
|
||||
next if !triggers.include?(event.trigger)
|
||||
# If event coordinates and triggers are consistent
|
||||
next if !event.at_coordinate?(new_x, new_y)
|
||||
# If starting determinant is front event (other than jumping)
|
||||
next if event.jumping? || event.over_trigger?
|
||||
event.start
|
||||
result = true if event.starting
|
||||
end
|
||||
# If fitting event is not found
|
||||
if result == false && $game_map.counter?(new_x, new_y)
|
||||
# Calculate coordinates of 1 tile further away
|
||||
new_x += (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
|
||||
new_y += (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
|
||||
return false if !$game_map.valid?(new_x, new_y)
|
||||
# All event loops
|
||||
$game_map.events.each_value do |event|
|
||||
next if !triggers.include?(event.trigger)
|
||||
# If event coordinates and triggers are consistent
|
||||
next if !event.at_coordinate?(new_x, new_y)
|
||||
# If starting determinant is front event (other than jumping)
|
||||
next if event.jumping? || event.over_trigger?
|
||||
event.start
|
||||
result = true if event.starting
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
# Touch Event Starting Determinant
|
||||
def check_event_trigger_touch(dir)
|
||||
result = false
|
||||
return result if $game_system.map_interpreter.running?
|
||||
# All event loops
|
||||
x_offset = (dir == 4) ? -1 : (dir == 6) ? 1 : 0
|
||||
y_offset = (dir == 8) ? -1 : (dir == 2) ? 1 : 0
|
||||
$game_map.events.each_value do |event|
|
||||
next if ![1, 2].include?(event.trigger) # Overrides touch, event touch
|
||||
# If event coordinates and triggers are consistent
|
||||
next if !event.at_coordinate?(@x + x_offset, @y + y_offset)
|
||||
if event.name[/(?:sight|trainer)\((\d+)\)/i]
|
||||
distance = $~[1].to_i
|
||||
next if !pbEventCanReachPlayer?(event, self, distance)
|
||||
elsif event.name[/counter\((\d+)\)/i]
|
||||
distance = $~[1].to_i
|
||||
next if !pbEventFacesPlayer?(event, self, distance)
|
||||
end
|
||||
# If starting determinant is front event (other than jumping)
|
||||
next if event.jumping? || event.over_trigger?
|
||||
event.start
|
||||
result = true if event.starting
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def update
|
||||
last_real_x = @real_x
|
||||
last_real_y = @real_y
|
||||
@last_terrain_tag = pbTerrainTag
|
||||
super
|
||||
update_stop if $game_temp.in_menu && @stopped_last_frame
|
||||
update_screen_position(last_real_x, last_real_y)
|
||||
# Update dependent events
|
||||
if (!@moved_last_frame || @stopped_last_frame) && (moving? || jumping?)
|
||||
$game_temp.followers.move_followers
|
||||
end
|
||||
$game_temp.followers.update
|
||||
update_event_triggering
|
||||
end
|
||||
|
||||
def update_command_new
|
||||
dir = Input.dir4
|
||||
if $PokemonGlobal.forced_movement?
|
||||
move_forward
|
||||
@last_input_time = nil
|
||||
return
|
||||
elsif dir <= 0
|
||||
@last_input_time = nil
|
||||
return
|
||||
end
|
||||
return if pbMapInterpreterRunning? || $game_temp.message_window_showing ||
|
||||
$game_temp.in_mini_update || $game_temp.in_menu
|
||||
# Move player in the direction the directional button is being pressed
|
||||
if @moved_last_frame ||
|
||||
(dir == direction && (!@last_input_time || System.uptime - @last_input_time >= 0.075))
|
||||
case dir
|
||||
when 2 then move_down
|
||||
when 4 then move_left
|
||||
when 6 then move_right
|
||||
when 8 then move_up
|
||||
end
|
||||
@last_input_time = nil
|
||||
elsif dir != direction
|
||||
case dir
|
||||
when 2 then turn_down
|
||||
when 4 then turn_left
|
||||
when 6 then turn_right
|
||||
when 8 then turn_up
|
||||
end
|
||||
@last_input_time = System.uptime
|
||||
end
|
||||
end
|
||||
|
||||
def update_move
|
||||
if !@moved_last_frame || @stopped_last_frame # Started a new step
|
||||
if $PokemonGlobal.ice_sliding || @last_terrain_tag.ice
|
||||
set_movement_type(:ice_sliding)
|
||||
elsif $PokemonGlobal.descending_waterfall
|
||||
set_movement_type(:descending_waterfall)
|
||||
elsif $PokemonGlobal.ascending_waterfall
|
||||
set_movement_type(:ascending_waterfall)
|
||||
else
|
||||
faster = can_run?
|
||||
if $PokemonGlobal&.diving
|
||||
set_movement_type((faster) ? :diving_fast : :diving)
|
||||
elsif $PokemonGlobal&.surfing
|
||||
set_movement_type((faster) ? :surfing_fast : :surfing)
|
||||
elsif $PokemonGlobal&.bicycle
|
||||
set_movement_type((faster) ? :cycling_fast : :cycling)
|
||||
else
|
||||
set_movement_type((faster) ? :running : :walking)
|
||||
end
|
||||
end
|
||||
if jumping?
|
||||
if $PokemonGlobal&.diving
|
||||
set_movement_type(:diving_jumping)
|
||||
elsif $PokemonGlobal&.surfing
|
||||
set_movement_type(:surfing_jumping)
|
||||
elsif $PokemonGlobal&.bicycle
|
||||
set_movement_type(:cycling_jumping)
|
||||
else
|
||||
set_movement_type(:jumping) # Walking speed/charset while jumping
|
||||
end
|
||||
end
|
||||
end
|
||||
was_jumping = jumping?
|
||||
super
|
||||
if was_jumping && !jumping? && !@transparent && (@tile_id > 0 || @character_name != "")
|
||||
if !$PokemonGlobal.surfing || $game_temp.ending_surf
|
||||
spriteset = $scene.spriteset(map_id)
|
||||
spriteset&.addUserAnimation(Settings::DUST_ANIMATION_ID, self.x, self.y, true, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update_stop
|
||||
if @stopped_last_frame
|
||||
if $PokemonGlobal&.diving
|
||||
set_movement_type(:diving_stopped)
|
||||
elsif $PokemonGlobal&.surfing
|
||||
set_movement_type(:surfing_stopped)
|
||||
elsif $PokemonGlobal&.bicycle
|
||||
set_movement_type(:cycling_stopped)
|
||||
else
|
||||
set_movement_type(:walking_stopped)
|
||||
end
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
def update_pattern
|
||||
if $PokemonGlobal&.surfing || $PokemonGlobal&.diving
|
||||
bob_pattern = (4 * System.uptime / SURF_BOB_DURATION).to_i % 4
|
||||
@pattern = bob_pattern if !@lock_pattern
|
||||
@pattern_surf = bob_pattern
|
||||
@bob_height = (bob_pattern >= 2) ? 2 : 0
|
||||
@anime_count = 0
|
||||
else
|
||||
@bob_height = 0
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# Track the player on-screen as they move.
|
||||
def update_screen_position(last_real_x, last_real_y)
|
||||
return if self.map.scrolling? || !(@moved_last_frame || @moved_this_frame)
|
||||
if (@real_x < last_real_x && @real_x < $game_map.display_x + SCREEN_CENTER_X) ||
|
||||
(@real_x > last_real_x && @real_x > $game_map.display_x + SCREEN_CENTER_X)
|
||||
self.map.display_x += @real_x - last_real_x
|
||||
end
|
||||
if (@real_y < last_real_y && @real_y < $game_map.display_y + SCREEN_CENTER_Y) ||
|
||||
(@real_y > last_real_y && @real_y > $game_map.display_y + SCREEN_CENTER_Y)
|
||||
self.map.display_y += @real_y - last_real_y
|
||||
end
|
||||
end
|
||||
|
||||
def update_event_triggering
|
||||
return if moving? || jumping? || $PokemonGlobal.forced_movement?
|
||||
# Try triggering events upon walking into them/in front of them
|
||||
if @moved_this_frame
|
||||
$game_temp.followers.turn_followers
|
||||
result = pbCheckEventTriggerFromDistance([2])
|
||||
# Event determinant is via touch of same position event
|
||||
result |= check_event_trigger_here([1, 2])
|
||||
# No events triggered, try other event triggers upon finishing a step
|
||||
pbOnStepTaken(result)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
def pbGetPlayerCharset(charset, trainer = nil, force = false)
|
||||
trainer = $player if !trainer
|
||||
outfit = (trainer) ? trainer.outfit : 0
|
||||
return nil if !force && $game_player&.charsetData &&
|
||||
$game_player.charsetData[0] == trainer.character_ID &&
|
||||
$game_player.charsetData[1] == charset &&
|
||||
$game_player.charsetData[2] == outfit
|
||||
$game_player.charsetData = [trainer.character_ID, charset, outfit] if $game_player
|
||||
ret = charset
|
||||
if pbResolveBitmap("Graphics/Characters/" + ret + "_" + outfit.to_s)
|
||||
ret = ret + "_" + outfit.to_s
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def pbUpdateVehicle
|
||||
if $PokemonGlobal&.diving
|
||||
$game_player.set_movement_type(:diving_stopped)
|
||||
elsif $PokemonGlobal&.surfing
|
||||
$game_player.set_movement_type(:surfing_stopped)
|
||||
elsif $PokemonGlobal&.bicycle
|
||||
$game_player.set_movement_type(:cycling_stopped)
|
||||
else
|
||||
$game_player.set_movement_type(:walking_stopped)
|
||||
end
|
||||
end
|
||||
|
||||
def pbCancelVehicles(destination = nil, cancel_swimming = true)
|
||||
$PokemonGlobal.surfing = false if cancel_swimming
|
||||
$PokemonGlobal.diving = false if cancel_swimming
|
||||
$PokemonGlobal.bicycle = false if !destination || !pbCanUseBike?(destination)
|
||||
pbUpdateVehicle
|
||||
end
|
||||
|
||||
def pbCanUseBike?(map_id)
|
||||
map_metadata = GameData::MapMetadata.try_get(map_id)
|
||||
return false if !map_metadata
|
||||
return map_metadata.always_bicycle || map_metadata.can_bicycle || map_metadata.outdoor_map
|
||||
end
|
||||
|
||||
def pbMountBike
|
||||
return if $PokemonGlobal.bicycle
|
||||
$PokemonGlobal.bicycle = true
|
||||
$stats.cycle_count += 1
|
||||
pbUpdateVehicle
|
||||
bike_bgm = GameData::Metadata.get.bicycle_BGM
|
||||
pbCueBGM(bike_bgm, 0.4) if bike_bgm
|
||||
pbSEPlay("Bicycle")
|
||||
pbPokeRadarCancel
|
||||
end
|
||||
|
||||
def pbDismountBike
|
||||
return if !$PokemonGlobal.bicycle
|
||||
$PokemonGlobal.bicycle = false
|
||||
pbUpdateVehicle
|
||||
$game_map.autoplayAsCue
|
||||
end
|
||||
56
Data/Scripts/004_Game classes/009_Game_CommonEvent.rb
Normal file
56
Data/Scripts/004_Game classes/009_Game_CommonEvent.rb
Normal file
@@ -0,0 +1,56 @@
|
||||
#===============================================================================
|
||||
# ** Game_CommonEvent
|
||||
#-------------------------------------------------------------------------------
|
||||
# This class handles common events. It includes execution of parallel process
|
||||
# event. This class is used within the Game_Map class ($game_map).
|
||||
#===============================================================================
|
||||
class Game_CommonEvent
|
||||
def initialize(common_event_id)
|
||||
@common_event_id = common_event_id
|
||||
@interpreter = nil
|
||||
refresh
|
||||
end
|
||||
|
||||
def name
|
||||
return $data_common_events[@common_event_id].name
|
||||
end
|
||||
|
||||
def trigger
|
||||
return $data_common_events[@common_event_id].trigger
|
||||
end
|
||||
|
||||
def switch_id
|
||||
return $data_common_events[@common_event_id].switch_id
|
||||
end
|
||||
|
||||
def list
|
||||
return $data_common_events[@common_event_id].list
|
||||
end
|
||||
|
||||
def switchIsOn?(id)
|
||||
switchName = $data_system.switches[id]
|
||||
return false if !switchName
|
||||
if switchName[/^s\:/]
|
||||
return eval($~.post_match)
|
||||
else
|
||||
return $game_switches[id]
|
||||
end
|
||||
end
|
||||
|
||||
def refresh
|
||||
# Create an interpreter for parallel process if necessary
|
||||
if self.trigger == 2 && switchIsOn?(self.switch_id)
|
||||
@interpreter = Interpreter.new if @interpreter.nil?
|
||||
else
|
||||
@interpreter = nil
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
return if !@interpreter
|
||||
# Set up event if interpreter is not running
|
||||
@interpreter.setup(self.list, 0) if !@interpreter.running?
|
||||
# Update interpreter
|
||||
@interpreter.update
|
||||
end
|
||||
end
|
||||
@@ -1,442 +0,0 @@
|
||||
#===============================================================================
|
||||
# ** Game_Player
|
||||
#-------------------------------------------------------------------------------
|
||||
# This class handles the player. Its functions include event starting
|
||||
# determinants and map scrolling. Refer to "$game_player" for the one
|
||||
# instance of this class.
|
||||
#===============================================================================
|
||||
class Game_Player < Game_Character
|
||||
attr_accessor :bump_se
|
||||
attr_accessor :charsetData
|
||||
attr_accessor :encounter_count
|
||||
|
||||
SCREEN_CENTER_X = (Settings::SCREEN_WIDTH / 2 - Game_Map::TILE_WIDTH / 2) * Game_Map::X_SUBPIXELS
|
||||
SCREEN_CENTER_Y = (Settings::SCREEN_HEIGHT / 2 - Game_Map::TILE_HEIGHT / 2) * Game_Map::Y_SUBPIXELS
|
||||
|
||||
def initialize(*arg)
|
||||
super(*arg)
|
||||
@lastdir=0
|
||||
@lastdirframe=0
|
||||
@bump_se=0
|
||||
end
|
||||
|
||||
def map
|
||||
@map = nil
|
||||
return $game_map
|
||||
end
|
||||
|
||||
def pbHasDependentEvents?
|
||||
return $PokemonGlobal.dependentEvents.length>0
|
||||
end
|
||||
|
||||
def bump_into_object
|
||||
return if @bump_se && @bump_se>0
|
||||
pbSEPlay("Player bump")
|
||||
@bump_se = Graphics.frame_rate/4
|
||||
end
|
||||
|
||||
def move_generic(dir, turn_enabled = true)
|
||||
turn_generic(dir, true) if turn_enabled
|
||||
if !$PokemonTemp.encounterTriggered
|
||||
if can_move_in_direction?(dir)
|
||||
x_offset = (dir == 4) ? -1 : (dir == 6) ? 1 : 0
|
||||
y_offset = (dir == 8) ? -1 : (dir == 2) ? 1 : 0
|
||||
return if pbLedge(x_offset, y_offset)
|
||||
return if pbEndSurf(x_offset, y_offset)
|
||||
turn_generic(dir, true)
|
||||
if !$PokemonTemp.encounterTriggered
|
||||
@x += x_offset
|
||||
@y += y_offset
|
||||
$PokemonTemp.dependentEvents.pbMoveDependentEvents
|
||||
increase_steps
|
||||
end
|
||||
elsif !check_event_trigger_touch(dir)
|
||||
bump_into_object
|
||||
end
|
||||
end
|
||||
$PokemonTemp.encounterTriggered = false
|
||||
end
|
||||
|
||||
def turn_generic(dir, keep_enc_indicator = false)
|
||||
old_direction = @direction
|
||||
super(dir)
|
||||
if @direction != old_direction && !@move_route_forcing && !pbMapInterpreterRunning?
|
||||
Events.onChangeDirection.trigger(self, self)
|
||||
$PokemonTemp.encounterTriggered = false if !keep_enc_indicator
|
||||
end
|
||||
end
|
||||
|
||||
def pbTriggeredTrainerEvents(triggers,checkIfRunning=true)
|
||||
result = []
|
||||
# If event is running
|
||||
return result if checkIfRunning && $game_system.map_interpreter.running?
|
||||
# All event loops
|
||||
for event in $game_map.events.values
|
||||
next if !event.name[/trainer\((\d+)\)/i]
|
||||
distance = $~[1].to_i
|
||||
# If event coordinates and triggers are consistent
|
||||
if pbEventCanReachPlayer?(event,self,distance) && triggers.include?(event.trigger)
|
||||
# If starting determinant is front event (other than jumping)
|
||||
result.push(event) if !event.jumping? && !event.over_trigger?
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
def pbTriggeredCounterEvents(triggers,checkIfRunning=true)
|
||||
result = []
|
||||
# If event is running
|
||||
return result if checkIfRunning && $game_system.map_interpreter.running?
|
||||
# All event loops
|
||||
for event in $game_map.events.values
|
||||
next if !event.name[/counter\((\d+)\)/i]
|
||||
distance = $~[1].to_i
|
||||
# If event coordinates and triggers are consistent
|
||||
if pbEventFacesPlayer?(event,self,distance) && triggers.include?(event.trigger)
|
||||
# If starting determinant is front event (other than jumping)
|
||||
result.push(event) if !event.jumping? && !event.over_trigger?
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
def pbCheckEventTriggerAfterTurning; end
|
||||
|
||||
def pbCheckEventTriggerFromDistance(triggers)
|
||||
ret = pbTriggeredTrainerEvents(triggers)
|
||||
ret.concat(pbTriggeredCounterEvents(triggers))
|
||||
return false if ret.length==0
|
||||
for event in ret
|
||||
event.start
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def pbTerrainTag(countBridge = false)
|
||||
return $MapFactory.getTerrainTag(self.map.map_id, @x, @y, countBridge) if $MapFactory
|
||||
return $game_map.terrain_tag(@x, @y, countBridge)
|
||||
end
|
||||
|
||||
def pbFacingEvent(ignoreInterpreter=false)
|
||||
return nil if $game_system.map_interpreter.running? && !ignoreInterpreter
|
||||
# Check the tile in front of the player for events
|
||||
new_x = @x + (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
|
||||
new_y = @y + (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
|
||||
return nil if !$game_map.valid?(new_x, new_y)
|
||||
for event in $game_map.events.values
|
||||
next if !event.at_coordinate?(new_x, new_y)
|
||||
next if event.jumping? || event.over_trigger?
|
||||
return event
|
||||
end
|
||||
# If the tile in front is a counter, check one tile beyond that for events
|
||||
if $game_map.counter?(new_x, new_y)
|
||||
new_x += (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
|
||||
new_y += (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
|
||||
for event in $game_map.events.values
|
||||
next if !event.at_coordinate?(new_x, new_y)
|
||||
next if event.jumping? || event.over_trigger?
|
||||
return event
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def pbFacingTerrainTag(dir = nil)
|
||||
dir = self.direction if !dir
|
||||
return $MapFactory.getFacingTerrainTag(dir, self) if $MapFactory
|
||||
facing = pbFacingTile(dir, self)
|
||||
return $game_map.terrain_tag(facing[1], facing[2])
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Passable Determinants
|
||||
# x : x-coordinate
|
||||
# y : y-coordinate
|
||||
# d : direction (0,2,4,6,8)
|
||||
# * 0 = Determines if all directions are impassable (for jumping)
|
||||
#-----------------------------------------------------------------------------
|
||||
def passable?(x, y, d, strict = false)
|
||||
# Get new coordinates
|
||||
new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
|
||||
new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
|
||||
# If coordinates are outside of map
|
||||
return false if !$game_map.validLax?(new_x, new_y)
|
||||
if !$game_map.valid?(new_x, new_y)
|
||||
return false if !$MapFactory
|
||||
return $MapFactory.isPassableFromEdge?(new_x, new_y)
|
||||
end
|
||||
# If debug mode is ON and Ctrl key was pressed
|
||||
return true if $DEBUG && Input.press?(Input::CTRL)
|
||||
return super
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Set Map Display Position to Center of Screen
|
||||
#-----------------------------------------------------------------------------
|
||||
def center(x, y)
|
||||
self.map.display_x = x * Game_Map::REAL_RES_X - SCREEN_CENTER_X
|
||||
self.map.display_y = y * Game_Map::REAL_RES_Y - SCREEN_CENTER_Y
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Move to Designated Position
|
||||
# x : x-coordinate
|
||||
# y : y-coordinate
|
||||
#-----------------------------------------------------------------------------
|
||||
def moveto(x, y)
|
||||
super
|
||||
# Centering
|
||||
center(x, y)
|
||||
# Make encounter count
|
||||
make_encounter_count
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Make Encounter Count
|
||||
#-----------------------------------------------------------------------------
|
||||
def make_encounter_count
|
||||
# Image of two dice rolling
|
||||
if $game_map.map_id != 0
|
||||
n = $game_map.encounter_step
|
||||
@encounter_count = rand(n) + rand(n) + 1
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Refresh
|
||||
#-----------------------------------------------------------------------------
|
||||
def refresh
|
||||
@opacity = 255
|
||||
@blend_type = 0
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Trigger event(s) at the same coordinates as self with the appropriate
|
||||
# trigger(s) that can be triggered
|
||||
#-----------------------------------------------------------------------------
|
||||
def check_event_trigger_here(triggers)
|
||||
result = false
|
||||
# If event is running
|
||||
return result if $game_system.map_interpreter.running?
|
||||
# All event loops
|
||||
for event in $game_map.events.values
|
||||
# If event coordinates and triggers are consistent
|
||||
next if !event.at_coordinate?(@x, @y)
|
||||
next if !triggers.include?(event.trigger)
|
||||
# If starting determinant is same position event (other than jumping)
|
||||
next if event.jumping? || !event.over_trigger?
|
||||
event.start
|
||||
result = true
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Front Event Starting Determinant
|
||||
#-----------------------------------------------------------------------------
|
||||
def check_event_trigger_there(triggers)
|
||||
result = false
|
||||
# If event is running
|
||||
return result if $game_system.map_interpreter.running?
|
||||
# Calculate front event coordinates
|
||||
new_x = @x + (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
|
||||
new_y = @y + (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
|
||||
return false if !$game_map.valid?(new_x, new_y)
|
||||
# All event loops
|
||||
for event in $game_map.events.values
|
||||
# If event coordinates and triggers are consistent
|
||||
next if !event.at_coordinate?(new_x, new_y)
|
||||
next if !triggers.include?(event.trigger)
|
||||
# If starting determinant is front event (other than jumping)
|
||||
next if event.jumping? || event.over_trigger?
|
||||
event.start
|
||||
result = true
|
||||
end
|
||||
# If fitting event is not found
|
||||
if result == false
|
||||
# If front tile is a counter
|
||||
if $game_map.counter?(new_x, new_y)
|
||||
# Calculate coordinates of 1 tile further away
|
||||
new_x += (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
|
||||
new_y += (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
|
||||
return false if !$game_map.valid?(new_x, new_y)
|
||||
# All event loops
|
||||
for event in $game_map.events.values
|
||||
# If event coordinates and triggers are consistent
|
||||
next if !event.at_coordinate?(new_x, new_y)
|
||||
next if !triggers.include?(event.trigger)
|
||||
# If starting determinant is front event (other than jumping)
|
||||
next if event.jumping? || event.over_trigger?
|
||||
event.start
|
||||
result = true
|
||||
end
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Touch Event Starting Determinant
|
||||
#-----------------------------------------------------------------------------
|
||||
def check_event_trigger_touch(dir)
|
||||
result = false
|
||||
return result if $game_system.map_interpreter.running?
|
||||
# All event loops
|
||||
x_offset = (dir == 4) ? -1 : (dir == 6) ? 1 : 0
|
||||
y_offset = (dir == 8) ? -1 : (dir == 2) ? 1 : 0
|
||||
for event in $game_map.events.values
|
||||
next if ![1, 2].include?(event.trigger) # Player touch, event touch
|
||||
# If event coordinates and triggers are consistent
|
||||
next if !event.at_coordinate?(@x + x_offset, @y + y_offset)
|
||||
if event.name[/trainer\((\d+)\)/i]
|
||||
distance = $~[1].to_i
|
||||
next if !pbEventCanReachPlayer?(event,self,distance)
|
||||
elsif event.name[/counter\((\d+)\)/i]
|
||||
distance = $~[1].to_i
|
||||
next if !pbEventFacesPlayer?(event,self,distance)
|
||||
end
|
||||
# If starting determinant is front event (other than jumping)
|
||||
next if event.jumping? || event.over_trigger?
|
||||
event.start
|
||||
result = true
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Frame Update
|
||||
#-----------------------------------------------------------------------------
|
||||
def update
|
||||
last_real_x = @real_x
|
||||
last_real_y = @real_y
|
||||
super
|
||||
update_screen_position(last_real_x, last_real_y)
|
||||
# Update dependent events
|
||||
$PokemonTemp.dependentEvents.updateDependentEvents
|
||||
# Count down the time between allowed bump sounds
|
||||
@bump_se -= 1 if @bump_se && @bump_se>0
|
||||
# Finish up dismounting from surfing
|
||||
if $PokemonTemp.endSurf && !moving?
|
||||
pbCancelVehicles
|
||||
$PokemonTemp.surfJump = nil
|
||||
$PokemonTemp.endSurf = false
|
||||
end
|
||||
update_event_triggering
|
||||
end
|
||||
|
||||
def update_command_new
|
||||
dir = Input.dir4
|
||||
unless pbMapInterpreterRunning? || $game_temp.message_window_showing ||
|
||||
$PokemonTemp.miniupdate || $game_temp.in_menu
|
||||
# Move player in the direction the directional button is being pressed
|
||||
if @moved_last_frame ||
|
||||
(dir > 0 && dir == @lastdir && Graphics.frame_count - @lastdirframe > Graphics.frame_rate / 20)
|
||||
case dir
|
||||
when 2 then move_down
|
||||
when 4 then move_left
|
||||
when 6 then move_right
|
||||
when 8 then move_up
|
||||
end
|
||||
elsif dir != @lastdir
|
||||
case dir
|
||||
when 2 then turn_down
|
||||
when 4 then turn_left
|
||||
when 6 then turn_right
|
||||
when 8 then turn_up
|
||||
end
|
||||
end
|
||||
end
|
||||
# Record last direction input
|
||||
@lastdirframe = Graphics.frame_count if dir != @lastdir
|
||||
@lastdir = dir
|
||||
end
|
||||
|
||||
# Center player on-screen
|
||||
def update_screen_position(last_real_x, last_real_y)
|
||||
return if self.map.scrolling? || !(@moved_last_frame || @moved_this_frame)
|
||||
self.map.display_x = @real_x - SCREEN_CENTER_X
|
||||
self.map.display_y = @real_y - SCREEN_CENTER_Y
|
||||
end
|
||||
|
||||
def update_event_triggering
|
||||
return if moving?
|
||||
# Try triggering events upon walking into them/in front of them
|
||||
if @moved_this_frame
|
||||
$PokemonTemp.dependentEvents.pbTurnDependentEvents
|
||||
result = pbCheckEventTriggerFromDistance([2])
|
||||
# Event determinant is via touch of same position event
|
||||
result |= check_event_trigger_here([1,2])
|
||||
# No events triggered, try other event triggers upon finishing a step
|
||||
pbOnStepTaken(result)
|
||||
end
|
||||
# Try to manually interact with events
|
||||
if Input.trigger?(Input::USE) && !$PokemonTemp.miniupdate
|
||||
# Same position and front event determinant
|
||||
check_event_trigger_here([0])
|
||||
check_event_trigger_there([0,2])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def pbGetPlayerCharset(meta,charset,trainer=nil,force=false)
|
||||
trainer = $Trainer if !trainer
|
||||
outfit = (trainer) ? trainer.outfit : 0
|
||||
if $game_player && $game_player.charsetData && !force
|
||||
return nil if $game_player.charsetData[0] == $Trainer.character_ID &&
|
||||
$game_player.charsetData[1] == charset &&
|
||||
$game_player.charsetData[2] == outfit
|
||||
end
|
||||
$game_player.charsetData = [$Trainer.character_ID,charset,outfit] if $game_player
|
||||
ret = meta[charset]
|
||||
ret = meta[1] if nil_or_empty?(ret)
|
||||
if pbResolveBitmap("Graphics/Characters/"+ret+"_"+outfit.to_s)
|
||||
ret = ret+"_"+outfit.to_s
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def pbUpdateVehicle
|
||||
meta = GameData::Metadata.get_player($Trainer.character_ID)
|
||||
if meta
|
||||
charset = 1 # Regular graphic
|
||||
if $PokemonGlobal.diving; charset = 5 # Diving graphic
|
||||
elsif $PokemonGlobal.surfing; charset = 3 # Surfing graphic
|
||||
elsif $PokemonGlobal.bicycle; charset = 2 # Bicycle graphic
|
||||
end
|
||||
newCharName = pbGetPlayerCharset(meta,charset)
|
||||
$game_player.character_name = newCharName if newCharName
|
||||
end
|
||||
end
|
||||
|
||||
def pbCancelVehicles(destination=nil)
|
||||
$PokemonGlobal.surfing = false
|
||||
$PokemonGlobal.diving = false
|
||||
$PokemonGlobal.bicycle = false if !destination || !pbCanUseBike?(destination)
|
||||
pbUpdateVehicle
|
||||
end
|
||||
|
||||
def pbCanUseBike?(map_id)
|
||||
map_metadata = GameData::MapMetadata.try_get(map_id)
|
||||
return false if !map_metadata
|
||||
return true if map_metadata.always_bicycle
|
||||
val = map_metadata.can_bicycle || map_metadata.outdoor_map
|
||||
return (val) ? true : false
|
||||
end
|
||||
|
||||
def pbMountBike
|
||||
return if $PokemonGlobal.bicycle
|
||||
$PokemonGlobal.bicycle = true
|
||||
pbUpdateVehicle
|
||||
bike_bgm = GameData::Metadata.get.bicycle_BGM
|
||||
pbCueBGM(bike_bgm, 0.5) if bike_bgm
|
||||
pbPokeRadarCancel
|
||||
end
|
||||
|
||||
def pbDismountBike
|
||||
return if !$PokemonGlobal.bicycle
|
||||
$PokemonGlobal.bicycle = false
|
||||
pbUpdateVehicle
|
||||
$game_map.autoplayAsCue
|
||||
end
|
||||
215
Data/Scripts/004_Game classes/010_Game_Follower.rb
Normal file
215
Data/Scripts/004_Game classes/010_Game_Follower.rb
Normal file
@@ -0,0 +1,215 @@
|
||||
#===============================================================================
|
||||
# Instances of this are stored in @realEvents.
|
||||
#===============================================================================
|
||||
class Game_Follower < Game_Event
|
||||
attr_writer :map
|
||||
|
||||
def initialize(event_data)
|
||||
# Create RPG::Event to base self on
|
||||
rpg_event = RPG::Event.new(event_data.x, event_data.y)
|
||||
rpg_event.id = event_data.event_id
|
||||
rpg_event.name = event_data.event_name
|
||||
if event_data.common_event_id
|
||||
# Must setup common event list here and now
|
||||
common_event = Game_CommonEvent.new(event_data.common_event_id)
|
||||
rpg_event.pages[0].list = common_event.list
|
||||
end
|
||||
# Create self
|
||||
super(event_data.original_map_id, rpg_event, $map_factory.getMap(event_data.current_map_id))
|
||||
# Modify self
|
||||
self.character_name = event_data.character_name
|
||||
self.character_hue = event_data.character_hue
|
||||
case event_data.direction
|
||||
when 2 then turn_down
|
||||
when 4 then turn_left
|
||||
when 6 then turn_right
|
||||
when 8 then turn_up
|
||||
end
|
||||
end
|
||||
|
||||
def map_id
|
||||
return @map.map_id
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def move_through(direction)
|
||||
old_through = @through
|
||||
@through = true
|
||||
case direction
|
||||
when 2 then move_down
|
||||
when 4 then move_left
|
||||
when 6 then move_right
|
||||
when 8 then move_up
|
||||
end
|
||||
@through = old_through
|
||||
end
|
||||
|
||||
def move_fancy(direction)
|
||||
delta_x = (direction == 6) ? 1 : (direction == 4) ? -1 : 0
|
||||
delta_y = (direction == 2) ? 1 : (direction == 8) ? -1 : 0
|
||||
new_x = self.x + delta_x
|
||||
new_y = self.y + delta_y
|
||||
# Move if new position is the player's, or the new position is passable,
|
||||
# or self's current position is not passable
|
||||
if ($game_player.x == new_x && $game_player.y == new_y) ||
|
||||
location_passable?(new_x, new_y, 10 - direction) ||
|
||||
!location_passable?(self.x, self.y, direction)
|
||||
move_through(direction)
|
||||
end
|
||||
end
|
||||
|
||||
def jump_fancy(direction, leader)
|
||||
delta_x = (direction == 6) ? 2 : (direction == 4) ? -2 : 0
|
||||
delta_y = (direction == 2) ? 2 : (direction == 8) ? -2 : 0
|
||||
half_delta_x = delta_x / 2
|
||||
half_delta_y = delta_y / 2
|
||||
if location_passable?(self.x + half_delta_x, self.y + half_delta_y, 10 - direction)
|
||||
# Can walk over the middle tile normally; just take two steps
|
||||
move_fancy(direction)
|
||||
move_fancy(direction)
|
||||
elsif location_passable?(self.x + delta_x, self.y + delta_y, 10 - direction)
|
||||
# Can't walk over the middle tile, but can walk over the end tile; jump over
|
||||
if location_passable?(self.x, self.y, direction)
|
||||
if leader.jumping?
|
||||
self.jump_speed = leader.jump_speed || 3
|
||||
else
|
||||
self.jump_speed = leader.move_speed || 3
|
||||
# This is halved because self has to jump 2 tiles in the time it takes
|
||||
# the leader to move one tile
|
||||
@jump_time /= 2
|
||||
end
|
||||
jump(delta_x, delta_y)
|
||||
else
|
||||
# self's current tile isn't passable; just take two steps ignoring passability
|
||||
move_through(direction)
|
||||
move_through(direction)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def fancy_moveto(new_x, new_y, leader)
|
||||
if self.x - new_x == 1 && self.y == new_y
|
||||
move_fancy(4)
|
||||
elsif self.x - new_x == -1 && self.y == new_y
|
||||
move_fancy(6)
|
||||
elsif self.x == new_x && self.y - new_y == 1
|
||||
move_fancy(8)
|
||||
elsif self.x == new_x && self.y - new_y == -1
|
||||
move_fancy(2)
|
||||
elsif self.x - new_x == 2 && self.y == new_y
|
||||
jump_fancy(4, leader)
|
||||
elsif self.x - new_x == -2 && self.y == new_y
|
||||
jump_fancy(6, leader)
|
||||
elsif self.x == new_x && self.y - new_y == 2
|
||||
jump_fancy(8, leader)
|
||||
elsif self.x == new_x && self.y - new_y == -2
|
||||
jump_fancy(2, leader)
|
||||
elsif self.x != new_x || self.y != new_y
|
||||
moveto(new_x, new_y)
|
||||
end
|
||||
end
|
||||
|
||||
# Ceases all movement immediately. Used when the leader wants to move another
|
||||
# tile but self hasn't quite finished its previous movement yet.
|
||||
def end_movement
|
||||
@x = x % self.map.width
|
||||
@y = y % self.map.height
|
||||
@real_x = @x * Game_Map::REAL_RES_X
|
||||
@real_y = @y * Game_Map::REAL_RES_Y
|
||||
@move_timer = nil
|
||||
@jump_timer = nil
|
||||
@jump_peak = 0
|
||||
@jump_distance = 0
|
||||
@jump_fraction = 0
|
||||
@jumping_on_spot = false
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def turn_towards_leader(leader)
|
||||
pbTurnTowardEvent(self, leader)
|
||||
end
|
||||
|
||||
def follow_leader(leader, instant = false, leaderIsTrueLeader = true)
|
||||
return if @move_route_forcing
|
||||
end_movement
|
||||
maps_connected = $map_factory.areConnected?(leader.map.map_id, self.map.map_id)
|
||||
target = nil
|
||||
# Get the target tile that self wants to move to
|
||||
if maps_connected
|
||||
behind_direction = 10 - leader.direction
|
||||
target = $map_factory.getFacingTile(behind_direction, leader)
|
||||
if target && $map_factory.getTerrainTag(target[0], target[1], target[2]).ledge
|
||||
# Get the tile above the ledge (where the leader jumped from)
|
||||
target = $map_factory.getFacingTileFromPos(target[0], target[1], target[2], behind_direction)
|
||||
end
|
||||
target = [leader.map.map_id, leader.x, leader.y] if !target
|
||||
else
|
||||
# Map transfer to an unconnected map
|
||||
target = [leader.map.map_id, leader.x, leader.y]
|
||||
end
|
||||
# Move self to the target
|
||||
if self.map.map_id != target[0]
|
||||
vector = $map_factory.getRelativePos(target[0], 0, 0, self.map.map_id, @x, @y)
|
||||
@map = $map_factory.getMap(target[0])
|
||||
# NOTE: Can't use moveto because vector is outside the boundaries of the
|
||||
# map, and moveto doesn't allow setting invalid coordinates.
|
||||
@x = vector[0]
|
||||
@y = vector[1]
|
||||
@real_x = @x * Game_Map::REAL_RES_X
|
||||
@real_y = @y * Game_Map::REAL_RES_Y
|
||||
end
|
||||
if instant || !maps_connected
|
||||
moveto(target[1], target[2])
|
||||
else
|
||||
fancy_moveto(target[1], target[2], leader)
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
private
|
||||
|
||||
def location_passable?(x, y, direction)
|
||||
this_map = self.map
|
||||
return false if !this_map || !this_map.valid?(x, y)
|
||||
return true if @through
|
||||
passed_tile_checks = false
|
||||
bit = (1 << ((direction / 2) - 1)) & 0x0f
|
||||
# Check all events for ones using tiles as graphics, and see if they're passable
|
||||
this_map.events.each_value do |event|
|
||||
next if event.tile_id < 0 || event.through || !event.at_coordinate?(x, y)
|
||||
tile_data = GameData::TerrainTag.try_get(this_map.terrain_tags[event.tile_id])
|
||||
next if tile_data.ignore_passability
|
||||
next if tile_data.bridge && $PokemonGlobal.bridge == 0
|
||||
return false if tile_data.ledge
|
||||
passage = this_map.passages[event.tile_id] || 0
|
||||
return false if passage & bit != 0
|
||||
passed_tile_checks = true if (tile_data.bridge && $PokemonGlobal.bridge > 0) ||
|
||||
(this_map.priorities[event.tile_id] || -1) == 0
|
||||
break if passed_tile_checks
|
||||
end
|
||||
# Check if tiles at (x, y) allow passage for followe
|
||||
if !passed_tile_checks
|
||||
[2, 1, 0].each do |i|
|
||||
tile_id = this_map.data[x, y, i] || 0
|
||||
next if tile_id == 0
|
||||
tile_data = GameData::TerrainTag.try_get(this_map.terrain_tags[tile_id])
|
||||
next if tile_data.ignore_passability
|
||||
next if tile_data.bridge && $PokemonGlobal.bridge == 0
|
||||
return false if tile_data.ledge
|
||||
passage = this_map.passages[tile_id] || 0
|
||||
return false if passage & bit != 0
|
||||
break if tile_data.bridge && $PokemonGlobal.bridge > 0
|
||||
break if (this_map.priorities[tile_id] || -1) == 0
|
||||
end
|
||||
end
|
||||
# Check all events on the map to see if any are in the way
|
||||
this_map.events.each_value do |event|
|
||||
next if !event.at_coordinate?(x, y)
|
||||
return false if !event.through && event.character_name != ""
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -1,102 +0,0 @@
|
||||
class Game_Player < Game_Character
|
||||
@@bobFrameSpeed = 1.0/15
|
||||
|
||||
def fullPattern
|
||||
case self.direction
|
||||
when 2 then return self.pattern
|
||||
when 4 then return self.pattern + 4
|
||||
when 6 then return self.pattern + 8
|
||||
when 8 then return self.pattern + 12
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
def setDefaultCharName(chname,pattern,lockpattern=false)
|
||||
return if pattern<0 || pattern>=16
|
||||
@defaultCharacterName = chname
|
||||
@direction = [2,4,6,8][pattern/4]
|
||||
@pattern = pattern%4
|
||||
@lock_pattern = lockpattern
|
||||
end
|
||||
|
||||
def pbCanRun?
|
||||
return false if $game_temp.in_menu || $game_temp.in_battle ||
|
||||
@move_route_forcing || $game_temp.message_window_showing ||
|
||||
pbMapInterpreterRunning?
|
||||
input = ($PokemonSystem.runstyle == 1) ^ Input.press?(Input::ACTION)
|
||||
return input && $Trainer.has_running_shoes && !jumping? &&
|
||||
!$PokemonGlobal.diving && !$PokemonGlobal.surfing &&
|
||||
!$PokemonGlobal.bicycle && !$game_player.pbTerrainTag.must_walk
|
||||
end
|
||||
|
||||
def pbIsRunning?
|
||||
return moving? && !@move_route_forcing && pbCanRun?
|
||||
end
|
||||
|
||||
def character_name
|
||||
@defaultCharacterName = "" if !@defaultCharacterName
|
||||
return @defaultCharacterName if @defaultCharacterName!=""
|
||||
if !@move_route_forcing && $Trainer.character_ID>=0
|
||||
meta = GameData::Metadata.get_player($Trainer.character_ID)
|
||||
if meta && !$PokemonGlobal.bicycle && !$PokemonGlobal.diving && !$PokemonGlobal.surfing
|
||||
charset = 1 # Display normal character sprite
|
||||
if pbCanRun? && (moving? || @wasmoving) && Input.dir4!=0 && meta[4] && meta[4]!=""
|
||||
charset = 4 # Display running character sprite
|
||||
end
|
||||
newCharName = pbGetPlayerCharset(meta,charset)
|
||||
@character_name = newCharName if newCharName
|
||||
@wasmoving = moving?
|
||||
end
|
||||
end
|
||||
return @character_name
|
||||
end
|
||||
|
||||
def update_command
|
||||
if $game_player.pbTerrainTag.ice
|
||||
self.move_speed = 4 # Sliding on ice
|
||||
elsif !moving? && !@move_route_forcing && $PokemonGlobal
|
||||
if $PokemonGlobal.bicycle
|
||||
self.move_speed = 5 # Cycling
|
||||
elsif pbCanRun? || $PokemonGlobal.surfing
|
||||
self.move_speed = 4 # Running, surfing
|
||||
else
|
||||
self.move_speed = 3 # Walking, diving
|
||||
end
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
def update_pattern
|
||||
if $PokemonGlobal.surfing || $PokemonGlobal.diving
|
||||
p = ((Graphics.frame_count%60)*@@bobFrameSpeed).floor
|
||||
@pattern = p if !@lock_pattern
|
||||
@pattern_surf = p
|
||||
@bob_height = (p>=2) ? 2 : 0
|
||||
else
|
||||
@bob_height = 0
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
=begin
|
||||
class Game_Character
|
||||
alias update_old2 update
|
||||
|
||||
def update
|
||||
if self.is_a?(Game_Event)
|
||||
if @dependentEvents
|
||||
for i in 0...@dependentEvents.length
|
||||
if @dependentEvents[i][0]==$game_map.map_id &&
|
||||
@dependentEvents[i][1]==self.id
|
||||
self.move_speed_real = $game_player.move_speed_real
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
update_old2
|
||||
end
|
||||
end
|
||||
=end
|
||||
@@ -1,81 +0,0 @@
|
||||
#===============================================================================
|
||||
# ** Game_CommonEvent
|
||||
#-------------------------------------------------------------------------------
|
||||
# This class handles common events. It includes execution of parallel process
|
||||
# event. This class is used within the Game_Map class ($game_map).
|
||||
#===============================================================================
|
||||
class Game_CommonEvent
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Object Initialization
|
||||
# common_event_id : common event ID
|
||||
#-----------------------------------------------------------------------------
|
||||
def initialize(common_event_id)
|
||||
@common_event_id = common_event_id
|
||||
@interpreter = nil
|
||||
refresh
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Get Name
|
||||
#-----------------------------------------------------------------------------
|
||||
def name
|
||||
return $data_common_events[@common_event_id].name
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Get Trigger
|
||||
#-----------------------------------------------------------------------------
|
||||
def trigger
|
||||
return $data_common_events[@common_event_id].trigger
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Get Condition Switch ID
|
||||
#-----------------------------------------------------------------------------
|
||||
def switch_id
|
||||
return $data_common_events[@common_event_id].switch_id
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Get List of Event Commands
|
||||
#-----------------------------------------------------------------------------
|
||||
def list
|
||||
return $data_common_events[@common_event_id].list
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Checks if switch is on
|
||||
#-----------------------------------------------------------------------------
|
||||
def switchIsOn?(id)
|
||||
switchName = $data_system.switches[id]
|
||||
return false if !switchName
|
||||
if switchName[/^s\:/]
|
||||
return eval($~.post_match)
|
||||
else
|
||||
return $game_switches[id]
|
||||
end
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Refresh
|
||||
#-----------------------------------------------------------------------------
|
||||
def refresh
|
||||
# Create an interpreter for parallel process if necessary
|
||||
if self.trigger == 2 && switchIsOn?(self.switch_id)
|
||||
if @interpreter == nil
|
||||
@interpreter = Interpreter.new
|
||||
end
|
||||
else
|
||||
@interpreter = nil
|
||||
end
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Frame Update
|
||||
#-----------------------------------------------------------------------------
|
||||
def update
|
||||
# If parallel process is valid
|
||||
if @interpreter != nil
|
||||
# If not running
|
||||
unless @interpreter.running?
|
||||
# Set up event
|
||||
@interpreter.setup(self.list, 0)
|
||||
end
|
||||
# Update interpreter
|
||||
@interpreter.update
|
||||
end
|
||||
end
|
||||
end
|
||||
389
Data/Scripts/004_Game classes/011_Game_FollowerFactory.rb
Normal file
389
Data/Scripts/004_Game classes/011_Game_FollowerFactory.rb
Normal file
@@ -0,0 +1,389 @@
|
||||
#===============================================================================
|
||||
# Data saved in $PokemonGlobal.followers.
|
||||
#===============================================================================
|
||||
class FollowerData
|
||||
attr_accessor :original_map_id
|
||||
attr_accessor :event_id
|
||||
attr_accessor :event_name
|
||||
attr_accessor :current_map_id
|
||||
attr_accessor :x, :y
|
||||
attr_accessor :direction
|
||||
attr_accessor :character_name, :character_hue
|
||||
attr_accessor :name
|
||||
attr_accessor :common_event_id
|
||||
attr_accessor :visible
|
||||
attr_accessor :invisible_after_transfer
|
||||
|
||||
def initialize(original_map_id, event_id, event_name, current_map_id, x, y,
|
||||
direction, character_name, character_hue)
|
||||
@original_map_id = original_map_id
|
||||
@event_id = event_id
|
||||
@event_name = event_name
|
||||
@current_map_id = current_map_id
|
||||
@x = x
|
||||
@y = y
|
||||
@direction = direction
|
||||
@character_name = character_name
|
||||
@character_hue = character_hue
|
||||
@name = nil
|
||||
@common_event_id = nil
|
||||
@visible = true
|
||||
@invisible_after_transfer = false
|
||||
end
|
||||
|
||||
def visible?
|
||||
return @visible && !@invisible_after_transfer
|
||||
end
|
||||
|
||||
def interact(event)
|
||||
return if !event || event.list.size <= 1
|
||||
return if !@common_event_id
|
||||
# Start event
|
||||
$game_map.refresh if $game_map.need_refresh
|
||||
event.lock
|
||||
pbMapInterpreter.setup(event.list, event.id, event.map.map_id)
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Permanently stores data of follower events (i.e. in save files).
|
||||
#===============================================================================
|
||||
class PokemonGlobalMetadata
|
||||
attr_writer :followers
|
||||
|
||||
def followers
|
||||
@followers = [] if !@followers
|
||||
return @followers
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Stores Game_Follower instances just for the current play session.
|
||||
#===============================================================================
|
||||
class Game_Temp
|
||||
attr_writer :followers
|
||||
|
||||
def followers
|
||||
@followers = Game_FollowerFactory.new if !@followers
|
||||
return @followers
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Game_FollowerFactory
|
||||
attr_reader :last_update
|
||||
|
||||
def initialize
|
||||
@events = []
|
||||
$PokemonGlobal.followers.each do |follower|
|
||||
@events.push(create_follower_object(follower))
|
||||
end
|
||||
@last_update = -1
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def add_follower(event, name = nil, common_event_id = nil)
|
||||
return if !event
|
||||
followers = $PokemonGlobal.followers
|
||||
if followers.any? { |data| data.original_map_id == $game_map.map_id && data.event_id == event.id }
|
||||
return # Event is already dependent
|
||||
end
|
||||
eventData = FollowerData.new($game_map.map_id, event.id, event.name,
|
||||
$game_map.map_id, event.x, event.y, event.direction,
|
||||
event.character_name.clone, event.character_hue)
|
||||
eventData.name = name
|
||||
eventData.common_event_id = common_event_id
|
||||
newEvent = create_follower_object(eventData)
|
||||
followers.push(eventData)
|
||||
@events.push(newEvent)
|
||||
@last_update += 1
|
||||
end
|
||||
|
||||
def remove_follower_by_event(event)
|
||||
followers = $PokemonGlobal.followers
|
||||
map_id = $game_map.map_id
|
||||
followers.each_with_index do |follower, i|
|
||||
next if follower.current_map_id != map_id
|
||||
next if follower.original_map_id != event.map_id
|
||||
next if follower.event_id != event.id
|
||||
followers[i] = nil
|
||||
@events[i] = nil
|
||||
@last_update += 1
|
||||
end
|
||||
followers.compact!
|
||||
@events.compact!
|
||||
end
|
||||
|
||||
def remove_follower_by_name(name)
|
||||
followers = $PokemonGlobal.followers
|
||||
followers.each_with_index do |follower, i|
|
||||
next if follower.name != name
|
||||
followers[i] = nil
|
||||
@events[i] = nil
|
||||
@last_update += 1
|
||||
end
|
||||
followers.compact!
|
||||
@events.compact!
|
||||
end
|
||||
|
||||
def remove_all_followers
|
||||
$PokemonGlobal.followers.clear
|
||||
@events.clear
|
||||
@last_update += 1
|
||||
end
|
||||
|
||||
def get_follower_by_index(index = 0)
|
||||
@events.each_with_index { |event, i| return event if i == index }
|
||||
return nil
|
||||
end
|
||||
|
||||
def get_follower_by_name(name)
|
||||
each_follower { |event, follower| return event if follower&.name == name }
|
||||
return nil
|
||||
end
|
||||
|
||||
def each_follower
|
||||
$PokemonGlobal.followers.each_with_index { |follower, i| yield @events[i], follower }
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def turn_followers
|
||||
leader = $game_player
|
||||
$PokemonGlobal.followers.each_with_index do |follower, i|
|
||||
event = @events[i]
|
||||
event.turn_towards_leader(leader)
|
||||
follower.direction = event.direction
|
||||
leader = event
|
||||
end
|
||||
end
|
||||
|
||||
def move_followers
|
||||
leader = $game_player
|
||||
$PokemonGlobal.followers.each_with_index do |follower, i|
|
||||
event = @events[i]
|
||||
event.follow_leader(leader, false, (i == 0))
|
||||
follower.x = event.x
|
||||
follower.y = event.y
|
||||
follower.current_map_id = event.map.map_id
|
||||
follower.direction = event.direction
|
||||
leader = event
|
||||
end
|
||||
end
|
||||
|
||||
def map_transfer_followers
|
||||
$PokemonGlobal.followers.each_with_index do |follower, i|
|
||||
event = @events[i]
|
||||
event.map = $game_map
|
||||
event.moveto($game_player.x, $game_player.y)
|
||||
event.direction = $game_player.direction
|
||||
event.opacity = 255
|
||||
follower.x = event.x
|
||||
follower.y = event.y
|
||||
follower.current_map_id = event.map.map_id
|
||||
follower.direction = event.direction
|
||||
follower.invisible_after_transfer = true
|
||||
end
|
||||
end
|
||||
|
||||
def follow_into_door
|
||||
# Setting an event's move route also makes it start along that move route,
|
||||
# so we need to record all followers' current positions first before setting
|
||||
# any move routes
|
||||
follower_pos = []
|
||||
follower_pos.push([$game_player.map.map_id, $game_player.x, $game_player.y])
|
||||
$PokemonGlobal.followers.each_with_index do |follower, i|
|
||||
event = @events[i]
|
||||
follower_pos.push([event.map.map_id, event.x, event.y])
|
||||
end
|
||||
# Calculate and set move route from each follower to player
|
||||
move_route = []
|
||||
$PokemonGlobal.followers.each_with_index do |follower, i|
|
||||
event = @events[i]
|
||||
leader = follower_pos[i]
|
||||
vector = $map_factory.getRelativePos(event.map.map_id, event.x, event.y,
|
||||
leader[0], leader[1], leader[2])
|
||||
if vector[0] != 0
|
||||
move_route.prepend((vector[0] > 0) ? PBMoveRoute::RIGHT : PBMoveRoute::LEFT)
|
||||
elsif vector[1] != 0
|
||||
move_route.prepend((vector[1] > 0) ? PBMoveRoute::DOWN : PBMoveRoute::UP)
|
||||
end
|
||||
pbMoveRoute(event, move_route + [PBMoveRoute::OPACITY, 0])
|
||||
end
|
||||
end
|
||||
|
||||
# Used when coming out of a door.
|
||||
def hide_followers
|
||||
$PokemonGlobal.followers.each_with_index do |follower, i|
|
||||
event = @events[i]
|
||||
event.opacity = 0
|
||||
end
|
||||
end
|
||||
|
||||
# Used when coming out of a door. Makes all followers invisible until the
|
||||
# player starts moving.
|
||||
def put_followers_on_player
|
||||
$PokemonGlobal.followers.each_with_index do |follower, i|
|
||||
event = @events[i]
|
||||
event.moveto($game_player.x, $game_player.y)
|
||||
event.opacity = 255
|
||||
follower.x = event.x
|
||||
follower.y = event.y
|
||||
follower.invisible_after_transfer = true
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def update
|
||||
return if $game_temp.in_menu
|
||||
followers = $PokemonGlobal.followers
|
||||
return if followers.length == 0
|
||||
# Update all followers
|
||||
leader = $game_player
|
||||
player_moving = $game_player.moving? || $game_player.jumping?
|
||||
followers.each_with_index do |follower, i|
|
||||
event = @events[i]
|
||||
next if !@events[i]
|
||||
if follower.invisible_after_transfer && player_moving
|
||||
follower.invisible_after_transfer = false
|
||||
event.turn_towards_leader($game_player)
|
||||
end
|
||||
event.move_speed = leader.move_speed
|
||||
event.transparent = !follower.visible?
|
||||
if $PokemonGlobal.ice_sliding
|
||||
event.straighten
|
||||
event.walk_anime = false
|
||||
else
|
||||
event.walk_anime = true
|
||||
end
|
||||
if event.jumping? || event.moving? || !player_moving
|
||||
event.update
|
||||
elsif !event.starting
|
||||
event.set_starting
|
||||
event.update
|
||||
event.clear_starting
|
||||
end
|
||||
follower.direction = event.direction
|
||||
leader = event
|
||||
end
|
||||
# Check event triggers
|
||||
if Input.trigger?(Input::USE) && !$game_temp.in_menu && !$game_temp.in_battle &&
|
||||
!$game_player.move_route_forcing && !$game_temp.message_window_showing &&
|
||||
!pbMapInterpreterRunning?
|
||||
# Get position of tile facing the player
|
||||
facing_tile = $map_factory.getFacingTile
|
||||
# Assumes player is 1x1 tile in size
|
||||
each_follower do |event, follower|
|
||||
next if !facing_tile || event.map.map_id != facing_tile[0] ||
|
||||
!event.at_coordinate?(facing_tile[1], facing_tile[2]) # Not on facing tile
|
||||
next if event.jumping?
|
||||
follower.interact(event)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
private
|
||||
|
||||
def create_follower_object(event_data)
|
||||
return Game_Follower.new(event_data)
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class FollowerSprites
|
||||
def initialize(viewport)
|
||||
@viewport = viewport
|
||||
@sprites = []
|
||||
@last_update = nil
|
||||
@disposed = false
|
||||
end
|
||||
|
||||
def dispose
|
||||
return if @disposed
|
||||
@sprites.each { |sprite| sprite.dispose }
|
||||
@sprites.clear
|
||||
@disposed = true
|
||||
end
|
||||
|
||||
def disposed?
|
||||
return @disposed
|
||||
end
|
||||
|
||||
def refresh
|
||||
@sprites.each { |sprite| sprite.dispose }
|
||||
@sprites.clear
|
||||
$game_temp.followers.each_follower do |event, follower|
|
||||
@sprites.push(Sprite_Character.new(@viewport, event))
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if $game_temp.followers.last_update != @last_update
|
||||
refresh
|
||||
@last_update = $game_temp.followers.last_update
|
||||
end
|
||||
@sprites.each { |sprite| sprite.update }
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Helper module for adding/removing/getting followers.
|
||||
#===============================================================================
|
||||
module Followers
|
||||
module_function
|
||||
|
||||
# @param event_id [Integer] ID of the event on the current map to be added as a follower
|
||||
# @param name [String] identifier name of the follower to be added
|
||||
# @param common_event_id [Integer] ID of the Common Event triggered when interacting with this follower
|
||||
def add(event_id, name, common_event_id)
|
||||
$game_temp.followers.add_follower($game_map.events[event_id], name, common_event_id)
|
||||
end
|
||||
|
||||
# @param event [Game_Event] map event to be added as a follower
|
||||
def add_event(event)
|
||||
$game_temp.followers.add_follower(event)
|
||||
end
|
||||
|
||||
# @param name [String] identifier name of the follower to be removed
|
||||
def remove(name)
|
||||
$game_temp.followers.remove_follower_by_name(name)
|
||||
end
|
||||
|
||||
# @param event [Game_Event] map event to be removed as a follower
|
||||
def remove_event(event)
|
||||
$game_temp.followers.remove_follower_by_event(event)
|
||||
end
|
||||
|
||||
# Removes all followers.
|
||||
def clear
|
||||
$game_temp.followers.remove_all_followers
|
||||
pbDeregisterPartner rescue nil
|
||||
end
|
||||
|
||||
# @param name [String, nil] name of the follower to get, or nil for the first follower
|
||||
# @return [Game_Follower, nil] follower object
|
||||
def get(name = nil)
|
||||
return $game_temp.followers.get_follower_by_name(name) if name
|
||||
return $game_temp.followers.get_follower_by_index
|
||||
end
|
||||
|
||||
def follow_into_door
|
||||
$game_temp.followers.follow_into_door
|
||||
end
|
||||
|
||||
def hide_followers
|
||||
$game_temp.followers.hide_followers
|
||||
end
|
||||
|
||||
def put_followers_on_player
|
||||
$game_temp.followers.put_followers_on_player
|
||||
end
|
||||
end
|
||||
@@ -1,563 +0,0 @@
|
||||
class PokemonTemp
|
||||
attr_writer :dependentEvents
|
||||
|
||||
def dependentEvents
|
||||
@dependentEvents = DependentEvents.new if !@dependentEvents
|
||||
return @dependentEvents
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def pbRemoveDependencies()
|
||||
$PokemonTemp.dependentEvents.removeAllEvents()
|
||||
pbDeregisterPartner() rescue nil
|
||||
end
|
||||
|
||||
def pbAddDependency(event)
|
||||
$PokemonTemp.dependentEvents.addEvent(event)
|
||||
end
|
||||
|
||||
def pbRemoveDependency(event)
|
||||
$PokemonTemp.dependentEvents.removeEvent(event)
|
||||
end
|
||||
|
||||
def pbAddDependency2(eventID, eventName, commonEvent)
|
||||
$PokemonTemp.dependentEvents.addEvent($game_map.events[eventID],eventName,commonEvent)
|
||||
end
|
||||
|
||||
# Gets the Game_Character object associated with a dependent event.
|
||||
def pbGetDependency(eventName)
|
||||
return $PokemonTemp.dependentEvents.getEventByName(eventName)
|
||||
end
|
||||
|
||||
def pbRemoveDependency2(eventName)
|
||||
$PokemonTemp.dependentEvents.removeEventByName(eventName)
|
||||
end
|
||||
|
||||
|
||||
|
||||
class PokemonGlobalMetadata
|
||||
attr_writer :dependentEvents
|
||||
|
||||
def dependentEvents
|
||||
@dependentEvents = [] if !@dependentEvents
|
||||
return @dependentEvents
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def pbTestPass(follower,x,y,_direction=nil)
|
||||
return $MapFactory.isPassableStrict?(follower.map.map_id,x,y,follower)
|
||||
end
|
||||
|
||||
# Same map only
|
||||
def moveThrough(follower,direction)
|
||||
oldThrough=follower.through
|
||||
follower.through=true
|
||||
case direction
|
||||
when 2 then follower.move_down
|
||||
when 4 then follower.move_left
|
||||
when 6 then follower.move_right
|
||||
when 8 then follower.move_up
|
||||
end
|
||||
follower.through=oldThrough
|
||||
end
|
||||
|
||||
# Same map only
|
||||
def moveFancy(follower,direction)
|
||||
deltaX=(direction == 6 ? 1 : (direction == 4 ? -1 : 0))
|
||||
deltaY=(direction == 2 ? 1 : (direction == 8 ? -1 : 0))
|
||||
newX = follower.x + deltaX
|
||||
newY = follower.y + deltaY
|
||||
# Move if new position is the player's, or the new position is passable,
|
||||
# or the current position is not passable
|
||||
if ($game_player.x==newX && $game_player.y==newY) ||
|
||||
pbTestPass(follower,newX,newY,0) ||
|
||||
!pbTestPass(follower,follower.x,follower.y,0)
|
||||
oldThrough=follower.through
|
||||
follower.through=true
|
||||
case direction
|
||||
when 2 then follower.move_down
|
||||
when 4 then follower.move_left
|
||||
when 6 then follower.move_right
|
||||
when 8 then follower.move_up
|
||||
end
|
||||
follower.through=oldThrough
|
||||
end
|
||||
end
|
||||
|
||||
# Same map only
|
||||
def jumpFancy(follower,direction,leader)
|
||||
deltaX=(direction == 6 ? 2 : (direction == 4 ? -2 : 0))
|
||||
deltaY=(direction == 2 ? 2 : (direction == 8 ? -2 : 0))
|
||||
halfDeltaX=(direction == 6 ? 1 : (direction == 4 ? -1 : 0))
|
||||
halfDeltaY=(direction == 2 ? 1 : (direction == 8 ? -1 : 0))
|
||||
middle=pbTestPass(follower,follower.x+halfDeltaX,follower.y+halfDeltaY,0)
|
||||
ending=pbTestPass(follower,follower.x+deltaX, follower.y+deltaY, 0)
|
||||
if middle
|
||||
moveFancy(follower,direction)
|
||||
moveFancy(follower,direction)
|
||||
elsif ending
|
||||
if pbTestPass(follower,follower.x,follower.y,0)
|
||||
if leader.jumping?
|
||||
follower.jump_speed_real = leader.jump_speed_real * Graphics.frame_rate / 40.0
|
||||
else
|
||||
follower.jump_speed_real = leader.move_speed_real * Graphics.frame_rate / 20.0
|
||||
end
|
||||
follower.jump(deltaX,deltaY)
|
||||
else
|
||||
moveThrough(follower,direction)
|
||||
moveThrough(follower,direction)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbFancyMoveTo(follower,newX,newY,leader)
|
||||
if follower.x-newX==-1 && follower.y==newY
|
||||
moveFancy(follower,6)
|
||||
elsif follower.x-newX==1 && follower.y==newY
|
||||
moveFancy(follower,4)
|
||||
elsif follower.y-newY==-1 && follower.x==newX
|
||||
moveFancy(follower,2)
|
||||
elsif follower.y-newY==1 && follower.x==newX
|
||||
moveFancy(follower,8)
|
||||
elsif follower.x-newX==-2 && follower.y==newY
|
||||
jumpFancy(follower,6,leader)
|
||||
elsif follower.x-newX==2 && follower.y==newY
|
||||
jumpFancy(follower,4,leader)
|
||||
elsif follower.y-newY==-2 && follower.x==newX
|
||||
jumpFancy(follower,2,leader)
|
||||
elsif follower.y-newY==2 && follower.x==newX
|
||||
jumpFancy(follower,8,leader)
|
||||
elsif follower.x!=newX || follower.y!=newY
|
||||
follower.moveto(newX,newY)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class DependentEvents
|
||||
attr_reader :lastUpdate
|
||||
|
||||
def createEvent(eventData)
|
||||
rpgEvent = RPG::Event.new(eventData[3],eventData[4])
|
||||
rpgEvent.id = eventData[1]
|
||||
if eventData[9]
|
||||
# Must setup common event list here and now
|
||||
commonEvent = Game_CommonEvent.new(eventData[9])
|
||||
rpgEvent.pages[0].list = commonEvent.list
|
||||
end
|
||||
newEvent = Game_Event.new(eventData[0],rpgEvent,$MapFactory.getMap(eventData[2]))
|
||||
newEvent.character_name = eventData[6]
|
||||
newEvent.character_hue = eventData[7]
|
||||
case eventData[5] # direction
|
||||
when 2 then newEvent.turn_down
|
||||
when 4 then newEvent.turn_left
|
||||
when 6 then newEvent.turn_right
|
||||
when 8 then newEvent.turn_up
|
||||
end
|
||||
return newEvent
|
||||
end
|
||||
|
||||
def initialize
|
||||
# Original map, Event ID, Current map, X, Y, Direction
|
||||
events=$PokemonGlobal.dependentEvents
|
||||
@realEvents=[]
|
||||
@lastUpdate=-1
|
||||
for event in events
|
||||
@realEvents.push(createEvent(event))
|
||||
end
|
||||
end
|
||||
|
||||
def pbEnsureEvent(event, newMapID)
|
||||
events=$PokemonGlobal.dependentEvents
|
||||
for i in 0...events.length
|
||||
# Check original map ID and original event ID
|
||||
if events[i][0]==event.map_id && events[i][1]==event.id
|
||||
# Change current map ID
|
||||
events[i][2]=newMapID
|
||||
newEvent=createEvent(events[i])
|
||||
# Replace event
|
||||
@realEvents[i]=newEvent
|
||||
@lastUpdate+=1
|
||||
return i
|
||||
end
|
||||
end
|
||||
return -1
|
||||
end
|
||||
|
||||
def pbFollowEventAcrossMaps(leader,follower,instant=false,leaderIsTrueLeader=true)
|
||||
d=leader.direction
|
||||
areConnected=$MapFactory.areConnected?(leader.map.map_id,follower.map.map_id)
|
||||
# Get the rear facing tile of leader
|
||||
facingDirection=10-d
|
||||
if !leaderIsTrueLeader && areConnected
|
||||
relativePos=$MapFactory.getThisAndOtherEventRelativePos(leader,follower)
|
||||
# Assumes leader and follower are both 1x1 tile in size
|
||||
if (relativePos[1]==0 && relativePos[0]==2) # 2 spaces to the right of leader
|
||||
facingDirection=6
|
||||
elsif (relativePos[1]==0 && relativePos[0]==-2) # 2 spaces to the left of leader
|
||||
facingDirection=4
|
||||
elsif relativePos[1]==-2 && relativePos[0]==0 # 2 spaces above leader
|
||||
facingDirection=8
|
||||
elsif relativePos[1]==2 && relativePos[0]==0 # 2 spaces below leader
|
||||
facingDirection=2
|
||||
end
|
||||
end
|
||||
facings=[facingDirection] # Get facing from behind
|
||||
# facings.push([0,0,4,0,8,0,2,0,6][d]) # Get right facing
|
||||
# facings.push([0,0,6,0,2,0,8,0,4][d]) # Get left facing
|
||||
if !leaderIsTrueLeader
|
||||
facings.push(d) # Get forward facing
|
||||
end
|
||||
mapTile=nil
|
||||
if areConnected
|
||||
bestRelativePos=-1
|
||||
oldthrough=follower.through
|
||||
follower.through=false
|
||||
for i in 0...facings.length
|
||||
facing=facings[i]
|
||||
tile=$MapFactory.getFacingTile(facing,leader)
|
||||
# Assumes leader is 1x1 tile in size
|
||||
passable=tile && $MapFactory.isPassableStrict?(tile[0],tile[1],tile[2],follower)
|
||||
if i==0 && !passable && tile &&
|
||||
$MapFactory.getTerrainTag(tile[0],tile[1],tile[2]).ledge
|
||||
# If the tile isn't passable and the tile is a ledge,
|
||||
# get tile from further behind
|
||||
tile=$MapFactory.getFacingTileFromPos(tile[0],tile[1],tile[2],facing)
|
||||
passable=tile && $MapFactory.isPassableStrict?(tile[0],tile[1],tile[2],follower)
|
||||
end
|
||||
if passable
|
||||
relativePos=$MapFactory.getThisAndOtherPosRelativePos(
|
||||
follower,tile[0],tile[1],tile[2])
|
||||
# Assumes follower is 1x1 tile in size
|
||||
distance=Math.sqrt(relativePos[0]*relativePos[0]+relativePos[1]*relativePos[1])
|
||||
if bestRelativePos==-1 || bestRelativePos>distance
|
||||
bestRelativePos=distance
|
||||
mapTile=tile
|
||||
end
|
||||
if i==0 && distance<=1 # Prefer behind if tile can move up to 1 space
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
follower.through=oldthrough
|
||||
else
|
||||
tile=$MapFactory.getFacingTile(facings[0],leader)
|
||||
# Assumes leader is 1x1 tile in size
|
||||
passable=tile && $MapFactory.isPassableStrict?(tile[0],tile[1],tile[2],follower)
|
||||
mapTile=passable ? mapTile : nil
|
||||
end
|
||||
if mapTile && follower.map.map_id==mapTile[0]
|
||||
# Follower is on same map
|
||||
newX=mapTile[1]
|
||||
newY=mapTile[2]
|
||||
deltaX=(d == 6 ? -1 : d == 4 ? 1 : 0)
|
||||
deltaY=(d == 2 ? -1 : d == 8 ? 1 : 0)
|
||||
posX = newX + deltaX
|
||||
posY = newY + deltaY
|
||||
follower.move_speed=leader.move_speed # sync movespeed
|
||||
if (follower.x-newX==-1 && follower.y==newY) ||
|
||||
(follower.x-newX==1 && follower.y==newY) ||
|
||||
(follower.y-newY==-1 && follower.x==newX) ||
|
||||
(follower.y-newY==1 && follower.x==newX)
|
||||
if instant
|
||||
follower.moveto(newX,newY)
|
||||
else
|
||||
pbFancyMoveTo(follower,newX,newY,leader)
|
||||
end
|
||||
elsif (follower.x-newX==-2 && follower.y==newY) ||
|
||||
(follower.x-newX==2 && follower.y==newY) ||
|
||||
(follower.y-newY==-2 && follower.x==newX) ||
|
||||
(follower.y-newY==2 && follower.x==newX)
|
||||
if instant
|
||||
follower.moveto(newX,newY)
|
||||
else
|
||||
pbFancyMoveTo(follower,newX,newY,leader)
|
||||
end
|
||||
elsif follower.x!=posX || follower.y!=posY
|
||||
if instant
|
||||
follower.moveto(newX,newY)
|
||||
else
|
||||
pbFancyMoveTo(follower,posX,posY,leader)
|
||||
pbFancyMoveTo(follower,newX,newY,leader)
|
||||
end
|
||||
end
|
||||
else
|
||||
if !mapTile
|
||||
# Make current position into leader's position
|
||||
mapTile=[leader.map.map_id,leader.x,leader.y]
|
||||
end
|
||||
if follower.map.map_id==mapTile[0]
|
||||
# Follower is on same map as leader
|
||||
follower.moveto(leader.x,leader.y)
|
||||
else
|
||||
# Follower will move to different map
|
||||
events=$PokemonGlobal.dependentEvents
|
||||
eventIndex=pbEnsureEvent(follower,mapTile[0])
|
||||
if eventIndex>=0
|
||||
newFollower=@realEvents[eventIndex]
|
||||
newEventData=events[eventIndex]
|
||||
newFollower.moveto(mapTile[1],mapTile[2])
|
||||
newEventData[3]=mapTile[1]
|
||||
newEventData[4]=mapTile[2]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def debugEcho
|
||||
self.eachEvent { |e,d|
|
||||
echoln d
|
||||
echoln [e.map_id,e.map.map_id,e.id]
|
||||
}
|
||||
end
|
||||
|
||||
def pbMapChangeMoveDependentEvents
|
||||
events=$PokemonGlobal.dependentEvents
|
||||
updateDependentEvents
|
||||
leader=$game_player
|
||||
for i in 0...events.length
|
||||
event=@realEvents[i]
|
||||
pbFollowEventAcrossMaps(leader,event,true,i==0)
|
||||
# Update X and Y for this event
|
||||
events[i][3]=event.x
|
||||
events[i][4]=event.y
|
||||
events[i][5]=event.direction
|
||||
# Set leader to this event
|
||||
leader=event
|
||||
end
|
||||
end
|
||||
|
||||
def pbMoveDependentEvents
|
||||
events=$PokemonGlobal.dependentEvents
|
||||
updateDependentEvents
|
||||
leader=$game_player
|
||||
for i in 0...events.length
|
||||
event=@realEvents[i]
|
||||
pbFollowEventAcrossMaps(leader,event,false,i==0)
|
||||
# Update X and Y for this event
|
||||
events[i][3]=event.x
|
||||
events[i][4]=event.y
|
||||
events[i][5]=event.direction
|
||||
# Set leader to this event
|
||||
leader=event
|
||||
end
|
||||
end
|
||||
|
||||
def pbTurnDependentEvents
|
||||
events=$PokemonGlobal.dependentEvents
|
||||
updateDependentEvents
|
||||
leader=$game_player
|
||||
for i in 0...events.length
|
||||
event=@realEvents[i]
|
||||
pbTurnTowardEvent(event,leader)
|
||||
# Update direction for this event
|
||||
events[i][5]=event.direction
|
||||
# Set leader to this event
|
||||
leader=event
|
||||
end
|
||||
end
|
||||
|
||||
def eachEvent
|
||||
events=$PokemonGlobal.dependentEvents
|
||||
for i in 0...events.length
|
||||
yield @realEvents[i],events[i]
|
||||
end
|
||||
end
|
||||
|
||||
def updateDependentEvents
|
||||
events=$PokemonGlobal.dependentEvents
|
||||
return if events.length==0
|
||||
for i in 0...events.length
|
||||
event=@realEvents[i]
|
||||
next if !@realEvents[i]
|
||||
event.transparent=$game_player.transparent
|
||||
if event.jumping? || event.moving? ||
|
||||
!($game_player.jumping? || $game_player.moving?)
|
||||
event.update
|
||||
elsif !event.starting
|
||||
event.set_starting
|
||||
event.update
|
||||
event.clear_starting
|
||||
end
|
||||
events[i][3]=event.x
|
||||
events[i][4]=event.y
|
||||
events[i][5]=event.direction
|
||||
end
|
||||
# Check event triggers
|
||||
if Input.trigger?(Input::USE) && !$game_temp.in_menu && !$game_temp.in_battle &&
|
||||
!$game_player.move_route_forcing && !$game_temp.message_window_showing &&
|
||||
!pbMapInterpreterRunning?
|
||||
# Get position of tile facing the player
|
||||
facingTile=$MapFactory.getFacingTile()
|
||||
# Assumes player is 1x1 tile in size
|
||||
self.eachEvent { |e,d|
|
||||
next if !d[9]
|
||||
if e.at_coordinate?($game_player.x, $game_player.y)
|
||||
# On same position
|
||||
if !e.jumping? && (!e.respond_to?("over_trigger") || e.over_trigger?)
|
||||
if e.list.size>1
|
||||
# Start event
|
||||
$game_map.refresh if $game_map.need_refresh
|
||||
e.lock
|
||||
pbMapInterpreter.setup(e.list,e.id,e.map.map_id)
|
||||
end
|
||||
end
|
||||
elsif facingTile && e.map.map_id==facingTile[0] &&
|
||||
e.at_coordinate?(facingTile[1], facingTile[2])
|
||||
# On facing tile
|
||||
if !e.jumping? && (!e.respond_to?("over_trigger") || !e.over_trigger?)
|
||||
if e.list.size>1
|
||||
# Start event
|
||||
$game_map.refresh if $game_map.need_refresh
|
||||
e.lock
|
||||
pbMapInterpreter.setup(e.list,e.id,e.map.map_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def removeEvent(event)
|
||||
events=$PokemonGlobal.dependentEvents
|
||||
mapid=$game_map.map_id
|
||||
for i in 0...events.length
|
||||
if events[i][2]==mapid && # Refer to current map
|
||||
events[i][0]==event.map_id && # Event's map ID is original ID
|
||||
events[i][1]==event.id
|
||||
events[i]=nil
|
||||
@realEvents[i]=nil
|
||||
@lastUpdate+=1
|
||||
end
|
||||
end
|
||||
events.compact!
|
||||
@realEvents.compact!
|
||||
end
|
||||
|
||||
def getEventByName(name)
|
||||
events=$PokemonGlobal.dependentEvents
|
||||
for i in 0...events.length
|
||||
if events[i] && events[i][8]==name # Arbitrary name given to dependent event
|
||||
return @realEvents[i]
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def removeAllEvents
|
||||
events=$PokemonGlobal.dependentEvents
|
||||
events.clear
|
||||
@realEvents.clear
|
||||
@lastUpdate+=1
|
||||
end
|
||||
|
||||
def removeEventByName(name)
|
||||
events=$PokemonGlobal.dependentEvents
|
||||
for i in 0...events.length
|
||||
if events[i] && events[i][8]==name # Arbitrary name given to dependent event
|
||||
events[i]=nil
|
||||
@realEvents[i]=nil
|
||||
@lastUpdate+=1
|
||||
end
|
||||
end
|
||||
events.compact!
|
||||
@realEvents.compact!
|
||||
end
|
||||
|
||||
def addEvent(event,eventName=nil,commonEvent=nil)
|
||||
return if !event
|
||||
events=$PokemonGlobal.dependentEvents
|
||||
for i in 0...events.length
|
||||
if events[i] && events[i][0]==$game_map.map_id && events[i][1]==event.id
|
||||
# Already exists
|
||||
return
|
||||
end
|
||||
end
|
||||
# Original map ID, original event ID, current map ID,
|
||||
# event X, event Y, event direction,
|
||||
# event's filename,
|
||||
# event's hue, event's name, common event ID
|
||||
eventData=[
|
||||
$game_map.map_id,event.id,$game_map.map_id,
|
||||
event.x,event.y,event.direction,
|
||||
event.character_name.clone,
|
||||
event.character_hue,eventName,commonEvent
|
||||
]
|
||||
newEvent=createEvent(eventData)
|
||||
events.push(eventData)
|
||||
@realEvents.push(newEvent)
|
||||
@lastUpdate+=1
|
||||
event.erase
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class DependentEventSprites
|
||||
def initialize(viewport,map)
|
||||
@disposed=false
|
||||
@sprites=[]
|
||||
@map=map
|
||||
@viewport=viewport
|
||||
refresh
|
||||
@lastUpdate=nil
|
||||
end
|
||||
|
||||
def refresh
|
||||
for sprite in @sprites
|
||||
sprite.dispose
|
||||
end
|
||||
@sprites.clear
|
||||
$PokemonTemp.dependentEvents.eachEvent { |event,data|
|
||||
if data[0]==@map.map_id # Check original map
|
||||
@map.events[data[1]].erase
|
||||
end
|
||||
if data[2]==@map.map_id # Check current map
|
||||
@sprites.push(Sprite_Character.new(@viewport,event))
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
def update
|
||||
if $PokemonTemp.dependentEvents.lastUpdate!=@lastUpdate
|
||||
refresh
|
||||
@lastUpdate=$PokemonTemp.dependentEvents.lastUpdate
|
||||
end
|
||||
for sprite in @sprites
|
||||
sprite.update
|
||||
end
|
||||
end
|
||||
|
||||
def dispose
|
||||
return if @disposed
|
||||
for sprite in @sprites
|
||||
sprite.dispose
|
||||
end
|
||||
@sprites.clear
|
||||
@disposed=true
|
||||
end
|
||||
|
||||
def disposed?
|
||||
@disposed
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
Events.onSpritesetCreate += proc { |_sender,e|
|
||||
spriteset = e[0] # Spriteset being created
|
||||
viewport = e[1] # Viewport used for tilemap and characters
|
||||
map = spriteset.map # Map associated with the spriteset (not necessarily the current map)
|
||||
spriteset.addUserSprite(DependentEventSprites.new(viewport,map))
|
||||
}
|
||||
|
||||
Events.onMapSceneChange += proc { |_sender,e|
|
||||
mapChanged = e[1]
|
||||
if mapChanged
|
||||
$PokemonTemp.dependentEvents.pbMapChangeMoveDependentEvents
|
||||
end
|
||||
}
|
||||
214
Data/Scripts/004_Game classes/012_Game_Stats.rb
Normal file
214
Data/Scripts/004_Game classes/012_Game_Stats.rb
Normal file
@@ -0,0 +1,214 @@
|
||||
#===============================================================================
|
||||
# Stored in $stats
|
||||
#===============================================================================
|
||||
class GameStats
|
||||
# Travel
|
||||
attr_accessor :distance_walked, :distance_cycled, :distance_surfed # surfed includes diving
|
||||
attr_accessor :distance_slid_on_ice # Also counted in distance_walked
|
||||
attr_accessor :bump_count # Times the player walked into something
|
||||
attr_accessor :cycle_count, :surf_count, :dive_count
|
||||
# Field actions
|
||||
attr_accessor :fly_count, :cut_count, :flash_count
|
||||
attr_accessor :rock_smash_count, :rock_smash_battles
|
||||
attr_accessor :headbutt_count, :headbutt_battles
|
||||
attr_accessor :strength_push_count # Number of shoves, not the times Strength was used
|
||||
attr_accessor :waterfall_count, :waterfalls_descended
|
||||
# Items
|
||||
attr_accessor :repel_count
|
||||
attr_accessor :itemfinder_count
|
||||
attr_accessor :fishing_count, :fishing_battles
|
||||
attr_accessor :poke_radar_count, :poke_radar_longest_chain
|
||||
attr_accessor :berry_plants_picked, :max_yield_berry_plants
|
||||
attr_accessor :berries_planted
|
||||
# NPCs
|
||||
attr_accessor :poke_center_count
|
||||
attr_accessor :revived_fossil_count
|
||||
attr_accessor :lottery_prize_count # Times won any prize at all
|
||||
# Pokémon
|
||||
attr_accessor :eggs_hatched
|
||||
attr_accessor :evolution_count, :evolutions_cancelled
|
||||
attr_accessor :trade_count
|
||||
attr_accessor :pokemon_release_count
|
||||
attr_accessor :moves_taught_by_item, :moves_taught_by_tutor, :moves_taught_by_reminder
|
||||
attr_accessor :day_care_deposits, :day_care_levels_gained
|
||||
attr_accessor :pokerus_infections
|
||||
attr_accessor :shadow_pokemon_purified
|
||||
# Battles
|
||||
attr_accessor :wild_battles_won, :wild_battles_lost, :wild_battles_fled # Fled counts both player and wild Pokémon fleeing
|
||||
attr_accessor :trainer_battles_won, :trainer_battles_lost
|
||||
attr_accessor :total_exp_gained
|
||||
attr_accessor :battle_money_gained, :battle_money_lost
|
||||
attr_accessor :blacked_out_count
|
||||
attr_accessor :mega_evolution_count, :primal_reversion_count
|
||||
attr_accessor :failed_poke_ball_count
|
||||
# Currency
|
||||
attr_accessor :money_spent_at_marts
|
||||
attr_accessor :money_earned_at_marts
|
||||
attr_accessor :mart_items_bought, :premier_balls_earned
|
||||
attr_accessor :drinks_bought, :drinks_won # From vending machines
|
||||
attr_accessor :coins_won, :coins_lost # Not bought, not spent
|
||||
attr_accessor :battle_points_won, :battle_points_spent
|
||||
attr_accessor :soot_collected
|
||||
# Special stats
|
||||
attr_accessor :gym_leader_attempts # An array of integers
|
||||
attr_accessor :times_to_get_badges # An array of times in seconds
|
||||
attr_accessor :elite_four_attempts
|
||||
attr_accessor :hall_of_fame_entry_count # See also Game Variable 13
|
||||
attr_accessor :time_to_enter_hall_of_fame # In seconds
|
||||
attr_accessor :safari_pokemon_caught, :most_captures_per_safari_game
|
||||
attr_accessor :bug_contest_count, :bug_contest_wins
|
||||
# Play
|
||||
attr_writer :play_time # In seconds; the reader also updates the value
|
||||
attr_accessor :play_sessions
|
||||
attr_accessor :time_last_saved # In seconds
|
||||
attr_reader :real_time_saved
|
||||
attr_accessor :save_filename_number # -1 if haven't saved yet
|
||||
|
||||
def initialize
|
||||
# Travel
|
||||
@distance_walked = 0
|
||||
@distance_cycled = 0
|
||||
@distance_surfed = 0
|
||||
@distance_slid_on_ice = 0
|
||||
@bump_count = 0
|
||||
@cycle_count = 0
|
||||
@surf_count = 0
|
||||
@dive_count = 0
|
||||
# Field actions
|
||||
@fly_count = 0
|
||||
@cut_count = 0
|
||||
@flash_count = 0
|
||||
@rock_smash_count = 0
|
||||
@rock_smash_battles = 0
|
||||
@headbutt_count = 0
|
||||
@headbutt_battles = 0
|
||||
@strength_push_count = 0
|
||||
@waterfall_count = 0
|
||||
@waterfalls_descended = 0
|
||||
# Items
|
||||
@repel_count = 0
|
||||
@itemfinder_count = 0
|
||||
@fishing_count = 0
|
||||
@fishing_battles = 0
|
||||
@poke_radar_count = 0
|
||||
@poke_radar_longest_chain = 0
|
||||
@berry_plants_picked = 0
|
||||
@max_yield_berry_plants = 0
|
||||
@berries_planted = 0
|
||||
# NPCs
|
||||
@poke_center_count = 0 # Incremented in Poké Center nurse events
|
||||
@revived_fossil_count = 0 # Incremented in fossil reviver events
|
||||
@lottery_prize_count = 0 # Incremented in lottery NPC events
|
||||
# Pokémon
|
||||
@eggs_hatched = 0
|
||||
@evolution_count = 0
|
||||
@evolutions_cancelled = 0
|
||||
@trade_count = 0
|
||||
@pokemon_release_count = 0
|
||||
@moves_taught_by_item = 0
|
||||
@moves_taught_by_tutor = 0
|
||||
@moves_taught_by_reminder = 0
|
||||
@day_care_deposits = 0
|
||||
@day_care_levels_gained = 0
|
||||
@pokerus_infections = 0
|
||||
@shadow_pokemon_purified = 0
|
||||
# Battles
|
||||
@wild_battles_won = 0
|
||||
@wild_battles_lost = 0
|
||||
@wild_battles_fled = 0
|
||||
@trainer_battles_won = 0
|
||||
@trainer_battles_lost = 0
|
||||
@total_exp_gained = 0
|
||||
@battle_money_gained = 0
|
||||
@battle_money_lost = 0
|
||||
@blacked_out_count = 0
|
||||
@mega_evolution_count = 0
|
||||
@primal_reversion_count = 0
|
||||
@failed_poke_ball_count = 0
|
||||
# Currency
|
||||
@money_spent_at_marts = 0
|
||||
@money_earned_at_marts = 0
|
||||
@mart_items_bought = 0
|
||||
@premier_balls_earned = 0
|
||||
@drinks_bought = 0 # Incremented in vending machine events
|
||||
@drinks_won = 0 # Incremented in vending machine events
|
||||
@coins_won = 0
|
||||
@coins_lost = 0
|
||||
@battle_points_won = 0
|
||||
@battle_points_spent = 0
|
||||
@soot_collected = 0
|
||||
# Special stats
|
||||
@gym_leader_attempts = [0] * 50 # Incremented in Gym Leader events (50 is arbitrary but suitably large)
|
||||
@times_to_get_badges = [] # Set with set_time_to_badge(number) in Gym Leader events
|
||||
@elite_four_attempts = 0 # Incremented in door event leading to the first E4 member
|
||||
@hall_of_fame_entry_count = 0 # Incremented in Hall of Fame event
|
||||
@time_to_enter_hall_of_fame = 0 # Set with set_time_to_hall_of_fame in Hall of Fame event
|
||||
@safari_pokemon_caught = 0
|
||||
@most_captures_per_safari_game = 0
|
||||
@bug_contest_count = 0
|
||||
@bug_contest_wins = 0
|
||||
# Play
|
||||
@play_time = 0
|
||||
@play_sessions = 0
|
||||
@time_last_saved = 0
|
||||
@real_time_saved = 0
|
||||
@save_filename_number = -1
|
||||
end
|
||||
|
||||
def distance_moved
|
||||
return @distance_walked + @distance_cycled + @distance_surfed
|
||||
end
|
||||
|
||||
def caught_pokemon_count
|
||||
return 0 if !$player
|
||||
ret = 0
|
||||
GameData::Species.each_species { |sp| ret += $player.pokedex.caught_count(sp) }
|
||||
return ret
|
||||
end
|
||||
|
||||
def save_count
|
||||
return $game_system&.save_count || 0
|
||||
end
|
||||
|
||||
def set_time_to_badge(number)
|
||||
@times_to_get_badges[number] = play_time
|
||||
end
|
||||
|
||||
def set_time_to_hall_of_fame
|
||||
@time_to_enter_hall_of_fame = play_time if @time_to_enter_hall_of_fame == 0
|
||||
end
|
||||
|
||||
def play_time
|
||||
if $game_temp&.last_uptime_refreshed_play_time
|
||||
now = System.uptime
|
||||
@play_time += now - $game_temp.last_uptime_refreshed_play_time
|
||||
$game_temp.last_uptime_refreshed_play_time = now
|
||||
end
|
||||
return @play_time
|
||||
end
|
||||
|
||||
# For looking at a save file's play time.
|
||||
def real_play_time
|
||||
return @play_time
|
||||
end
|
||||
|
||||
def play_time_per_session
|
||||
return play_time / @play_sessions
|
||||
end
|
||||
|
||||
def set_time_last_saved
|
||||
@time_last_saved = play_time
|
||||
@real_time_saved = Time.now.to_i
|
||||
end
|
||||
|
||||
def time_since_last_save
|
||||
return play_time - @time_last_saved
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Game_Temp
|
||||
attr_accessor :last_uptime_refreshed_play_time
|
||||
end
|
||||
@@ -1,3 +1,6 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Sprite_Picture
|
||||
def initialize(viewport, picture)
|
||||
@viewport = viewport
|
||||
@@ -7,11 +10,11 @@ class Sprite_Picture
|
||||
end
|
||||
|
||||
def dispose
|
||||
@sprite.dispose if @sprite
|
||||
@sprite&.dispose
|
||||
end
|
||||
|
||||
def update
|
||||
@sprite.update if @sprite
|
||||
@sprite&.update
|
||||
# If picture file name is different from current one
|
||||
if @picture_name != @picture.name
|
||||
# Remember file name to instance variables
|
||||
@@ -19,16 +22,16 @@ class Sprite_Picture
|
||||
# If file name is not empty
|
||||
if @picture_name != ""
|
||||
# Get picture graphic
|
||||
@sprite=IconSprite.new(0,0,@viewport) if !@sprite
|
||||
@sprite.setBitmap("Graphics/Pictures/"+@picture_name)
|
||||
@sprite = IconSprite.new(0, 0, @viewport) if !@sprite
|
||||
@sprite.setBitmap("Graphics/Pictures/" + @picture_name)
|
||||
end
|
||||
end
|
||||
# If file name is empty
|
||||
if @picture_name == ""
|
||||
# Set sprite to invisible
|
||||
if @sprite
|
||||
@sprite.dispose if @sprite
|
||||
@sprite=nil
|
||||
@sprite&.dispose
|
||||
@sprite = nil
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Sprite_Timer
|
||||
def initialize(viewport=nil)
|
||||
@viewport=viewport
|
||||
@timer=nil
|
||||
@total_sec=nil
|
||||
@disposed=false
|
||||
def initialize(viewport = nil)
|
||||
@viewport = viewport
|
||||
@timer = nil
|
||||
@total_sec = nil
|
||||
@disposed = false
|
||||
end
|
||||
|
||||
def dispose
|
||||
@timer.dispose if @timer
|
||||
@timer=nil
|
||||
@disposed=true
|
||||
@timer&.dispose
|
||||
@timer = nil
|
||||
@disposed = true
|
||||
end
|
||||
|
||||
def disposed?
|
||||
@@ -18,17 +21,17 @@ class Sprite_Timer
|
||||
|
||||
def update
|
||||
return if disposed?
|
||||
if $game_system.timer_working
|
||||
if $game_system.timer_start
|
||||
@timer.visible = true if @timer
|
||||
if !@timer
|
||||
@timer=Window_AdvancedTextPokemon.newWithSize("",Graphics.width-120,0,120,64)
|
||||
@timer.width=@timer.borderX+96
|
||||
@timer.x=Graphics.width-@timer.width
|
||||
@timer.viewport=@viewport
|
||||
@timer.z=99998
|
||||
@timer = Window_AdvancedTextPokemon.newWithSize("", Graphics.width - 120, 0, 120, 64)
|
||||
@timer.width = @timer.borderX + 96
|
||||
@timer.x = Graphics.width - @timer.width
|
||||
@timer.viewport = @viewport
|
||||
@timer.z = 99998
|
||||
end
|
||||
curtime=$game_system.timer / Graphics.frame_rate
|
||||
curtime=0 if curtime<0
|
||||
curtime = $game_system.timer
|
||||
curtime = 0 if curtime < 0
|
||||
if curtime != @total_sec
|
||||
# Calculate total number of seconds
|
||||
@total_sec = curtime
|
||||
@@ -38,8 +41,8 @@ class Sprite_Timer
|
||||
@timer.text = _ISPRINTF("<ac>{1:02d}:{2:02d}", min, sec)
|
||||
end
|
||||
@timer.update
|
||||
else
|
||||
@timer.visible=false if @timer
|
||||
elsif @timer
|
||||
@timer.visible = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class BushBitmap
|
||||
def initialize(bitmap, isTile, depth)
|
||||
@bitmaps = []
|
||||
@@ -8,7 +11,7 @@ class BushBitmap
|
||||
end
|
||||
|
||||
def dispose
|
||||
@bitmaps.each { |b| b.dispose if b }
|
||||
@bitmaps.each { |b| b&.dispose }
|
||||
end
|
||||
|
||||
def bitmap
|
||||
@@ -28,7 +31,7 @@ class BushBitmap
|
||||
ret = Bitmap.new(bitmap.width, bitmap.height)
|
||||
charheight = ret.height / 4
|
||||
cy = charheight - depth - 2
|
||||
for i in 0...4
|
||||
4.times do |i|
|
||||
y = i * charheight
|
||||
if cy >= 0
|
||||
ret.blt(0, y, bitmap, Rect.new(0, y, ret.width, cy))
|
||||
@@ -53,8 +56,9 @@ class BushBitmap
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Sprite_Character < RPG::Sprite
|
||||
attr_accessor :character
|
||||
|
||||
@@ -64,9 +68,11 @@ class Sprite_Character < RPG::Sprite
|
||||
@oldbushdepth = 0
|
||||
@spriteoffset = false
|
||||
if !character || character == $game_player || (character.name[/reflection/i] rescue false)
|
||||
@reflection = Sprite_Reflection.new(self, character, viewport)
|
||||
@reflection = Sprite_Reflection.new(self, viewport)
|
||||
end
|
||||
@surfbase = Sprite_SurfBase.new(self, character, viewport) if character == $game_player
|
||||
@surfbase = Sprite_SurfBase.new(self, viewport) if character == $game_player
|
||||
self.zoom_x = TilemapRenderer::ZOOM_X
|
||||
self.zoom_y = TilemapRenderer::ZOOM_Y
|
||||
update
|
||||
end
|
||||
|
||||
@@ -80,57 +86,66 @@ class Sprite_Character < RPG::Sprite
|
||||
end
|
||||
|
||||
def dispose
|
||||
@bushbitmap.dispose if @bushbitmap
|
||||
@bushbitmap&.dispose
|
||||
@bushbitmap = nil
|
||||
@charbitmap.dispose if @charbitmap
|
||||
@charbitmap&.dispose
|
||||
@charbitmap = nil
|
||||
@reflection.dispose if @reflection
|
||||
@reflection&.dispose
|
||||
@reflection = nil
|
||||
@surfbase.dispose if @surfbase
|
||||
@surfbase&.dispose
|
||||
@surfbase = nil
|
||||
@character = nil
|
||||
super
|
||||
end
|
||||
|
||||
def refresh_graphic
|
||||
return if @tile_id == @character.tile_id &&
|
||||
@character_name == @character.character_name &&
|
||||
@character_hue == @character.character_hue &&
|
||||
@oldbushdepth == @character.bush_depth
|
||||
@tile_id = @character.tile_id
|
||||
@character_name = @character.character_name
|
||||
@character_hue = @character.character_hue
|
||||
@oldbushdepth = @character.bush_depth
|
||||
@charbitmap&.dispose
|
||||
@charbitmap = nil
|
||||
@bushbitmap&.dispose
|
||||
@bushbitmap = nil
|
||||
|
||||
if @tile_id >= 384
|
||||
@charbitmap = pbGetTileBitmap(@character.map.tileset_name, @tile_id,
|
||||
@character_hue, @character.width, @character.height)
|
||||
@charbitmapAnimated = false
|
||||
@spriteoffset = false
|
||||
@cw = Game_Map::TILE_WIDTH * @character.width
|
||||
@ch = Game_Map::TILE_HEIGHT * @character.height
|
||||
self.src_rect.set(0, 0, @cw, @ch)
|
||||
self.ox = @cw / 2
|
||||
self.oy = @ch
|
||||
elsif @character_name != ""
|
||||
@charbitmap = AnimatedBitmap.new(
|
||||
"Graphics/Characters/" + @character_name, @character_hue
|
||||
)
|
||||
RPG::Cache.retain("Graphics/Characters/", @character_name, @character_hue) if @character == $game_player
|
||||
@charbitmapAnimated = true
|
||||
@spriteoffset = @character_name[/offset/i]
|
||||
@cw = @charbitmap.width / 4
|
||||
@ch = @charbitmap.height / 4
|
||||
self.ox = @cw / 2
|
||||
else
|
||||
self.bitmap = nil
|
||||
@cw = 0
|
||||
@ch = 0
|
||||
@reflection&.update
|
||||
end
|
||||
@character.sprite_size = [@cw, @ch]
|
||||
end
|
||||
|
||||
def update
|
||||
return if @character.is_a?(Game_Event) && !@character.should_update?
|
||||
super
|
||||
if @tile_id != @character.tile_id ||
|
||||
@character_name != @character.character_name ||
|
||||
@character_hue != @character.character_hue ||
|
||||
@oldbushdepth != @character.bush_depth
|
||||
@tile_id = @character.tile_id
|
||||
@character_name = @character.character_name
|
||||
@character_hue = @character.character_hue
|
||||
@oldbushdepth = @character.bush_depth
|
||||
if @tile_id >= 384
|
||||
@charbitmap.dispose if @charbitmap
|
||||
@charbitmap = pbGetTileBitmap(@character.map.tileset_name, @tile_id,
|
||||
@character_hue, @character.width, @character.height)
|
||||
@charbitmapAnimated = false
|
||||
@bushbitmap.dispose if @bushbitmap
|
||||
@bushbitmap = nil
|
||||
@spriteoffset = false
|
||||
@cw = Game_Map::TILE_WIDTH * @character.width
|
||||
@ch = Game_Map::TILE_HEIGHT * @character.height
|
||||
self.src_rect.set(0, 0, @cw, @ch)
|
||||
self.ox = @cw / 2
|
||||
self.oy = @ch
|
||||
@character.sprite_size = [@cw, @ch]
|
||||
else
|
||||
@charbitmap.dispose if @charbitmap
|
||||
@charbitmap = AnimatedBitmap.new(
|
||||
'Graphics/Characters/' + @character_name, @character_hue)
|
||||
RPG::Cache.retain('Graphics/Characters/', @character_name, @character_hue) if @character == $game_player
|
||||
@charbitmapAnimated = true
|
||||
@bushbitmap.dispose if @bushbitmap
|
||||
@bushbitmap = nil
|
||||
@spriteoffset = @character_name[/offset/i]
|
||||
@cw = @charbitmap.width / 4
|
||||
@ch = @charbitmap.height / 4
|
||||
self.ox = @cw / 2
|
||||
@character.sprite_size = [@cw, @ch]
|
||||
end
|
||||
end
|
||||
refresh_graphic
|
||||
return if !@charbitmap
|
||||
@charbitmap.update if @charbitmapAnimated
|
||||
bushdepth = @character.bush_depth
|
||||
if bushdepth == 0
|
||||
@@ -154,20 +169,21 @@ class Sprite_Character < RPG::Sprite
|
||||
pbDayNightTint(self)
|
||||
end
|
||||
end
|
||||
self.x = @character.screen_x
|
||||
self.y = @character.screen_y
|
||||
self.z = @character.screen_z(@ch)
|
||||
# self.zoom_x = Game_Map::TILE_WIDTH / 32.0
|
||||
# self.zoom_y = Game_Map::TILE_HEIGHT / 32.0
|
||||
self.opacity = @character.opacity
|
||||
this_x = @character.screen_x
|
||||
this_x = ((this_x - (Graphics.width / 2)) * TilemapRenderer::ZOOM_X) + (Graphics.width / 2) if TilemapRenderer::ZOOM_X != 1
|
||||
self.x = this_x
|
||||
this_y = @character.screen_y
|
||||
this_y = ((this_y - (Graphics.height / 2)) * TilemapRenderer::ZOOM_Y) + (Graphics.height / 2) if TilemapRenderer::ZOOM_Y != 1
|
||||
self.y = this_y
|
||||
self.z = @character.screen_z(@ch)
|
||||
self.opacity = @character.opacity
|
||||
self.blend_type = @character.blend_type
|
||||
# self.bush_depth = @character.bush_depth
|
||||
if @character.animation_id != 0
|
||||
if @character.animation_id && @character.animation_id != 0
|
||||
animation = $data_animations[@character.animation_id]
|
||||
animation(animation, true)
|
||||
animation(animation, true, @character.animation_height || 3, @character.animation_regular_tone || false)
|
||||
@character.animation_id = 0
|
||||
end
|
||||
@reflection.update if @reflection
|
||||
@surfbase.update if @surfbase
|
||||
@reflection&.update
|
||||
@surfbase&.update
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Sprite_Reflection
|
||||
attr_reader :visible
|
||||
attr_accessor :event
|
||||
|
||||
def initialize(sprite,event,viewport=nil)
|
||||
@rsprite = sprite
|
||||
@sprite = nil
|
||||
@event = event
|
||||
@height = 0
|
||||
def initialize(parent_sprite, viewport = nil)
|
||||
@parent_sprite = parent_sprite
|
||||
@sprite = nil
|
||||
@height = 0
|
||||
@fixedheight = false
|
||||
if @event && @event!=$game_player
|
||||
if @event.name[/reflection\((\d+)\)/i]
|
||||
@height = $~[1].to_i || 0
|
||||
@fixedheight = true
|
||||
end
|
||||
if @parent_sprite.character && @parent_sprite.character != $game_player &&
|
||||
@parent_sprite.character.name[/reflection\((\d+)\)/i]
|
||||
@height = $~[1].to_i || 0
|
||||
@fixedheight = true
|
||||
end
|
||||
@viewport = viewport
|
||||
@disposed = false
|
||||
@@ -20,15 +20,19 @@ class Sprite_Reflection
|
||||
end
|
||||
|
||||
def dispose
|
||||
if !@disposed
|
||||
@sprite.dispose if @sprite
|
||||
@sprite = nil
|
||||
@disposed = true
|
||||
end
|
||||
return if @disposed
|
||||
@sprite&.dispose
|
||||
@sprite = nil
|
||||
@parent_sprite = nil
|
||||
@disposed = true
|
||||
end
|
||||
|
||||
def disposed?
|
||||
@disposed
|
||||
return @disposed
|
||||
end
|
||||
|
||||
def event
|
||||
return @parent_sprite.character
|
||||
end
|
||||
|
||||
def visible=(value)
|
||||
@@ -38,7 +42,7 @@ class Sprite_Reflection
|
||||
|
||||
def update
|
||||
return if disposed?
|
||||
shouldShow = @rsprite.visible
|
||||
shouldShow = @parent_sprite.visible
|
||||
if !shouldShow
|
||||
# Just-in-time disposal of sprite
|
||||
if @sprite
|
||||
@@ -50,37 +54,40 @@ class Sprite_Reflection
|
||||
# Just-in-time creation of sprite
|
||||
@sprite = Sprite.new(@viewport) if !@sprite
|
||||
if @sprite
|
||||
x = @rsprite.x-@rsprite.ox
|
||||
y = @rsprite.y-@rsprite.oy
|
||||
y -= 32 if @rsprite.character.character_name[/offset/i]
|
||||
x = @parent_sprite.x - (@parent_sprite.ox * TilemapRenderer::ZOOM_X)
|
||||
y = @parent_sprite.y - (@parent_sprite.oy * TilemapRenderer::ZOOM_Y)
|
||||
y -= Game_Map::TILE_HEIGHT * TilemapRenderer::ZOOM_Y if event.character_name[/offset/i]
|
||||
@height = $PokemonGlobal.bridge if !@fixedheight
|
||||
y += @height*16
|
||||
width = @rsprite.src_rect.width
|
||||
height = @rsprite.src_rect.height
|
||||
@sprite.x = x+width/2
|
||||
@sprite.y = y+height+height/2
|
||||
@sprite.ox = width/2
|
||||
@sprite.oy = height/2-2 # Hard-coded 2 pixel shift up
|
||||
@sprite.oy -= @rsprite.character.bob_height*2
|
||||
@sprite.z = -50 # Still water is -100, map is 0 and above
|
||||
@sprite.zoom_x = @rsprite.zoom_x
|
||||
@sprite.zoom_y = @rsprite.zoom_y
|
||||
frame = (Graphics.frame_count%40)/10
|
||||
@sprite.zoom_x *= [1.0, 0.95, 1.0, 1.05][frame]
|
||||
y += @height * TilemapRenderer::ZOOM_Y * Game_Map::TILE_HEIGHT / 2
|
||||
width = @parent_sprite.src_rect.width
|
||||
height = @parent_sprite.src_rect.height
|
||||
@sprite.x = x + ((width / 2) * TilemapRenderer::ZOOM_X)
|
||||
@sprite.y = y + ((height + (height / 2)) * TilemapRenderer::ZOOM_Y)
|
||||
@sprite.ox = width / 2
|
||||
@sprite.oy = (height / 2) - 2 # Hard-coded 2 pixel shift up
|
||||
@sprite.oy -= event.bob_height * 2
|
||||
@sprite.z = @parent_sprite.groundY - (Graphics.height / 2)
|
||||
@sprite.z -= 1000 # Still water is -2000, map is 0 and above
|
||||
@sprite.z += 1 if event == $game_player
|
||||
@sprite.zoom_x = @parent_sprite.zoom_x
|
||||
if Settings::ANIMATE_REFLECTIONS && !GameData::MapMetadata.try_get(event.map_id)&.still_reflections
|
||||
@sprite.zoom_x += 0.05 * @sprite.zoom_x * Math.sin(2 * Math::PI * System.uptime)
|
||||
end
|
||||
@sprite.zoom_y = @parent_sprite.zoom_y
|
||||
@sprite.angle = 180.0
|
||||
@sprite.mirror = true
|
||||
@sprite.bitmap = @rsprite.bitmap
|
||||
@sprite.tone = @rsprite.tone
|
||||
if @height>0
|
||||
@sprite.color = Color.new(48,96,160,255) # Dark still water
|
||||
@sprite.opacity = @rsprite.opacity
|
||||
@sprite.bitmap = @parent_sprite.bitmap
|
||||
@sprite.tone = @parent_sprite.tone
|
||||
if @height > 0
|
||||
@sprite.color = Color.new(48, 96, 160, 255) # Dark still water
|
||||
@sprite.opacity = @parent_sprite.opacity
|
||||
@sprite.visible = !Settings::TIME_SHADING # Can't time-tone a colored sprite
|
||||
else
|
||||
@sprite.color = Color.new(224,224,224,96)
|
||||
@sprite.opacity = @rsprite.opacity*3/4
|
||||
@sprite.color = Color.new(224, 224, 224, 96)
|
||||
@sprite.opacity = @parent_sprite.opacity * 3 / 4
|
||||
@sprite.visible = true
|
||||
end
|
||||
@sprite.src_rect = @rsprite.src_rect
|
||||
@sprite.src_rect = @parent_sprite.src_rect
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,35 +1,41 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Sprite_SurfBase
|
||||
attr_reader :visible
|
||||
attr_accessor :event
|
||||
attr_reader :visible
|
||||
|
||||
def initialize(sprite,event,viewport=nil)
|
||||
@rsprite = sprite
|
||||
@sprite = nil
|
||||
@event = event
|
||||
def initialize(parent_sprite, viewport = nil)
|
||||
@parent_sprite = parent_sprite
|
||||
@sprite = nil
|
||||
@viewport = viewport
|
||||
@disposed = false
|
||||
@surfbitmap = AnimatedBitmap.new("Graphics/Characters/base_surf")
|
||||
@divebitmap = AnimatedBitmap.new("Graphics/Characters/base_dive")
|
||||
RPG::Cache.retain("Graphics/Characters/base_surf")
|
||||
RPG::Cache.retain("Graphics/Characters/base_dive")
|
||||
@cws = @surfbitmap.width/4
|
||||
@chs = @surfbitmap.height/4
|
||||
@cwd = @divebitmap.width/4
|
||||
@chd = @divebitmap.height/4
|
||||
@cws = @surfbitmap.width / 4
|
||||
@chs = @surfbitmap.height / 4
|
||||
@cwd = @divebitmap.width / 4
|
||||
@chd = @divebitmap.height / 4
|
||||
update
|
||||
end
|
||||
|
||||
def dispose
|
||||
return if @disposed
|
||||
@sprite.dispose if @sprite
|
||||
@sprite = nil
|
||||
@sprite&.dispose
|
||||
@sprite = nil
|
||||
@parent_sprite = nil
|
||||
@surfbitmap.dispose
|
||||
@divebitmap.dispose
|
||||
@disposed = true
|
||||
end
|
||||
|
||||
def disposed?
|
||||
@disposed
|
||||
return @disposed
|
||||
end
|
||||
|
||||
def event
|
||||
return @parent_sprite.character
|
||||
end
|
||||
|
||||
def visible=(value)
|
||||
@@ -49,35 +55,40 @@ class Sprite_SurfBase
|
||||
end
|
||||
# Just-in-time creation of sprite
|
||||
@sprite = Sprite.new(@viewport) if !@sprite
|
||||
if @sprite
|
||||
if $PokemonGlobal.surfing
|
||||
@sprite.bitmap = @surfbitmap.bitmap
|
||||
cw = @cws
|
||||
ch = @chs
|
||||
elsif $PokemonGlobal.diving
|
||||
@sprite.bitmap = @divebitmap.bitmap
|
||||
cw = @cwd
|
||||
ch = @chd
|
||||
end
|
||||
sx = @event.pattern_surf*cw
|
||||
sy = ((@event.direction-2)/2)*ch
|
||||
@sprite.src_rect.set(sx,sy,cw,ch)
|
||||
if $PokemonTemp.surfJump
|
||||
@sprite.x = ($PokemonTemp.surfJump[0]*Game_Map::REAL_RES_X-@event.map.display_x+3)/4+(Game_Map::TILE_WIDTH/2)
|
||||
@sprite.y = ($PokemonTemp.surfJump[1]*Game_Map::REAL_RES_Y-@event.map.display_y+3)/4+(Game_Map::TILE_HEIGHT/2)+16
|
||||
else
|
||||
@sprite.x = @rsprite.x
|
||||
@sprite.y = @rsprite.y
|
||||
end
|
||||
@sprite.ox = cw/2
|
||||
@sprite.oy = ch-16 # Assume base needs offsetting
|
||||
@sprite.oy -= @event.bob_height
|
||||
@sprite.z = @event.screen_z(ch)-1
|
||||
@sprite.zoom_x = @rsprite.zoom_x
|
||||
@sprite.zoom_y = @rsprite.zoom_y
|
||||
@sprite.tone = @rsprite.tone
|
||||
@sprite.color = @rsprite.color
|
||||
@sprite.opacity = @rsprite.opacity
|
||||
return if !@sprite
|
||||
if $PokemonGlobal.surfing
|
||||
@sprite.bitmap = @surfbitmap.bitmap
|
||||
cw = @cws
|
||||
ch = @chs
|
||||
elsif $PokemonGlobal.diving
|
||||
@sprite.bitmap = @divebitmap.bitmap
|
||||
cw = @cwd
|
||||
ch = @chd
|
||||
end
|
||||
sx = event.pattern_surf * cw
|
||||
sy = ((event.direction - 2) / 2) * ch
|
||||
@sprite.src_rect.set(sx, sy, cw, ch)
|
||||
if $game_temp.surf_base_coords
|
||||
spr_x = ((($game_temp.surf_base_coords[0] * Game_Map::REAL_RES_X) - event.map.display_x).to_f / Game_Map::X_SUBPIXELS).round
|
||||
spr_x += (Game_Map::TILE_WIDTH / 2)
|
||||
spr_x = ((spr_x - (Graphics.width / 2)) * TilemapRenderer::ZOOM_X) + (Graphics.width / 2) if TilemapRenderer::ZOOM_X != 1
|
||||
@sprite.x = spr_x
|
||||
spr_y = ((($game_temp.surf_base_coords[1] * Game_Map::REAL_RES_Y) - event.map.display_y).to_f / Game_Map::Y_SUBPIXELS).round
|
||||
spr_y += (Game_Map::TILE_HEIGHT / 2) + 16
|
||||
spr_y = ((spr_y - (Graphics.height / 2)) * TilemapRenderer::ZOOM_Y) + (Graphics.height / 2) if TilemapRenderer::ZOOM_Y != 1
|
||||
@sprite.y = spr_y
|
||||
else
|
||||
@sprite.x = @parent_sprite.x
|
||||
@sprite.y = @parent_sprite.y
|
||||
end
|
||||
@sprite.ox = cw / 2
|
||||
@sprite.oy = ch - 16 # Assume base needs offsetting
|
||||
@sprite.oy -= event.bob_height
|
||||
@sprite.z = event.screen_z(ch) - 1
|
||||
@sprite.zoom_x = @parent_sprite.zoom_x
|
||||
@sprite.zoom_y = @parent_sprite.zoom_y
|
||||
@sprite.tone = @parent_sprite.tone
|
||||
@sprite.color = @parent_sprite.color
|
||||
@sprite.opacity = @parent_sprite.opacity
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Spriteset_Global
|
||||
attr_reader :playersprite
|
||||
|
||||
@@viewport2 = Viewport.new(0, 0, Settings::SCREEN_WIDTH, Settings::SCREEN_HEIGHT)
|
||||
@@viewport2.z = 200
|
||||
|
||||
def initialize
|
||||
@map_id = $game_map&.map_id || 0
|
||||
@follower_sprites = FollowerSprites.new(Spriteset_Map.viewport)
|
||||
@playersprite = Sprite_Character.new(Spriteset_Map.viewport, $game_player)
|
||||
@weather = RPG::Weather.new(Spriteset_Map.viewport)
|
||||
@picture_sprites = []
|
||||
for i in 1..100
|
||||
(1..100).each do |i|
|
||||
@picture_sprites.push(Sprite_Picture.new(@@viewport2, $game_screen.pictures[i]))
|
||||
end
|
||||
@timer_sprite = Sprite_Timer.new
|
||||
@@ -14,16 +21,38 @@ class Spriteset_Global
|
||||
end
|
||||
|
||||
def dispose
|
||||
@follower_sprites.dispose
|
||||
@follower_sprites = nil
|
||||
@playersprite.dispose
|
||||
@picture_sprites.each { |sprite| sprite.dispose }
|
||||
@timer_sprite.dispose
|
||||
@playersprite = nil
|
||||
@weather.dispose
|
||||
@weather = nil
|
||||
@picture_sprites.each { |sprite| sprite.dispose }
|
||||
@picture_sprites.clear
|
||||
@timer_sprite.dispose
|
||||
@timer_sprite = nil
|
||||
end
|
||||
|
||||
def update
|
||||
@follower_sprites.update
|
||||
@playersprite.update
|
||||
if @weather.type != $game_screen.weather_type
|
||||
@weather.fade_in($game_screen.weather_type, $game_screen.weather_max, $game_screen.weather_duration)
|
||||
end
|
||||
if @map_id != $game_map.map_id
|
||||
offsets = $map_factory.getRelativePos(@map_id, 0, 0, $game_map.map_id, 0, 0)
|
||||
if offsets == [0, 0]
|
||||
@weather.ox_offset = 0
|
||||
@weather.oy_offset = 0
|
||||
else
|
||||
@weather.ox_offset += offsets[0] * Game_Map::TILE_WIDTH
|
||||
@weather.oy_offset += offsets[1] * Game_Map::TILE_HEIGHT
|
||||
end
|
||||
@map_id = $game_map.map_id
|
||||
end
|
||||
@weather.ox = ($game_map.display_x / Game_Map::X_SUBPIXELS).round
|
||||
@weather.oy = ($game_map.display_y / Game_Map::Y_SUBPIXELS).round
|
||||
@weather.update
|
||||
@picture_sprites.each { |sprite| sprite.update }
|
||||
@timer_sprite.update
|
||||
end
|
||||
|
||||
@@ -1,38 +1,42 @@
|
||||
#===============================================================================
|
||||
# Unused.
|
||||
#===============================================================================
|
||||
class ClippableSprite < Sprite_Character
|
||||
def initialize(viewport,event,tilemap)
|
||||
def initialize(viewport, event, tilemap)
|
||||
@tilemap = tilemap
|
||||
@_src_rect = Rect.new(0,0,0,0)
|
||||
super(viewport,event)
|
||||
@_src_rect = Rect.new(0, 0, 0, 0)
|
||||
super(viewport, event)
|
||||
end
|
||||
|
||||
def update
|
||||
super
|
||||
@_src_rect = self.src_rect
|
||||
tmright = @tilemap.map_data.xsize*Game_Map::TILE_WIDTH-@tilemap.ox
|
||||
echoln("x=#{self.x},ox=#{self.ox},tmright=#{tmright},tmox=#{@tilemap.ox}")
|
||||
if @tilemap.ox-self.ox<-self.x
|
||||
tmright = (@tilemap.map_data.xsize * Game_Map::TILE_WIDTH) - @tilemap.ox
|
||||
echoln "x=#{self.x},ox=#{self.ox},tmright=#{tmright},tmox=#{@tilemap.ox}"
|
||||
if @tilemap.ox - self.ox < -self.x
|
||||
# clipped on left
|
||||
diff = -self.x-@tilemap.ox+self.ox
|
||||
self.src_rect = Rect.new(@_src_rect.x+diff,@_src_rect.y,
|
||||
@_src_rect.width-diff,@_src_rect.height)
|
||||
echoln("clipped out left: #{diff} #{@tilemap.ox-self.ox} #{self.x}")
|
||||
elsif tmright-self.ox<self.x
|
||||
diff = -self.x - @tilemap.ox + self.ox
|
||||
self.src_rect = Rect.new(@_src_rect.x + diff, @_src_rect.y,
|
||||
@_src_rect.width - diff, @_src_rect.height)
|
||||
echoln "clipped out left: #{diff} #{@tilemap.ox - self.ox} #{self.x}"
|
||||
elsif tmright - self.ox < self.x
|
||||
# clipped on right
|
||||
diff = self.x-tmright+self.ox
|
||||
self.src_rect = Rect.new(@_src_rect.x,@_src_rect.y,
|
||||
@_src_rect.width-diff,@_src_rect.height)
|
||||
echoln("clipped out right: #{diff} #{tmright+self.ox} #{self.x}")
|
||||
diff = self.x - tmright + self.ox
|
||||
self.src_rect = Rect.new(@_src_rect.x, @_src_rect.y,
|
||||
@_src_rect.width - diff, @_src_rect.height)
|
||||
echoln "clipped out right: #{diff} #{tmright + self.ox} #{self.x}"
|
||||
else
|
||||
echoln("-not- clipped out left: #{diff} #{@tilemap.ox-self.ox} #{self.x}")
|
||||
echoln "-not- clipped out left: #{diff} #{@tilemap.ox - self.ox} #{self.x}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Spriteset_Map
|
||||
attr_reader :map
|
||||
attr_accessor :tilemap
|
||||
|
||||
@@viewport0 = Viewport.new(0, 0, Settings::SCREEN_WIDTH, Settings::SCREEN_HEIGHT) # Panorama
|
||||
@@viewport0.z = -100
|
||||
@@viewport1 = Viewport.new(0, 0, Settings::SCREEN_WIDTH, Settings::SCREEN_HEIGHT) # Map, events, player, fog
|
||||
@@ -40,51 +44,40 @@ class Spriteset_Map
|
||||
@@viewport3 = Viewport.new(0, 0, Settings::SCREEN_WIDTH, Settings::SCREEN_HEIGHT) # Flashing
|
||||
@@viewport3.z = 500
|
||||
|
||||
def Spriteset_Map.viewport # For access by Spriteset_Global
|
||||
# For access by Spriteset_Global.
|
||||
def self.viewport
|
||||
return @@viewport1
|
||||
end
|
||||
|
||||
def initialize(map=nil)
|
||||
def initialize(map = nil)
|
||||
@map = (map) ? map : $game_map
|
||||
@tilemap = TilemapLoader.new(@@viewport1)
|
||||
@tilemap.tileset = pbGetTileset(@map.tileset_name)
|
||||
for i in 0...7
|
||||
autotile_name = @map.autotile_names[i]
|
||||
@tilemap.autotiles[i] = pbGetAutotile(autotile_name)
|
||||
end
|
||||
@tilemap.map_data = @map.data
|
||||
@tilemap.priorities = @map.priorities
|
||||
@tilemap.terrain_tags = @map.terrain_tags
|
||||
$scene.map_renderer.add_tileset(@map.tileset_name)
|
||||
@map.autotile_names.each { |filename| $scene.map_renderer.add_autotile(filename) }
|
||||
$scene.map_renderer.add_extra_autotiles(@map.tileset_id)
|
||||
@panorama = AnimatedPlane.new(@@viewport0)
|
||||
@fog = AnimatedPlane.new(@@viewport1)
|
||||
@fog.z = 3000
|
||||
@character_sprites = []
|
||||
for i in @map.events.keys.sort
|
||||
sprite = Sprite_Character.new(@@viewport1,@map.events[i])
|
||||
@map.events.keys.sort.each do |i|
|
||||
sprite = Sprite_Character.new(@@viewport1, @map.events[i])
|
||||
@character_sprites.push(sprite)
|
||||
end
|
||||
@weather = RPG::Weather.new(@@viewport1)
|
||||
pbOnSpritesetCreate(self,@@viewport1)
|
||||
EventHandlers.trigger(:on_new_spriteset_map, self, @@viewport1)
|
||||
update
|
||||
end
|
||||
|
||||
def dispose
|
||||
@tilemap.tileset.dispose
|
||||
for i in 0...7
|
||||
@tilemap.autotiles[i].dispose
|
||||
if $scene.is_a?(Scene_Map)
|
||||
$scene.map_renderer.remove_tileset(@map.tileset_name)
|
||||
@map.autotile_names.each { |filename| $scene.map_renderer.remove_autotile(filename) }
|
||||
$scene.map_renderer.remove_extra_autotiles(@map.tileset_id)
|
||||
end
|
||||
@tilemap.dispose
|
||||
@panorama.dispose
|
||||
@fog.dispose
|
||||
for sprite in @character_sprites
|
||||
sprite.dispose
|
||||
end
|
||||
@weather.dispose
|
||||
@tilemap = nil
|
||||
@character_sprites.each { |sprite| sprite.dispose }
|
||||
@panorama = nil
|
||||
@fog = nil
|
||||
@character_sprites.clear
|
||||
@weather = nil
|
||||
end
|
||||
|
||||
def getAnimations
|
||||
@@ -96,51 +89,40 @@ class Spriteset_Map
|
||||
end
|
||||
|
||||
def update
|
||||
if @panorama_name!=@map.panorama_name || @panorama_hue!=@map.panorama_hue
|
||||
if @panorama_name != @map.panorama_name || @panorama_hue != @map.panorama_hue
|
||||
@panorama_name = @map.panorama_name
|
||||
@panorama_hue = @map.panorama_hue
|
||||
@panorama.setPanorama(nil) if @panorama.bitmap!=nil
|
||||
@panorama.setPanorama(@panorama_name,@panorama_hue) if @panorama_name!=""
|
||||
@panorama.set_panorama(nil) if !@panorama.bitmap.nil?
|
||||
@panorama.set_panorama(@panorama_name, @panorama_hue) if !nil_or_empty?(@panorama_name)
|
||||
Graphics.frame_reset
|
||||
end
|
||||
if @fog_name!=@map.fog_name || @fog_hue!=@map.fog_hue
|
||||
if @fog_name != @map.fog_name || @fog_hue != @map.fog_hue
|
||||
@fog_name = @map.fog_name
|
||||
@fog_hue = @map.fog_hue
|
||||
@fog.setFog(nil) if @fog.bitmap!=nil
|
||||
@fog.setFog(@fog_name,@fog_hue) if @fog_name!=""
|
||||
@fog.set_fog(nil) if !@fog.bitmap.nil?
|
||||
@fog.set_fog(@fog_name, @fog_hue) if !nil_or_empty?(@fog_name)
|
||||
Graphics.frame_reset
|
||||
end
|
||||
tmox = (@map.display_x/Game_Map::X_SUBPIXELS).round
|
||||
tmoy = (@map.display_y/Game_Map::Y_SUBPIXELS).round
|
||||
@tilemap.ox = tmox
|
||||
@tilemap.oy = tmoy
|
||||
@@viewport1.rect.set(0,0,Graphics.width,Graphics.height)
|
||||
tmox = (@map.display_x / Game_Map::X_SUBPIXELS).round
|
||||
tmoy = (@map.display_y / Game_Map::Y_SUBPIXELS).round
|
||||
@@viewport1.rect.set(0, 0, Graphics.width, Graphics.height)
|
||||
@@viewport1.ox = 0
|
||||
@@viewport1.oy = 0
|
||||
@@viewport1.ox += $game_screen.shake
|
||||
@tilemap.update
|
||||
@panorama.ox = tmox/2
|
||||
@panorama.oy = tmoy/2
|
||||
@fog.ox = tmox+@map.fog_ox
|
||||
@fog.oy = tmoy+@map.fog_oy
|
||||
@fog.zoom_x = @map.fog_zoom/100.0
|
||||
@fog.zoom_y = @map.fog_zoom/100.0
|
||||
@panorama.ox = tmox / 2
|
||||
@panorama.oy = tmoy / 2
|
||||
@fog.ox = tmox + @map.fog_ox
|
||||
@fog.oy = tmoy + @map.fog_oy
|
||||
@fog.zoom_x = @map.fog_zoom / 100.0
|
||||
@fog.zoom_y = @map.fog_zoom / 100.0
|
||||
@fog.opacity = @map.fog_opacity
|
||||
@fog.blend_type = @map.fog_blend_type
|
||||
@fog.tone = @map.fog_tone
|
||||
@panorama.update
|
||||
@fog.update
|
||||
for sprite in @character_sprites
|
||||
@character_sprites.each do |sprite|
|
||||
sprite.update
|
||||
end
|
||||
if self.map!=$game_map
|
||||
@weather.fade_in(:None, 0, 20)
|
||||
else
|
||||
@weather.fade_in($game_screen.weather_type, $game_screen.weather_max, $game_screen.weather_duration)
|
||||
end
|
||||
@weather.ox = tmox
|
||||
@weather.oy = tmoy
|
||||
@weather.update
|
||||
@@viewport1.tone = $game_screen.tone
|
||||
@@viewport3.color = $game_screen.flash_color
|
||||
@@viewport1.update
|
||||
|
||||
@@ -1,86 +1,336 @@
|
||||
=begin
|
||||
A sprite whose sole purpose is to display an animation. This sprite
|
||||
can be displayed anywhere on the map and is disposed
|
||||
automatically when its animation is finished.
|
||||
Used for grass rustling and so forth.
|
||||
=end
|
||||
class AnimationSprite < RPG::Sprite
|
||||
def initialize(animID,map,tileX,tileY,viewport=nil,tinting=false,height=3)
|
||||
super(viewport)
|
||||
@tileX = tileX
|
||||
@tileY = tileY
|
||||
self.bitmap = Bitmap.new(1, 1)
|
||||
self.bitmap.clear
|
||||
@map = map
|
||||
setCoords
|
||||
pbDayNightTint(self) if tinting
|
||||
self.animation($data_animations[animID],true,height)
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class SpriteAnimation
|
||||
@@_animations = []
|
||||
@@_reference_count = {}
|
||||
|
||||
def initialize(sprite)
|
||||
@sprite = sprite
|
||||
end
|
||||
|
||||
def setCoords
|
||||
self.x = ((@tileX * Game_Map::REAL_RES_X - @map.display_x) / Game_Map::X_SUBPIXELS).ceil
|
||||
self.x += Game_Map::TILE_WIDTH / 2
|
||||
self.y = ((@tileY * Game_Map::REAL_RES_Y - @map.display_y) / Game_Map::Y_SUBPIXELS).ceil
|
||||
self.y += Game_Map::TILE_HEIGHT
|
||||
def x(*arg); @sprite.x(*arg); end
|
||||
def y(*arg); @sprite.y(*arg); end
|
||||
def ox(*arg); @sprite.ox(*arg); end
|
||||
def oy(*arg); @sprite.oy(*arg); end
|
||||
def viewport(*arg); @sprite.viewport(*arg); end
|
||||
def flash(*arg); @sprite.flash(*arg); end
|
||||
def src_rect(*arg); @sprite.src_rect(*arg); end
|
||||
def opacity(*arg); @sprite.opacity(*arg); end
|
||||
def tone(*arg); @sprite.tone(*arg); end
|
||||
|
||||
def self.clear
|
||||
@@_animations.clear
|
||||
end
|
||||
|
||||
def dispose
|
||||
self.bitmap.dispose
|
||||
super
|
||||
dispose_animation
|
||||
dispose_loop_animation
|
||||
end
|
||||
|
||||
def animation(animation, hit, height = 3, no_tone = false)
|
||||
dispose_animation
|
||||
@_animation = animation
|
||||
return if @_animation.nil?
|
||||
@_animation_hit = hit
|
||||
@_animation_height = height
|
||||
@_animation_no_tone = no_tone
|
||||
@_animation_duration = @_animation.frame_max
|
||||
@_animation_index = -1
|
||||
fr = 20
|
||||
if @_animation.name[/\[\s*(\d+?)\s*\]\s*$/]
|
||||
fr = $~[1].to_i
|
||||
end
|
||||
@_animation_time_per_frame = 1.0 / fr
|
||||
@_animation_timer_start = System.uptime
|
||||
animation_name = @_animation.animation_name
|
||||
animation_hue = @_animation.animation_hue
|
||||
bitmap = pbGetAnimation(animation_name, animation_hue)
|
||||
if @@_reference_count.include?(bitmap)
|
||||
@@_reference_count[bitmap] += 1
|
||||
else
|
||||
@@_reference_count[bitmap] = 1
|
||||
end
|
||||
@_animation_sprites = []
|
||||
if @_animation.position != 3 || !@@_animations.include?(animation)
|
||||
16.times do
|
||||
sprite = ::Sprite.new(self.viewport)
|
||||
sprite.bitmap = bitmap
|
||||
sprite.visible = false
|
||||
@_animation_sprites.push(sprite)
|
||||
end
|
||||
@@_animations.push(animation) unless @@_animations.include?(animation)
|
||||
end
|
||||
update_animation
|
||||
end
|
||||
|
||||
def loop_animation(animation)
|
||||
return if animation == @_loop_animation
|
||||
dispose_loop_animation
|
||||
@_loop_animation = animation
|
||||
return if @_loop_animation.nil?
|
||||
@_loop_animation_duration = @_animation.frame_max
|
||||
@_loop_animation_index = -1
|
||||
fr = 20
|
||||
if @_animation.name[/\[\s*(\d+?)\s*\]\s*$/]
|
||||
fr = $~[1].to_i
|
||||
end
|
||||
@_loop_animation_time_per_frame = 1.0 / fr
|
||||
@_loop_animation_timer_start = System.uptime
|
||||
animation_name = @_loop_animation.animation_name
|
||||
animation_hue = @_loop_animation.animation_hue
|
||||
bitmap = pbGetAnimation(animation_name, animation_hue)
|
||||
if @@_reference_count.include?(bitmap)
|
||||
@@_reference_count[bitmap] += 1
|
||||
else
|
||||
@@_reference_count[bitmap] = 1
|
||||
end
|
||||
@_loop_animation_sprites = []
|
||||
16.times do
|
||||
sprite = ::Sprite.new(self.viewport)
|
||||
sprite.bitmap = bitmap
|
||||
sprite.visible = false
|
||||
@_loop_animation_sprites.push(sprite)
|
||||
end
|
||||
update_loop_animation
|
||||
end
|
||||
|
||||
def dispose_animation
|
||||
return if @_animation_sprites.nil?
|
||||
sprite = @_animation_sprites[0]
|
||||
if sprite
|
||||
@@_reference_count[sprite.bitmap] -= 1
|
||||
sprite.bitmap.dispose if @@_reference_count[sprite.bitmap] == 0
|
||||
end
|
||||
@_animation_sprites.each { |s| s.dispose }
|
||||
@_animation_sprites = nil
|
||||
@_animation = nil
|
||||
@_animation_duration = 0
|
||||
end
|
||||
|
||||
def dispose_loop_animation
|
||||
return if @_loop_animation_sprites.nil?
|
||||
sprite = @_loop_animation_sprites[0]
|
||||
if sprite
|
||||
@@_reference_count[sprite.bitmap] -= 1
|
||||
sprite.bitmap.dispose if @@_reference_count[sprite.bitmap] == 0
|
||||
end
|
||||
@_loop_animation_sprites.each { |s| s.dispose }
|
||||
@_loop_animation_sprites = nil
|
||||
@_loop_animation = nil
|
||||
end
|
||||
|
||||
def active?
|
||||
return @_loop_animation_sprites || @_animation_sprites
|
||||
end
|
||||
|
||||
def effect?
|
||||
return @_animation_duration > 0
|
||||
end
|
||||
|
||||
def update
|
||||
if !self.disposed?
|
||||
setCoords
|
||||
super
|
||||
self.dispose if !self.effect?
|
||||
update_animation if @_animation
|
||||
update_loop_animation if @_loop_animation
|
||||
end
|
||||
|
||||
def update_animation
|
||||
new_index = ((System.uptime - @_animation_timer_start) / @_animation_time_per_frame).to_i
|
||||
if new_index >= @_animation_duration
|
||||
dispose_animation
|
||||
return
|
||||
end
|
||||
quick_update = (@_animation_index == new_index)
|
||||
@_animation_index = new_index
|
||||
frame_index = @_animation_index
|
||||
cell_data = @_animation.frames[frame_index].cell_data
|
||||
position = @_animation.position
|
||||
animation_set_sprites(@_animation_sprites, cell_data, position, quick_update)
|
||||
return if quick_update
|
||||
@_animation.timings.each do |timing|
|
||||
next if timing.frame != frame_index
|
||||
animation_process_timing(timing, @_animation_hit)
|
||||
end
|
||||
end
|
||||
|
||||
def update_loop_animation
|
||||
new_index = ((System.uptime - @_loop_animation_timer_start) / @_loop_animation_time_per_frame).to_i
|
||||
new_index %= @_loop_animation_duration
|
||||
quick_update = (@_loop_animation_index == new_index)
|
||||
@_loop_animation_index = new_index
|
||||
frame_index = @_loop_animation_index
|
||||
cell_data = @_loop_animation.frames[frame_index].cell_data
|
||||
position = @_loop_animation.position
|
||||
animation_set_sprites(@_loop_animation_sprites, cell_data, position, quick_update)
|
||||
return if quick_update
|
||||
@_loop_animation.timings.each do |timing|
|
||||
next if timing.frame != frame_index
|
||||
animation_process_timing(timing, true)
|
||||
end
|
||||
end
|
||||
|
||||
def animation_set_sprites(sprites, cell_data, position, quick_update = false)
|
||||
sprite_x = 320
|
||||
sprite_y = 240
|
||||
if position == 3 # Screen
|
||||
if self.viewport
|
||||
sprite_x = self.viewport.rect.width / 2
|
||||
sprite_y = self.viewport.rect.height - 160
|
||||
end
|
||||
else
|
||||
sprite_x = self.x - self.ox + (self.src_rect.width / 2)
|
||||
sprite_y = self.y - self.oy
|
||||
if self.src_rect.height > 1
|
||||
sprite_y += self.src_rect.height / 2 if position == 1 # Middle
|
||||
sprite_y += self.src_rect.height if position == 2 # Bottom
|
||||
end
|
||||
end
|
||||
16.times do |i|
|
||||
sprite = sprites[i]
|
||||
pattern = cell_data[i, 0]
|
||||
if sprite.nil? || pattern.nil? || pattern == -1
|
||||
sprite.visible = false if sprite
|
||||
next
|
||||
end
|
||||
sprite.x = sprite_x + cell_data[i, 1]
|
||||
sprite.y = sprite_y + cell_data[i, 2]
|
||||
next if quick_update
|
||||
sprite.visible = true
|
||||
sprite.src_rect.set((pattern % 5) * 192, (pattern / 5) * 192, 192, 192)
|
||||
case @_animation_height
|
||||
when -1 then sprite.z = -25
|
||||
when 0 then sprite.z = 1
|
||||
when 1 then sprite.z = sprite.y + (Game_Map::TILE_HEIGHT * 3 / 2) + 1
|
||||
when 2 then sprite.z = sprite.y + (Game_Map::TILE_HEIGHT * 3) + 1
|
||||
else sprite.z = 2000
|
||||
end
|
||||
sprite.ox = 96
|
||||
sprite.oy = 96
|
||||
sprite.zoom_x = cell_data[i, 3] / 100.0
|
||||
sprite.zoom_y = cell_data[i, 3] / 100.0
|
||||
sprite.angle = cell_data[i, 4]
|
||||
sprite.mirror = (cell_data[i, 5] == 1)
|
||||
sprite.tone = self.tone if !@_animation_no_tone
|
||||
sprite.opacity = cell_data[i, 6] * self.opacity / 255.0
|
||||
sprite.blend_type = cell_data[i, 7]
|
||||
end
|
||||
end
|
||||
|
||||
def animation_process_timing(timing, hit)
|
||||
if timing.condition == 0 ||
|
||||
(timing.condition == 1 && hit == true) ||
|
||||
(timing.condition == 2 && hit == false)
|
||||
if timing.se.name != ""
|
||||
se = timing.se
|
||||
pbSEPlay(se)
|
||||
end
|
||||
case timing.flash_scope
|
||||
when 1
|
||||
self.flash(timing.flash_color, timing.flash_duration * 2)
|
||||
when 2
|
||||
self.viewport.flash(timing.flash_color, timing.flash_duration * 2) if self.viewport
|
||||
when 3
|
||||
self.flash(nil, timing.flash_duration * 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def x=(x)
|
||||
sx = x - self.x
|
||||
return if sx == 0
|
||||
if @_animation_sprites
|
||||
16.times { |i| @_animation_sprites[i].x += sx }
|
||||
end
|
||||
if @_loop_animation_sprites
|
||||
16.times { |i| @_loop_animation_sprites[i].x += sx }
|
||||
end
|
||||
end
|
||||
|
||||
def y=(y)
|
||||
sy = y - self.y
|
||||
return if sy == 0
|
||||
if @_animation_sprites
|
||||
16.times { |i| @_animation_sprites[i].y += sy }
|
||||
end
|
||||
if @_loop_animation_sprites
|
||||
16.times { |i| @_loop_animation_sprites[i].y += sy }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# A sprite whose sole purpose is to display an animation (a SpriteAnimation).
|
||||
# This sprite can be displayed anywhere on the map and is disposed automatically
|
||||
# when its animation is finished. Used for grass rustling and so forth.
|
||||
#===============================================================================
|
||||
class AnimationContainerSprite < RPG::Sprite
|
||||
def initialize(animID, map, tileX, tileY, viewport = nil, tinting = false, height = 3)
|
||||
super(viewport)
|
||||
@tileX = tileX
|
||||
@tileY = tileY
|
||||
@map = map
|
||||
setCoords
|
||||
pbDayNightTint(self) if tinting
|
||||
self.animation($data_animations[animID], true, height)
|
||||
end
|
||||
|
||||
def setCoords
|
||||
self.x = (((@tileX * Game_Map::REAL_RES_X) - @map.display_x) / Game_Map::X_SUBPIXELS).ceil
|
||||
self.x += Game_Map::TILE_WIDTH / 2
|
||||
self.y = (((@tileY * Game_Map::REAL_RES_Y) - @map.display_y) / Game_Map::Y_SUBPIXELS).ceil
|
||||
self.y += Game_Map::TILE_HEIGHT
|
||||
end
|
||||
|
||||
def update
|
||||
return if disposed?
|
||||
setCoords
|
||||
super
|
||||
dispose if !effect?
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Spriteset_Map
|
||||
alias _animationSprite_initialize initialize
|
||||
alias _animationSprite_update update
|
||||
alias _animationSprite_dispose dispose
|
||||
attr_reader :usersprites
|
||||
|
||||
def initialize(map=nil)
|
||||
@usersprites=[]
|
||||
alias _animationSprite_initialize initialize unless private_method_defined?(:_animationSprite_initialize)
|
||||
alias _animationSprite_update update unless method_defined?(:_animationSprite_update)
|
||||
alias _animationSprite_dispose dispose unless method_defined?(:_animationSprite_dispose)
|
||||
|
||||
def initialize(map = nil)
|
||||
@usersprites = []
|
||||
_animationSprite_initialize(map)
|
||||
end
|
||||
|
||||
def addUserAnimation(animID,x,y,tinting=false,height=3)
|
||||
sprite=AnimationSprite.new(animID,$game_map,x,y,@@viewport1,tinting,height)
|
||||
# Used to display animations that remain in the same location on the map.
|
||||
# Typically for grass rustling and dust clouds, and other animations that
|
||||
# aren't relative to an event.
|
||||
def addUserAnimation(animID, x, y, tinting = false, height = 3)
|
||||
sprite = AnimationContainerSprite.new(animID, self.map, x, y, @@viewport1, tinting, height)
|
||||
addUserSprite(sprite)
|
||||
return sprite
|
||||
end
|
||||
|
||||
def addUserSprite(sprite)
|
||||
for i in 0...@usersprites.length
|
||||
if @usersprites[i]==nil || @usersprites[i].disposed?
|
||||
@usersprites[i]=sprite
|
||||
return
|
||||
end
|
||||
def addUserSprite(new_sprite)
|
||||
@usersprites.each_with_index do |sprite, i|
|
||||
next if sprite && !sprite.disposed?
|
||||
@usersprites[i] = new_sprite
|
||||
return
|
||||
end
|
||||
@usersprites.push(sprite)
|
||||
@usersprites.push(new_sprite)
|
||||
end
|
||||
|
||||
def dispose
|
||||
_animationSprite_dispose
|
||||
for i in 0...@usersprites.length
|
||||
@usersprites[i].dispose
|
||||
end
|
||||
@usersprites.each { |sprite| sprite.dispose }
|
||||
@usersprites.clear
|
||||
end
|
||||
|
||||
def update
|
||||
return if @tilemap.disposed?
|
||||
pbDayNightTint(@tilemap)
|
||||
@@viewport3.tone.set(0,0,0,0)
|
||||
@@viewport3.tone.set(0, 0, 0, 0)
|
||||
_animationSprite_update
|
||||
for i in 0...@usersprites.length
|
||||
@usersprites[i].update if !@usersprites[i].disposed?
|
||||
end
|
||||
@usersprites.each { |sprite| sprite.update if !sprite.disposed? }
|
||||
@usersprites.delete_if { |sprite| sprite.disposed? }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,19 +7,19 @@
|
||||
class Sprite_Shadow < RPG::Sprite
|
||||
attr_accessor :character
|
||||
|
||||
def initialize(viewport, character = nil,params=[])
|
||||
def initialize(viewport, character = nil, params = [])
|
||||
super(viewport)
|
||||
@source = params[0]
|
||||
@anglemin = (params.size>1) ? params[1] : 0
|
||||
@anglemax = (params.size>2) ? params[2] : 0
|
||||
@self_opacity = (params.size>4) ? params[4] : 100
|
||||
@distancemax = (params.size>3) ? params[3] : 350
|
||||
@anglemin = (params.size > 1) ? params[1] : 0
|
||||
@anglemax = (params.size > 2) ? params[2] : 0
|
||||
@self_opacity = (params.size > 4) ? params[4] : 100
|
||||
@distancemax = (params.size > 3) ? params[3] : 350
|
||||
@character = character
|
||||
update
|
||||
end
|
||||
|
||||
def dispose
|
||||
@chbitmap.dispose if @chbitmap
|
||||
@chbitmap&.dispose
|
||||
super
|
||||
end
|
||||
|
||||
@@ -35,19 +35,18 @@ class Sprite_Shadow < RPG::Sprite
|
||||
@tile_id = @character.tile_id
|
||||
@character_name = @character.character_name
|
||||
@character_hue = @character.character_hue
|
||||
@chbitmap&.dispose
|
||||
if @tile_id >= 384
|
||||
@chbitmap.dispose if @chbitmap
|
||||
@chbitmap = pbGetTileBitmap(@character.map.tileset_name,
|
||||
@tile_id, @character.character_hue)
|
||||
@tile_id, @character.character_hue)
|
||||
self.src_rect.set(0, 0, 32, 32)
|
||||
@ch = 32
|
||||
@cw = 32
|
||||
self.ox = 16
|
||||
self.oy = 32
|
||||
else
|
||||
@chbitmap.dispose if @chbitmap
|
||||
@chbitmap = AnimatedBitmap.new(
|
||||
'Graphics/Characters/'+@character.character_name,@character.character_hue)
|
||||
@chbitmap = AnimatedBitmap.new("Graphics/Characters/" + @character.character_name,
|
||||
@character.character_hue)
|
||||
@cw = @chbitmap.width / 4
|
||||
@ch = @chbitmap.height / 4
|
||||
self.ox = @cw / 2
|
||||
@@ -75,8 +74,8 @@ class Sprite_Shadow < RPG::Sprite
|
||||
self.src_rect.set(sx, sy, @cw, @ch)
|
||||
end
|
||||
self.x = ScreenPosHelper.pbScreenX(@character)
|
||||
self.y = ScreenPosHelper.pbScreenY(@character)-5
|
||||
self.z = ScreenPosHelper.pbScreenZ(@character,@ch)-1
|
||||
self.y = ScreenPosHelper.pbScreenY(@character) - 5
|
||||
self.z = ScreenPosHelper.pbScreenZ(@character, @ch) - 1
|
||||
self.zoom_x = ScreenPosHelper.pbScreenZoomX(@character)
|
||||
self.zoom_y = ScreenPosHelper.pbScreenZoomY(@character)
|
||||
self.blend_type = @character.blend_type
|
||||
@@ -88,11 +87,11 @@ class Sprite_Shadow < RPG::Sprite
|
||||
end
|
||||
@deltax = ScreenPosHelper.pbScreenX(@source) - self.x
|
||||
@deltay = ScreenPosHelper.pbScreenY(@source) - self.y
|
||||
self.color = Color.new(0, 0, 0)
|
||||
@distance = ((@deltax ** 2) + (@deltay ** 2))
|
||||
self.opacity = @self_opacity * 13000 / ((@distance * 370 / @distancemax) + 6000)
|
||||
self.color = Color.black
|
||||
@distance = ((@deltax**2) + (@deltay**2))
|
||||
self.opacity = @self_opacity * 13_000 / ((@distance * 370 / @distancemax) + 6000)
|
||||
self.angle = 57.3 * Math.atan2(@deltax, @deltay)
|
||||
@angle_trigo = self.angle+90
|
||||
@angle_trigo = self.angle + 90
|
||||
@angle_trigo += 360 if @angle_trigo < 0
|
||||
if @anglemin != 0 || @anglemax != 0
|
||||
if (@angle_trigo < @anglemin || @angle_trigo > @anglemax) && @anglemin < @anglemax
|
||||
@@ -106,7 +105,8 @@ class Sprite_Shadow < RPG::Sprite
|
||||
end
|
||||
end
|
||||
|
||||
def in_range?(element, object, range) # From Near's Anti Lag Script, edited
|
||||
# From Near's Anti Lag Script, edited.
|
||||
def in_range?(element, object, range)
|
||||
elemScreenX = ScreenPosHelper.pbScreenX(element)
|
||||
elemScreenY = ScreenPosHelper.pbScreenY(element)
|
||||
objScreenX = ScreenPosHelper.pbScreenX(object)
|
||||
@@ -118,13 +118,11 @@ class Sprite_Shadow < RPG::Sprite
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===================================================
|
||||
#===============================================================================
|
||||
# ? CLASS Sprite_Character edit
|
||||
#===================================================
|
||||
#===============================================================================
|
||||
class Sprite_Character < RPG::Sprite
|
||||
alias :shadow_initialize :initialize
|
||||
alias shadow_initialize initialize unless private_method_defined?(:shadow_initialize)
|
||||
|
||||
def initialize(viewport, character = nil)
|
||||
@ombrelist = []
|
||||
@@ -132,84 +130,74 @@ class Sprite_Character < RPG::Sprite
|
||||
shadow_initialize(viewport, @character)
|
||||
end
|
||||
|
||||
def setShadows(map,shadows)
|
||||
def setShadows(map, shadows)
|
||||
if character.is_a?(Game_Event) && shadows.length > 0
|
||||
params = XPML_read(map,"Shadow",@character,4)
|
||||
if params != nil
|
||||
for i in 0...shadows.size
|
||||
@ombrelist.push(Sprite_Shadow.new(viewport, @character, shadows[i]))
|
||||
params = XPML_read(map, "Shadow", @character, 4)
|
||||
if params
|
||||
shadows.each do |shadow|
|
||||
@ombrelist.push(Sprite_Shadow.new(viewport, @character, shadows))
|
||||
end
|
||||
end
|
||||
end
|
||||
if character.is_a?(Game_Player) && shadows.length > 0
|
||||
for i in 0...shadows.size
|
||||
@ombrelist.push(Sprite_Shadow.new(viewport, $game_player, shadows[i]))
|
||||
shadows.each do |shadow|
|
||||
@ombrelist.push(Sprite_Shadow.new(viewport, $game_player, shadow))
|
||||
end
|
||||
end
|
||||
update
|
||||
end
|
||||
|
||||
def clearShadows
|
||||
@ombrelist.each { |s| s.dispose if s }
|
||||
@ombrelist.each { |s| s&.dispose }
|
||||
@ombrelist.clear
|
||||
end
|
||||
|
||||
alias shadow_update update
|
||||
alias shadow_update update unless method_defined?(:shadow_update)
|
||||
|
||||
def update
|
||||
shadow_update
|
||||
if @ombrelist.length>0
|
||||
for i in 0...@ombrelist.size
|
||||
@ombrelist[i].update
|
||||
end
|
||||
end
|
||||
@ombrelist.each { |ombre| ombre.update }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===================================================
|
||||
#===============================================================================
|
||||
# ? CLASS Game_Event edit
|
||||
#===================================================
|
||||
#===============================================================================
|
||||
class Game_Event
|
||||
attr_accessor :id
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===================================================
|
||||
#===============================================================================
|
||||
# ? CLASS Spriteset_Map edit
|
||||
#===================================================
|
||||
#===============================================================================
|
||||
class Spriteset_Map
|
||||
attr_accessor :shadows
|
||||
|
||||
alias shadow_initialize initialize
|
||||
def initialize(map=nil)
|
||||
alias shadow_initialize initialize unless private_method_defined?(:shadow_initialize)
|
||||
|
||||
def initialize(map = nil)
|
||||
@shadows = []
|
||||
warn = false
|
||||
map = $game_map if !map
|
||||
for k in map.events.keys.sort
|
||||
map.events.keys.sort.each do |k|
|
||||
ev = map.events[k]
|
||||
warn = true if (ev.list != nil && ev.list.length > 0 &&
|
||||
ev.list[0].code == 108 &&
|
||||
(ev.list[0].parameters == ["s"] || ev.list[0].parameters == ["o"]))
|
||||
params = XPML_read(map,"Shadow Source", ev, 4)
|
||||
@shadows.push([ev] + params) if params != nil
|
||||
warn = true if ev.list && ev.list.length > 0 && ev.list[0].code == 108 &&
|
||||
(ev.list[0].parameters == ["s"] || ev.list[0].parameters == ["o"])
|
||||
params = XPML_read(map, "Shadow Source", ev, 4)
|
||||
@shadows.push([ev] + params) if params
|
||||
end
|
||||
if warn == true
|
||||
p "Warning : At least one event on this map uses the obsolete way to add shadows"
|
||||
end
|
||||
shadow_initialize(map)
|
||||
for sprite in @character_sprites
|
||||
@character_sprites.each do |sprite|
|
||||
sprite.setShadows(map, @shadows)
|
||||
end
|
||||
$scene.spritesetGlobal.playersprite.setShadows(map, @shadows)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===================================================
|
||||
#===============================================================================
|
||||
# ? XPML Definition, by Rataime, using ideas from Near Fantastica
|
||||
#
|
||||
# Returns nil if the markup wasn't present at all,
|
||||
@@ -227,32 +215,25 @@ end
|
||||
# p XPML_read("second", event_id) -> [1, "two"]
|
||||
# p XPML_read("third", event_id) -> [3]
|
||||
# p XPML_read("forth", event_id) -> nil
|
||||
#===================================================
|
||||
def XPML_read(map,markup,event,max_param_number=0)
|
||||
#===============================================================================
|
||||
def XPML_read(map, markup, event, max_param_number = 0)
|
||||
parameter_list = nil
|
||||
return nil if !event || event.list == nil
|
||||
for i in 0...event.list.size
|
||||
if event.list[i].code == 108 &&
|
||||
event.list[i].parameters[0].downcase == "begin " + markup.downcase
|
||||
parameter_list = [] if parameter_list == nil
|
||||
for j in i+1...event.list.size
|
||||
if event.list[j].code == 108
|
||||
parts = event.list[j].parameters[0].split
|
||||
if parts.size != 1 && parts[0].downcase != "begin"
|
||||
if parts[1].to_i != 0 || parts[1] == "0"
|
||||
parameter_list.push(parts[1].to_i)
|
||||
else
|
||||
parameter_list.push(parts[1])
|
||||
end
|
||||
else
|
||||
return parameter_list
|
||||
end
|
||||
else
|
||||
return parameter_list
|
||||
end
|
||||
return parameter_list if max_param_number != 0 && j == i + max_param_number
|
||||
end
|
||||
return nil if !event || event.list.nil?
|
||||
event.list.size.times do |i|
|
||||
next unless event.list[i].code == 108 &&
|
||||
event.list[i].parameters[0].downcase == "begin " + markup.downcase
|
||||
parameter_list = [] if parameter_list.nil?
|
||||
((i + 1)...event.list.size).each do |j|
|
||||
return parameter_list if event.list[j].code != 108
|
||||
parts = event.list[j].parameters[0].split
|
||||
return parameter_list if parts.size == 1 || parts[0].downcase == "begin"
|
||||
if parts[1].to_i != 0 || parts[1] == "0"
|
||||
parameter_list.push(parts[1].to_i)
|
||||
else
|
||||
parameter_list.push(parts[1])
|
||||
end
|
||||
return parameter_list if max_param_number != 0 && j == i + max_param_number
|
||||
end
|
||||
end
|
||||
return parameter_list
|
||||
end
|
||||
|
||||
@@ -1,587 +0,0 @@
|
||||
# Particle Engine, Peter O., 2007-11-03
|
||||
# Based on version 2 by Near Fantastica, 04.01.06
|
||||
# In turn based on the Particle Engine designed by PinkMan
|
||||
class Particle_Engine
|
||||
def initialize(viewport=nil,map=nil)
|
||||
@map = (map) ? map : $game_map
|
||||
@viewport = viewport
|
||||
@effect = []
|
||||
@disposed = false
|
||||
@firsttime = true
|
||||
@effects = {
|
||||
# PinkMan's Effects
|
||||
"fire" => Particle_Engine::Fire,
|
||||
"smoke" => Particle_Engine::Smoke,
|
||||
"teleport" => Particle_Engine::Teleport,
|
||||
"spirit" => Particle_Engine::Spirit,
|
||||
"explosion" => Particle_Engine::Explosion,
|
||||
"aura" => Particle_Engine::Aura,
|
||||
# BlueScope's Effects
|
||||
"soot" => Particle_Engine::Soot,
|
||||
"sootsmoke" => Particle_Engine::SootSmoke,
|
||||
"rocket" => Particle_Engine::Rocket,
|
||||
"fixteleport" => Particle_Engine::FixedTeleport,
|
||||
"smokescreen" => Particle_Engine::Smokescreen,
|
||||
"flare" => Particle_Engine::Flare,
|
||||
"splash" => Particle_Engine::Splash,
|
||||
# By Peter O.
|
||||
"starteleport" => Particle_Engine::StarTeleport
|
||||
}
|
||||
end
|
||||
|
||||
def dispose
|
||||
return if disposed?
|
||||
for particle in @effect
|
||||
next if particle.nil?
|
||||
particle.dispose
|
||||
end
|
||||
@effect.clear
|
||||
@map = nil
|
||||
@disposed = true
|
||||
end
|
||||
|
||||
def disposed?
|
||||
return @disposed
|
||||
end
|
||||
|
||||
def add_effect(event)
|
||||
@effect[event.id] = pbParticleEffect(event)
|
||||
end
|
||||
|
||||
def remove_effect(event)
|
||||
return if @effect[event.id].nil?
|
||||
@effect[event.id].dispose
|
||||
@effect.delete_at(event.id)
|
||||
end
|
||||
|
||||
def realloc_effect(event,particle)
|
||||
type = pbEventCommentInput(event, 1, "Particle Engine Type")
|
||||
if type.nil?
|
||||
particle.dispose if particle
|
||||
return nil
|
||||
end
|
||||
type = type[0].downcase
|
||||
cls = @effects[type]
|
||||
if cls.nil?
|
||||
particle.dispose if particle
|
||||
return nil
|
||||
end
|
||||
if !particle || !particle.is_a?(cls)
|
||||
particle.dispose if particle
|
||||
particle = cls.new(event,@viewport)
|
||||
end
|
||||
return particle
|
||||
end
|
||||
|
||||
def pbParticleEffect(event)
|
||||
return realloc_effect(event,nil)
|
||||
end
|
||||
|
||||
def update
|
||||
if @firsttime
|
||||
@firsttime = false
|
||||
for event in @map.events.values
|
||||
remove_effect(event)
|
||||
add_effect(event)
|
||||
end
|
||||
end
|
||||
for i in 0...@effect.length
|
||||
particle = @effect[i]
|
||||
next if particle.nil?
|
||||
if particle.event.pe_refresh
|
||||
event = particle.event
|
||||
event.pe_refresh = false
|
||||
particle = realloc_effect(event,particle)
|
||||
@effect[i] = particle
|
||||
end
|
||||
particle.update if particle
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class ParticleEffect
|
||||
attr_accessor :x, :y, :z
|
||||
|
||||
def initialize
|
||||
@x = 0
|
||||
@y = 0
|
||||
@z = 0
|
||||
end
|
||||
|
||||
def update; end
|
||||
def dispose; end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class ParticleSprite
|
||||
attr_accessor :x, :y, :z, :ox, :oy, :opacity, :blend_type
|
||||
attr_reader :bitmap
|
||||
|
||||
def initialize(viewport)
|
||||
@viewport = viewport
|
||||
@sprite = nil
|
||||
@x = 0
|
||||
@y = 0
|
||||
@z = 0
|
||||
@ox = 0
|
||||
@oy = 0
|
||||
@opacity = 255
|
||||
@bitmap = nil
|
||||
@blend_type = 0
|
||||
@minleft = 0
|
||||
@mintop = 0
|
||||
end
|
||||
|
||||
def dispose
|
||||
@sprite.dispose if @sprite
|
||||
end
|
||||
|
||||
def bitmap=(value)
|
||||
@bitmap = value
|
||||
if value
|
||||
@minleft = -value.width
|
||||
@mintop = -value.height
|
||||
else
|
||||
@minleft = 0
|
||||
@mintop = 0
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
w = Graphics.width
|
||||
h = Graphics.height
|
||||
if !@sprite && @x>=@minleft && @y>=@mintop && @x<w && @y<h
|
||||
@sprite = Sprite.new(@viewport)
|
||||
elsif @sprite && (@x<@minleft || @y<@mintop || @x>=w || @y>=h)
|
||||
@sprite.dispose
|
||||
@sprite = nil
|
||||
end
|
||||
if @sprite
|
||||
@sprite.x = @x if @sprite.x!=@x
|
||||
@sprite.x -= @ox
|
||||
@sprite.y = @y if @sprite.y!=@y
|
||||
@sprite.y -= @oy
|
||||
@sprite.z = @z if @sprite.z!=@z
|
||||
@sprite.opacity = @opacity if @sprite.opacity!=@opacity
|
||||
@sprite.blend_type = @blend_type if @sprite.blend_type!=@blend_type
|
||||
@sprite.bitmap = @bitmap if @sprite.bitmap!=@bitmap
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class ParticleEffect_Event < ParticleEffect
|
||||
attr_accessor :event
|
||||
|
||||
def initialize(event,viewport=nil)
|
||||
@event = event
|
||||
@viewport = viewport
|
||||
@particles = []
|
||||
@bitmaps = {}
|
||||
end
|
||||
|
||||
def setParameters(params)
|
||||
@randomhue,@leftright,@fade,
|
||||
@maxparticless,@hue,@slowdown,
|
||||
@ytop,@ybottom,@xleft,@xright,
|
||||
@xgravity,@ygravity,@xoffset,@yoffset,
|
||||
@opacityvar,@originalopacity = params
|
||||
end
|
||||
|
||||
def loadBitmap(filename,hue)
|
||||
key = [filename,hue]
|
||||
bitmap = @bitmaps[key]
|
||||
if !bitmap || bitmap.disposed?
|
||||
bitmap = AnimatedBitmap.new("Graphics/Fogs/"+filename,hue).deanimate
|
||||
@bitmaps[key] = bitmap
|
||||
end
|
||||
return bitmap
|
||||
end
|
||||
|
||||
def initParticles(filename,opacity,zOffset=0,blendtype=1)
|
||||
@particles = []
|
||||
@particlex = []
|
||||
@particley = []
|
||||
@opacity = []
|
||||
@startingx = self.x + @xoffset
|
||||
@startingy = self.y + @yoffset
|
||||
@screen_x = self.x
|
||||
@screen_y = self.y
|
||||
@real_x = @event.real_x
|
||||
@real_y = @event.real_y
|
||||
@filename = filename
|
||||
@zoffset = zOffset
|
||||
@bmwidth = 32
|
||||
@bmheight = 32
|
||||
for i in 0...@maxparticless
|
||||
@particlex[i] = -@xoffset
|
||||
@particley[i] = -@yoffset
|
||||
@particles[i] = ParticleSprite.new(@viewport)
|
||||
@particles[i].bitmap = loadBitmap(filename, @hue) if filename
|
||||
if i==0 && @particles[i].bitmap
|
||||
@bmwidth = @particles[i].bitmap.width
|
||||
@bmheight = @particles[i].bitmap.height
|
||||
end
|
||||
@particles[i].blend_type = blendtype
|
||||
@particles[i].y = @startingy
|
||||
@particles[i].x = @startingx
|
||||
@particles[i].z = self.z+zOffset
|
||||
@opacity[i] = rand(opacity/4)
|
||||
@particles[i].opacity = @opacity[i]
|
||||
@particles[i].update
|
||||
end
|
||||
end
|
||||
|
||||
def x; return ScreenPosHelper.pbScreenX(@event); end
|
||||
def y; return ScreenPosHelper.pbScreenY(@event); end
|
||||
def z; return ScreenPosHelper.pbScreenZ(@event); end
|
||||
|
||||
def update
|
||||
if @viewport &&
|
||||
(@viewport.rect.x >= Graphics.width ||
|
||||
@viewport.rect.y >= Graphics.height)
|
||||
return
|
||||
end
|
||||
selfX = self.x
|
||||
selfY = self.y
|
||||
selfZ = self.z
|
||||
newRealX = @event.real_x
|
||||
newRealY = @event.real_y
|
||||
@startingx = selfX + @xoffset
|
||||
@startingy = selfY + @yoffset
|
||||
@__offsetx = (@real_x==newRealX) ? 0 : selfX-@screen_x
|
||||
@__offsety = (@real_y==newRealY) ? 0 : selfY-@screen_y
|
||||
@screen_x = selfX
|
||||
@screen_y = selfY
|
||||
@real_x = newRealX
|
||||
@real_y = newRealY
|
||||
if @opacityvar>0 && @viewport
|
||||
opac = 255.0/@opacityvar
|
||||
minX = opac*(-@xgravity*1.0 / @slowdown).floor + @startingx
|
||||
maxX = opac*(@xgravity*1.0 / @slowdown).floor + @startingx
|
||||
minY = opac*(-@ygravity*1.0 / @slowdown).floor + @startingy
|
||||
maxY = @startingy
|
||||
minX -= @bmwidth
|
||||
minY -= @bmheight
|
||||
maxX += @bmwidth
|
||||
maxY += @bmheight
|
||||
if maxX<0 || maxY<0 || minX>=Graphics.width || minY>=Graphics.height
|
||||
# echo "skipped"
|
||||
return
|
||||
end
|
||||
end
|
||||
particleZ = selfZ+@zoffset
|
||||
for i in 0...@maxparticless
|
||||
@particles[i].z = particleZ
|
||||
if @particles[i].y <= @ytop
|
||||
@particles[i].y = @startingy + @yoffset
|
||||
@particles[i].x = @startingx + @xoffset
|
||||
@particlex[i] = 0.0
|
||||
@particley[i] = 0.0
|
||||
end
|
||||
if @particles[i].x <= @xleft
|
||||
@particles[i].y = @startingy + @yoffset
|
||||
@particles[i].x = @startingx + @xoffset
|
||||
@particlex[i] = 0.0
|
||||
@particley[i] = 0.0
|
||||
end
|
||||
if @particles[i].y >= @ybottom
|
||||
@particles[i].y = @startingy + @yoffset
|
||||
@particles[i].x = @startingx + @xoffset
|
||||
@particlex[i] = 0.0
|
||||
@particley[i] = 0.0
|
||||
end
|
||||
if @particles[i].x >= @xright
|
||||
@particles[i].y = @startingy + @yoffset
|
||||
@particles[i].x = @startingx + @xoffset
|
||||
@particlex[i] = 0.0
|
||||
@particley[i] = 0.0
|
||||
end
|
||||
if @fade == 0
|
||||
if @opacity[i] <= 0
|
||||
@opacity[i] = @originalopacity
|
||||
@particles[i].y = @startingy + @yoffset
|
||||
@particles[i].x = @startingx + @xoffset
|
||||
@particlex[i] = 0.0
|
||||
@particley[i] = 0.0
|
||||
end
|
||||
else
|
||||
if @opacity[i] <= 0
|
||||
@opacity[i] = 250
|
||||
@particles[i].y = @startingy + @yoffset
|
||||
@particles[i].x = @startingx + @xoffset
|
||||
@particlex[i] = 0.0
|
||||
@particley[i] = 0.0
|
||||
end
|
||||
end
|
||||
calcParticlePos(i)
|
||||
if @randomhue == 1
|
||||
@hue += 0.5
|
||||
@hue = 0 if @hue >= 360
|
||||
@particles[i].bitmap = loadBitmap(@filename, @hue) if @filename
|
||||
end
|
||||
@opacity[i] = @opacity[i] - rand(@opacityvar)
|
||||
@particles[i].opacity = @opacity[i]
|
||||
@particles[i].update
|
||||
end
|
||||
end
|
||||
|
||||
def calcParticlePos(i)
|
||||
@leftright = rand(2)
|
||||
if @leftright == 1
|
||||
xo = -@xgravity*1.0 / @slowdown
|
||||
else
|
||||
xo = @xgravity*1.0 / @slowdown
|
||||
end
|
||||
yo = -@ygravity*1.0 / @slowdown
|
||||
@particlex[i] += xo
|
||||
@particley[i] += yo
|
||||
@particlex[i] -= @__offsetx
|
||||
@particley[i] -= @__offsety
|
||||
@particlex[i] = @particlex[i].floor
|
||||
@particley[i] = @particley[i].floor
|
||||
@particles[i].x = @particlex[i]+@startingx+@xoffset
|
||||
@particles[i].y = @particley[i]+@startingy+@yoffset
|
||||
end
|
||||
|
||||
def dispose
|
||||
for particle in @particles
|
||||
particle.dispose
|
||||
end
|
||||
for bitmap in @bitmaps.values
|
||||
bitmap.dispose
|
||||
end
|
||||
@particles.clear
|
||||
@bitmaps.clear
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Particle_Engine::Fire < ParticleEffect_Event
|
||||
def initialize(event,viewport)
|
||||
super
|
||||
setParameters([0,0,1,20,40,0.5,-64,
|
||||
Graphics.height,-64,Graphics.width,0.5,0.10,-5,-13,30,0])
|
||||
initParticles("particle",250)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Particle_Engine::Smoke < ParticleEffect_Event
|
||||
def initialize(event,viewport)
|
||||
super
|
||||
setParameters([0,0,0,80,20,0.5,-64,
|
||||
Graphics.height,-64,Graphics.width,0.5,0.10,-5,-15,5,80])
|
||||
initParticles("smoke",250)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Particle_Engine::Teleport < ParticleEffect_Event
|
||||
def initialize(event,viewport)
|
||||
super
|
||||
setParameters([1,1,1,10,rand(360),1,-64,
|
||||
Graphics.height,-64,Graphics.width,0,3,-8,-15,20,0])
|
||||
initParticles("wideportal",250)
|
||||
for i in 0...@maxparticless
|
||||
@particles[i].ox = 16
|
||||
@particles[i].oy = 16
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Particle_Engine::Spirit < ParticleEffect_Event
|
||||
def initialize(event,viewport)
|
||||
super
|
||||
setParameters([1,0,1,20,rand(360),0.5,-64,
|
||||
Graphics.height,-64,Graphics.width,0.5,0.10,-5,-13,30,0])
|
||||
initParticles("particle",250)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Particle_Engine::Explosion < ParticleEffect_Event
|
||||
def initialize(event,viewport)
|
||||
super
|
||||
setParameters([0,0,1,20,0,0.5,-64,
|
||||
Graphics.height,-64,Graphics.width,0.5,0.10,-5,-13,30,0])
|
||||
initParticles("explosion",250)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Particle_Engine::Aura < ParticleEffect_Event
|
||||
def initialize(event,viewport)
|
||||
super
|
||||
setParameters([0,0,1,20,0,1,-64,
|
||||
Graphics.height,-64,Graphics.width,2,2,-5,-13,30,0])
|
||||
initParticles("particle",250)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Particle_Engine::Soot < ParticleEffect_Event
|
||||
def initialize(event,viewport)
|
||||
super
|
||||
setParameters([0,0,0,20,0,0.5,-64,
|
||||
Graphics.height,-64,Graphics.width,0.5,0.10,-5,-15,5,80])
|
||||
initParticles("smoke",100,0,2)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Particle_Engine::SootSmoke < ParticleEffect_Event
|
||||
def initialize(event,viewport)
|
||||
super
|
||||
setParameters([0,0,0,30,0,0.5,-64,
|
||||
Graphics.height,-64,Graphics.width,0.5,0.10,-5,-15,5,80])
|
||||
initParticles("smoke",100,0)
|
||||
for i in 0...@maxparticless
|
||||
@particles[i].blend_type = rand(6) < 3 ? 1 : 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Particle_Engine::Rocket < ParticleEffect_Event
|
||||
def initialize(event,viewport)
|
||||
super
|
||||
setParameters([0,0,0,60,0,0.5,-64,
|
||||
Graphics.height,-64,Graphics.width,0.5,0,-5,-15,5,80])
|
||||
initParticles("smoke",100,-1)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Particle_Engine::FixedTeleport < ParticleEffect_Event
|
||||
def initialize(event,viewport)
|
||||
super
|
||||
setParameters([1,0,1,10,rand(360),1,
|
||||
-Graphics.height,Graphics.height,0,Graphics.width,0,3,-8,-15,20,0])
|
||||
initParticles("wideportal",250)
|
||||
for i in 0...@maxparticless
|
||||
@particles[i].ox = 16
|
||||
@particles[i].oy = 16
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# By Peter O.
|
||||
class Particle_Engine::StarTeleport < ParticleEffect_Event
|
||||
def initialize(event,viewport)
|
||||
super
|
||||
setParameters([0,0,1,10,0,1,
|
||||
-Graphics.height,Graphics.height,0,Graphics.width,0,3,-8,-15,10,0])
|
||||
initParticles("star",250)
|
||||
for i in 0...@maxparticless
|
||||
@particles[i].ox = 48
|
||||
@particles[i].oy = 48
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Particle_Engine::Smokescreen < ParticleEffect_Event
|
||||
def initialize(event,viewport)
|
||||
super
|
||||
setParameters([0,0,0,250,0,0.2,-64,
|
||||
Graphics.height,-64,Graphics.width,0.8,0.8,-5,-15,5,80])
|
||||
initParticles(nil,100)
|
||||
for i in 0...@maxparticless
|
||||
rnd = rand(3)
|
||||
@opacity[i] = (rnd==0) ? 1 : 100
|
||||
filename = (rnd==0) ? "explosionsmoke" : "smoke"
|
||||
@particles[i].bitmap = loadBitmap(filename, @hue)
|
||||
end
|
||||
end
|
||||
|
||||
def calcParticlePos(i)
|
||||
if @randomhue==1
|
||||
filename = (rand(3)==0) ? "explosionsmoke" : "smoke"
|
||||
@particles[i].bitmap = loadBitmap(filename, @hue)
|
||||
end
|
||||
multiple = 1.7
|
||||
xgrav = @xgravity*multiple/@slowdown
|
||||
xgrav = -xgrav if (rand(2)==1)
|
||||
ygrav = @ygravity*multiple/@slowdown
|
||||
ygrav = -ygrav if (rand(2)==1)
|
||||
@particlex[i] += xgrav
|
||||
@particley[i] += ygrav
|
||||
@particlex[i] -= @__offsetx
|
||||
@particley[i] -= @__offsety
|
||||
@particlex[i] = @particlex[i].floor
|
||||
@particley[i] = @particley[i].floor
|
||||
@particles[i].x = @particlex[i]+@startingx+@xoffset
|
||||
@particles[i].y = @particley[i]+@startingy+@yoffset
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Particle_Engine::Flare < ParticleEffect_Event
|
||||
def initialize(event,viewport)
|
||||
super
|
||||
setParameters([0,0,1,30,10,1,-64,
|
||||
Graphics.height,-64,Graphics.width,2,2,-5,-12,30,0])
|
||||
initParticles("particle",255)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Particle_Engine::Splash < ParticleEffect_Event
|
||||
def initialize(event,viewport)
|
||||
super
|
||||
setParameters([0,0,1,30,255,1,-64,
|
||||
Graphics.height,-64,Graphics.width,4,2,-5,-12,30,0])
|
||||
initParticles("smoke",50)
|
||||
end
|
||||
|
||||
def update
|
||||
super
|
||||
for i in 0...@maxparticless
|
||||
@particles[i].opacity = 50
|
||||
@particles[i].update
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Game_Event < Game_Character
|
||||
attr_accessor :pe_refresh
|
||||
|
||||
alias nf_particles_game_map_initialize initialize
|
||||
def initialize(map_id,event,map=nil)
|
||||
@pe_refresh = false
|
||||
begin
|
||||
nf_particles_game_map_initialize(map_id, event, map)
|
||||
rescue ArgumentError
|
||||
nf_particles_game_map_initialize(map_id, event)
|
||||
end
|
||||
end
|
||||
|
||||
alias nf_particles_game_map_refresh refresh
|
||||
def refresh
|
||||
nf_particles_game_map_refresh
|
||||
@pe_refresh = true
|
||||
end
|
||||
end
|
||||
548
Data/Scripts/005_Sprites/010_PictureEx.rb
Normal file
548
Data/Scripts/005_Sprites/010_PictureEx.rb
Normal file
@@ -0,0 +1,548 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class PictureOrigin
|
||||
TOP_LEFT = 0
|
||||
CENTER = 1
|
||||
TOP_RIGHT = 2
|
||||
BOTTOM_LEFT = 3
|
||||
LOWER_LEFT = 3
|
||||
BOTTOM_RIGHT = 4
|
||||
LOWER_RIGHT = 4
|
||||
TOP = 5
|
||||
BOTTOM = 6
|
||||
LEFT = 7
|
||||
RIGHT = 8
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Processes
|
||||
XY = 0
|
||||
DELTA_XY = 1
|
||||
Z = 2
|
||||
CURVE = 3
|
||||
ZOOM = 4
|
||||
ANGLE = 5
|
||||
TONE = 6
|
||||
COLOR = 7
|
||||
HUE = 8
|
||||
OPACITY = 9
|
||||
VISIBLE = 10
|
||||
BLEND_TYPE = 11
|
||||
SE = 12
|
||||
NAME = 13
|
||||
ORIGIN = 14
|
||||
SRC = 15
|
||||
SRC_SIZE = 16
|
||||
CROP_BOTTOM = 17
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
def getCubicPoint2(src, t)
|
||||
x0 = src[0]
|
||||
y0 = src[1]
|
||||
cx0 = src[2]
|
||||
cy0 = src[3]
|
||||
cx1 = src[4]
|
||||
cy1 = src[5]
|
||||
x1 = src[6]
|
||||
y1 = src[7]
|
||||
|
||||
x1 = cx1 + ((x1 - cx1) * t)
|
||||
x0 += ((cx0 - x0) * t)
|
||||
cx0 += ((cx1 - cx0) * t)
|
||||
cx1 = cx0 + ((x1 - cx0) * t)
|
||||
cx0 = x0 + ((cx0 - x0) * t)
|
||||
cx = cx0 + ((cx1 - cx0) * t)
|
||||
# a = x1 - 3 * cx1 + 3 * cx0 - x0
|
||||
# b = 3 * (cx1 - 2 * cx0 + x0)
|
||||
# c = 3 * (cx0 - x0)
|
||||
# d = x0
|
||||
# cx = a*t*t*t + b*t*t + c*t + d
|
||||
y1 = cy1 + ((y1 - cy1) * t)
|
||||
y0 += ((cy0 - y0) * t)
|
||||
cy0 += ((cy1 - cy0) * t)
|
||||
cy1 = cy0 + ((y1 - cy0) * t)
|
||||
cy0 = y0 + ((cy0 - y0) * t)
|
||||
cy = cy0 + ((cy1 - cy0) * t)
|
||||
# a = y1 - 3 * cy1 + 3 * cy0 - y0
|
||||
# b = 3 * (cy1 - 2 * cy0 + y0)
|
||||
# c = 3 * (cy0 - y0)
|
||||
# d = y0
|
||||
# cy = a*t*t*t + b*t*t + c*t + d
|
||||
return [cx, cy]
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# PictureEx
|
||||
#===============================================================================
|
||||
class PictureEx
|
||||
attr_accessor :x # x-coordinate
|
||||
attr_accessor :y # y-coordinate
|
||||
attr_accessor :z # z value
|
||||
attr_accessor :zoom_x # x directional zoom rate
|
||||
attr_accessor :zoom_y # y directional zoom rate
|
||||
attr_accessor :angle # rotation angle
|
||||
attr_accessor :tone # tone
|
||||
attr_accessor :color # color
|
||||
attr_accessor :hue # filename hue
|
||||
attr_accessor :opacity # opacity level
|
||||
attr_accessor :visible # visibility boolean
|
||||
attr_accessor :blend_type # blend method
|
||||
attr_accessor :name # file name
|
||||
attr_accessor :origin # starting point
|
||||
attr_reader :src_rect # source rect
|
||||
attr_reader :cropBottom # crops sprite to above this y-coordinate
|
||||
attr_reader :frameUpdates # Array of processes updated in a frame
|
||||
|
||||
def move_processes
|
||||
ret = []
|
||||
@processes.each do |p|
|
||||
next if ![Processes::XY, Processes::DELTA_XY].include?(p[0])
|
||||
pro = []
|
||||
pro.push(p[0] == Processes::XY ? "XY" : "DELTA")
|
||||
if p[1] == 0 && p[2] == 0
|
||||
pro.push("start " + p[7].to_i.to_s + ", " + p[8].to_i.to_s)
|
||||
else
|
||||
pro.push("for " + p[2].to_s) if p[2] > 0
|
||||
if p[0] == Processes::XY
|
||||
pro.push("go to " + p[7].to_i.to_s + ", " + p[8].to_i.to_s)
|
||||
else
|
||||
pro.push("move by " + p[7].to_i.to_s + ", " + p[8].to_i.to_s)
|
||||
end
|
||||
end
|
||||
ret.push(pro)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def initialize(z)
|
||||
# process: [type, delay, total_duration, frame_counter, cb, etc.]
|
||||
@processes = []
|
||||
@x = 0.0
|
||||
@y = 0.0
|
||||
@z = z
|
||||
@zoom_x = 100.0
|
||||
@zoom_y = 100.0
|
||||
@angle = 0
|
||||
@rotate_speed = 0
|
||||
@auto_angle = 0 # Cumulative angle change caused by @rotate_speed
|
||||
@tone = Tone.new(0, 0, 0, 0)
|
||||
@tone_duration = 0
|
||||
@color = Color.new(0, 0, 0, 0)
|
||||
@hue = 0
|
||||
@opacity = 255.0
|
||||
@visible = true
|
||||
@blend_type = 0
|
||||
@name = ""
|
||||
@origin = PictureOrigin::TOP_LEFT
|
||||
@src_rect = Rect.new(0, 0, -1, -1)
|
||||
@cropBottom = -1
|
||||
@frameUpdates = []
|
||||
end
|
||||
|
||||
def callback(cb)
|
||||
case cb
|
||||
when Proc
|
||||
cb.call(self)
|
||||
when Array
|
||||
cb[0].method(cb[1]).call(self, *cb[2])
|
||||
when Method
|
||||
cb.call(self)
|
||||
end
|
||||
end
|
||||
|
||||
def setCallback(delay, cb = nil)
|
||||
delay = ensureDelayAndDuration(delay)
|
||||
@processes.push([nil, delay, 0, false, cb])
|
||||
end
|
||||
|
||||
def running?
|
||||
return @processes.length > 0
|
||||
end
|
||||
|
||||
def totalDuration
|
||||
ret = 0
|
||||
@processes.each do |process|
|
||||
dur = process[1] + process[2]
|
||||
ret = dur if dur > ret
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def ensureDelayAndDuration(delay, duration = nil)
|
||||
delay = self.totalDuration if delay < 0
|
||||
return delay, duration if !duration.nil?
|
||||
return delay
|
||||
end
|
||||
|
||||
def ensureDelay(delay)
|
||||
return ensureDelayAndDuration(delay)
|
||||
end
|
||||
|
||||
# speed is the angle to change by in 1/20 of a second. @rotate_speed is the
|
||||
# angle to change by per frame.
|
||||
# NOTE: This is not compatible with manually changing the angle at a certain
|
||||
# point. If you make a sprite auto-rotate, you should not try to alter
|
||||
# the angle another way too.
|
||||
def rotate(speed)
|
||||
@rotate_speed = speed * 20.0
|
||||
end
|
||||
|
||||
def erase
|
||||
self.name = ""
|
||||
end
|
||||
|
||||
def clearProcesses
|
||||
@processes = []
|
||||
@timer_start = nil
|
||||
end
|
||||
|
||||
def adjustPosition(xOffset, yOffset)
|
||||
@processes.each do |process|
|
||||
next if process[0] != Processes::XY
|
||||
process[5] += xOffset
|
||||
process[6] += yOffset
|
||||
process[7] += xOffset
|
||||
process[8] += yOffset
|
||||
end
|
||||
end
|
||||
|
||||
def move(delay, duration, origin, x, y, zoom_x = 100.0, zoom_y = 100.0, opacity = 255)
|
||||
setOrigin(delay, duration, origin)
|
||||
moveXY(delay, duration, x, y)
|
||||
moveZoomXY(delay, duration, zoom_x, zoom_y)
|
||||
moveOpacity(delay, duration, opacity)
|
||||
end
|
||||
|
||||
def moveXY(delay, duration, x, y, cb = nil)
|
||||
delay, duration = ensureDelayAndDuration(delay, duration)
|
||||
@processes.push([Processes::XY, delay, duration, false, cb, @x, @y, x, y])
|
||||
end
|
||||
|
||||
def setXY(delay, x, y, cb = nil)
|
||||
moveXY(delay, 0, x, y, cb)
|
||||
end
|
||||
|
||||
def moveCurve(delay, duration, x1, y1, x2, y2, x3, y3, cb = nil)
|
||||
delay, duration = ensureDelayAndDuration(delay, duration)
|
||||
@processes.push([Processes::CURVE, delay, duration, false, cb, [@x, @y, x1, y1, x2, y2, x3, y3]])
|
||||
end
|
||||
|
||||
def moveDelta(delay, duration, x, y, cb = nil)
|
||||
delay, duration = ensureDelayAndDuration(delay, duration)
|
||||
@processes.push([Processes::DELTA_XY, delay, duration, false, cb, @x, @y, x, y])
|
||||
end
|
||||
|
||||
def setDelta(delay, x, y, cb = nil)
|
||||
moveDelta(delay, 0, x, y, cb)
|
||||
end
|
||||
|
||||
def moveZ(delay, duration, z, cb = nil)
|
||||
delay, duration = ensureDelayAndDuration(delay, duration)
|
||||
@processes.push([Processes::Z, delay, duration, false, cb, @z, z])
|
||||
end
|
||||
|
||||
def setZ(delay, z, cb = nil)
|
||||
moveZ(delay, 0, z, cb)
|
||||
end
|
||||
|
||||
def moveZoomXY(delay, duration, zoom_x, zoom_y, cb = nil)
|
||||
delay, duration = ensureDelayAndDuration(delay, duration)
|
||||
@processes.push([Processes::ZOOM, delay, duration, false, cb, @zoom_x, @zoom_y, zoom_x, zoom_y])
|
||||
end
|
||||
|
||||
def setZoomXY(delay, zoom_x, zoom_y, cb = nil)
|
||||
moveZoomXY(delay, 0, zoom_x, zoom_y, cb)
|
||||
end
|
||||
|
||||
def moveZoom(delay, duration, zoom, cb = nil)
|
||||
moveZoomXY(delay, duration, zoom, zoom, cb)
|
||||
end
|
||||
|
||||
def setZoom(delay, zoom, cb = nil)
|
||||
moveZoomXY(delay, 0, zoom, zoom, cb)
|
||||
end
|
||||
|
||||
def moveAngle(delay, duration, angle, cb = nil)
|
||||
delay, duration = ensureDelayAndDuration(delay, duration)
|
||||
@processes.push([Processes::ANGLE, delay, duration, false, cb, @angle, angle])
|
||||
end
|
||||
|
||||
def setAngle(delay, angle, cb = nil)
|
||||
moveAngle(delay, 0, angle, cb)
|
||||
end
|
||||
|
||||
def moveTone(delay, duration, tone, cb = nil)
|
||||
delay, duration = ensureDelayAndDuration(delay, duration)
|
||||
target = (tone) ? tone.clone : Tone.new(0, 0, 0, 0)
|
||||
@processes.push([Processes::TONE, delay, duration, false, cb, @tone.clone, target])
|
||||
end
|
||||
|
||||
def setTone(delay, tone, cb = nil)
|
||||
moveTone(delay, 0, tone, cb)
|
||||
end
|
||||
|
||||
def moveColor(delay, duration, color, cb = nil)
|
||||
delay, duration = ensureDelayAndDuration(delay, duration)
|
||||
target = (color) ? color.clone : Color.new(0, 0, 0, 0)
|
||||
@processes.push([Processes::COLOR, delay, duration, false, cb, @color.clone, target])
|
||||
end
|
||||
|
||||
def setColor(delay, color, cb = nil)
|
||||
moveColor(delay, 0, color, cb)
|
||||
end
|
||||
|
||||
# Hue changes don't actually work.
|
||||
def moveHue(delay, duration, hue, cb = nil)
|
||||
delay, duration = ensureDelayAndDuration(delay, duration)
|
||||
@processes.push([Processes::HUE, delay, duration, false, cb, @hue, hue])
|
||||
end
|
||||
|
||||
# Hue changes don't actually work.
|
||||
def setHue(delay, hue, cb = nil)
|
||||
moveHue(delay, 0, hue, cb)
|
||||
end
|
||||
|
||||
def moveOpacity(delay, duration, opacity, cb = nil)
|
||||
delay, duration = ensureDelayAndDuration(delay, duration)
|
||||
@processes.push([Processes::OPACITY, delay, duration, false, cb, @opacity, opacity])
|
||||
end
|
||||
|
||||
def setOpacity(delay, opacity, cb = nil)
|
||||
moveOpacity(delay, 0, opacity, cb)
|
||||
end
|
||||
|
||||
def setVisible(delay, visible, cb = nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::VISIBLE, delay, 0, false, cb, visible])
|
||||
end
|
||||
|
||||
# Only values of 0 (normal), 1 (additive) and 2 (subtractive) are allowed.
|
||||
def setBlendType(delay, blend, cb = nil)
|
||||
delay = ensureDelayAndDuration(delay)
|
||||
@processes.push([Processes::BLEND_TYPE, delay, 0, false, cb, blend])
|
||||
end
|
||||
|
||||
def setSE(delay, seFile, volume = nil, pitch = nil, cb = nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::SE, delay, 0, false, cb, seFile, volume, pitch])
|
||||
end
|
||||
|
||||
def setName(delay, name, cb = nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::NAME, delay, 0, false, cb, name])
|
||||
end
|
||||
|
||||
def setOrigin(delay, origin, cb = nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::ORIGIN, delay, 0, false, cb, origin])
|
||||
end
|
||||
|
||||
def setSrc(delay, srcX, srcY, cb = nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::SRC, delay, 0, false, cb, srcX, srcY])
|
||||
end
|
||||
|
||||
def setSrcSize(delay, srcWidth, srcHeight, cb = nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::SRC_SIZE, delay, 0, false, cb, srcWidth, srcHeight])
|
||||
end
|
||||
|
||||
# Used to cut Pokémon sprites off when they faint and sink into the ground.
|
||||
def setCropBottom(delay, y, cb = nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::CROP_BOTTOM, delay, 0, false, cb, y])
|
||||
end
|
||||
|
||||
def update
|
||||
time_now = System.uptime
|
||||
@timer_start = time_now if !@timer_start
|
||||
this_frame = ((time_now - @timer_start) * 20).to_i # 20 frames per second
|
||||
procEnded = false
|
||||
@frameUpdates.clear
|
||||
@processes.each_with_index do |process, i|
|
||||
# Skip processes that aren't due to start yet
|
||||
next if process[1] > this_frame
|
||||
# Set initial values if the process has just started
|
||||
if !process[3] # Not started yet
|
||||
process[3] = true # Running
|
||||
case process[0]
|
||||
when Processes::XY
|
||||
process[5] = @x
|
||||
process[6] = @y
|
||||
when Processes::DELTA_XY
|
||||
process[5] = @x
|
||||
process[6] = @y
|
||||
process[7] += @x
|
||||
process[8] += @y
|
||||
when Processes::CURVE
|
||||
process[5][0] = @x
|
||||
process[5][1] = @y
|
||||
when Processes::Z
|
||||
process[5] = @z
|
||||
when Processes::ZOOM
|
||||
process[5] = @zoom_x
|
||||
process[6] = @zoom_y
|
||||
when Processes::ANGLE
|
||||
process[5] = @angle
|
||||
when Processes::TONE
|
||||
process[5] = @tone.clone
|
||||
when Processes::COLOR
|
||||
process[5] = @color.clone
|
||||
when Processes::HUE
|
||||
process[5] = @hue
|
||||
when Processes::OPACITY
|
||||
process[5] = @opacity
|
||||
end
|
||||
end
|
||||
# Update process
|
||||
@frameUpdates.push(process[0]) if !@frameUpdates.include?(process[0])
|
||||
start_time = @timer_start + (process[1] / 20.0)
|
||||
duration = process[2] / 20.0
|
||||
case process[0]
|
||||
when Processes::XY, Processes::DELTA_XY
|
||||
@x = lerp(process[5], process[7], duration, start_time, time_now)
|
||||
@y = lerp(process[6], process[8], duration, start_time, time_now)
|
||||
when Processes::CURVE
|
||||
@x, @y = getCubicPoint2(process[5], (time_now - start_time) / duration)
|
||||
when Processes::Z
|
||||
@z = lerp(process[5], process[6], duration, start_time, time_now)
|
||||
when Processes::ZOOM
|
||||
@zoom_x = lerp(process[5], process[7], duration, start_time, time_now)
|
||||
@zoom_y = lerp(process[6], process[8], duration, start_time, time_now)
|
||||
when Processes::ANGLE
|
||||
@angle = lerp(process[5], process[6], duration, start_time, time_now)
|
||||
when Processes::TONE
|
||||
@tone.red = lerp(process[5].red, process[6].red, duration, start_time, time_now)
|
||||
@tone.green = lerp(process[5].green, process[6].green, duration, start_time, time_now)
|
||||
@tone.blue = lerp(process[5].blue, process[6].blue, duration, start_time, time_now)
|
||||
@tone.gray = lerp(process[5].gray, process[6].gray, duration, start_time, time_now)
|
||||
when Processes::COLOR
|
||||
@color.red = lerp(process[5].red, process[6].red, duration, start_time, time_now)
|
||||
@color.green = lerp(process[5].green, process[6].green, duration, start_time, time_now)
|
||||
@color.blue = lerp(process[5].blue, process[6].blue, duration, start_time, time_now)
|
||||
@color.alpha = lerp(process[5].alpha, process[6].alpha, duration, start_time, time_now)
|
||||
when Processes::HUE
|
||||
@hue = lerp(process[5], process[6], duration, start_time, time_now)
|
||||
when Processes::OPACITY
|
||||
@opacity = lerp(process[5], process[6], duration, start_time, time_now)
|
||||
when Processes::VISIBLE
|
||||
@visible = process[5]
|
||||
when Processes::BLEND_TYPE
|
||||
@blend_type = process[5]
|
||||
when Processes::SE
|
||||
pbSEPlay(process[5], process[6], process[7])
|
||||
when Processes::NAME
|
||||
@name = process[5]
|
||||
when Processes::ORIGIN
|
||||
@origin = process[5]
|
||||
when Processes::SRC
|
||||
@src_rect.x = process[5]
|
||||
@src_rect.y = process[6]
|
||||
when Processes::SRC_SIZE
|
||||
@src_rect.width = process[5]
|
||||
@src_rect.height = process[6]
|
||||
when Processes::CROP_BOTTOM
|
||||
@cropBottom = process[5]
|
||||
end
|
||||
# Erase process if its duration has elapsed
|
||||
if process[1] + process[2] <= this_frame
|
||||
callback(process[4]) if process[4]
|
||||
@processes[i] = nil
|
||||
procEnded = true
|
||||
end
|
||||
end
|
||||
# Clear out empty spaces in @processes array caused by finished processes
|
||||
@processes.compact! if procEnded
|
||||
@timer_start = nil if @processes.empty? && @rotate_speed == 0
|
||||
# Add the constant rotation speed
|
||||
if @rotate_speed != 0
|
||||
@frameUpdates.push(Processes::ANGLE) if !@frameUpdates.include?(Processes::ANGLE)
|
||||
@auto_angle = @rotate_speed * (time_now - @timer_start)
|
||||
while @auto_angle < 0
|
||||
@auto_angle += 360
|
||||
end
|
||||
@auto_angle %= 360
|
||||
@angle += @rotate_speed
|
||||
while @angle < 0
|
||||
@angle += 360
|
||||
end
|
||||
@angle %= 360
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
def setPictureSprite(sprite, picture, iconSprite = false)
|
||||
return if picture.frameUpdates.length == 0
|
||||
picture.frameUpdates.each do |type|
|
||||
case type
|
||||
when Processes::XY, Processes::DELTA_XY
|
||||
sprite.x = picture.x.round
|
||||
sprite.y = picture.y.round
|
||||
when Processes::Z
|
||||
sprite.z = picture.z
|
||||
when Processes::ZOOM
|
||||
sprite.zoom_x = picture.zoom_x / 100.0
|
||||
sprite.zoom_y = picture.zoom_y / 100.0
|
||||
when Processes::ANGLE
|
||||
sprite.angle = picture.angle
|
||||
when Processes::TONE
|
||||
sprite.tone = picture.tone
|
||||
when Processes::COLOR
|
||||
sprite.color = picture.color
|
||||
when Processes::HUE
|
||||
# This doesn't do anything.
|
||||
when Processes::BLEND_TYPE
|
||||
sprite.blend_type = picture.blend_type
|
||||
when Processes::OPACITY
|
||||
sprite.opacity = picture.opacity
|
||||
when Processes::VISIBLE
|
||||
sprite.visible = picture.visible
|
||||
when Processes::NAME
|
||||
sprite.name = picture.name if iconSprite && sprite.name != picture.name
|
||||
when Processes::ORIGIN
|
||||
case picture.origin
|
||||
when PictureOrigin::TOP_LEFT, PictureOrigin::LEFT, PictureOrigin::BOTTOM_LEFT
|
||||
sprite.ox = 0
|
||||
when PictureOrigin::TOP, PictureOrigin::CENTER, PictureOrigin::BOTTOM
|
||||
sprite.ox = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.width / 2 : 0
|
||||
when PictureOrigin::TOP_RIGHT, PictureOrigin::RIGHT, PictureOrigin::BOTTOM_RIGHT
|
||||
sprite.ox = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.width : 0
|
||||
end
|
||||
case picture.origin
|
||||
when PictureOrigin::TOP_LEFT, PictureOrigin::TOP, PictureOrigin::TOP_RIGHT
|
||||
sprite.oy = 0
|
||||
when PictureOrigin::LEFT, PictureOrigin::CENTER, PictureOrigin::RIGHT
|
||||
sprite.oy = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.height / 2 : 0
|
||||
when PictureOrigin::BOTTOM_LEFT, PictureOrigin::BOTTOM, PictureOrigin::BOTTOM_RIGHT
|
||||
sprite.oy = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.height : 0
|
||||
end
|
||||
when Processes::SRC
|
||||
next unless iconSprite && sprite.src_rect
|
||||
sprite.src_rect.x = picture.src_rect.x
|
||||
sprite.src_rect.y = picture.src_rect.y
|
||||
when Processes::SRC_SIZE
|
||||
next unless iconSprite && sprite.src_rect
|
||||
sprite.src_rect.width = picture.src_rect.width
|
||||
sprite.src_rect.height = picture.src_rect.height
|
||||
end
|
||||
end
|
||||
if iconSprite && sprite.src_rect && picture.cropBottom >= 0
|
||||
spriteBottom = sprite.y - sprite.oy + sprite.src_rect.height
|
||||
if spriteBottom > picture.cropBottom
|
||||
sprite.src_rect.height = [picture.cropBottom - sprite.y + sprite.oy, 0].max
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def setPictureIconSprite(sprite, picture)
|
||||
setPictureSprite(sprite, picture, true)
|
||||
end
|
||||
@@ -1,519 +0,0 @@
|
||||
class PictureOrigin
|
||||
TopLeft = 0
|
||||
Center = 1
|
||||
TopRight = 2
|
||||
BottomLeft = 3
|
||||
LowerLeft = 3
|
||||
BottomRight = 4
|
||||
LowerRight = 4
|
||||
Top = 5
|
||||
Bottom = 6
|
||||
Left = 7
|
||||
Right = 8
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Processes
|
||||
XY = 0
|
||||
DeltaXY = 1
|
||||
Z = 2
|
||||
Curve = 3
|
||||
Zoom = 4
|
||||
Angle = 5
|
||||
Tone = 6
|
||||
Color = 7
|
||||
Hue = 8
|
||||
Opacity = 9
|
||||
Visible = 10
|
||||
BlendType = 11
|
||||
SE = 12
|
||||
Name = 13
|
||||
Origin = 14
|
||||
Src = 15
|
||||
SrcSize = 16
|
||||
CropBottom = 17
|
||||
end
|
||||
|
||||
|
||||
|
||||
def getCubicPoint2(src,t)
|
||||
x0 = src[0]; y0 = src[1]
|
||||
cx0 = src[2]; cy0 = src[3]
|
||||
cx1 = src[4]; cy1 = src[5]
|
||||
x1 = src[6]; y1 = src[7]
|
||||
|
||||
x1 = cx1+(x1-cx1)*t
|
||||
x0 = x0+(cx0-x0)*t
|
||||
cx0 = cx0+(cx1-cx0)*t
|
||||
cx1 = cx0+(x1-cx0)*t
|
||||
cx0 = x0+(cx0-x0)*t
|
||||
cx = cx0+(cx1-cx0)*t
|
||||
# a = x1 - 3 * cx1 + 3 * cx0 - x0
|
||||
# b = 3 * (cx1 - 2 * cx0 + x0)
|
||||
# c = 3 * (cx0 - x0)
|
||||
# d = x0
|
||||
# cx = a*t*t*t + b*t*t + c*t + d
|
||||
y1 = cy1+(y1-cy1)*t
|
||||
y0 = y0+(cy0-y0)*t
|
||||
cy0 = cy0+(cy1-cy0)*t
|
||||
cy1 = cy0+(y1-cy0)*t
|
||||
cy0 = y0+(cy0-y0)*t
|
||||
cy = cy0+(cy1-cy0)*t
|
||||
# a = y1 - 3 * cy1 + 3 * cy0 - y0
|
||||
# b = 3 * (cy1 - 2 * cy0 + y0)
|
||||
# c = 3 * (cy0 - y0)
|
||||
# d = y0
|
||||
# cy = a*t*t*t + b*t*t + c*t + d
|
||||
return [cx,cy]
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# PictureEx
|
||||
#===============================================================================
|
||||
class PictureEx
|
||||
attr_accessor :x # x-coordinate
|
||||
attr_accessor :y # y-coordinate
|
||||
attr_accessor :z # z value
|
||||
attr_accessor :zoom_x # x directional zoom rate
|
||||
attr_accessor :zoom_y # y directional zoom rate
|
||||
attr_accessor :angle # rotation angle
|
||||
attr_accessor :tone # tone
|
||||
attr_accessor :color # color
|
||||
attr_accessor :hue # filename hue
|
||||
attr_accessor :opacity # opacity level
|
||||
attr_accessor :visible # visibility boolean
|
||||
attr_accessor :blend_type # blend method
|
||||
attr_accessor :name # file name
|
||||
attr_accessor :origin # starting point
|
||||
attr_reader :src_rect # source rect
|
||||
attr_reader :cropBottom # crops sprite to above this y-coordinate
|
||||
attr_reader :frameUpdates # Array of processes updated in a frame
|
||||
|
||||
def initialize(z)
|
||||
# process: [type, delay, total_duration, frame_counter, cb, etc.]
|
||||
@processes = []
|
||||
@x = 0.0
|
||||
@y = 0.0
|
||||
@z = z
|
||||
@zoom_x = 100.0
|
||||
@zoom_y = 100.0
|
||||
@angle = 0
|
||||
@rotate_speed = 0
|
||||
@tone = Tone.new(0, 0, 0, 0)
|
||||
@tone_duration = 0
|
||||
@color = Color.new(0, 0, 0, 0)
|
||||
@hue = 0
|
||||
@opacity = 255.0
|
||||
@visible = true
|
||||
@blend_type = 0
|
||||
@name = ""
|
||||
@origin = PictureOrigin::TopLeft
|
||||
@src_rect = Rect.new(0,0,-1,-1)
|
||||
@cropBottom = -1
|
||||
@frameUpdates = []
|
||||
end
|
||||
|
||||
def callback(cb)
|
||||
if cb.is_a?(Proc); cb.call(self)
|
||||
elsif cb.is_a?(Array); cb[0].method(cb[1]).call(self)
|
||||
elsif cb.is_a?(Method); cb.call(self)
|
||||
end
|
||||
end
|
||||
|
||||
def setCallback(delay, cb=nil)
|
||||
delay = ensureDelayAndDuration(delay)
|
||||
@processes.push([nil,delay,0,0,cb])
|
||||
end
|
||||
|
||||
def running?
|
||||
return @processes.length>0
|
||||
end
|
||||
|
||||
def totalDuration
|
||||
ret = 0
|
||||
for process in @processes
|
||||
dur = process[1]+process[2]
|
||||
ret = dur if dur>ret
|
||||
end
|
||||
ret *= 20.0/Graphics.frame_rate
|
||||
return ret.to_i
|
||||
end
|
||||
|
||||
def ensureDelayAndDuration(delay, duration=nil)
|
||||
delay = self.totalDuration if delay<0
|
||||
delay *= Graphics.frame_rate/20.0
|
||||
if !duration.nil?
|
||||
duration *= Graphics.frame_rate/20.0
|
||||
return delay.to_i, duration.to_i
|
||||
end
|
||||
return delay.to_i
|
||||
end
|
||||
|
||||
def ensureDelay(delay)
|
||||
return ensureDelayAndDuration(delay)
|
||||
end
|
||||
|
||||
# speed is the angle to change by in 1/20 of a second. @rotate_speed is the
|
||||
# angle to change by per frame.
|
||||
# NOTE: This is not compatible with manually changing the angle at a certain
|
||||
# point. If you make a sprite auto-rotate, you should not try to alter
|
||||
# the angle another way too.
|
||||
def rotate(speed)
|
||||
@rotate_speed = speed*20.0/Graphics.frame_rate
|
||||
while @rotate_speed<0; @rotate_speed += 360; end
|
||||
@rotate_speed %= 360
|
||||
end
|
||||
|
||||
def erase
|
||||
self.name = ""
|
||||
end
|
||||
|
||||
def clearProcesses
|
||||
@processes = []
|
||||
end
|
||||
|
||||
def adjustPosition(xOffset, yOffset)
|
||||
for process in @processes
|
||||
next if process[0]!=Processes::XY
|
||||
process[5] += xOffset
|
||||
process[6] += yOffset
|
||||
process[7] += xOffset
|
||||
process[8] += yOffset
|
||||
end
|
||||
end
|
||||
|
||||
def move(delay, duration, origin, x, y, zoom_x=100.0, zoom_y=100.0, opacity=255)
|
||||
setOrigin(delay,duration,origin)
|
||||
moveXY(delay,duration,x,y)
|
||||
moveZoomXY(delay,duration,zoom_x,zoom_y)
|
||||
moveOpacity(delay,duration,opacity)
|
||||
end
|
||||
|
||||
def moveXY(delay, duration, x, y, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::XY,delay,duration,0,cb,@x,@y,x,y])
|
||||
end
|
||||
|
||||
def setXY(delay, x, y, cb=nil)
|
||||
moveXY(delay,0,x,y,cb)
|
||||
end
|
||||
|
||||
def moveCurve(delay, duration, x1, y1, x2, y2, x3, y3, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::Curve,delay,duration,0,cb,[@x,@y,x1,y1,x2,y2,x3,y3]])
|
||||
end
|
||||
|
||||
def moveDelta(delay, duration, x, y, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::DeltaXY,delay,duration,0,cb,@x,@y,x,y])
|
||||
end
|
||||
|
||||
def setDelta(delay, x, y, cb=nil)
|
||||
moveDelta(delay,0,x,y,cb)
|
||||
end
|
||||
|
||||
def moveZ(delay, duration, z, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::Z,delay,duration,0,cb,@z,z])
|
||||
end
|
||||
|
||||
def setZ(delay, z, cb=nil)
|
||||
moveZ(delay,0,z,cb)
|
||||
end
|
||||
|
||||
def moveZoomXY(delay, duration, zoom_x, zoom_y, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::Zoom,delay,duration,0,cb,@zoom_x,@zoom_y,zoom_x,zoom_y])
|
||||
end
|
||||
|
||||
def setZoomXY(delay, zoom_x, zoom_y, cb=nil)
|
||||
moveZoomXY(delay,0,zoom_x,zoom_y,cb)
|
||||
end
|
||||
|
||||
def moveZoom(delay, duration, zoom, cb=nil)
|
||||
moveZoomXY(delay,duration,zoom,zoom,cb)
|
||||
end
|
||||
|
||||
def setZoom(delay, zoom, cb=nil)
|
||||
moveZoomXY(delay,0,zoom,zoom,cb)
|
||||
end
|
||||
|
||||
def moveAngle(delay, duration, angle, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::Angle,delay,duration,0,cb,@angle,angle])
|
||||
end
|
||||
|
||||
def setAngle(delay, angle, cb=nil)
|
||||
moveAngle(delay,0,angle,cb)
|
||||
end
|
||||
|
||||
def moveTone(delay, duration, tone, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
target = (tone) ? tone.clone : Tone.new(0,0,0,0)
|
||||
@processes.push([Processes::Tone,delay,duration,0,cb,@tone.clone,target])
|
||||
end
|
||||
|
||||
def setTone(delay, tone, cb=nil)
|
||||
moveTone(delay,0,tone,cb)
|
||||
end
|
||||
|
||||
def moveColor(delay, duration, color, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
target = (color) ? color.clone : Color.new(0,0,0,0)
|
||||
@processes.push([Processes::Color,delay,duration,0,cb,@color.clone,target])
|
||||
end
|
||||
|
||||
def setColor(delay, color, cb=nil)
|
||||
moveColor(delay,0,color,cb)
|
||||
end
|
||||
|
||||
# Hue changes don't actually work.
|
||||
def moveHue(delay, duration, hue, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::Hue,delay,duration,0,cb,@hue,hue])
|
||||
end
|
||||
|
||||
# Hue changes don't actually work.
|
||||
def setHue(delay, hue, cb=nil)
|
||||
moveHue(delay,0,hue,cb)
|
||||
end
|
||||
|
||||
def moveOpacity(delay, duration, opacity, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::Opacity,delay,duration,0,cb,@opacity,opacity])
|
||||
end
|
||||
|
||||
def setOpacity(delay, opacity, cb=nil)
|
||||
moveOpacity(delay,0,opacity,cb)
|
||||
end
|
||||
|
||||
def setVisible(delay, visible, cb=nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::Visible,delay,0,0,cb,visible])
|
||||
end
|
||||
|
||||
# Only values of 0 (normal), 1 (additive) and 2 (subtractive) are allowed.
|
||||
def setBlendType(delay, blend, cb=nil)
|
||||
delay = ensureDelayAndDuration(delay)
|
||||
@processes.push([Processes::BlendType,delay,0,0,cb,blend])
|
||||
end
|
||||
|
||||
def setSE(delay, seFile, volume=nil, pitch=nil, cb=nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::SE,delay,0,0,cb,seFile,volume,pitch])
|
||||
end
|
||||
|
||||
def setName(delay, name, cb=nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::Name,delay,0,0,cb,name])
|
||||
end
|
||||
|
||||
def setOrigin(delay, origin, cb=nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::Origin,delay,0,0,cb,origin])
|
||||
end
|
||||
|
||||
def setSrc(delay, srcX, srcY, cb=nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::Src,delay,0,0,cb,srcX,srcY])
|
||||
end
|
||||
|
||||
def setSrcSize(delay, srcWidth, srcHeight, cb=nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::SrcSize,delay,0,0,cb,srcWidth,srcHeight])
|
||||
end
|
||||
|
||||
# Used to cut Pokémon sprites off when they faint and sink into the ground.
|
||||
def setCropBottom(delay, y, cb=nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::CropBottom,delay,0,0,cb,y])
|
||||
end
|
||||
|
||||
def update
|
||||
procEnded = false
|
||||
@frameUpdates.clear
|
||||
for i in 0...@processes.length
|
||||
process = @processes[i]
|
||||
# Decrease delay of processes that are scheduled to start later
|
||||
if process[1]>=0
|
||||
# Set initial values if the process will start this frame
|
||||
if process[1]==0
|
||||
case process[0]
|
||||
when Processes::XY
|
||||
process[5] = @x
|
||||
process[6] = @y
|
||||
when Processes::DeltaXY
|
||||
process[5] = @x
|
||||
process[6] = @y
|
||||
process[7] += @x
|
||||
process[8] += @y
|
||||
when Processes::Curve
|
||||
process[5][0] = @x
|
||||
process[5][1] = @y
|
||||
when Processes::Z
|
||||
process[5] = @z
|
||||
when Processes::Zoom
|
||||
process[5] = @zoom_x
|
||||
process[6] = @zoom_y
|
||||
when Processes::Angle
|
||||
process[5] = @angle
|
||||
when Processes::Tone
|
||||
process[5] = @tone.clone
|
||||
when Processes::Color
|
||||
process[5] = @color.clone
|
||||
when Processes::Hue
|
||||
process[5] = @hue
|
||||
when Processes::Opacity
|
||||
process[5] = @opacity
|
||||
end
|
||||
end
|
||||
# Decrease delay counter
|
||||
process[1] -= 1
|
||||
# Process hasn't started yet, skip to the next one
|
||||
next if process[1]>=0
|
||||
end
|
||||
# Update process
|
||||
@frameUpdates.push(process[0]) if !@frameUpdates.include?(process[0])
|
||||
fra = (process[2]==0) ? 1 : process[3] # Frame counter
|
||||
dur = (process[2]==0) ? 1 : process[2] # Total duration of process
|
||||
case process[0]
|
||||
when Processes::XY, Processes::DeltaXY
|
||||
@x = process[5] + fra * (process[7] - process[5]) / dur
|
||||
@y = process[6] + fra * (process[8] - process[6]) / dur
|
||||
when Processes::Curve
|
||||
@x, @y = getCubicPoint2(process[5],fra.to_f/dur)
|
||||
when Processes::Z
|
||||
@z = process[5] + fra * (process[6] - process[5]) / dur
|
||||
when Processes::Zoom
|
||||
@zoom_x = process[5] + fra * (process[7] - process[5]) / dur
|
||||
@zoom_y = process[6] + fra * (process[8] - process[6]) / dur
|
||||
when Processes::Angle
|
||||
@angle = process[5] + fra * (process[6] - process[5]) / dur
|
||||
when Processes::Tone
|
||||
@tone.red = process[5].red + fra * (process[6].red - process[5].red) / dur
|
||||
@tone.green = process[5].green + fra * (process[6].green - process[5].green) / dur
|
||||
@tone.blue = process[5].blue + fra * (process[6].blue - process[5].blue) / dur
|
||||
@tone.gray = process[5].gray + fra * (process[6].gray - process[5].gray) / dur
|
||||
when Processes::Color
|
||||
@color.red = process[5].red + fra * (process[6].red - process[5].red) / dur
|
||||
@color.green = process[5].green + fra * (process[6].green - process[5].green) / dur
|
||||
@color.blue = process[5].blue + fra * (process[6].blue - process[5].blue) / dur
|
||||
@color.alpha = process[5].alpha + fra * (process[6].alpha - process[5].alpha) / dur
|
||||
when Processes::Hue
|
||||
@hue = (process[6] - process[5]).to_f / dur
|
||||
when Processes::Opacity
|
||||
@opacity = process[5] + fra * (process[6] - process[5]) / dur
|
||||
when Processes::Visible
|
||||
@visible = process[5]
|
||||
when Processes::BlendType
|
||||
@blend_type = process[5]
|
||||
when Processes::SE
|
||||
pbSEPlay(process[5],process[6],process[7])
|
||||
when Processes::Name
|
||||
@name = process[5]
|
||||
when Processes::Origin
|
||||
@origin = process[5]
|
||||
when Processes::Src
|
||||
@src_rect.x = process[5]
|
||||
@src_rect.y = process[6]
|
||||
when Processes::SrcSize
|
||||
@src_rect.width = process[5]
|
||||
@src_rect.height = process[6]
|
||||
when Processes::CropBottom
|
||||
@cropBottom = process[5]
|
||||
end
|
||||
# Increase frame counter
|
||||
process[3] += 1
|
||||
if process[3]>process[2]
|
||||
# Process has ended, erase it
|
||||
callback(process[4]) if process[4]
|
||||
@processes[i] = nil
|
||||
procEnded = true
|
||||
end
|
||||
end
|
||||
# Clear out empty spaces in @processes array caused by finished processes
|
||||
@processes.compact! if procEnded
|
||||
# Add the constant rotation speed
|
||||
if @rotate_speed != 0
|
||||
@frameUpdates.push(Processes::Angle) if !@frameUpdates.include?(Processes::Angle)
|
||||
@angle += @rotate_speed
|
||||
while @angle<0; @angle += 360; end
|
||||
@angle %= 360
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
def setPictureSprite(sprite, picture, iconSprite=false)
|
||||
return if picture.frameUpdates.length==0
|
||||
for i in 0...picture.frameUpdates.length
|
||||
case picture.frameUpdates[i]
|
||||
when Processes::XY, Processes::DeltaXY
|
||||
sprite.x = picture.x.round
|
||||
sprite.y = picture.y.round
|
||||
when Processes::Z
|
||||
sprite.z = picture.z
|
||||
when Processes::Zoom
|
||||
sprite.zoom_x = picture.zoom_x / 100.0
|
||||
sprite.zoom_y = picture.zoom_y / 100.0
|
||||
when Processes::Angle
|
||||
sprite.angle = picture.angle
|
||||
when Processes::Tone
|
||||
sprite.tone = picture.tone
|
||||
when Processes::Color
|
||||
sprite.color = picture.color
|
||||
when Processes::Hue
|
||||
# This doesn't do anything.
|
||||
when Processes::BlendType
|
||||
sprite.blend_type = picture.blend_type
|
||||
when Processes::Opacity
|
||||
sprite.opacity = picture.opacity
|
||||
when Processes::Visible
|
||||
sprite.visible = picture.visible
|
||||
when Processes::Name
|
||||
sprite.name = picture.name if iconSprite && sprite.name != picture.name
|
||||
when Processes::Origin
|
||||
case picture.origin
|
||||
when PictureOrigin::TopLeft, PictureOrigin::Left, PictureOrigin::BottomLeft
|
||||
sprite.ox = 0
|
||||
when PictureOrigin::Top, PictureOrigin::Center, PictureOrigin::Bottom
|
||||
sprite.ox = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.width/2 : 0
|
||||
when PictureOrigin::TopRight, PictureOrigin::Right, PictureOrigin::BottomRight
|
||||
sprite.ox = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.width : 0
|
||||
end
|
||||
case picture.origin
|
||||
when PictureOrigin::TopLeft, PictureOrigin::Top, PictureOrigin::TopRight
|
||||
sprite.oy = 0
|
||||
when PictureOrigin::Left, PictureOrigin::Center, PictureOrigin::Right
|
||||
sprite.oy = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.height/2 : 0
|
||||
when PictureOrigin::BottomLeft, PictureOrigin::Bottom, PictureOrigin::BottomRight
|
||||
sprite.oy = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.height : 0
|
||||
end
|
||||
when Processes::Src
|
||||
next unless iconSprite && sprite.src_rect
|
||||
sprite.src_rect.x = picture.src_rect.x
|
||||
sprite.src_rect.y = picture.src_rect.y
|
||||
when Processes::SrcSize
|
||||
next unless iconSprite && sprite.src_rect
|
||||
sprite.src_rect.width = picture.src_rect.width
|
||||
sprite.src_rect.height = picture.src_rect.height
|
||||
end
|
||||
end
|
||||
if iconSprite && sprite.src_rect && picture.cropBottom>=0
|
||||
spriteBottom = sprite.y-sprite.oy+sprite.src_rect.height
|
||||
if spriteBottom>picture.cropBottom
|
||||
sprite.src_rect.height = [picture.cropBottom-sprite.y+sprite.oy,0].max
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def setPictureIconSprite(sprite, picture)
|
||||
setPictureSprite(sprite,picture,true)
|
||||
end
|
||||
48
Data/Scripts/005_Sprites/011_ScreenPosHelper.rb
Normal file
48
Data/Scripts/005_Sprites/011_ScreenPosHelper.rb
Normal file
@@ -0,0 +1,48 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module ScreenPosHelper
|
||||
@heightcache = {}
|
||||
|
||||
module_function
|
||||
|
||||
def pbScreenZoomX(ch)
|
||||
return Game_Map::TILE_WIDTH / 32.0
|
||||
end
|
||||
|
||||
def pbScreenZoomY(ch)
|
||||
return Game_Map::TILE_HEIGHT / 32.0
|
||||
end
|
||||
|
||||
def pbScreenX(ch)
|
||||
return ch.screen_x
|
||||
end
|
||||
|
||||
def pbScreenY(ch)
|
||||
return ch.screen_y
|
||||
end
|
||||
|
||||
def bmHeight(bm)
|
||||
h = @heightcache[bm]
|
||||
if !h
|
||||
bmap = AnimatedBitmap.new("Graphics/Characters/" + bm, 0)
|
||||
h = bmap.height
|
||||
@heightcache[bm] = h
|
||||
bmap.dispose
|
||||
end
|
||||
return h
|
||||
end
|
||||
|
||||
def pbScreenZ(ch, height = nil)
|
||||
if height.nil?
|
||||
height = 0
|
||||
if ch.tile_id > 0
|
||||
height = 32
|
||||
elsif ch.character_name != ""
|
||||
height = bmHeight(ch.character_name) / 4
|
||||
end
|
||||
end
|
||||
ret = ch.screen_z(height)
|
||||
return ret
|
||||
end
|
||||
end
|
||||
@@ -1,172 +0,0 @@
|
||||
class Interpolator
|
||||
ZOOM_X = 1
|
||||
ZOOM_Y = 2
|
||||
X = 3
|
||||
Y = 4
|
||||
OPACITY = 5
|
||||
COLOR = 6
|
||||
WAIT = 7
|
||||
|
||||
def initialize
|
||||
@tweening = false
|
||||
@tweensteps = []
|
||||
@sprite = nil
|
||||
@frames = 0
|
||||
@step = 0
|
||||
end
|
||||
|
||||
def tweening?
|
||||
return @tweening
|
||||
end
|
||||
|
||||
def tween(sprite,items,frames)
|
||||
@tweensteps = []
|
||||
if sprite && !sprite.disposed? && frames>0
|
||||
@frames = frames
|
||||
@step = 0
|
||||
@sprite = sprite
|
||||
for item in items
|
||||
case item[0]
|
||||
when ZOOM_X
|
||||
@tweensteps[item[0]] = [sprite.zoom_x,item[1]-sprite.zoom_x]
|
||||
when ZOOM_Y
|
||||
@tweensteps[item[0]] = [sprite.zoom_y,item[1]-sprite.zoom_y]
|
||||
when X
|
||||
@tweensteps[item[0]] = [sprite.x,item[1]-sprite.x]
|
||||
when Y
|
||||
@tweensteps[item[0]] = [sprite.y,item[1]-sprite.y]
|
||||
when OPACITY
|
||||
@tweensteps[item[0]] = [sprite.opacity,item[1]-sprite.opacity]
|
||||
when COLOR
|
||||
@tweensteps[item[0]] = [sprite.color.clone,Color.new(
|
||||
item[1].red-sprite.color.red,
|
||||
item[1].green-sprite.color.green,
|
||||
item[1].blue-sprite.color.blue,
|
||||
item[1].alpha-sprite.color.alpha
|
||||
)]
|
||||
end
|
||||
end
|
||||
@tweening = true
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @tweening
|
||||
t = (@step*1.0)/@frames
|
||||
for i in 0...@tweensteps.length
|
||||
item = @tweensteps[i]
|
||||
next if !item
|
||||
case i
|
||||
when ZOOM_X
|
||||
@sprite.zoom_x = item[0]+item[1]*t
|
||||
when ZOOM_Y
|
||||
@sprite.zoom_y = item[0]+item[1]*t
|
||||
when X
|
||||
@sprite.x = item[0]+item[1]*t
|
||||
when Y
|
||||
@sprite.y = item[0]+item[1]*t
|
||||
when OPACITY
|
||||
@sprite.opacity = item[0]+item[1]*t
|
||||
when COLOR
|
||||
@sprite.color = Color.new(
|
||||
item[0].red+item[1].red*t,
|
||||
item[0].green+item[1].green*t,
|
||||
item[0].blue+item[1].blue*t,
|
||||
item[0].alpha+item[1].alpha*t
|
||||
)
|
||||
end
|
||||
end
|
||||
@step += 1
|
||||
if @step==@frames
|
||||
@step = 0
|
||||
@frames = 0
|
||||
@tweening = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class RectInterpolator
|
||||
def initialize(oldrect,newrect,frames)
|
||||
restart(oldrect,newrect,frames)
|
||||
end
|
||||
|
||||
def restart(oldrect,newrect,frames)
|
||||
@oldrect = oldrect
|
||||
@newrect = newrect
|
||||
@frames = [frames,1].max
|
||||
@curframe = 0
|
||||
@rect = oldrect.clone
|
||||
end
|
||||
|
||||
def set(rect)
|
||||
rect.set(@rect.x,@rect.y,@rect.width,@rect.height)
|
||||
end
|
||||
|
||||
def done?
|
||||
@curframe>@frames
|
||||
end
|
||||
|
||||
def update
|
||||
return if done?
|
||||
t = (@curframe*1.0/@frames)
|
||||
x1 = @oldrect.x
|
||||
x2 = @newrect.x
|
||||
x = x1+t*(x2-x1)
|
||||
y1 = @oldrect.y
|
||||
y2 = @newrect.y
|
||||
y = y1+t*(y2-y1)
|
||||
rx1 = @oldrect.x+@oldrect.width
|
||||
rx2 = @newrect.x+@newrect.width
|
||||
rx = rx1+t*(rx2-rx1)
|
||||
ry1 = @oldrect.y+@oldrect.height
|
||||
ry2 = @newrect.y+@newrect.height
|
||||
ry = ry1+t*(ry2-ry1)
|
||||
minx = x<rx ? x : rx
|
||||
maxx = x>rx ? x : rx
|
||||
miny = y<ry ? y : ry
|
||||
maxy = y>ry ? y : ry
|
||||
@rect.set(minx,miny,maxx-minx,maxy-miny)
|
||||
@curframe += 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class PointInterpolator
|
||||
attr_reader :x
|
||||
attr_reader :y
|
||||
|
||||
def initialize(oldx,oldy,newx,newy,frames)
|
||||
restart(oldx,oldy,newx,newy,frames)
|
||||
end
|
||||
|
||||
def restart(oldx,oldy,newx,newy,frames)
|
||||
@oldx = oldx
|
||||
@oldy = oldy
|
||||
@newx = newx
|
||||
@newy = newy
|
||||
@frames = frames
|
||||
@curframe = 0
|
||||
@x = oldx
|
||||
@y = oldy
|
||||
end
|
||||
|
||||
def done?
|
||||
@curframe>@frames
|
||||
end
|
||||
|
||||
def update
|
||||
return if done?
|
||||
t = (@curframe*1.0/@frames)
|
||||
rx1 = @oldx
|
||||
rx2 = @newx
|
||||
@x = rx1+t*(rx2-rx1)
|
||||
ry1 = @oldy
|
||||
ry2 = @newy
|
||||
@y = ry1+t*(ry2-ry1)
|
||||
@curframe += 1
|
||||
end
|
||||
end
|
||||
@@ -1,43 +0,0 @@
|
||||
module ScreenPosHelper
|
||||
def self.pbScreenZoomX(ch)
|
||||
return Game_Map::TILE_WIDTH/32.0
|
||||
end
|
||||
|
||||
def self.pbScreenZoomY(ch)
|
||||
return Game_Map::TILE_HEIGHT/32.0
|
||||
end
|
||||
|
||||
def self.pbScreenX(ch)
|
||||
return ch.screen_x
|
||||
end
|
||||
|
||||
def self.pbScreenY(ch)
|
||||
return ch.screen_y
|
||||
end
|
||||
|
||||
@heightcache={}
|
||||
|
||||
def self.bmHeight(bm)
|
||||
h=@heightcache[bm]
|
||||
if !h
|
||||
bmap=AnimatedBitmap.new("Graphics/Characters/"+bm,0)
|
||||
h=bmap.height
|
||||
@heightcache[bm]=h
|
||||
bmap.dispose
|
||||
end
|
||||
return h
|
||||
end
|
||||
|
||||
def self.pbScreenZ(ch,height=nil)
|
||||
if height==nil
|
||||
height=0
|
||||
if ch.tile_id > 0
|
||||
height=32
|
||||
elsif ch.character_name!=""
|
||||
height=bmHeight(ch.character_name)/4
|
||||
end
|
||||
end
|
||||
ret=ch.screen_z(height)
|
||||
return ret
|
||||
end
|
||||
end
|
||||
@@ -1,59 +0,0 @@
|
||||
class TilemapLoader
|
||||
def initialize(viewport)
|
||||
@viewport = viewport
|
||||
@tilemap = nil
|
||||
@color = Color.new(0,0,0,0)
|
||||
@tone = Tone.new(0,0,0,0)
|
||||
updateClass
|
||||
end
|
||||
|
||||
def updateClass
|
||||
setClass(CustomTilemap)
|
||||
end
|
||||
|
||||
def setClass(cls)
|
||||
newtilemap = cls.new(@viewport)
|
||||
if @tilemap
|
||||
newtilemap.tileset = @tilemap.tileset
|
||||
newtilemap.map_data = @tilemap.map_data
|
||||
newtilemap.flash_data = @tilemap.flash_data
|
||||
newtilemap.priorities = @tilemap.priorities
|
||||
newtilemap.terrain_tags = @tilemap.terrain_tags
|
||||
newtilemap.visible = @tilemap.visible
|
||||
newtilemap.ox = @tilemap.ox
|
||||
newtilemap.oy = @tilemap.oy
|
||||
for i in 0...7
|
||||
newtilemap.autotiles[i] = @tilemap.autotiles[i]
|
||||
end
|
||||
@tilemap.dispose
|
||||
@tilemap = newtilemap
|
||||
newtilemap.update
|
||||
else
|
||||
@tilemap = newtilemap
|
||||
end
|
||||
end
|
||||
|
||||
def dispose; @tilemap.dispose; end
|
||||
def disposed?; @tilemap && @tilemap.disposed?; end
|
||||
def update; @tilemap.update; end
|
||||
def viewport; @tilemap.viewport; end
|
||||
def autotiles; @tilemap.autotiles; end
|
||||
def tileset; @tilemap.tileset; end
|
||||
def tileset=(v); @tilemap.tileset = v; end
|
||||
def map_data; @tilemap.map_data; end
|
||||
def map_data=(v); @tilemap.map_data = v; end
|
||||
def flash_data; @tilemap.flash_data; end
|
||||
def flash_data=(v); @tilemap.flash_data = v; end
|
||||
def priorities; @tilemap.priorities; end
|
||||
def priorities=(v); @tilemap.priorities = v; end
|
||||
def terrain_tags; (@tilemap.terrain_tags rescue nil); end
|
||||
def terrain_tags=(v); (@tilemap.terrain_tags = v rescue nil); end
|
||||
def visible; @tilemap.visible; end
|
||||
def visible=(v); @tilemap.visible = v; end
|
||||
def tone; (@tilemap.tone rescue @tone); end
|
||||
def tone=(value); (@tilemap.tone = value rescue nil); end
|
||||
def ox; @tilemap.ox; end
|
||||
def ox=(v); @tilemap.ox = v; end
|
||||
def oy; @tilemap.oy; end
|
||||
def oy=(v); @tilemap.oy = v; end
|
||||
end
|
||||
643
Data/Scripts/006_Map renderer/001_TilemapRenderer.rb
Normal file
643
Data/Scripts/006_Map renderer/001_TilemapRenderer.rb
Normal file
@@ -0,0 +1,643 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class TilemapRenderer
|
||||
attr_reader :tilesets
|
||||
attr_reader :autotiles
|
||||
attr_accessor :tone
|
||||
attr_accessor :color
|
||||
attr_reader :viewport
|
||||
attr_accessor :ox # Does nothing
|
||||
attr_accessor :oy # Does nothing
|
||||
attr_accessor :visible # Does nothing
|
||||
|
||||
DISPLAY_TILE_WIDTH = Game_Map::TILE_WIDTH rescue 32
|
||||
DISPLAY_TILE_HEIGHT = Game_Map::TILE_HEIGHT rescue 32
|
||||
SOURCE_TILE_WIDTH = 32
|
||||
SOURCE_TILE_HEIGHT = 32
|
||||
ZOOM_X = DISPLAY_TILE_WIDTH / SOURCE_TILE_WIDTH
|
||||
ZOOM_Y = DISPLAY_TILE_HEIGHT / SOURCE_TILE_HEIGHT
|
||||
TILESET_TILES_PER_ROW = 8
|
||||
AUTOTILES_COUNT = 8 # Counting the blank tile as an autotile
|
||||
TILES_PER_AUTOTILE = 48
|
||||
TILESET_START_ID = AUTOTILES_COUNT * TILES_PER_AUTOTILE
|
||||
# If an autotile's filename ends with "[x]", its frame duration will be x/20
|
||||
# seconds instead.
|
||||
AUTOTILE_FRAME_DURATION = 5 # In 1/20ths of a second
|
||||
|
||||
# Filenames of extra autotiles for each tileset. Each tileset's entry is an
|
||||
# array containing two other arrays (you can leave either of those empty, but
|
||||
# they must be defined):
|
||||
# - The first sub-array is for large autotiles, i.e. ones with 48 different
|
||||
# tile layouts. For example, "Brick path" and "Sea".
|
||||
# - The second is for single tile autotiles. For example, "Flowers1" and
|
||||
# "Waterfall"
|
||||
# The top tiles of the tileset will instead use these autotiles. Large
|
||||
# autotiles come first, in the same 8x6 layout as you see when you double-
|
||||
# click on a real autotile in RMXP. After that are the single tile autotiles.
|
||||
# Extra autotiles are only useful if the tiles are animated, because otherwise
|
||||
# you just have some tiles which belong in the tileset instead.
|
||||
EXTRA_AUTOTILES = {
|
||||
# Examples:
|
||||
# 1 => [["Sand shore"], ["Flowers2"]],
|
||||
# 2 => [[], ["Flowers2", "Waterfall", "Waterfall crest", "Waterfall bottom"]],
|
||||
# 6 => [["Water rock", "Sea deep"], []]
|
||||
}
|
||||
|
||||
#=============================================================================
|
||||
#
|
||||
#=============================================================================
|
||||
class TilesetBitmaps
|
||||
attr_accessor :changed
|
||||
attr_accessor :bitmaps
|
||||
|
||||
def initialize
|
||||
@bitmaps = {}
|
||||
@bitmap_wraps = {} # Whether each tileset is a mega texture and has multiple columns
|
||||
@load_counts = {}
|
||||
@bridge = 0
|
||||
@changed = true
|
||||
end
|
||||
|
||||
def [](filename)
|
||||
return @bitmaps[filename]
|
||||
end
|
||||
|
||||
def []=(filename, bitmap)
|
||||
return if nil_or_empty?(filename)
|
||||
@bitmaps[filename] = bitmap
|
||||
@bitmap_wraps[filename] = false
|
||||
@changed = true
|
||||
end
|
||||
|
||||
def add(filename)
|
||||
return if nil_or_empty?(filename)
|
||||
if @bitmaps[filename]
|
||||
@load_counts[filename] += 1
|
||||
return
|
||||
end
|
||||
bitmap = pbGetTileset(filename)
|
||||
@bitmap_wraps[filename] = false
|
||||
if bitmap.mega?
|
||||
self[filename] = TilemapRenderer::TilesetWrapper.wrapTileset(bitmap)
|
||||
@bitmap_wraps[filename] = true
|
||||
bitmap.dispose
|
||||
else
|
||||
self[filename] = bitmap
|
||||
end
|
||||
@load_counts[filename] = 1
|
||||
end
|
||||
|
||||
def remove(filename)
|
||||
return if nil_or_empty?(filename) || !@bitmaps[filename]
|
||||
if @load_counts[filename] > 1
|
||||
@load_counts[filename] -= 1
|
||||
return
|
||||
end
|
||||
@bitmaps[filename].dispose
|
||||
@bitmaps.delete(filename)
|
||||
@bitmap_wraps.delete(filename)
|
||||
@load_counts.delete(filename)
|
||||
end
|
||||
|
||||
def set_src_rect(tile, tile_id)
|
||||
return if nil_or_empty?(tile.filename)
|
||||
return if !@bitmaps[tile.filename]
|
||||
tile.src_rect.x = ((tile_id - TILESET_START_ID) % TILESET_TILES_PER_ROW) * SOURCE_TILE_WIDTH
|
||||
tile.src_rect.y = ((tile_id - TILESET_START_ID) / TILESET_TILES_PER_ROW) * SOURCE_TILE_HEIGHT
|
||||
if @bitmap_wraps[tile.filename]
|
||||
height = @bitmaps[tile.filename].height
|
||||
col = (tile_id - TILESET_START_ID) * SOURCE_TILE_HEIGHT / (TILESET_TILES_PER_ROW * height)
|
||||
tile.src_rect.x += col * TILESET_TILES_PER_ROW * SOURCE_TILE_WIDTH
|
||||
tile.src_rect.y -= col * height
|
||||
end
|
||||
end
|
||||
|
||||
def update; end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#
|
||||
#=============================================================================
|
||||
class AutotileBitmaps < TilesetBitmaps
|
||||
attr_reader :current_frames
|
||||
|
||||
def initialize
|
||||
super
|
||||
@frame_counts = {} # Number of frames in each autotile
|
||||
@frame_durations = {} # How long each frame lasts per autotile
|
||||
@current_frames = {} # Which frame each autotile is currently showing
|
||||
@timer_start = System.uptime
|
||||
end
|
||||
|
||||
def []=(filename, value)
|
||||
super
|
||||
return if nil_or_empty?(filename)
|
||||
frame_count(filename, true)
|
||||
set_current_frame(filename)
|
||||
end
|
||||
|
||||
EXPANDED_AUTOTILES_FOLDER = "Graphics/Autotiles/ExpandedAutotiles/"
|
||||
|
||||
def add(filename)
|
||||
return if nil_or_empty?(filename)
|
||||
if @bitmaps[filename]
|
||||
@load_counts[filename] += 1
|
||||
return
|
||||
end
|
||||
|
||||
# Try to load expanded autotile from cache first
|
||||
cached_path = File.join("Graphics", "Autotiles/ExpandedAutotiles", "#{filename}.png")
|
||||
if FileTest.exist?(cached_path)
|
||||
bitmap = RPG::Cache.load_bitmap(EXPANDED_AUTOTILES_FOLDER, filename)
|
||||
|
||||
duration = AUTOTILE_FRAME_DURATION
|
||||
if filename[/\[\s*(\d+?)\s*\]\s*$/]
|
||||
duration = $~[1].to_i
|
||||
end
|
||||
@frame_durations[filename] = duration.to_f / 20
|
||||
|
||||
else
|
||||
orig_bitmap = pbGetAutotile(filename)
|
||||
@bitmap_wraps[filename] = false
|
||||
duration = AUTOTILE_FRAME_DURATION
|
||||
if filename[/\[\s*(\d+?)\s*\]\s*$/]
|
||||
duration = $~[1].to_i
|
||||
end
|
||||
@frame_durations[filename] = duration.to_f / 20
|
||||
expanded_bitmap = AutotileExpander.expand(orig_bitmap)
|
||||
|
||||
# Save expanded bitmap to cache for next time
|
||||
Dir.mkdir(EXPANDED_AUTOTILES_FOLDER) unless Dir.exist?(EXPANDED_AUTOTILES_FOLDER)
|
||||
expanded_bitmap.save_to_png(cached_path)
|
||||
|
||||
bitmap = expanded_bitmap
|
||||
orig_bitmap.dispose if orig_bitmap != expanded_bitmap
|
||||
end
|
||||
|
||||
self[filename] = bitmap
|
||||
if bitmap.height > SOURCE_TILE_HEIGHT && bitmap.height < TILES_PER_AUTOTILE * SOURCE_TILE_HEIGHT
|
||||
@bitmap_wraps[filename] = true
|
||||
end
|
||||
@load_counts[filename] = 1
|
||||
end
|
||||
|
||||
def remove(filename)
|
||||
super
|
||||
return if @load_counts[filename] && @load_counts[filename] > 0
|
||||
@frame_counts.delete(filename)
|
||||
@current_frames.delete(filename)
|
||||
@frame_durations.delete(filename)
|
||||
end
|
||||
|
||||
def frame_count(filename, force_recalc = false)
|
||||
if !@frame_counts[filename] || force_recalc
|
||||
return 0 if !@bitmaps[filename]
|
||||
bitmap = @bitmaps[filename]
|
||||
@frame_counts[filename] = [bitmap.width / SOURCE_TILE_WIDTH, 1].max
|
||||
if bitmap.height > SOURCE_TILE_HEIGHT && @bitmap_wraps[filename]
|
||||
@frame_counts[filename] /= 2
|
||||
end
|
||||
end
|
||||
return @frame_counts[filename]
|
||||
end
|
||||
|
||||
def animated?(filename)
|
||||
return frame_count(filename) > 1
|
||||
end
|
||||
|
||||
def current_frame(filename)
|
||||
set_current_frame(filename) if !@current_frames[filename]
|
||||
return @current_frames[filename]
|
||||
end
|
||||
|
||||
def set_current_frame(filename)
|
||||
frames = frame_count(filename)
|
||||
if frames < 2
|
||||
@current_frames[filename] = 0
|
||||
else
|
||||
@current_frames[filename] = ((System.uptime - @timer_start) / @frame_durations[filename]).floor % frames
|
||||
end
|
||||
end
|
||||
|
||||
def set_src_rect(tile, tile_id)
|
||||
return if nil_or_empty?(tile.filename)
|
||||
return if !@bitmaps[tile.filename]
|
||||
frame = current_frame(tile.filename)
|
||||
if @bitmaps[tile.filename].height == SOURCE_TILE_HEIGHT
|
||||
tile.src_rect.x = frame * SOURCE_TILE_WIDTH
|
||||
tile.src_rect.y = 0
|
||||
return
|
||||
end
|
||||
wraps = @bitmap_wraps[tile.filename]
|
||||
high_id = ((tile_id % TILES_PER_AUTOTILE) >= TILES_PER_AUTOTILE / 2)
|
||||
tile.src_rect.x = 0
|
||||
tile.src_rect.y = (tile_id % TILES_PER_AUTOTILE) * SOURCE_TILE_HEIGHT
|
||||
if wraps && high_id
|
||||
tile.src_rect.x = SOURCE_TILE_WIDTH
|
||||
tile.src_rect.y -= SOURCE_TILE_HEIGHT * TILES_PER_AUTOTILE / 2
|
||||
end
|
||||
tile.src_rect.x += frame * SOURCE_TILE_WIDTH * (wraps ? 2 : 1)
|
||||
end
|
||||
|
||||
def update
|
||||
super
|
||||
# Update the current frame for each autotile
|
||||
@bitmaps.each_key do |filename|
|
||||
next if !@bitmaps[filename] || @bitmaps[filename].disposed?
|
||||
old_frame = @current_frames[filename]
|
||||
set_current_frame(filename)
|
||||
@changed = true if @current_frames[filename] != old_frame
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#
|
||||
#=============================================================================
|
||||
class TileSprite < Sprite
|
||||
attr_accessor :filename
|
||||
attr_accessor :tile_id
|
||||
attr_accessor :is_autotile
|
||||
attr_accessor :animated
|
||||
attr_accessor :priority
|
||||
attr_accessor :shows_reflection
|
||||
attr_accessor :bridge
|
||||
attr_accessor :need_refresh
|
||||
|
||||
def set_bitmap(filename, tile_id, autotile, animated, priority, bitmap)
|
||||
self.bitmap = bitmap
|
||||
self.src_rect = Rect.new(0, 0, SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT)
|
||||
self.zoom_x = ZOOM_X
|
||||
self.zoom_y = ZOOM_Y
|
||||
@filename = filename
|
||||
@tile_id = tile_id
|
||||
@is_autotile = autotile
|
||||
@animated = animated
|
||||
@priority = priority
|
||||
@shows_reflection = false
|
||||
@bridge = false
|
||||
self.visible = !bitmap.nil?
|
||||
@need_refresh = true
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def initialize(viewport)
|
||||
@tilesets = TilesetBitmaps.new
|
||||
@autotiles = AutotileBitmaps.new
|
||||
@tiles_horizontal_count = (Graphics.width.to_f / DISPLAY_TILE_WIDTH).ceil + 1
|
||||
@tiles_vertical_count = (Graphics.height.to_f / DISPLAY_TILE_HEIGHT).ceil + 1
|
||||
@tone = Tone.new(0, 0, 0, 0)
|
||||
@old_tone = Tone.new(0, 0, 0, 0)
|
||||
@color = Color.new(0, 0, 0, 0)
|
||||
@old_color = Color.new(0, 0, 0, 0)
|
||||
@self_viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
|
||||
@viewport = (viewport) ? viewport : @self_viewport
|
||||
@old_viewport_ox = 0
|
||||
@old_viewport_oy = 0
|
||||
# NOTE: The extra tiles horizontally/vertically hang off the left and top
|
||||
# edges of the screen, because the pixel_offset values are positive
|
||||
# and are added to the tile sprite coordinates.
|
||||
@tiles = []
|
||||
@tiles_horizontal_count.times do |i|
|
||||
@tiles[i] = []
|
||||
@tiles_vertical_count.times do |j|
|
||||
@tiles[i][j] = Array.new(3) { TileSprite.new(@viewport) }
|
||||
end
|
||||
end
|
||||
@current_map_id = 0
|
||||
@tile_offset_x = 0
|
||||
@tile_offset_y = 0
|
||||
@pixel_offset_x = 0
|
||||
@pixel_offset_y = 0
|
||||
@ox = 0
|
||||
@oy = 0
|
||||
@visible = true
|
||||
@need_refresh = true
|
||||
@disposed = false
|
||||
end
|
||||
|
||||
def dispose
|
||||
return if disposed?
|
||||
@tiles.each do |col|
|
||||
col.each do |coord|
|
||||
coord.each { |tile| tile.dispose }
|
||||
coord.clear
|
||||
end
|
||||
end
|
||||
@tiles.clear
|
||||
@tilesets.bitmaps.each_value { |bitmap| bitmap.dispose }
|
||||
@tilesets.bitmaps.clear
|
||||
@autotiles.bitmaps.each_value { |bitmap| bitmap.dispose }
|
||||
@autotiles.bitmaps.clear
|
||||
@self_viewport.dispose
|
||||
@self_viewport = nil
|
||||
@disposed = true
|
||||
end
|
||||
|
||||
def disposed?
|
||||
return @disposed
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def add_tileset(filename)
|
||||
@tilesets.add(filename)
|
||||
end
|
||||
|
||||
def remove_tileset(filename)
|
||||
@tilesets.remove(filename)
|
||||
end
|
||||
|
||||
def add_autotile(filename)
|
||||
@autotiles.add(filename)
|
||||
end
|
||||
|
||||
def remove_autotile(filename)
|
||||
@autotiles.remove(filename)
|
||||
end
|
||||
|
||||
def add_extra_autotiles(tileset_id)
|
||||
return if !EXTRA_AUTOTILES[tileset_id]
|
||||
EXTRA_AUTOTILES[tileset_id].each do |arr|
|
||||
arr.each { |filename| add_autotile(filename) }
|
||||
end
|
||||
end
|
||||
|
||||
def remove_extra_autotiles(tileset_id)
|
||||
return if !EXTRA_AUTOTILES[tileset_id]
|
||||
EXTRA_AUTOTILES[tileset_id].each do |arr|
|
||||
arr.each { |filename| remove_autotile(filename) }
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def refresh
|
||||
@need_refresh = true
|
||||
end
|
||||
|
||||
def refresh_tile_bitmap(tile, map, tile_id)
|
||||
tile.tile_id = tile_id
|
||||
if tile_id < TILES_PER_AUTOTILE
|
||||
tile.set_bitmap("", tile_id, false, false, 0, nil)
|
||||
tile.shows_reflection = false
|
||||
tile.bridge = false
|
||||
else
|
||||
terrain_tag = map.terrain_tags[tile_id] || 0
|
||||
terrain_tag_data = GameData::TerrainTag.try_get(terrain_tag)
|
||||
priority = map.priorities[tile_id] || 0
|
||||
single_autotile_start_id = TILESET_START_ID
|
||||
true_tileset_start_id = TILESET_START_ID
|
||||
extra_autotile_arrays = EXTRA_AUTOTILES[map.tileset_id]
|
||||
if extra_autotile_arrays
|
||||
large_autotile_count = extra_autotile_arrays[0].length
|
||||
single_autotile_count = extra_autotile_arrays[1].length
|
||||
single_autotile_start_id += large_autotile_count * TILES_PER_AUTOTILE
|
||||
true_tileset_start_id += large_autotile_count * TILES_PER_AUTOTILE
|
||||
true_tileset_start_id += single_autotile_count
|
||||
end
|
||||
if tile_id < true_tileset_start_id
|
||||
filename = ""
|
||||
if tile_id < TILESET_START_ID # Real autotiles
|
||||
filename = map.autotile_names[(tile_id / TILES_PER_AUTOTILE) - 1]
|
||||
elsif tile_id < single_autotile_start_id # Large extra autotiles
|
||||
filename = extra_autotile_arrays[0][(tile_id - TILESET_START_ID) / TILES_PER_AUTOTILE]
|
||||
else
|
||||
# Single extra autotiles
|
||||
filename = extra_autotile_arrays[1][tile_id - single_autotile_start_id]
|
||||
end
|
||||
tile.set_bitmap(filename, tile_id, true, @autotiles.animated?(filename),
|
||||
priority, @autotiles[filename])
|
||||
else
|
||||
filename = map.tileset_name
|
||||
tile.set_bitmap(filename, tile_id, false, false, priority, @tilesets[filename])
|
||||
end
|
||||
tile.shows_reflection = terrain_tag_data&.shows_reflections
|
||||
tile.bridge = terrain_tag_data&.bridge
|
||||
end
|
||||
refresh_tile_src_rect(tile, tile_id)
|
||||
end
|
||||
|
||||
def refresh_tile_src_rect(tile, tile_id)
|
||||
if tile.is_autotile
|
||||
@autotiles.set_src_rect(tile, tile_id)
|
||||
else
|
||||
@tilesets.set_src_rect(tile, tile_id)
|
||||
end
|
||||
end
|
||||
|
||||
# For animated autotiles only
|
||||
def refresh_tile_frame(tile, tile_id)
|
||||
return if !tile.animated
|
||||
@autotiles.set_src_rect(tile, tile_id)
|
||||
end
|
||||
|
||||
# x and y are the positions of tile within @tiles, not a map x/y
|
||||
def refresh_tile_coordinates(tile, x, y)
|
||||
tile.x = (x * DISPLAY_TILE_WIDTH) - @pixel_offset_x
|
||||
tile.y = (y * DISPLAY_TILE_HEIGHT) - @pixel_offset_y
|
||||
end
|
||||
|
||||
def refresh_tile_z(tile, map, y, layer, tile_id)
|
||||
if tile.shows_reflection
|
||||
tile.z = -2000
|
||||
elsif tile.bridge && $PokemonGlobal.bridge > 0
|
||||
tile.z = 0
|
||||
else
|
||||
priority = tile.priority
|
||||
tile.z = (priority == 0) ? 0 : (y * SOURCE_TILE_HEIGHT) + (priority * SOURCE_TILE_HEIGHT) + SOURCE_TILE_HEIGHT + 1
|
||||
end
|
||||
end
|
||||
|
||||
def refresh_tile(tile, x, y, map, layer, tile_id)
|
||||
refresh_tile_bitmap(tile, map, tile_id)
|
||||
refresh_tile_coordinates(tile, x, y)
|
||||
refresh_tile_z(tile, map, y, layer, tile_id)
|
||||
tile.need_refresh = false
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def check_if_screen_moved
|
||||
ret = false
|
||||
# Check for map change
|
||||
if @current_map_id != $game_map.map_id
|
||||
if MapFactoryHelper.hasConnections?(@current_map_id)
|
||||
offsets = $map_factory.getRelativePos(@current_map_id, 0, 0, $game_map.map_id, 0, 0)
|
||||
if offsets
|
||||
@tile_offset_x -= offsets[0]
|
||||
@tile_offset_y -= offsets[1]
|
||||
else
|
||||
ret = true # Need a full refresh
|
||||
end
|
||||
else
|
||||
ret = true
|
||||
end
|
||||
@current_map_id = $game_map.map_id
|
||||
end
|
||||
# Check for tile movement
|
||||
current_map_display_x = ($game_map.display_x.to_f / Game_Map::X_SUBPIXELS).round
|
||||
current_map_display_y = ($game_map.display_y.to_f / Game_Map::Y_SUBPIXELS).round
|
||||
new_tile_offset_x = (current_map_display_x / SOURCE_TILE_WIDTH) * ZOOM_X
|
||||
new_tile_offset_y = (current_map_display_y / SOURCE_TILE_HEIGHT) * ZOOM_Y
|
||||
if new_tile_offset_x != @tile_offset_x
|
||||
if new_tile_offset_x > @tile_offset_x
|
||||
# Take tile stacks off the right and insert them at the beginning (left)
|
||||
(new_tile_offset_x - @tile_offset_x).times do
|
||||
c = @tiles.shift
|
||||
@tiles.push(c)
|
||||
c.each do |coord|
|
||||
coord.each { |tile| tile.need_refresh = true }
|
||||
end
|
||||
end
|
||||
else
|
||||
# Take tile stacks off the beginning (left) and push them onto the end (right)
|
||||
(@tile_offset_x - new_tile_offset_x).times do
|
||||
c = @tiles.pop
|
||||
@tiles.prepend(c)
|
||||
c.each do |coord|
|
||||
coord.each { |tile| tile.need_refresh = true }
|
||||
end
|
||||
end
|
||||
end
|
||||
@screen_moved = true
|
||||
@tile_offset_x = new_tile_offset_x
|
||||
end
|
||||
if new_tile_offset_y != @tile_offset_y
|
||||
if new_tile_offset_y > @tile_offset_y
|
||||
# Take tile stacks off the bottom and insert them at the beginning (top)
|
||||
@tiles.each do |col|
|
||||
(new_tile_offset_y - @tile_offset_y).times do
|
||||
c = col.shift
|
||||
col.push(c)
|
||||
c.each { |tile| tile.need_refresh = true }
|
||||
end
|
||||
end
|
||||
else
|
||||
# Take tile stacks off the beginning (top) and push them onto the end (bottom)
|
||||
@tiles.each do |col|
|
||||
(@tile_offset_y - new_tile_offset_y).times do
|
||||
c = col.pop
|
||||
col.prepend(c)
|
||||
c.each { |tile| tile.need_refresh = true }
|
||||
end
|
||||
end
|
||||
end
|
||||
@screen_moved = true
|
||||
@screen_moved_vertically = true
|
||||
@tile_offset_y = new_tile_offset_y
|
||||
end
|
||||
# Check for pixel movement
|
||||
new_pixel_offset_x = (current_map_display_x % SOURCE_TILE_WIDTH) * ZOOM_X
|
||||
new_pixel_offset_y = (current_map_display_y % SOURCE_TILE_HEIGHT) * ZOOM_Y
|
||||
if new_pixel_offset_x != @pixel_offset_x
|
||||
@screen_moved = true
|
||||
@pixel_offset_x = new_pixel_offset_x
|
||||
end
|
||||
if new_pixel_offset_y != @pixel_offset_y
|
||||
@screen_moved = true
|
||||
@screen_moved_vertically = true
|
||||
@pixel_offset_y = new_pixel_offset_y
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def update
|
||||
# Update tone
|
||||
if @old_tone != @tone
|
||||
@tiles.each do |col|
|
||||
col.each do |coord|
|
||||
coord.each { |tile| tile.tone = @tone }
|
||||
end
|
||||
end
|
||||
@old_tone = @tone.clone
|
||||
end
|
||||
# Update color
|
||||
if @old_color != @color
|
||||
@tiles.each do |col|
|
||||
col.each do |coord|
|
||||
coord.each { |tile| tile.color = @color }
|
||||
end
|
||||
end
|
||||
@old_color = @color.clone
|
||||
end
|
||||
# Recalculate autotile frames
|
||||
@tilesets.update
|
||||
@autotiles.update
|
||||
do_full_refresh = @need_refresh
|
||||
if @viewport.ox != @old_viewport_ox || @viewport.oy != @old_viewport_oy
|
||||
@old_viewport_ox = @viewport.ox
|
||||
@old_viewport_oy = @viewport.oy
|
||||
do_full_refresh = true
|
||||
end
|
||||
# Check whether the screen has moved since the last update
|
||||
@screen_moved = false
|
||||
@screen_moved_vertically = false
|
||||
if $PokemonGlobal.bridge != @bridge
|
||||
@bridge = $PokemonGlobal.bridge
|
||||
@screen_moved_vertically = true # To update bridge tiles' z values
|
||||
end
|
||||
do_full_refresh = true if check_if_screen_moved
|
||||
# Update all tile sprites
|
||||
visited = []
|
||||
@tiles_horizontal_count.times do |i|
|
||||
visited[i] = []
|
||||
@tiles_vertical_count.times { |j| visited[i][j] = false }
|
||||
end
|
||||
$map_factory.maps.each do |map|
|
||||
# Calculate x/y ranges of tile sprites that represent them
|
||||
map_display_x = (map.display_x.to_f / Game_Map::X_SUBPIXELS).round
|
||||
map_display_x = ((map_display_x + (Graphics.width / 2)) * ZOOM_X) - (Graphics.width / 2) if ZOOM_X != 1
|
||||
map_display_y = (map.display_y.to_f / Game_Map::Y_SUBPIXELS).round
|
||||
map_display_y = ((map_display_y + (Graphics.height / 2)) * ZOOM_Y) - (Graphics.height / 2) if ZOOM_Y != 1
|
||||
map_display_x_tile = map_display_x / DISPLAY_TILE_WIDTH
|
||||
map_display_y_tile = map_display_y / DISPLAY_TILE_HEIGHT
|
||||
start_x = [-map_display_x_tile, 0].max
|
||||
start_y = [-map_display_y_tile, 0].max
|
||||
end_x = @tiles_horizontal_count - 1
|
||||
end_x = [end_x, map.width - map_display_x_tile - 1].min
|
||||
end_y = @tiles_vertical_count - 1
|
||||
end_y = [end_y, map.height - map_display_y_tile - 1].min
|
||||
next if start_x > end_x || start_y > end_y || end_x < 0 || end_y < 0
|
||||
# Update all tile sprites representing this map
|
||||
(start_x..end_x).each do |i|
|
||||
tile_x = i + map_display_x_tile
|
||||
(start_y..end_y).each do |j|
|
||||
tile_y = j + map_display_y_tile
|
||||
@tiles[i][j].each_with_index do |tile, layer|
|
||||
tile_id = map.data[tile_x, tile_y, layer]
|
||||
if do_full_refresh || tile.need_refresh || tile.tile_id != tile_id
|
||||
refresh_tile(tile, i, j, map, layer, tile_id)
|
||||
else
|
||||
refresh_tile_frame(tile, tile_id) if tile.animated && @autotiles.changed
|
||||
# Update tile's x/y coordinates
|
||||
refresh_tile_coordinates(tile, i, j) if @screen_moved
|
||||
# Update tile's z value
|
||||
refresh_tile_z(tile, map, j, layer, tile_id) if @screen_moved_vertically
|
||||
end
|
||||
end
|
||||
# Record x/y as visited
|
||||
visited[i][j] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
# Clear all unvisited tile sprites
|
||||
@tiles.each_with_index do |col, i|
|
||||
col.each_with_index do |coord, j|
|
||||
next if visited[i][j]
|
||||
coord.each do |tile|
|
||||
tile.set_bitmap("", 0, false, false, 0, nil)
|
||||
tile.shows_reflection = false
|
||||
tile.bridge = false
|
||||
end
|
||||
end
|
||||
end
|
||||
@need_refresh = false
|
||||
@autotiles.changed = false
|
||||
end
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
97
Data/Scripts/006_Map renderer/002_TilesetWrapper.rb
Normal file
97
Data/Scripts/006_Map renderer/002_TilesetWrapper.rb
Normal file
@@ -0,0 +1,97 @@
|
||||
#===============================================================================
|
||||
# This module is a little fix that works around PC hardware limitations. Since
|
||||
# Essentials isn't working with software rendering anymore, it now has to deal
|
||||
# with the limits of the GPU. For the most part this is no big deal, but people
|
||||
# do have some really big tilesets.
|
||||
#
|
||||
# The fix is simple enough: If your tileset is too big, a new bitmap will be
|
||||
# constructed with all the excess pixels sent to the image's right side. This
|
||||
# basically means that you now have a limit far higher than you should ever
|
||||
# actually need.
|
||||
#
|
||||
# Hardware limit -> max tileset length:
|
||||
# 1024px -> 4096px
|
||||
# 2048px -> 16384px (enough to get the normal limit)
|
||||
# 4096px -> 65536px (enough to load pretty much any tileset)
|
||||
# 8192px -> 262144px
|
||||
# 16384px -> 1048576px (what most people have at this point)
|
||||
#===============================================================================
|
||||
class TilemapRenderer
|
||||
module TilesetWrapper
|
||||
TILESET_WIDTH = SOURCE_TILE_WIDTH * TILESET_TILES_PER_ROW
|
||||
# Looks useless, but covers weird numbers given to mkxp.json or a funky driver
|
||||
MAX_TEX_SIZE = (Bitmap.max_size / 1024) * 1024
|
||||
MAX_TEX_SIZE_BOOSTED = (MAX_TEX_SIZE**2) / TILESET_WIDTH
|
||||
|
||||
module_function
|
||||
|
||||
def wrapTileset(originalbmp)
|
||||
width = originalbmp.width
|
||||
height = originalbmp.height
|
||||
if width == TILESET_WIDTH && originalbmp.mega?
|
||||
columns = (height / MAX_TEX_SIZE.to_f).ceil
|
||||
if columns * TILESET_WIDTH > MAX_TEX_SIZE
|
||||
raise "Tileset is too long!\n\nSIZE: #{originalbmp.height}px\nHARDWARE LIMIT: #{MAX_TEX_SIZE}px\nBOOSTED LIMIT: #{MAX_TEX_SIZE_BOOSTED}px"
|
||||
end
|
||||
bmp = Bitmap.new(TILESET_WIDTH * columns, MAX_TEX_SIZE)
|
||||
remainder = height % MAX_TEX_SIZE
|
||||
remainder = MAX_TEX_SIZE if remainder == 0
|
||||
columns.times do |col|
|
||||
srcrect = Rect.new(0, col * MAX_TEX_SIZE, width, (col + 1 == columns) ? remainder : MAX_TEX_SIZE)
|
||||
bmp.blt(col * TILESET_WIDTH, 0, originalbmp, srcrect)
|
||||
end
|
||||
return bmp
|
||||
end
|
||||
return originalbmp
|
||||
end
|
||||
|
||||
def getWrappedRect(src_rect)
|
||||
ret = Rect.new(0, 0, 0, 0)
|
||||
col = (src_rect.y / MAX_TEX_SIZE.to_f).floor
|
||||
ret.x = (col * TILESET_WIDTH) + src_rect.x.clamp(0, TILESET_WIDTH)
|
||||
ret.y = src_rect.y % MAX_TEX_SIZE
|
||||
ret.width = src_rect.width.clamp(0, TILESET_WIDTH - src_rect.x)
|
||||
ret.height = src_rect.height.clamp(0, MAX_TEX_SIZE)
|
||||
return ret
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
private
|
||||
|
||||
def blitWrappedPixels(destX, destY, dest, src, srcrect)
|
||||
if srcrect.y + srcrect.width < MAX_TEX_SIZE
|
||||
# Save the processing power
|
||||
dest.blt(destX, destY, src, srcrect)
|
||||
return
|
||||
end
|
||||
merge = (srcrect.y % MAX_TEX_SIZE) > ((srcrect.y + srcrect.height) % MAX_TEX_SIZE)
|
||||
srcrect_mod = getWrappedRect(srcrect)
|
||||
if merge
|
||||
# FIXME: won't work on heights longer than two columns, but nobody should need
|
||||
# more than 32k pixels high at once anyway
|
||||
side = {
|
||||
:a => MAX_TEX_SIZE - srcrect_mod.y,
|
||||
:b => srcrect_mod.height - MAX_TEX_SIZE + srcrect_mod.y
|
||||
}
|
||||
dest.blt(destX, destY, src, Rect.new(srcrect_mod.x, srcrect_mod.y, srcrect_mod.width, side[:a]))
|
||||
dest.blt(destX, destY + side[:a], src, Rect.new(srcrect_mod.x + TILESET_WIDTH, 0, srcrect_mod.width, side[:b]))
|
||||
else
|
||||
dest.blt(destX, destY, src, srcrect_mod)
|
||||
end
|
||||
end
|
||||
|
||||
def stretchBlitWrappedPixels(destrect, dest, src, srcrect)
|
||||
if srcrect.y + srcrect.width < MAX_TEX_SIZE
|
||||
# Save the processing power
|
||||
dest.stretch_blt(destrect, src, srcrect)
|
||||
return
|
||||
end
|
||||
# Does a regular blit to a non-megasurface, then stretch_blts that to
|
||||
# the destination. Yes it is slow
|
||||
tmp = Bitmap.new(srcrect.width, srcrect.height)
|
||||
blitWrappedPixels(0, 0, tmp, src, srcrect)
|
||||
dest.stretch_blt(destrect, tmp, Rect.new(0, 0, srcrect.width, srcrect.height))
|
||||
end
|
||||
end
|
||||
end
|
||||
75
Data/Scripts/006_Map renderer/003_AutotileExpander.rb
Normal file
75
Data/Scripts/006_Map renderer/003_AutotileExpander.rb
Normal file
@@ -0,0 +1,75 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class TilemapRenderer
|
||||
module AutotileExpander
|
||||
MAX_TEXTURE_SIZE = (Bitmap.max_size / 1024) * 1024
|
||||
|
||||
module_function
|
||||
|
||||
# This doesn't allow for cache sizes smaller than 768, but if that applies
|
||||
# to you, you've got bigger problems.
|
||||
def expand(bitmap)
|
||||
return bitmap if bitmap.height == SOURCE_TILE_HEIGHT
|
||||
expanded_format = (bitmap.height == SOURCE_TILE_HEIGHT * 6)
|
||||
wrap = false
|
||||
if MAX_TEXTURE_SIZE < TILES_PER_AUTOTILE * SOURCE_TILE_HEIGHT
|
||||
wrap = true # Each autotile will occupy two columns instead of one
|
||||
end
|
||||
frames_count = [bitmap.width / (3 * SOURCE_TILE_WIDTH), 1].max
|
||||
new_bitmap = Bitmap.new(frames_count * (wrap ? 2 : 1) * SOURCE_TILE_WIDTH,
|
||||
TILES_PER_AUTOTILE * SOURCE_TILE_HEIGHT / (wrap ? 2 : 1))
|
||||
rect = Rect.new(0, 0, SOURCE_TILE_WIDTH / 2, SOURCE_TILE_HEIGHT / 2)
|
||||
TILES_PER_AUTOTILE.times do |id|
|
||||
pattern = TileDrawingHelper::AUTOTILE_PATTERNS[id >> 3][id % TILESET_TILES_PER_ROW]
|
||||
wrap_offset_x = (wrap && id >= TILES_PER_AUTOTILE / 2) ? SOURCE_TILE_WIDTH : 0
|
||||
wrap_offset_y = (wrap && id >= TILES_PER_AUTOTILE / 2) ? (TILES_PER_AUTOTILE / 2) * SOURCE_TILE_HEIGHT : 0
|
||||
frames_count.times do |frame|
|
||||
if expanded_format && [1, 2, 4, 8].include?(id)
|
||||
dest_x = frame * SOURCE_TILE_WIDTH * (wrap ? 2 : 1)
|
||||
dest_x += wrap_offset_x
|
||||
next if dest_x > MAX_TEXTURE_SIZE
|
||||
dest_y = id * SOURCE_TILE_HEIGHT
|
||||
dest_y -= wrap_offset_y
|
||||
next if dest_y > MAX_TEXTURE_SIZE
|
||||
case id
|
||||
when 1 # Top left corner
|
||||
new_bitmap.blt(dest_x, dest_y, bitmap,
|
||||
Rect.new(frame * SOURCE_TILE_WIDTH * 3, SOURCE_TILE_HEIGHT * 4,
|
||||
SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT))
|
||||
when 2 # Top right corner
|
||||
new_bitmap.blt(dest_x, dest_y, bitmap,
|
||||
Rect.new(SOURCE_TILE_WIDTH + (frame * SOURCE_TILE_WIDTH * 3), SOURCE_TILE_HEIGHT * 4,
|
||||
SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT))
|
||||
when 4 # Bottom right corner
|
||||
new_bitmap.blt(dest_x, dest_y, bitmap,
|
||||
Rect.new(SOURCE_TILE_WIDTH + (frame * SOURCE_TILE_WIDTH * 3), SOURCE_TILE_HEIGHT * 5,
|
||||
SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT))
|
||||
when 8 # Bottom left corner
|
||||
new_bitmap.blt(dest_x, dest_y, bitmap,
|
||||
Rect.new(frame * SOURCE_TILE_WIDTH * 3, SOURCE_TILE_HEIGHT * 5,
|
||||
SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT))
|
||||
end
|
||||
next
|
||||
end
|
||||
pattern.each_with_index do |src_chunk, i|
|
||||
real_src_chunk = src_chunk - 1
|
||||
dest_x = (i % 2) * SOURCE_TILE_WIDTH / 2
|
||||
dest_x += frame * SOURCE_TILE_WIDTH * (wrap ? 2 : 1)
|
||||
dest_x += wrap_offset_x
|
||||
next if dest_x > MAX_TEXTURE_SIZE
|
||||
dest_y = (i / 2) * SOURCE_TILE_HEIGHT / 2
|
||||
dest_y += id * SOURCE_TILE_HEIGHT
|
||||
dest_y -= wrap_offset_y
|
||||
next if dest_y > MAX_TEXTURE_SIZE
|
||||
rect.x = (real_src_chunk % 6) * SOURCE_TILE_WIDTH / 2
|
||||
rect.x += SOURCE_TILE_WIDTH * 3 * frame
|
||||
rect.y = (real_src_chunk / 6) * SOURCE_TILE_HEIGHT / 2
|
||||
new_bitmap.blt(dest_x, dest_y, bitmap, rect)
|
||||
end
|
||||
end
|
||||
end
|
||||
return new_bitmap
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,228 +0,0 @@
|
||||
class TileDrawingHelper
|
||||
attr_accessor :tileset
|
||||
attr_accessor :autotiles
|
||||
|
||||
Autotiles = [
|
||||
[ [27, 28, 33, 34], [ 5, 28, 33, 34], [27, 6, 33, 34], [ 5, 6, 33, 34],
|
||||
[27, 28, 33, 12], [ 5, 28, 33, 12], [27, 6, 33, 12], [ 5, 6, 33, 12] ],
|
||||
[ [27, 28, 11, 34], [ 5, 28, 11, 34], [27, 6, 11, 34], [ 5, 6, 11, 34],
|
||||
[27, 28, 11, 12], [ 5, 28, 11, 12], [27, 6, 11, 12], [ 5, 6, 11, 12] ],
|
||||
[ [25, 26, 31, 32], [25, 6, 31, 32], [25, 26, 31, 12], [25, 6, 31, 12],
|
||||
[15, 16, 21, 22], [15, 16, 21, 12], [15, 16, 11, 22], [15, 16, 11, 12] ],
|
||||
[ [29, 30, 35, 36], [29, 30, 11, 36], [ 5, 30, 35, 36], [ 5, 30, 11, 36],
|
||||
[39, 40, 45, 46], [ 5, 40, 45, 46], [39, 6, 45, 46], [ 5, 6, 45, 46] ],
|
||||
[ [25, 30, 31, 36], [15, 16, 45, 46], [13, 14, 19, 20], [13, 14, 19, 12],
|
||||
[17, 18, 23, 24], [17, 18, 11, 24], [41, 42, 47, 48], [ 5, 42, 47, 48] ],
|
||||
[ [37, 38, 43, 44], [37, 6, 43, 44], [13, 18, 19, 24], [13, 14, 43, 44],
|
||||
[37, 42, 43, 48], [17, 18, 47, 48], [13, 18, 43, 48], [ 1, 2, 7, 8] ]
|
||||
]
|
||||
|
||||
# converts neighbors returned from tableNeighbors to tile indexes
|
||||
NeighborsToTiles = [
|
||||
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
|
||||
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
|
||||
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
|
||||
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
|
||||
45, 39, 45, 39, 33, 31, 33, 29, 45, 39, 45, 39, 33, 31, 33, 29,
|
||||
37, 27, 37, 27, 23, 15, 23, 13, 37, 27, 37, 27, 22, 11, 22, 9,
|
||||
45, 39, 45, 39, 33, 31, 33, 29, 45, 39, 45, 39, 33, 31, 33, 29,
|
||||
36, 26, 36, 26, 21, 7, 21, 5, 36, 26, 36, 26, 20, 3, 20, 1,
|
||||
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
|
||||
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
|
||||
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
|
||||
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
|
||||
45, 38, 45, 38, 33, 30, 33, 28, 45, 38, 45, 38, 33, 30, 33, 28,
|
||||
37, 25, 37, 25, 23, 14, 23, 12, 37, 25, 37, 25, 22, 10, 22, 8,
|
||||
45, 38, 45, 38, 33, 30, 33, 28, 45, 38, 45, 38, 33, 30, 33, 28,
|
||||
36, 24, 36, 24, 21, 6, 21, 4, 36, 24, 36, 24, 20, 2, 20, 0
|
||||
]
|
||||
|
||||
def self.tableNeighbors(data,x,y)
|
||||
return 0 if x < 0 || x >= data.xsize
|
||||
return 0 if y < 0 || y >= data.ysize
|
||||
t = data[x,y]
|
||||
xp1 = [x + 1, data.xsize - 1].min
|
||||
yp1 = [y + 1, data.ysize - 1].min
|
||||
xm1 = [x - 1, 0].max
|
||||
ym1 = [y - 1, 0].max
|
||||
i = 0
|
||||
i |= 0x01 if data[ x, ym1] == t # N
|
||||
i |= 0x02 if data[xp1, ym1] == t # NE
|
||||
i |= 0x04 if data[xp1, y] == t # E
|
||||
i |= 0x08 if data[xp1, yp1] == t # SE
|
||||
i |= 0x10 if data[ x, yp1] == t # S
|
||||
i |= 0x20 if data[xm1, yp1] == t # SW
|
||||
i |= 0x40 if data[xm1, y] == t # W
|
||||
i |= 0x80 if data[xm1, ym1] == t # NW
|
||||
return i
|
||||
end
|
||||
|
||||
def self.fromTileset(tileset)
|
||||
bmtileset=pbGetTileset(tileset.tileset_name)
|
||||
bmautotiles=[]
|
||||
for i in 0...7
|
||||
bmautotiles.push(pbGetAutotile(tileset.autotile_names[i]))
|
||||
end
|
||||
return self.new(bmtileset,bmautotiles)
|
||||
end
|
||||
|
||||
def initialize(tileset, autotiles)
|
||||
if tileset.mega?
|
||||
@tileset = TileWrap::wrapTileset(tileset)
|
||||
tileset.dispose
|
||||
@shouldWrap = true
|
||||
else
|
||||
@tileset = tileset
|
||||
@shouldWrap = false
|
||||
end
|
||||
@autotiles = autotiles
|
||||
end
|
||||
|
||||
def dispose
|
||||
@tileset.dispose if @tileset
|
||||
@tileset = nil
|
||||
for i in 0...@autotiles.length
|
||||
@autotiles[i].dispose
|
||||
@autotiles[i] = nil
|
||||
end
|
||||
end
|
||||
|
||||
def bltSmallAutotile(bitmap,x,y,cxTile,cyTile,id,frame)
|
||||
return if id >= 384 || frame < 0 || !@autotiles
|
||||
autotile = @autotiles[id / 48 - 1]
|
||||
return if !autotile || autotile.disposed?
|
||||
cxTile = [cxTile / 2, 1].max
|
||||
cyTile = [cyTile / 2, 1].max
|
||||
if autotile.height == 32
|
||||
anim = frame * 32
|
||||
src_rect = Rect.new(anim, 0, 32, 32)
|
||||
bitmap.stretch_blt(Rect.new(x, y, cxTile * 2, cyTile * 2), autotile, src_rect)
|
||||
else
|
||||
anim = frame * 96
|
||||
id %= 48
|
||||
tiles = TileDrawingHelper::Autotiles[id >> 3][id & 7]
|
||||
src = Rect.new(0, 0, 0, 0)
|
||||
for i in 0...4
|
||||
tile_position = tiles[i] - 1
|
||||
src.set(tile_position % 6 * 16 + anim, tile_position / 6 * 16, 16, 16)
|
||||
bitmap.stretch_blt(Rect.new(i % 2 * cxTile + x, i / 2 * cyTile + y, cxTile, cyTile),
|
||||
autotile, src)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def bltSmallRegularTile(bitmap,x,y,cxTile,cyTile,id)
|
||||
return if id < 384 || !@tileset || @tileset.disposed?
|
||||
rect = Rect.new((id - 384) % 8 * 32, (id - 384) / 8 * 32, 32, 32)
|
||||
rect = TileWrap::getWrappedRect(rect) if @shouldWrap
|
||||
bitmap.stretch_blt(Rect.new(x, y, cxTile, cyTile), @tileset, rect)
|
||||
end
|
||||
|
||||
def bltSmallTile(bitmap,x,y,cxTile,cyTile,id,frame=0)
|
||||
if id >= 384
|
||||
bltSmallRegularTile(bitmap, x, y, cxTile, cyTile, id)
|
||||
elsif id > 0
|
||||
bltSmallAutotile(bitmap, x, y, cxTile, cyTile, id, frame)
|
||||
end
|
||||
end
|
||||
|
||||
def bltAutotile(bitmap,x,y,id,frame)
|
||||
bltSmallAutotile(bitmap, x, y, 32, 32, id, frame)
|
||||
end
|
||||
|
||||
def bltRegularTile(bitmap,x,y,id)
|
||||
bltSmallRegularTile(bitmap, x, y, 32, 32, id)
|
||||
end
|
||||
|
||||
def bltTile(bitmap,x,y,id,frame=0)
|
||||
if id >= 384
|
||||
bltRegularTile(bitmap, x, y, id)
|
||||
elsif id > 0
|
||||
bltAutotile(bitmap, x, y, id, frame)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
def createMinimap(mapid)
|
||||
map=load_data(sprintf("Data/Map%03d.rxdata",mapid)) rescue nil
|
||||
return BitmapWrapper.new(32,32) if !map
|
||||
bitmap=BitmapWrapper.new(map.width*4,map.height*4)
|
||||
black=Color.new(0,0,0)
|
||||
tilesets=$data_tilesets
|
||||
tileset=tilesets[map.tileset_id]
|
||||
return bitmap if !tileset
|
||||
helper=TileDrawingHelper.fromTileset(tileset)
|
||||
for y in 0...map.height
|
||||
for x in 0...map.width
|
||||
for z in 0..2
|
||||
id=map.data[x,y,z]
|
||||
id=0 if !id
|
||||
helper.bltSmallTile(bitmap,x*4,y*4,4,4,id)
|
||||
end
|
||||
end
|
||||
end
|
||||
bitmap.fill_rect(0,0,bitmap.width,1,black)
|
||||
bitmap.fill_rect(0,bitmap.height-1,bitmap.width,1,black)
|
||||
bitmap.fill_rect(0,0,1,bitmap.height,black)
|
||||
bitmap.fill_rect(bitmap.width-1,0,1,bitmap.height,black)
|
||||
return bitmap
|
||||
end
|
||||
|
||||
def bltMinimapAutotile(dstBitmap,x,y,srcBitmap,id)
|
||||
return if id>=48 || !srcBitmap || srcBitmap.disposed?
|
||||
anim=0
|
||||
cxTile=3
|
||||
cyTile=3
|
||||
tiles = TileDrawingHelper::Autotiles[id>>3][id&7]
|
||||
src=Rect.new(0,0,0,0)
|
||||
for i in 0...4
|
||||
tile_position = tiles[i] - 1
|
||||
src.set(
|
||||
tile_position % 6 * cxTile + anim,
|
||||
tile_position / 6 * cyTile, cxTile, cyTile)
|
||||
dstBitmap.blt(i%2*cxTile+x,i/2*cyTile+y, srcBitmap, src)
|
||||
end
|
||||
end
|
||||
|
||||
def passable?(passages,tile_id)
|
||||
return false if tile_id == nil
|
||||
passage = passages[tile_id]
|
||||
return (passage && passage<15)
|
||||
end
|
||||
|
||||
# Unused
|
||||
def getPassabilityMinimap(mapid)
|
||||
map = load_data(sprintf("Data/Map%03d.rxdata",mapid))
|
||||
tileset = $data_tilesets[map.tileset_id]
|
||||
minimap = AnimatedBitmap.new("Graphics/Pictures/minimap_tiles")
|
||||
ret = Bitmap.new(map.width*6,map.height*6)
|
||||
passtable = Table.new(map.width,map.height)
|
||||
passages = tileset.passages
|
||||
for i in 0...map.width
|
||||
for j in 0...map.height
|
||||
pass=true
|
||||
for z in [2,1,0]
|
||||
if !passable?(passages,map.data[i,j,z])
|
||||
pass=false
|
||||
break
|
||||
end
|
||||
end
|
||||
passtable[i,j]=pass ? 1 : 0
|
||||
end
|
||||
end
|
||||
neighbors=TileDrawingHelper::NeighborsToTiles
|
||||
for i in 0...map.width
|
||||
for j in 0...map.height
|
||||
if passtable[i,j]==0
|
||||
nb=TileDrawingHelper.tableNeighbors(passtable,i,j)
|
||||
tile=neighbors[nb]
|
||||
bltMinimapAutotile(ret,i*6,j*6,minimap.bitmap,tile)
|
||||
end
|
||||
end
|
||||
end
|
||||
minimap.disposes
|
||||
return ret
|
||||
end
|
||||
246
Data/Scripts/006_Map renderer/004_TileDrawingHelper.rb
Normal file
246
Data/Scripts/006_Map renderer/004_TileDrawingHelper.rb
Normal file
@@ -0,0 +1,246 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class TileDrawingHelper
|
||||
attr_accessor :tileset
|
||||
attr_accessor :autotiles
|
||||
|
||||
AUTOTILE_PATTERNS = [
|
||||
[[27, 28, 33, 34], [5, 28, 33, 34], [27, 6, 33, 34], [5, 6, 33, 34],
|
||||
[27, 28, 33, 12], [5, 28, 33, 12], [27, 6, 33, 12], [5, 6, 33, 12]],
|
||||
[[27, 28, 11, 34], [5, 28, 11, 34], [27, 6, 11, 34], [5, 6, 11, 34],
|
||||
[27, 28, 11, 12], [5, 28, 11, 12], [27, 6, 11, 12], [5, 6, 11, 12]],
|
||||
[[25, 26, 31, 32], [25, 6, 31, 32], [25, 26, 31, 12], [25, 6, 31, 12],
|
||||
[15, 16, 21, 22], [15, 16, 21, 12], [15, 16, 11, 22], [15, 16, 11, 12]],
|
||||
[[29, 30, 35, 36], [29, 30, 11, 36], [5, 30, 35, 36], [5, 30, 11, 36],
|
||||
[39, 40, 45, 46], [5, 40, 45, 46], [39, 6, 45, 46], [5, 6, 45, 46]],
|
||||
[[25, 30, 31, 36], [15, 16, 45, 46], [13, 14, 19, 20], [13, 14, 19, 12],
|
||||
[17, 18, 23, 24], [17, 18, 11, 24], [41, 42, 47, 48], [5, 42, 47, 48]],
|
||||
[[37, 38, 43, 44], [37, 6, 43, 44], [13, 18, 19, 24], [13, 14, 43, 44],
|
||||
[37, 42, 43, 48], [17, 18, 47, 48], [13, 18, 43, 48], [1, 2, 7, 8]]
|
||||
]
|
||||
|
||||
# converts neighbors returned from tableNeighbors to tile indexes
|
||||
NEIGHBORS_TO_AUTOTILE_INDEX = [
|
||||
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
|
||||
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
|
||||
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
|
||||
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
|
||||
45, 39, 45, 39, 33, 31, 33, 29, 45, 39, 45, 39, 33, 31, 33, 29,
|
||||
37, 27, 37, 27, 23, 15, 23, 13, 37, 27, 37, 27, 22, 11, 22, 9,
|
||||
45, 39, 45, 39, 33, 31, 33, 29, 45, 39, 45, 39, 33, 31, 33, 29,
|
||||
36, 26, 36, 26, 21, 7, 21, 5, 36, 26, 36, 26, 20, 3, 20, 1,
|
||||
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
|
||||
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
|
||||
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
|
||||
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
|
||||
45, 38, 45, 38, 33, 30, 33, 28, 45, 38, 45, 38, 33, 30, 33, 28,
|
||||
37, 25, 37, 25, 23, 14, 23, 12, 37, 25, 37, 25, 22, 10, 22, 8,
|
||||
45, 38, 45, 38, 33, 30, 33, 28, 45, 38, 45, 38, 33, 30, 33, 28,
|
||||
36, 24, 36, 24, 21, 6, 21, 4, 36, 24, 36, 24, 20, 2, 20, 0
|
||||
]
|
||||
|
||||
def self.tableNeighbors(data, x, y, layer = nil)
|
||||
return 0 if x < 0 || x >= data.xsize
|
||||
return 0 if y < 0 || y >= data.ysize
|
||||
if layer.nil?
|
||||
t = data[x, y]
|
||||
else
|
||||
t = data[x, y, layer]
|
||||
end
|
||||
xp1 = [x + 1, data.xsize - 1].min
|
||||
yp1 = [y + 1, data.ysize - 1].min
|
||||
xm1 = [x - 1, 0].max
|
||||
ym1 = [y - 1, 0].max
|
||||
i = 0
|
||||
if layer.nil?
|
||||
i |= 0x01 if data[ x, ym1] == t # N
|
||||
i |= 0x02 if data[xp1, ym1] == t # NE
|
||||
i |= 0x04 if data[xp1, y] == t # E
|
||||
i |= 0x08 if data[xp1, yp1] == t # SE
|
||||
i |= 0x10 if data[ x, yp1] == t # S
|
||||
i |= 0x20 if data[xm1, yp1] == t # SW
|
||||
i |= 0x40 if data[xm1, y] == t # W
|
||||
i |= 0x80 if data[xm1, ym1] == t # NW
|
||||
else
|
||||
i |= 0x01 if data[ x, ym1, layer] == t # N
|
||||
i |= 0x02 if data[xp1, ym1, layer] == t # NE
|
||||
i |= 0x04 if data[xp1, y, layer] == t # E
|
||||
i |= 0x08 if data[xp1, yp1, layer] == t # SE
|
||||
i |= 0x10 if data[ x, yp1, layer] == t # S
|
||||
i |= 0x20 if data[xm1, yp1, layer] == t # SW
|
||||
i |= 0x40 if data[xm1, y, layer] == t # W
|
||||
i |= 0x80 if data[xm1, ym1, layer] == t # NW
|
||||
end
|
||||
return i
|
||||
end
|
||||
|
||||
def self.fromTileset(tileset)
|
||||
bmtileset = pbGetTileset(tileset.tileset_name)
|
||||
bmautotiles = []
|
||||
7.times do |i|
|
||||
bmautotiles.push(pbGetAutotile(tileset.autotile_names[i]))
|
||||
end
|
||||
return self.new(bmtileset, bmautotiles)
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def initialize(tileset, autotiles)
|
||||
if tileset.mega?
|
||||
@tileset = TilemapRenderer::TilesetWrapper.wrapTileset(tileset)
|
||||
tileset.dispose
|
||||
@shouldWrap = true
|
||||
else
|
||||
@tileset = tileset
|
||||
@shouldWrap = false
|
||||
end
|
||||
@autotiles = autotiles
|
||||
end
|
||||
|
||||
def dispose
|
||||
@tileset&.dispose
|
||||
@tileset = nil
|
||||
@autotiles.each_with_index do |autotile, i|
|
||||
autotile.dispose
|
||||
@autotiles[i] = nil
|
||||
end
|
||||
end
|
||||
|
||||
def bltSmallAutotile(bitmap, x, y, cxTile, cyTile, id, frame)
|
||||
return if id >= 384 || frame < 0 || !@autotiles
|
||||
autotile = @autotiles[(id / 48) - 1]
|
||||
return if !autotile || autotile.disposed?
|
||||
cxTile = [cxTile / 2, 1].max
|
||||
cyTile = [cyTile / 2, 1].max
|
||||
if autotile.height == 32
|
||||
anim = frame * 32
|
||||
src_rect = Rect.new(anim, 0, 32, 32)
|
||||
bitmap.stretch_blt(Rect.new(x, y, cxTile * 2, cyTile * 2), autotile, src_rect)
|
||||
else
|
||||
anim = frame * 96
|
||||
id %= 48
|
||||
tiles = AUTOTILE_PATTERNS[id >> 3][id & 7]
|
||||
src = Rect.new(0, 0, 0, 0)
|
||||
4.times do |i|
|
||||
tile_position = tiles[i] - 1
|
||||
src.set(((tile_position % 6) * 16) + anim, (tile_position / 6) * 16, 16, 16)
|
||||
bitmap.stretch_blt(Rect.new((i % 2 * cxTile) + x, (i / 2 * cyTile) + y, cxTile, cyTile),
|
||||
autotile, src)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def bltSmallRegularTile(bitmap, x, y, cxTile, cyTile, id)
|
||||
return if id < 384 || !@tileset || @tileset.disposed?
|
||||
rect = Rect.new(((id - 384) % 8) * 32, ((id - 384) / 8) * 32, 32, 32)
|
||||
rect = TilemapRenderer::TilesetWrapper.getWrappedRect(rect) if @shouldWrap
|
||||
bitmap.stretch_blt(Rect.new(x, y, cxTile, cyTile), @tileset, rect)
|
||||
end
|
||||
|
||||
def bltSmallTile(bitmap, x, y, cxTile, cyTile, id, frame = 0)
|
||||
if id >= 384
|
||||
bltSmallRegularTile(bitmap, x, y, cxTile, cyTile, id)
|
||||
elsif id > 0
|
||||
bltSmallAutotile(bitmap, x, y, cxTile, cyTile, id, frame)
|
||||
end
|
||||
end
|
||||
|
||||
def bltAutotile(bitmap, x, y, id, frame)
|
||||
bltSmallAutotile(bitmap, x, y, 32, 32, id, frame)
|
||||
end
|
||||
|
||||
def bltRegularTile(bitmap, x, y, id)
|
||||
bltSmallRegularTile(bitmap, x, y, 32, 32, id)
|
||||
end
|
||||
|
||||
def bltTile(bitmap, x, y, id, frame = 0)
|
||||
if id >= 384
|
||||
bltRegularTile(bitmap, x, y, id)
|
||||
elsif id > 0
|
||||
bltAutotile(bitmap, x, y, id, frame)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
def createMinimap(mapid)
|
||||
map = load_data(sprintf("Data/Map%03d.rxdata", mapid)) rescue nil
|
||||
return Bitmap.new(32, 32) if !map
|
||||
bitmap = Bitmap.new(map.width * 4, map.height * 4)
|
||||
black = Color.black
|
||||
tilesets = $data_tilesets
|
||||
tileset = tilesets[map.tileset_id]
|
||||
return bitmap if !tileset
|
||||
helper = TileDrawingHelper.fromTileset(tileset)
|
||||
map.height.times do |y|
|
||||
map.width.times do |x|
|
||||
3.times do |z|
|
||||
id = map.data[x, y, z]
|
||||
id = 0 if !id
|
||||
helper.bltSmallTile(bitmap, x * 4, y * 4, 4, 4, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
bitmap.fill_rect(0, 0, bitmap.width, 1, black)
|
||||
bitmap.fill_rect(0, bitmap.height - 1, bitmap.width, 1, black)
|
||||
bitmap.fill_rect(0, 0, 1, bitmap.height, black)
|
||||
bitmap.fill_rect(bitmap.width - 1, 0, 1, bitmap.height, black)
|
||||
return bitmap
|
||||
end
|
||||
|
||||
def bltMinimapAutotile(dstBitmap, x, y, srcBitmap, id)
|
||||
return if id >= 48 || !srcBitmap || srcBitmap.disposed?
|
||||
anim = 0
|
||||
cxTile = 3
|
||||
cyTile = 3
|
||||
tiles = TileDrawingHelper::AUTOTILE_PATTERNS[id >> 3][id & 7]
|
||||
src = Rect.new(0, 0, 0, 0)
|
||||
4.times do |i|
|
||||
tile_position = tiles[i] - 1
|
||||
src.set((tile_position % 6 * cxTile) + anim,
|
||||
tile_position / 6 * cyTile, cxTile, cyTile)
|
||||
dstBitmap.blt((i % 2 * cxTile) + x, (i / 2 * cyTile) + y, srcBitmap, src)
|
||||
end
|
||||
end
|
||||
|
||||
def passable?(passages, tile_id)
|
||||
return false if tile_id.nil?
|
||||
passage = passages[tile_id]
|
||||
return (passage && passage < 15)
|
||||
end
|
||||
|
||||
# Unused
|
||||
def getPassabilityMinimap(mapid)
|
||||
map = load_data(sprintf("Data/Map%03d.rxdata", mapid))
|
||||
tileset = $data_tilesets[map.tileset_id]
|
||||
minimap = AnimatedBitmap.new("Graphics/UI/minimap_tiles")
|
||||
ret = Bitmap.new(map.width * 6, map.height * 6)
|
||||
passtable = Table.new(map.width, map.height)
|
||||
passages = tileset.passages
|
||||
map.width.times do |i|
|
||||
map.height.times do |j|
|
||||
pass = true
|
||||
[2, 1, 0].each do |z|
|
||||
if !passable?(passages, map.data[i, j, z])
|
||||
pass = false
|
||||
break
|
||||
end
|
||||
end
|
||||
passtable[i, j] = pass ? 1 : 0
|
||||
end
|
||||
end
|
||||
neighbors = TileDrawingHelper::NEIGHBORS_TO_AUTOTILE_INDEX
|
||||
map.width.times do |i|
|
||||
map.height.times do |j|
|
||||
next if passtable[i, j] != 0
|
||||
nb = TileDrawingHelper.tableNeighbors(passtable, i, j)
|
||||
tile = neighbors[nb]
|
||||
bltMinimapAutotile(ret, i * 6, j * 6, minimap.bitmap, tile)
|
||||
end
|
||||
end
|
||||
minimap.dispose
|
||||
return ret
|
||||
end
|
||||
@@ -1,13 +1,17 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Hangup < Exception; end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module RPG
|
||||
module Cache
|
||||
def self.debug
|
||||
t = Time.now
|
||||
filename = t.strftime("%H %M %S.%L.txt")
|
||||
File.open("cache_" + filename, "wb") { |f|
|
||||
File.open("cache_" + filename, "wb") do |f|
|
||||
@cache.each do |key, value|
|
||||
if !value
|
||||
f.write("#{key} (nil)\r\n")
|
||||
@@ -17,7 +21,7 @@ module RPG
|
||||
f.write("#{key} (#{value.refcount}, #{value.width}x#{value.height})\r\n")
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def self.setKey(key, obj)
|
||||
@@ -27,7 +31,7 @@ module RPG
|
||||
def self.fromCache(i)
|
||||
return nil if !@cache.include?(i)
|
||||
obj = @cache[i]
|
||||
return nil if obj && obj.disposed?
|
||||
return nil if obj&.disposed?
|
||||
return obj
|
||||
end
|
||||
|
||||
@@ -67,7 +71,7 @@ module RPG
|
||||
ret.addRef
|
||||
else
|
||||
ret = BitmapWrapper.new(32 * width, 32 * height)
|
||||
x = (tile_id - 384) % 8 * 32
|
||||
x = ((tile_id - 384) % 8) * 32
|
||||
y = (((tile_id - 384) / 8) - height + 1) * 32
|
||||
tileset = yield(filename)
|
||||
ret.blt(0, 0, tileset, Rect.new(x, y, 32 * width, 32 * height))
|
||||
@@ -86,6 +90,10 @@ module RPG
|
||||
self.load_bitmap("Graphics/Transitions/", filename)
|
||||
end
|
||||
|
||||
def self.ui(filename)
|
||||
self.load_bitmap("Graphics/UI/", filename)
|
||||
end
|
||||
|
||||
def self.retain(folder_name, filename = "", hue = 0)
|
||||
path = folder_name + filename
|
||||
ret = fromCache(path)
|
||||
@@ -102,8 +110,9 @@ module RPG
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class BitmapWrapper < Bitmap
|
||||
attr_reader :refcount
|
||||
attr_accessor :never_dispose
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,6 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class WindowCursorRect < Rect
|
||||
def initialize(window)
|
||||
super(0, 0, 0, 0)
|
||||
@@ -6,7 +9,6 @@ class WindowCursorRect < Rect
|
||||
|
||||
def empty
|
||||
return unless needs_update?(0, 0, 0, 0)
|
||||
|
||||
set(0, 0, 0, 0)
|
||||
end
|
||||
|
||||
@@ -16,9 +18,7 @@ class WindowCursorRect < Rect
|
||||
|
||||
def set(x, y, width, height)
|
||||
return unless needs_update?(x, y, width, height)
|
||||
|
||||
super(x, y, width, height)
|
||||
|
||||
@window.width = @window.width
|
||||
end
|
||||
|
||||
@@ -42,6 +42,8 @@ class WindowCursorRect < Rect
|
||||
@window.width = @window.width
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
private
|
||||
|
||||
def needs_update?(x, y, width, height)
|
||||
@@ -49,7 +51,9 @@ class WindowCursorRect < Rect
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Window
|
||||
attr_reader :tone
|
||||
attr_reader :color
|
||||
@@ -78,108 +82,107 @@ class Window
|
||||
@_windowskin
|
||||
end
|
||||
|
||||
def initialize(viewport=nil)
|
||||
@sprites={}
|
||||
@spritekeys=[
|
||||
"back",
|
||||
"corner0","side0","scroll0",
|
||||
"corner1","side1","scroll1",
|
||||
"corner2","side2","scroll2",
|
||||
"corner3","side3","scroll3",
|
||||
"cursor","contents","pause"
|
||||
def initialize(viewport = nil)
|
||||
@sprites = {}
|
||||
@spritekeys = [
|
||||
"back",
|
||||
"corner0", "side0", "scroll0",
|
||||
"corner1", "side1", "scroll1",
|
||||
"corner2", "side2", "scroll2",
|
||||
"corner3", "side3", "scroll3",
|
||||
"cursor", "contents", "pause"
|
||||
]
|
||||
@sidebitmaps=[nil,nil,nil,nil]
|
||||
@cursorbitmap=nil
|
||||
@bgbitmap=nil
|
||||
@viewport=viewport
|
||||
for i in @spritekeys
|
||||
@sprites[i]=Sprite.new(@viewport)
|
||||
@sidebitmaps = [nil, nil, nil, nil]
|
||||
@cursorbitmap = nil
|
||||
@bgbitmap = nil
|
||||
@viewport = viewport
|
||||
@spritekeys.each do |i|
|
||||
@sprites[i] = Sprite.new(@viewport)
|
||||
end
|
||||
@disposed=false
|
||||
@tone=Tone.new(0,0,0)
|
||||
@color=Color.new(0,0,0,0)
|
||||
@blankcontents=Bitmap.new(1,1) # RGSS2 requires this
|
||||
@contents=@blankcontents
|
||||
@_windowskin=nil
|
||||
@rpgvx=false # Set to true to emulate RPGVX windows
|
||||
@x=0
|
||||
@y=0
|
||||
@width=0
|
||||
@openness=255
|
||||
@height=0
|
||||
@ox=0
|
||||
@oy=0
|
||||
@z=0
|
||||
@stretch=true
|
||||
@visible=true
|
||||
@active=true
|
||||
@blend_type=0
|
||||
@contents_blend_type=0
|
||||
@opacity=255
|
||||
@back_opacity=255
|
||||
@contents_opacity=255
|
||||
@cursor_rect=WindowCursorRect.new(self)
|
||||
@cursorblink=0
|
||||
@cursoropacity=255
|
||||
@pause=false
|
||||
@pauseopacity=255
|
||||
@pauseframe=0
|
||||
@disposed = false
|
||||
@tone = Tone.new(0, 0, 0)
|
||||
@color = Color.new(0, 0, 0, 0)
|
||||
@blankcontents = Bitmap.new(1, 1) # RGSS2 requires this
|
||||
@contents = @blankcontents
|
||||
@_windowskin = nil
|
||||
@rpgvx = false # Set to true to emulate RPGVX windows
|
||||
@x = 0
|
||||
@y = 0
|
||||
@width = 0
|
||||
@openness = 255
|
||||
@height = 0
|
||||
@ox = 0
|
||||
@oy = 0
|
||||
@z = 0
|
||||
@stretch = true
|
||||
@visible = true
|
||||
@active = true
|
||||
@blend_type = 0
|
||||
@contents_blend_type = 0
|
||||
@opacity = 255
|
||||
@back_opacity = 255
|
||||
@contents_opacity = 255
|
||||
@cursor_rect = WindowCursorRect.new(self)
|
||||
@cursoropacity = 255
|
||||
@pause = false
|
||||
@pauseopacity = 255
|
||||
@pauseframe = 0
|
||||
privRefresh(true)
|
||||
end
|
||||
|
||||
def dispose
|
||||
if !self.disposed?
|
||||
for i in @sprites
|
||||
i[1].dispose if i[1]
|
||||
@sprites[i[0]]=nil
|
||||
@sprites.each do |i|
|
||||
i[1]&.dispose
|
||||
@sprites[i[0]] = nil
|
||||
end
|
||||
for i in 0...@sidebitmaps.length
|
||||
@sidebitmaps[i].dispose if @sidebitmaps[i]
|
||||
@sidebitmaps[i]=nil
|
||||
@sidebitmaps.each_with_index do |bitmap, i|
|
||||
bitmap&.dispose
|
||||
@sidebitmaps[i] = nil
|
||||
end
|
||||
@blankcontents.dispose
|
||||
@cursorbitmap.dispose if @cursorbitmap
|
||||
@backbitmap.dispose if @backbitmap
|
||||
@cursorbitmap&.dispose
|
||||
@backbitmap&.dispose
|
||||
@sprites.clear
|
||||
@sidebitmaps.clear
|
||||
@_windowskin=nil
|
||||
@_contents=nil
|
||||
@disposed=true
|
||||
@_windowskin = nil
|
||||
@_contents = nil
|
||||
@disposed = true
|
||||
end
|
||||
end
|
||||
|
||||
def openness=(value)
|
||||
@openness=value
|
||||
@openness=0 if @openness<0
|
||||
@openness=255 if @openness>255
|
||||
@openness = value
|
||||
@openness = 0 if @openness < 0
|
||||
@openness = 255 if @openness > 255
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def stretch=(value)
|
||||
@stretch=value
|
||||
@stretch = value
|
||||
privRefresh(true)
|
||||
end
|
||||
|
||||
def visible=(value)
|
||||
@visible=value
|
||||
@visible = value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def viewport=(value)
|
||||
@viewport=value
|
||||
for i in @spritekeys
|
||||
@viewport = value
|
||||
@spritekeys.each do |i|
|
||||
@sprites[i].dispose
|
||||
if @sprites[i].is_a?(Sprite)
|
||||
@sprites[i]=Sprite.new(@viewport)
|
||||
@sprites[i] = Sprite.new(@viewport)
|
||||
else
|
||||
@sprites[i]=nil
|
||||
@sprites[i] = nil
|
||||
end
|
||||
end
|
||||
privRefresh(true)
|
||||
end
|
||||
|
||||
def z=(value)
|
||||
@z=value
|
||||
@z = value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
@@ -188,417 +191,415 @@ class Window
|
||||
end
|
||||
|
||||
def contents=(value)
|
||||
@contents=value
|
||||
@contents = value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def windowskin=(value)
|
||||
@_windowskin=value
|
||||
if value && value.is_a?(Bitmap) && !value.disposed? && value.width==128
|
||||
@rpgvx=true
|
||||
@_windowskin = value
|
||||
if value.is_a?(Bitmap) && !value.disposed? && value.width == 128
|
||||
@rpgvx = true
|
||||
else
|
||||
@rpgvx=false
|
||||
@rpgvx = false
|
||||
end
|
||||
privRefresh(true)
|
||||
end
|
||||
|
||||
def ox=(value)
|
||||
@ox=value
|
||||
@ox = value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def active=(value)
|
||||
@active=value
|
||||
@active = value
|
||||
privRefresh(true)
|
||||
end
|
||||
|
||||
def cursor_rect=(value)
|
||||
if !value
|
||||
@cursor_rect.empty
|
||||
if value
|
||||
@cursor_rect.set(value.x, value.y, value.width, value.height)
|
||||
else
|
||||
@cursor_rect.set(value.x,value.y,value.width,value.height)
|
||||
@cursor_rect.empty
|
||||
end
|
||||
end
|
||||
|
||||
def oy=(value)
|
||||
@oy=value
|
||||
@oy = value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def width=(value)
|
||||
@width=value
|
||||
@width = value
|
||||
privRefresh(true)
|
||||
end
|
||||
|
||||
def height=(value)
|
||||
@height=value
|
||||
@height = value
|
||||
privRefresh(true)
|
||||
end
|
||||
|
||||
def pause=(value)
|
||||
@pause=value
|
||||
@pauseopacity=0 if !value
|
||||
@pause = value
|
||||
@pauseopacity = 0 if !value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def x=(value)
|
||||
@x=value
|
||||
@x = value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def y=(value)
|
||||
@y=value
|
||||
@y = value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def opacity=(value)
|
||||
@opacity=value
|
||||
@opacity=0 if @opacity<0
|
||||
@opacity=255 if @opacity>255
|
||||
@opacity = value
|
||||
@opacity = 0 if @opacity < 0
|
||||
@opacity = 255 if @opacity > 255
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def back_opacity=(value)
|
||||
@back_opacity=value
|
||||
@back_opacity=0 if @back_opacity<0
|
||||
@back_opacity=255 if @back_opacity>255
|
||||
@back_opacity = value
|
||||
@back_opacity = 0 if @back_opacity < 0
|
||||
@back_opacity = 255 if @back_opacity > 255
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def contents_opacity=(value)
|
||||
@contents_opacity=value
|
||||
@contents_opacity=0 if @contents_opacity<0
|
||||
@contents_opacity=255 if @contents_opacity>255
|
||||
@contents_opacity = value
|
||||
@contents_opacity = 0 if @contents_opacity < 0
|
||||
@contents_opacity = 255 if @contents_opacity > 255
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def tone=(value)
|
||||
@tone=value
|
||||
@tone = value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def color=(value)
|
||||
@color=value
|
||||
@color = value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def blend_type=(value)
|
||||
@blend_type=value
|
||||
@blend_type = value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def flash(color,duration)
|
||||
def flash(color, duration)
|
||||
return if disposed?
|
||||
for i in @sprites
|
||||
i[1].flash(color,duration)
|
||||
@sprites.each do |i|
|
||||
i[1].flash(color, duration)
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
return if disposed?
|
||||
mustchange=false
|
||||
mustchange = false
|
||||
if @active
|
||||
if @cursorblink==0
|
||||
@cursoropacity-=8
|
||||
@cursorblink=1 if @cursoropacity<=128
|
||||
cursor_time = System.uptime / 0.4
|
||||
if cursor_time.to_i.even?
|
||||
@cursoropacity = lerp(255, 128, 0.4, cursor_time % 2)
|
||||
else
|
||||
@cursoropacity+=8
|
||||
@cursorblink=0 if @cursoropacity>=255
|
||||
@cursoropacity = lerp(128, 255, 0.4, (cursor_time - 1) % 2)
|
||||
end
|
||||
mustchange=true if !@cursor_rect.empty?
|
||||
mustchange = true if !@cursor_rect.empty?
|
||||
else
|
||||
mustchange=true if @cursoropacity!=128
|
||||
@cursoropacity=128
|
||||
mustchange = true if @cursoropacity != 128
|
||||
@cursoropacity = 128
|
||||
end
|
||||
if @pause
|
||||
@pauseframe=(Graphics.frame_count / 8) % 4
|
||||
@pauseopacity=[@pauseopacity+64,255].min
|
||||
mustchange=true
|
||||
@pauseframe = (System.uptime * 5).to_i % 4 # 4 frames, 5 frames per second
|
||||
@pauseopacity = [@pauseopacity + 64, 255].min
|
||||
mustchange = true
|
||||
end
|
||||
privRefresh if mustchange
|
||||
for i in @sprites
|
||||
@sprites.each do |i|
|
||||
i[1].update
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
private
|
||||
|
||||
def ensureBitmap(bitmap,dwidth,dheight)
|
||||
if !bitmap||bitmap.disposed?||bitmap.width<dwidth||bitmap.height<dheight
|
||||
bitmap.dispose if bitmap
|
||||
bitmap=Bitmap.new([1,dwidth].max,[1,dheight].max)
|
||||
def ensureBitmap(bitmap, dwidth, dheight)
|
||||
if !bitmap || bitmap.disposed? || bitmap.width < dwidth || bitmap.height < dheight
|
||||
bitmap&.dispose
|
||||
bitmap = Bitmap.new([1, dwidth].max, [1, dheight].max)
|
||||
end
|
||||
return bitmap
|
||||
end
|
||||
|
||||
def tileBitmap(dstbitmap,dstrect,srcbitmap,srcrect)
|
||||
def tileBitmap(dstbitmap, dstrect, srcbitmap, srcrect)
|
||||
return if !srcbitmap || srcbitmap.disposed?
|
||||
left=dstrect.x
|
||||
top=dstrect.y
|
||||
y=0;loop do break unless y<dstrect.height
|
||||
x=0;loop do break unless x<dstrect.width
|
||||
dstbitmap.blt(x+left,y+top,srcbitmap,srcrect)
|
||||
x+=srcrect.width
|
||||
left = dstrect.x
|
||||
top = dstrect.y
|
||||
y = 0
|
||||
loop do
|
||||
break unless y < dstrect.height
|
||||
x = 0
|
||||
loop do
|
||||
break unless x < dstrect.width
|
||||
dstbitmap.blt(x + left, y + top, srcbitmap, srcrect)
|
||||
x += srcrect.width
|
||||
end
|
||||
y+=srcrect.height
|
||||
y += srcrect.height
|
||||
end
|
||||
end
|
||||
|
||||
def privRefresh(changeBitmap=false)
|
||||
def privRefresh(changeBitmap = false)
|
||||
return if self.disposed?
|
||||
backopac=self.back_opacity*self.opacity/255
|
||||
contopac=self.contents_opacity
|
||||
cursoropac=@cursoropacity*contopac/255
|
||||
for i in 0...4
|
||||
@sprites["corner#{i}"].bitmap=@_windowskin
|
||||
@sprites["scroll#{i}"].bitmap=@_windowskin
|
||||
backopac = self.back_opacity * self.opacity / 255
|
||||
contopac = self.contents_opacity
|
||||
cursoropac = @cursoropacity * contopac / 255
|
||||
4.times do |i|
|
||||
@sprites["corner#{i}"].bitmap = @_windowskin
|
||||
@sprites["scroll#{i}"].bitmap = @_windowskin
|
||||
end
|
||||
@sprites["pause"].bitmap=@_windowskin
|
||||
@sprites["contents"].bitmap=@contents
|
||||
@sprites["pause"].bitmap = @_windowskin
|
||||
@sprites["contents"].bitmap = @contents
|
||||
if @_windowskin && !@_windowskin.disposed?
|
||||
for i in 0...4
|
||||
@sprites["corner#{i}"].opacity=@opacity
|
||||
@sprites["corner#{i}"].tone=@tone
|
||||
@sprites["corner#{i}"].color=@color
|
||||
@sprites["corner#{i}"].blend_type=@blend_type
|
||||
@sprites["corner#{i}"].visible=@visible
|
||||
@sprites["side#{i}"].opacity=@opacity
|
||||
@sprites["side#{i}"].tone=@tone
|
||||
@sprites["side#{i}"].color=@color
|
||||
@sprites["side#{i}"].blend_type=@blend_type
|
||||
@sprites["side#{i}"].visible=@visible
|
||||
@sprites["scroll#{i}"].opacity=@opacity
|
||||
@sprites["scroll#{i}"].tone=@tone
|
||||
@sprites["scroll#{i}"].blend_type=@blend_type
|
||||
@sprites["scroll#{i}"].color=@color
|
||||
@sprites["scroll#{i}"].visible=@visible
|
||||
4.times do |i|
|
||||
@sprites["corner#{i}"].opacity = @opacity
|
||||
@sprites["corner#{i}"].tone = @tone
|
||||
@sprites["corner#{i}"].color = @color
|
||||
@sprites["corner#{i}"].blend_type = @blend_type
|
||||
@sprites["corner#{i}"].visible = @visible
|
||||
@sprites["side#{i}"].opacity = @opacity
|
||||
@sprites["side#{i}"].tone = @tone
|
||||
@sprites["side#{i}"].color = @color
|
||||
@sprites["side#{i}"].blend_type = @blend_type
|
||||
@sprites["side#{i}"].visible = @visible
|
||||
@sprites["scroll#{i}"].opacity = @opacity
|
||||
@sprites["scroll#{i}"].tone = @tone
|
||||
@sprites["scroll#{i}"].blend_type = @blend_type
|
||||
@sprites["scroll#{i}"].color = @color
|
||||
@sprites["scroll#{i}"].visible = @visible
|
||||
end
|
||||
for i in ["back","cursor","pause","contents"]
|
||||
@sprites[i].color=@color
|
||||
@sprites[i].tone=@tone
|
||||
@sprites[i].blend_type=@blend_type
|
||||
["back", "cursor", "pause", "contents"].each do |i|
|
||||
@sprites[i].color = @color
|
||||
@sprites[i].tone = @tone
|
||||
@sprites[i].blend_type = @blend_type
|
||||
end
|
||||
@sprites["contents"].blend_type=@contents_blend_type
|
||||
@sprites["back"].opacity=backopac
|
||||
@sprites["contents"].opacity=contopac
|
||||
@sprites["cursor"].opacity=cursoropac
|
||||
@sprites["pause"].opacity=@pauseopacity
|
||||
@sprites["back"].visible=@visible
|
||||
@sprites["contents"].visible=@visible && @openness==255
|
||||
@sprites["pause"].visible=@visible && @pause
|
||||
@sprites["cursor"].visible=@visible && @openness==255
|
||||
hascontents=(@contents && !@contents.disposed?)
|
||||
@sprites["contents"].blend_type = @contents_blend_type
|
||||
@sprites["back"].opacity = backopac
|
||||
@sprites["contents"].opacity = contopac
|
||||
@sprites["cursor"].opacity = cursoropac
|
||||
@sprites["pause"].opacity = @pauseopacity
|
||||
@sprites["back"].visible = @visible
|
||||
@sprites["contents"].visible = @visible && @openness == 255
|
||||
@sprites["pause"].visible = @visible && @pause
|
||||
@sprites["cursor"].visible = @visible && @openness == 255
|
||||
hascontents = (@contents && !@contents.disposed?)
|
||||
@sprites["scroll0"].visible = @visible && hascontents && @oy > 0
|
||||
@sprites["scroll1"].visible = @visible && hascontents && @ox > 0
|
||||
@sprites["scroll2"].visible = @visible && hascontents &&
|
||||
(@contents.width - @ox) > @width-32
|
||||
(@contents.width - @ox) > @width - 32
|
||||
@sprites["scroll3"].visible = @visible && hascontents &&
|
||||
(@contents.height - @oy) > @height-32
|
||||
(@contents.height - @oy) > @height - 32
|
||||
else
|
||||
for i in 0...4
|
||||
@sprites["corner#{i}"].visible=false
|
||||
@sprites["side#{i}"].visible=false
|
||||
@sprites["scroll#{i}"].visible=false
|
||||
4.times do |i|
|
||||
@sprites["corner#{i}"].visible = false
|
||||
@sprites["side#{i}"].visible = false
|
||||
@sprites["scroll#{i}"].visible = false
|
||||
end
|
||||
@sprites["contents"].visible=@visible && @openness==255
|
||||
@sprites["contents"].color=@color
|
||||
@sprites["contents"].tone=@tone
|
||||
@sprites["contents"].blend_type=@contents_blend_type
|
||||
@sprites["contents"].opacity=contopac
|
||||
@sprites["back"].visible=false
|
||||
@sprites["pause"].visible=false
|
||||
@sprites["cursor"].visible=false
|
||||
@sprites["contents"].visible = @visible && @openness == 255
|
||||
@sprites["contents"].color = @color
|
||||
@sprites["contents"].tone = @tone
|
||||
@sprites["contents"].blend_type = @contents_blend_type
|
||||
@sprites["contents"].opacity = contopac
|
||||
@sprites["back"].visible = false
|
||||
@sprites["pause"].visible = false
|
||||
@sprites["cursor"].visible = false
|
||||
end
|
||||
for i in @sprites
|
||||
i[1].z=@z
|
||||
@sprites.each do |i|
|
||||
i[1].z = @z
|
||||
end
|
||||
if @rpgvx
|
||||
@sprites["cursor"].z=@z # For Compatibility
|
||||
@sprites["contents"].z=@z # For Compatibility
|
||||
@sprites["pause"].z=@z # For Compatibility
|
||||
@sprites["cursor"].z = @z # For Compatibility
|
||||
@sprites["contents"].z = @z # For Compatibility
|
||||
@sprites["pause"].z = @z # For Compatibility
|
||||
else
|
||||
@sprites["cursor"].z=@z+1 # For Compatibility
|
||||
@sprites["contents"].z=@z+2 # For Compatibility
|
||||
@sprites["pause"].z=@z+2 # For Compatibility
|
||||
@sprites["cursor"].z = @z + 1 # For Compatibility
|
||||
@sprites["contents"].z = @z + 2 # For Compatibility
|
||||
@sprites["pause"].z = @z + 2 # For Compatibility
|
||||
end
|
||||
if @rpgvx
|
||||
trimX=64
|
||||
trimY=0
|
||||
backRect=Rect.new(0,0,64,64)
|
||||
blindsRect=Rect.new(0,64,64,64)
|
||||
trimX = 64
|
||||
trimY = 0
|
||||
backRect = Rect.new(0, 0, 64, 64)
|
||||
blindsRect = Rect.new(0, 64, 64, 64)
|
||||
else
|
||||
trimX=128
|
||||
trimY=0
|
||||
backRect=Rect.new(0,0,128,128)
|
||||
blindsRect=nil
|
||||
trimX = 128
|
||||
trimY = 0
|
||||
backRect = Rect.new(0, 0, 128, 128)
|
||||
blindsRect = nil
|
||||
end
|
||||
@sprites["corner0"].src_rect.set(trimX,trimY+0,16,16);
|
||||
@sprites["corner1"].src_rect.set(trimX+48,trimY+0,16,16);
|
||||
@sprites["corner2"].src_rect.set(trimX,trimY+48,16,16);
|
||||
@sprites["corner3"].src_rect.set(trimX+48,trimY+48,16,16);
|
||||
@sprites["scroll0"].src_rect.set(trimX+24, trimY+16, 16, 8) # up
|
||||
@sprites["scroll3"].src_rect.set(trimX+24, trimY+40, 16, 8) # down
|
||||
@sprites["scroll1"].src_rect.set(trimX+16, trimY+24, 8, 16) # left
|
||||
@sprites["scroll2"].src_rect.set(trimX+40, trimY+24, 8, 16) # right
|
||||
cursorX=trimX
|
||||
cursorY=trimY+64
|
||||
sideRects=[
|
||||
Rect.new(trimX+16,trimY+0,32,16),
|
||||
Rect.new(trimX,trimY+16,16,32),
|
||||
Rect.new(trimX+48,trimY+16,16,32),
|
||||
Rect.new(trimX+16,trimY+48,32,16)
|
||||
@sprites["corner0"].src_rect.set(trimX, trimY + 0, 16, 16)
|
||||
@sprites["corner1"].src_rect.set(trimX + 48, trimY + 0, 16, 16)
|
||||
@sprites["corner2"].src_rect.set(trimX, trimY + 48, 16, 16)
|
||||
@sprites["corner3"].src_rect.set(trimX + 48, trimY + 48, 16, 16)
|
||||
@sprites["scroll0"].src_rect.set(trimX + 24, trimY + 16, 16, 8) # up
|
||||
@sprites["scroll3"].src_rect.set(trimX + 24, trimY + 40, 16, 8) # down
|
||||
@sprites["scroll1"].src_rect.set(trimX + 16, trimY + 24, 8, 16) # left
|
||||
@sprites["scroll2"].src_rect.set(trimX + 40, trimY + 24, 8, 16) # right
|
||||
cursorX = trimX
|
||||
cursorY = trimY + 64
|
||||
sideRects = [
|
||||
Rect.new(trimX + 16, trimY + 0, 32, 16),
|
||||
Rect.new(trimX, trimY + 16, 16, 32),
|
||||
Rect.new(trimX + 48, trimY + 16, 16, 32),
|
||||
Rect.new(trimX + 16, trimY + 48, 32, 16)
|
||||
]
|
||||
if @width>32 && @height>32
|
||||
@sprites["contents"].src_rect.set(@ox,@oy,@width-32,@height-32)
|
||||
if @width > 32 && @height > 32
|
||||
@sprites["contents"].src_rect.set(@ox, @oy, @width - 32, @height - 32)
|
||||
else
|
||||
@sprites["contents"].src_rect.set(0,0,0,0)
|
||||
@sprites["contents"].src_rect.set(0, 0, 0, 0)
|
||||
end
|
||||
pauseRects=[
|
||||
trimX+32,trimY+64,
|
||||
trimX+48,trimY+64,
|
||||
trimX+32,trimY+80,
|
||||
trimX+48,trimY+80,
|
||||
pauseRects = [
|
||||
trimX + 32, trimY + 64,
|
||||
trimX + 48, trimY + 64,
|
||||
trimX + 32, trimY + 80,
|
||||
trimX + 48, trimY + 80
|
||||
]
|
||||
pauseWidth=16
|
||||
pauseHeight=16
|
||||
@sprites["pause"].src_rect.set(
|
||||
pauseRects[@pauseframe*2],
|
||||
pauseRects[@pauseframe*2+1],
|
||||
pauseWidth,pauseHeight
|
||||
)
|
||||
@sprites["pause"].x=@x+(@width/2)-(pauseWidth/2)
|
||||
@sprites["pause"].y=@y+@height-16 # 16 refers to skin margin
|
||||
@sprites["contents"].x=@x+16
|
||||
@sprites["contents"].y=@y+16
|
||||
@sprites["corner0"].x=@x
|
||||
@sprites["corner0"].y=@y
|
||||
@sprites["corner1"].x=@x+@width-16
|
||||
@sprites["corner1"].y=@y
|
||||
@sprites["corner2"].x=@x
|
||||
@sprites["corner2"].y=@y+@height-16
|
||||
@sprites["corner3"].x=@x+@width-16
|
||||
@sprites["corner3"].y=@y+@height-16
|
||||
@sprites["side0"].x=@x+16
|
||||
@sprites["side0"].y=@y
|
||||
@sprites["side1"].x=@x
|
||||
@sprites["side1"].y=@y+16
|
||||
@sprites["side2"].x=@x+@width-16
|
||||
@sprites["side2"].y=@y+16
|
||||
@sprites["side3"].x=@x+16
|
||||
@sprites["side3"].y=@y+@height-16
|
||||
@sprites["scroll0"].x = @x+@width / 2 - 8
|
||||
@sprites["scroll0"].y = @y+8
|
||||
@sprites["scroll1"].x = @x+8
|
||||
@sprites["scroll1"].y = @y+@height / 2 - 8
|
||||
@sprites["scroll2"].x = @x+@width - 16
|
||||
@sprites["scroll2"].y = @y+@height / 2 - 8
|
||||
@sprites["scroll3"].x = @x+@width / 2 - 8
|
||||
@sprites["scroll3"].y = @y+@height - 16
|
||||
@sprites["back"].x=@x+2
|
||||
@sprites["back"].y=@y+2
|
||||
@sprites["cursor"].x=@x+16+@cursor_rect.x
|
||||
@sprites["cursor"].y=@y+16+@cursor_rect.y
|
||||
pauseWidth = 16
|
||||
pauseHeight = 16
|
||||
@sprites["pause"].src_rect.set(pauseRects[@pauseframe * 2],
|
||||
pauseRects[(@pauseframe * 2) + 1],
|
||||
pauseWidth,
|
||||
pauseHeight)
|
||||
@sprites["pause"].x = @x + (@width / 2) - (pauseWidth / 2)
|
||||
@sprites["pause"].y = @y + @height - 16 # 16 refers to skin margin
|
||||
@sprites["contents"].x = @x + 16
|
||||
@sprites["contents"].y = @y + 16
|
||||
@sprites["corner0"].x = @x
|
||||
@sprites["corner0"].y = @y
|
||||
@sprites["corner1"].x = @x + @width - 16
|
||||
@sprites["corner1"].y = @y
|
||||
@sprites["corner2"].x = @x
|
||||
@sprites["corner2"].y = @y + @height - 16
|
||||
@sprites["corner3"].x = @x + @width - 16
|
||||
@sprites["corner3"].y = @y + @height - 16
|
||||
@sprites["side0"].x = @x + 16
|
||||
@sprites["side0"].y = @y
|
||||
@sprites["side1"].x = @x
|
||||
@sprites["side1"].y = @y + 16
|
||||
@sprites["side2"].x = @x + @width - 16
|
||||
@sprites["side2"].y = @y + 16
|
||||
@sprites["side3"].x = @x + 16
|
||||
@sprites["side3"].y = @y + @height - 16
|
||||
@sprites["scroll0"].x = @x + (@width / 2) - 8
|
||||
@sprites["scroll0"].y = @y + 8
|
||||
@sprites["scroll1"].x = @x + 8
|
||||
@sprites["scroll1"].y = @y + (@height / 2) - 8
|
||||
@sprites["scroll2"].x = @x + @width - 16
|
||||
@sprites["scroll2"].y = @y + (@height / 2) - 8
|
||||
@sprites["scroll3"].x = @x + (@width / 2) - 8
|
||||
@sprites["scroll3"].y = @y + @height - 16
|
||||
@sprites["back"].x = @x + 2
|
||||
@sprites["back"].y = @y + 2
|
||||
@sprites["cursor"].x = @x + 16 + @cursor_rect.x
|
||||
@sprites["cursor"].y = @y + 16 + @cursor_rect.y
|
||||
if changeBitmap && @_windowskin && !@_windowskin.disposed?
|
||||
width=@cursor_rect.width
|
||||
height=@cursor_rect.height
|
||||
width = @cursor_rect.width
|
||||
height = @cursor_rect.height
|
||||
if width > 0 && height > 0
|
||||
cursorrects=[
|
||||
# sides
|
||||
Rect.new(cursorX+2, cursorY+0, 28, 2),
|
||||
Rect.new(cursorX+0, cursorY+2, 2, 28),
|
||||
Rect.new(cursorX+30, cursorY+2, 2, 28),
|
||||
Rect.new(cursorX+2, cursorY+30, 28, 2),
|
||||
# corners
|
||||
Rect.new(cursorX+0, cursorY+0, 2, 2),
|
||||
Rect.new(cursorX+30, cursorY+0, 2, 2),
|
||||
Rect.new(cursorX+0, cursorY+30, 2, 2),
|
||||
Rect.new(cursorX+30, cursorY+30, 2, 2),
|
||||
# back
|
||||
Rect.new(cursorX+2, cursorY+2, 28, 28)
|
||||
cursorrects = [
|
||||
# sides
|
||||
Rect.new(cursorX + 2, cursorY + 0, 28, 2),
|
||||
Rect.new(cursorX + 0, cursorY + 2, 2, 28),
|
||||
Rect.new(cursorX + 30, cursorY + 2, 2, 28),
|
||||
Rect.new(cursorX + 2, cursorY + 30, 28, 2),
|
||||
# corners
|
||||
Rect.new(cursorX + 0, cursorY + 0, 2, 2),
|
||||
Rect.new(cursorX + 30, cursorY + 0, 2, 2),
|
||||
Rect.new(cursorX + 0, cursorY + 30, 2, 2),
|
||||
Rect.new(cursorX + 30, cursorY + 30, 2, 2),
|
||||
# back
|
||||
Rect.new(cursorX + 2, cursorY + 2, 28, 28)
|
||||
]
|
||||
margin=2
|
||||
fullmargin=4
|
||||
margin = 2
|
||||
fullmargin = 4
|
||||
@cursorbitmap = ensureBitmap(@cursorbitmap, width, height)
|
||||
@cursorbitmap.clear
|
||||
@sprites["cursor"].bitmap=@cursorbitmap
|
||||
@sprites["cursor"].src_rect.set(0,0,width,height)
|
||||
rect = Rect.new(margin,margin,
|
||||
width - fullmargin, height - fullmargin)
|
||||
@sprites["cursor"].bitmap = @cursorbitmap
|
||||
@sprites["cursor"].src_rect.set(0, 0, width, height)
|
||||
rect = Rect.new(margin, margin, width - fullmargin, height - fullmargin)
|
||||
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[8])
|
||||
@cursorbitmap.blt(0, 0, @_windowskin, cursorrects[4])# top left
|
||||
@cursorbitmap.blt(width-margin, 0, @_windowskin, cursorrects[5]) # top right
|
||||
@cursorbitmap.blt(0, height-margin, @_windowskin, cursorrects[6]) # bottom right
|
||||
@cursorbitmap.blt(width-margin, height-margin, @_windowskin, cursorrects[7]) # bottom left
|
||||
rect = Rect.new(margin, 0,
|
||||
width - fullmargin, margin)
|
||||
@cursorbitmap.blt(0, 0, @_windowskin, cursorrects[4]) # top left
|
||||
@cursorbitmap.blt(width - margin, 0, @_windowskin, cursorrects[5]) # top right
|
||||
@cursorbitmap.blt(0, height - margin, @_windowskin, cursorrects[6]) # bottom right
|
||||
@cursorbitmap.blt(width - margin, height - margin, @_windowskin, cursorrects[7]) # bottom left
|
||||
rect = Rect.new(margin, 0, width - fullmargin, margin)
|
||||
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[0])
|
||||
rect = Rect.new(0, margin,
|
||||
margin, height - fullmargin)
|
||||
rect = Rect.new(0, margin, margin, height - fullmargin)
|
||||
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[1])
|
||||
rect = Rect.new(width - margin, margin,
|
||||
margin, height - fullmargin)
|
||||
rect = Rect.new(width - margin, margin, margin, height - fullmargin)
|
||||
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[2])
|
||||
rect = Rect.new(margin, height-margin,
|
||||
width - fullmargin, margin)
|
||||
rect = Rect.new(margin, height - margin, width - fullmargin, margin)
|
||||
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[3])
|
||||
else
|
||||
@sprites["cursor"].visible=false
|
||||
@sprites["cursor"].src_rect.set(0,0,0,0)
|
||||
@sprites["cursor"].visible = false
|
||||
@sprites["cursor"].src_rect.set(0, 0, 0, 0)
|
||||
end
|
||||
for i in 0...4
|
||||
dwidth = (i==0 || i==3) ? @width-32 : 16
|
||||
dheight = (i==0 || i==3) ? 16 : @height-32
|
||||
@sidebitmaps[i]=ensureBitmap(@sidebitmaps[i],dwidth,dheight)
|
||||
@sprites["side#{i}"].bitmap=@sidebitmaps[i]
|
||||
@sprites["side#{i}"].src_rect.set(0,0,dwidth,dheight)
|
||||
4.times do |i|
|
||||
dwidth = [0, 3].include?(i) ? @width - 32 : 16
|
||||
dheight = [0, 3].include?(i) ? 16 : @height - 32
|
||||
@sidebitmaps[i] = ensureBitmap(@sidebitmaps[i], dwidth, dheight)
|
||||
@sprites["side#{i}"].bitmap = @sidebitmaps[i]
|
||||
@sprites["side#{i}"].src_rect.set(0, 0, dwidth, dheight)
|
||||
@sidebitmaps[i].clear
|
||||
if sideRects[i].width>0 && sideRects[i].height>0
|
||||
@sidebitmaps[i].stretch_blt(@sprites["side#{i}"].src_rect,
|
||||
@_windowskin,sideRects[i])
|
||||
if sideRects[i].width > 0 && sideRects[i].height > 0
|
||||
@sidebitmaps[i].stretch_blt(@sprites["side#{i}"].src_rect, @_windowskin, sideRects[i])
|
||||
end
|
||||
end
|
||||
backwidth=@width-4
|
||||
backheight=@height-4
|
||||
if backwidth>0 && backheight>0
|
||||
@backbitmap=ensureBitmap(@backbitmap,backwidth,backheight)
|
||||
@sprites["back"].bitmap=@backbitmap
|
||||
@sprites["back"].src_rect.set(0,0,backwidth,backheight)
|
||||
backwidth = @width - 4
|
||||
backheight = @height - 4
|
||||
if backwidth > 0 && backheight > 0
|
||||
@backbitmap = ensureBitmap(@backbitmap, backwidth, backheight)
|
||||
@sprites["back"].bitmap = @backbitmap
|
||||
@sprites["back"].src_rect.set(0, 0, backwidth, backheight)
|
||||
@backbitmap.clear
|
||||
if @stretch
|
||||
@backbitmap.stretch_blt(@sprites["back"].src_rect,@_windowskin,backRect)
|
||||
@backbitmap.stretch_blt(@sprites["back"].src_rect, @_windowskin, backRect)
|
||||
else
|
||||
tileBitmap(@backbitmap,@sprites["back"].src_rect,@_windowskin,backRect)
|
||||
tileBitmap(@backbitmap, @sprites["back"].src_rect, @_windowskin, backRect)
|
||||
end
|
||||
if blindsRect
|
||||
tileBitmap(@backbitmap,@sprites["back"].src_rect,@_windowskin,blindsRect)
|
||||
tileBitmap(@backbitmap, @sprites["back"].src_rect, @_windowskin, blindsRect)
|
||||
end
|
||||
else
|
||||
@sprites["back"].visible=false
|
||||
@sprites["back"].src_rect.set(0,0,0,0)
|
||||
@sprites["back"].visible = false
|
||||
@sprites["back"].src_rect.set(0, 0, 0, 0)
|
||||
end
|
||||
end
|
||||
if @openness!=255
|
||||
opn=@openness/255.0
|
||||
for k in @spritekeys
|
||||
sprite=@sprites[k]
|
||||
ratio=(@height<=0) ? 0 : (sprite.y-@y)*1.0/@height
|
||||
sprite.zoom_y=opn
|
||||
sprite.oy=0
|
||||
sprite.y=(@y+(@height/2.0)+(@height*ratio*opn)-(@height/2*opn)).floor
|
||||
if @openness == 255
|
||||
@spritekeys.each do |k|
|
||||
sprite = @sprites[k]
|
||||
sprite.zoom_y = 1.0
|
||||
end
|
||||
else
|
||||
for k in @spritekeys
|
||||
sprite=@sprites[k]
|
||||
sprite.zoom_y=1.0
|
||||
opn = @openness / 255.0
|
||||
@spritekeys.each do |k|
|
||||
sprite = @sprites[k]
|
||||
ratio = (@height <= 0) ? 0 : (sprite.y - @y) / @height.to_f
|
||||
sprite.zoom_y = opn
|
||||
sprite.oy = 0
|
||||
sprite.y = (@y + (@height / 2.0) + (@height * ratio * opn) - (@height / 2 * opn)).floor
|
||||
end
|
||||
end
|
||||
i=0
|
||||
i = 0
|
||||
# Ensure Z order
|
||||
for k in @spritekeys
|
||||
sprite=@sprites[k]
|
||||
y=sprite.y
|
||||
sprite.y=i
|
||||
sprite.oy=(sprite.zoom_y<=0) ? 0 : (i-y)/sprite.zoom_y
|
||||
@spritekeys.each do |k|
|
||||
sprite = @sprites[k]
|
||||
y = sprite.y
|
||||
sprite.y = i
|
||||
sprite.oy = (sprite.zoom_y <= 0) ? 0 : (i - y) / sprite.zoom_y
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4,16 +4,16 @@
|
||||
class IconWindow < SpriteWindow_Base
|
||||
attr_reader :name
|
||||
|
||||
def initialize(x,y,width,height,viewport=nil)
|
||||
super(x,y,width,height)
|
||||
self.viewport=viewport
|
||||
self.contents=nil
|
||||
@name=""
|
||||
@_iconbitmap=nil
|
||||
def initialize(x, y, width, height, viewport = nil)
|
||||
super(x, y, width, height)
|
||||
self.viewport = viewport
|
||||
self.contents = nil
|
||||
@name = ""
|
||||
@_iconbitmap = nil
|
||||
end
|
||||
|
||||
def dispose
|
||||
clearBitmaps()
|
||||
clearBitmaps
|
||||
super
|
||||
end
|
||||
|
||||
@@ -21,14 +21,14 @@ class IconWindow < SpriteWindow_Base
|
||||
super
|
||||
if @_iconbitmap
|
||||
@_iconbitmap.update
|
||||
self.contents=@_iconbitmap.bitmap
|
||||
self.contents = @_iconbitmap.bitmap
|
||||
end
|
||||
end
|
||||
|
||||
def clearBitmaps
|
||||
@_iconbitmap.dispose if @_iconbitmap
|
||||
@_iconbitmap=nil
|
||||
self.contents=nil if !self.disposed?
|
||||
@_iconbitmap&.dispose
|
||||
@_iconbitmap = nil
|
||||
self.contents = nil if !self.disposed?
|
||||
end
|
||||
|
||||
# Sets the icon's filename. Alias for setBitmap.
|
||||
@@ -37,37 +37,35 @@ class IconWindow < SpriteWindow_Base
|
||||
end
|
||||
|
||||
# Sets the icon's filename.
|
||||
def setBitmap(file,hue=0)
|
||||
clearBitmaps()
|
||||
@name=file
|
||||
return if file==nil
|
||||
if file!=""
|
||||
@_iconbitmap=AnimatedBitmap.new(file,hue)
|
||||
# for compatibility
|
||||
self.contents=@_iconbitmap ? @_iconbitmap.bitmap : nil
|
||||
def setBitmap(file, hue = 0)
|
||||
clearBitmaps
|
||||
@name = file
|
||||
return if file.nil?
|
||||
if file == ""
|
||||
@_iconbitmap = nil
|
||||
else
|
||||
@_iconbitmap=nil
|
||||
@_iconbitmap = AnimatedBitmap.new(file, hue)
|
||||
# for compatibility
|
||||
self.contents = @_iconbitmap ? @_iconbitmap.bitmap : nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Displays an icon bitmap in a window. Supports animated images.
|
||||
# Accepts bitmaps and paths to bitmap files in its constructor.
|
||||
#===============================================================================
|
||||
class PictureWindow < SpriteWindow_Base
|
||||
def initialize(pathOrBitmap)
|
||||
super(0,0,32,32)
|
||||
self.viewport=viewport
|
||||
self.contents=nil
|
||||
@_iconbitmap=nil
|
||||
super(0, 0, 32, 32)
|
||||
self.viewport = viewport
|
||||
self.contents = nil
|
||||
@_iconbitmap = nil
|
||||
setBitmap(pathOrBitmap)
|
||||
end
|
||||
|
||||
def dispose
|
||||
clearBitmaps()
|
||||
clearBitmaps
|
||||
super
|
||||
end
|
||||
|
||||
@@ -75,47 +73,46 @@ class PictureWindow < SpriteWindow_Base
|
||||
super
|
||||
if @_iconbitmap
|
||||
if @_iconbitmap.is_a?(Bitmap)
|
||||
self.contents=@_iconbitmap
|
||||
self.contents = @_iconbitmap
|
||||
else
|
||||
@_iconbitmap.update
|
||||
self.contents=@_iconbitmap.bitmap
|
||||
self.contents = @_iconbitmap.bitmap
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def clearBitmaps
|
||||
@_iconbitmap.dispose if @_iconbitmap
|
||||
@_iconbitmap=nil
|
||||
self.contents=nil if !self.disposed?
|
||||
@_iconbitmap&.dispose
|
||||
@_iconbitmap = nil
|
||||
self.contents = nil if !self.disposed?
|
||||
end
|
||||
|
||||
# Sets the icon's bitmap or filename. (hue parameter
|
||||
# is ignored unless pathOrBitmap is a filename)
|
||||
def setBitmap(pathOrBitmap,hue=0)
|
||||
clearBitmaps()
|
||||
if pathOrBitmap!=nil && pathOrBitmap!=""
|
||||
if pathOrBitmap.is_a?(Bitmap)
|
||||
@_iconbitmap=pathOrBitmap
|
||||
self.contents=@_iconbitmap
|
||||
self.width=@_iconbitmap.width+self.borderX
|
||||
self.height=@_iconbitmap.height+self.borderY
|
||||
elsif pathOrBitmap.is_a?(AnimatedBitmap)
|
||||
@_iconbitmap=pathOrBitmap
|
||||
self.contents=@_iconbitmap.bitmap
|
||||
self.width=@_iconbitmap.bitmap.width+self.borderX
|
||||
self.height=@_iconbitmap.bitmap.height+self.borderY
|
||||
def setBitmap(pathOrBitmap, hue = 0)
|
||||
clearBitmaps
|
||||
if pathOrBitmap && pathOrBitmap != ""
|
||||
case pathOrBitmap
|
||||
when Bitmap
|
||||
@_iconbitmap = pathOrBitmap
|
||||
self.contents = @_iconbitmap
|
||||
self.width = @_iconbitmap.width + self.borderX
|
||||
self.height = @_iconbitmap.height + self.borderY
|
||||
when AnimatedBitmap
|
||||
@_iconbitmap = pathOrBitmap
|
||||
self.contents = @_iconbitmap.bitmap
|
||||
self.width = @_iconbitmap.bitmap.width + self.borderX
|
||||
self.height = @_iconbitmap.bitmap.height + self.borderY
|
||||
else
|
||||
@_iconbitmap=AnimatedBitmap.new(pathOrBitmap,hue)
|
||||
self.contents=@_iconbitmap ? @_iconbitmap.bitmap : nil
|
||||
self.width=@_iconbitmap ? @_iconbitmap.bitmap.width+self.borderX :
|
||||
32+self.borderX
|
||||
self.height=@_iconbitmap ? @_iconbitmap.bitmap.height+self.borderY :
|
||||
32+self.borderY
|
||||
@_iconbitmap = AnimatedBitmap.new(pathOrBitmap, hue)
|
||||
self.contents = @_iconbitmap&.bitmap
|
||||
self.width = self.borderX + (@_iconbitmap&.bitmap&.width || 32)
|
||||
self.height = self.borderY + (@_iconbitmap&.bitmap&.height || 32)
|
||||
end
|
||||
else
|
||||
@_iconbitmap=nil
|
||||
self.width=32+self.borderX
|
||||
self.height=32+self.borderY
|
||||
@_iconbitmap = nil
|
||||
self.width = 32 + self.borderX
|
||||
self.height = 32 + self.borderY
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
371
Data/Scripts/007_Objects and windows/007_BitmapSprite.rb
Normal file
371
Data/Scripts/007_Objects and windows/007_BitmapSprite.rb
Normal file
@@ -0,0 +1,371 @@
|
||||
#===============================================================================
|
||||
# Sprite class that maintains a bitmap of its own.
|
||||
# This bitmap can't be changed to a different one.
|
||||
#===============================================================================
|
||||
class BitmapSprite < Sprite
|
||||
attr_reader :text_themes
|
||||
|
||||
def initialize(width, height, viewport = nil)
|
||||
super(viewport)
|
||||
self.bitmap = Bitmap.new(width, height)
|
||||
@text_themes = {}
|
||||
@initialized = true
|
||||
end
|
||||
|
||||
def dispose
|
||||
self.bitmap.dispose if !self.disposed?
|
||||
super
|
||||
end
|
||||
|
||||
def bitmap=(value)
|
||||
super(value) if !@initialized
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def add_text_theme(id, base_color, shadow_color = nil)
|
||||
@text_themes[id] = [base_color, shadow_color]
|
||||
end
|
||||
|
||||
# TODO: Replaces def pbDrawTextPositions.
|
||||
def draw_themed_text(string, text_x, text_y, align = :left, theme = :default, outline = :shadow)
|
||||
string_size = self.bitmap.text_size(string)
|
||||
case align
|
||||
when :right
|
||||
text_x -= string_size.width
|
||||
when :center
|
||||
text_x -= (string_size.width / 2)
|
||||
end
|
||||
if !@text_themes[theme]
|
||||
theme = (@text_themes[:default]) ? :default : @text_themes.keys.first
|
||||
end
|
||||
case outline || :shadow
|
||||
when :shadow
|
||||
draw_shadowed_text(string, text_x, text_y, theme)
|
||||
when :outline
|
||||
draw_outlined_text(string, text_x, text_y, theme)
|
||||
when :none
|
||||
draw_plain_text(string, text_x, text_y, theme)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Replaces def pbDrawShadowText.
|
||||
def draw_shadowed_text(string, text_x, text_y, theme)
|
||||
return if !@text_themes[theme]
|
||||
base_color, shadow_color = @text_themes[theme]
|
||||
string_size = self.bitmap.text_size(string)
|
||||
string_width = string_size.width + 1
|
||||
string_height = string_size.height + 1
|
||||
if shadow_color && shadow_color.alpha > 0
|
||||
self.bitmap.font.color = shadow_color
|
||||
self.bitmap.draw_text(text_x + 2, text_y, string_width, string_height, string, 0)
|
||||
self.bitmap.draw_text(text_x, text_y + 2, string_width, string_height, string, 0)
|
||||
self.bitmap.draw_text(text_x + 2, text_y + 2, string_width, string_height, string, 0)
|
||||
end
|
||||
if base_color && base_color.alpha > 0
|
||||
self.bitmap.font.color = base_color
|
||||
self.bitmap.draw_text(text_x, text_y, string_width, string_height, string, 0)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Replaces def pbDrawOutlineText.
|
||||
def draw_outlined_text(string, text_x, text_y, theme)
|
||||
return if !@text_themes[theme]
|
||||
base_color, shadow_color = @text_themes[theme]
|
||||
string_size = self.bitmap.text_size(string)
|
||||
string_width = string_size.width + 1
|
||||
string_height = string_size.height + 1
|
||||
if shadow_color && shadow_color.alpha > 0
|
||||
self.bitmap.font.color = shadow_color
|
||||
self.bitmap.draw_text(text_x - 2, text_y - 2, string_width, string_height, string, 0)
|
||||
self.bitmap.draw_text(text_x, text_y - 2, string_width, string_height, string, 0)
|
||||
self.bitmap.draw_text(text_x + 2, text_y - 2, string_width, string_height, string, 0)
|
||||
self.bitmap.draw_text(text_x - 2, text_y, string_width, string_height, string, 0)
|
||||
self.bitmap.draw_text(text_x + 2, text_y, string_width, string_height, string, 0)
|
||||
self.bitmap.draw_text(text_x - 2, text_y + 2, string_width, string_height, string, 0)
|
||||
self.bitmap.draw_text(text_x, text_y + 2, string_width, string_height, string, 0)
|
||||
self.bitmap.draw_text(text_x + 2, text_y + 2, string_width, string_height, string, 0)
|
||||
end
|
||||
if base_color && base_color.alpha > 0
|
||||
self.bitmap.font.color = base_color
|
||||
self.bitmap.draw_text(text_x, text_y, string_width, string_height, string, 0)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Replaces def pbDrawPlainText.
|
||||
def draw_plain_text(string, text_x, text_y, theme)
|
||||
return if !@text_themes[theme]
|
||||
base_color = @text_themes[theme][0]
|
||||
return if !base_color || base_color.alpha == 0
|
||||
string_size = self.bitmap.text_size(string)
|
||||
string_width = string_size.width + 1
|
||||
string_height = string_size.height + 1
|
||||
self.bitmap.font.color = base_color
|
||||
self.bitmap.draw_text(text_x, text_y, string_width, string_height, string, 0)
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
# TODO: Replaces def pbDrawImagePositions.
|
||||
def draw_image(filename, image_x, image_y, src_x = 0, src_y = 0, src_width = -1, src_height = -1)
|
||||
src_bitmap = (filename.is_a?(AnimatedBitmap)) ? filename : AnimatedBitmap.new(pbBitmapName(filename))
|
||||
src_width = (src_width >= 0) ? src_width : src_bitmap.width
|
||||
src_height = (src_height >= 0) ? src_height : src_bitmap.height
|
||||
src_rect = Rect.new(src_x, src_y, src_width, src_height)
|
||||
self.bitmap.blt(image_x, image_y, src_bitmap.bitmap, src_rect)
|
||||
src_bitmap.dispose if !filename.is_a?(AnimatedBitmap)
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class AnimatedSprite < Sprite
|
||||
attr_reader :frame
|
||||
attr_reader :framewidth
|
||||
attr_reader :frameheight
|
||||
attr_reader :framecount
|
||||
attr_reader :animname
|
||||
|
||||
# frameskip is in 1/20ths of a second, and is the time between frame changes.
|
||||
def initializeLong(animname, framecount, framewidth, frameheight, frameskip)
|
||||
@animname = pbBitmapName(animname)
|
||||
@time_per_frame = [1, frameskip].max / 20.0
|
||||
raise _INTL("Frame width is 0") if framewidth == 0
|
||||
raise _INTL("Frame height is 0") if frameheight == 0
|
||||
begin
|
||||
@animbitmap = AnimatedBitmap.new(animname).deanimate
|
||||
rescue
|
||||
@animbitmap = Bitmap.new(framewidth, frameheight)
|
||||
end
|
||||
if @animbitmap.width % framewidth != 0
|
||||
raise _INTL("Bitmap's width ({1}) is not a multiple of frame width ({2}) [Bitmap={3}]",
|
||||
@animbitmap.width, framewidth, animname)
|
||||
end
|
||||
if @animbitmap.height % frameheight != 0
|
||||
raise _INTL("Bitmap's height ({1}) is not a multiple of frame height ({2}) [Bitmap={3}]",
|
||||
@animbitmap.height, frameheight, animname)
|
||||
end
|
||||
@framecount = framecount
|
||||
@framewidth = framewidth
|
||||
@frameheight = frameheight
|
||||
@framesperrow = @animbitmap.width / @framewidth
|
||||
@playing = false
|
||||
self.bitmap = @animbitmap
|
||||
self.src_rect.width = @framewidth
|
||||
self.src_rect.height = @frameheight
|
||||
self.frame = 0
|
||||
end
|
||||
|
||||
# Shorter version of AnimatedSprite. All frames are placed on a single row
|
||||
# of the bitmap, so that the width and height need not be defined beforehand.
|
||||
# frameskip is in 1/20ths of a second, and is the time between frame changes.
|
||||
def initializeShort(animname, framecount, frameskip)
|
||||
@animname = pbBitmapName(animname)
|
||||
@time_per_frame = [1, frameskip].max / 20.0
|
||||
begin
|
||||
@animbitmap = AnimatedBitmap.new(animname).deanimate
|
||||
rescue
|
||||
@animbitmap = Bitmap.new(framecount * 4, 32)
|
||||
end
|
||||
if @animbitmap.width % framecount != 0
|
||||
raise _INTL("Bitmap's width ({1}) is not a multiple of frame count ({2}) [Bitmap={3}]",
|
||||
@animbitmap.width, framewidth, animname)
|
||||
end
|
||||
@framecount = framecount
|
||||
@framewidth = @animbitmap.width / @framecount
|
||||
@frameheight = @animbitmap.height
|
||||
@framesperrow = framecount
|
||||
@playing = false
|
||||
self.bitmap = @animbitmap
|
||||
self.src_rect.width = @framewidth
|
||||
self.src_rect.height = @frameheight
|
||||
self.frame = 0
|
||||
end
|
||||
|
||||
def initialize(*args)
|
||||
if args.length == 1
|
||||
super(args[0][3])
|
||||
initializeShort(args[0][0], args[0][1], args[0][2])
|
||||
else
|
||||
super(args[5])
|
||||
initializeLong(args[0], args[1], args[2], args[3], args[4])
|
||||
end
|
||||
end
|
||||
|
||||
def self.create(animname, framecount, frameskip, viewport = nil)
|
||||
return self.new([animname, framecount, frameskip, viewport])
|
||||
end
|
||||
|
||||
def dispose
|
||||
return if disposed?
|
||||
@animbitmap.dispose
|
||||
@animbitmap = nil
|
||||
super
|
||||
end
|
||||
|
||||
def playing?
|
||||
return @playing
|
||||
end
|
||||
|
||||
def frame=(value)
|
||||
@frame = value
|
||||
self.src_rect.x = @frame % @framesperrow * @framewidth
|
||||
self.src_rect.y = @frame / @framesperrow * @frameheight
|
||||
end
|
||||
|
||||
def start
|
||||
@playing = true
|
||||
end
|
||||
|
||||
alias play start
|
||||
|
||||
def stop
|
||||
@playing = false
|
||||
end
|
||||
|
||||
def update
|
||||
super
|
||||
if @playing
|
||||
new_frame = (System.uptime / @time_per_frame).to_i % self.framecount
|
||||
self.frame = new_frame if self.frame != new_frame
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Displays an icon bitmap in a sprite. Supports animated images.
|
||||
#===============================================================================
|
||||
class IconSprite < Sprite
|
||||
attr_reader :name
|
||||
|
||||
def initialize(*args)
|
||||
case args.length
|
||||
when 0
|
||||
super(nil)
|
||||
self.bitmap = nil
|
||||
when 1
|
||||
super(args[0])
|
||||
self.bitmap = nil
|
||||
when 2
|
||||
super(nil)
|
||||
self.x = args[0]
|
||||
self.y = args[1]
|
||||
else
|
||||
super(args[2])
|
||||
self.x = args[0]
|
||||
self.y = args[1]
|
||||
end
|
||||
@name = ""
|
||||
@_iconbitmap = nil
|
||||
end
|
||||
|
||||
def dispose
|
||||
clearBitmaps
|
||||
super
|
||||
end
|
||||
|
||||
# Sets the icon's filename. Alias for setBitmap.
|
||||
def name=(value)
|
||||
setBitmap(value)
|
||||
end
|
||||
|
||||
# Sets the icon's filename.
|
||||
def setBitmap(file, hue = 0)
|
||||
oldrc = self.src_rect
|
||||
clearBitmaps
|
||||
@name = file
|
||||
return if file.nil?
|
||||
if file == ""
|
||||
@_iconbitmap = nil
|
||||
else
|
||||
@_iconbitmap = AnimatedBitmap.new(file, hue)
|
||||
# for compatibility
|
||||
self.bitmap = @_iconbitmap ? @_iconbitmap.bitmap : nil
|
||||
self.src_rect = oldrc
|
||||
end
|
||||
end
|
||||
|
||||
def clearBitmaps
|
||||
@_iconbitmap&.dispose
|
||||
@_iconbitmap = nil
|
||||
self.bitmap = nil if !self.disposed?
|
||||
end
|
||||
|
||||
def update
|
||||
super
|
||||
return if !@_iconbitmap
|
||||
@_iconbitmap.update
|
||||
if self.bitmap != @_iconbitmap.bitmap
|
||||
oldrc = self.src_rect
|
||||
self.bitmap = @_iconbitmap.bitmap
|
||||
self.src_rect = oldrc
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Sprite class that stores multiple bitmaps, and displays only one at once.
|
||||
#===============================================================================
|
||||
class ChangelingSprite < Sprite
|
||||
# Key is the mode (a symbol).
|
||||
# Value is one of:
|
||||
# filepath
|
||||
# [filepath, src_x, src_y, src_width, src_height]
|
||||
BITMAPS = {}
|
||||
|
||||
def initialize(x = 0, y = 0, viewport = nil)
|
||||
super(viewport)
|
||||
self.x = x
|
||||
self.y = y
|
||||
@bitmaps = {}
|
||||
@changeling_data = {}
|
||||
@current_bitmap = nil
|
||||
initialize_changeling_data
|
||||
end
|
||||
|
||||
def initialize_changeling_data
|
||||
self.class::BITMAPS.each_pair { |mode, data| add_bitmap(mode, data) }
|
||||
end
|
||||
|
||||
def dispose
|
||||
return if disposed?
|
||||
@bitmaps.each_value { |bm| bm.dispose }
|
||||
@bitmaps.clear
|
||||
super
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def add_bitmap(mode, *data)
|
||||
raise ArgumentError.new(_INTL("wrong number of arguments (given {1}, expected 2 or 6)", data.length + 1)) if ![1, 5].include?(data.length)
|
||||
filepath = (data[0].is_a?(Array)) ? data[0][0] : data[0]
|
||||
@bitmaps[filepath] = AnimatedBitmap.new(filepath) if !@bitmaps[filepath]
|
||||
@changeling_data[mode] = (data[0].is_a?(Array) ? data[0].clone : [data[0]])
|
||||
end
|
||||
|
||||
def change_bitmap(mode)
|
||||
@current_mode = mode
|
||||
if @current_mode && @changeling_data[@current_mode]
|
||||
data = @changeling_data[@current_mode]
|
||||
@current_bitmap = @bitmaps[data[0]]
|
||||
self.bitmap = @current_bitmap.bitmap
|
||||
if data.length > 1
|
||||
self.src_rect.set(data[1], data[2], data[3], data[4])
|
||||
else
|
||||
self.src_rect.set(0, 0, self.bitmap.width, self.bitmap.height)
|
||||
end
|
||||
else
|
||||
@current_bitmap = nil
|
||||
self.bitmap = nil
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def update
|
||||
return if disposed?
|
||||
@bitmaps.each_value { |bm| bm.update }
|
||||
self.bitmap = @current_bitmap.bitmap if @current_bitmap
|
||||
end
|
||||
end
|
||||
@@ -1,359 +0,0 @@
|
||||
#===============================================================================
|
||||
# SpriteWrapper is a class which wraps (most of) Sprite's properties.
|
||||
#===============================================================================
|
||||
class SpriteWrapper
|
||||
def initialize(viewport=nil)
|
||||
@sprite = Sprite.new(viewport)
|
||||
end
|
||||
|
||||
def dispose; @sprite.dispose; end
|
||||
def disposed?; return @sprite.disposed?; end
|
||||
def viewport; return @sprite.viewport; end
|
||||
def flash(color,duration); return @sprite.flash(color,duration); end
|
||||
def update; return @sprite.update; end
|
||||
def x; @sprite.x; end
|
||||
def x=(value); @sprite.x = value; end
|
||||
def y; @sprite.y; end
|
||||
def y=(value); @sprite.y = value; end
|
||||
def bitmap; @sprite.bitmap; end
|
||||
def bitmap=(value); @sprite.bitmap = value; end
|
||||
def src_rect; @sprite.src_rect; end
|
||||
def src_rect=(value); @sprite.src_rect = value; end
|
||||
def visible; @sprite.visible; end
|
||||
def visible=(value); @sprite.visible = value; end
|
||||
def z; @sprite.z; end
|
||||
def z=(value); @sprite.z = value; end
|
||||
def ox; @sprite.ox; end
|
||||
def ox=(value); @sprite.ox = value; end
|
||||
def oy; @sprite.oy; end
|
||||
def oy=(value); @sprite.oy = value; end
|
||||
def zoom_x; @sprite.zoom_x; end
|
||||
def zoom_x=(value); @sprite.zoom_x = value; end
|
||||
def zoom_y; @sprite.zoom_y; end
|
||||
def zoom_y=(value); @sprite.zoom_y = value; end
|
||||
def angle; @sprite.angle; end
|
||||
def angle=(value); @sprite.angle = value; end
|
||||
def mirror; @sprite.mirror; end
|
||||
def mirror=(value); @sprite.mirror = value; end
|
||||
def bush_depth; @sprite.bush_depth; end
|
||||
def bush_depth=(value); @sprite.bush_depth = value; end
|
||||
def opacity; @sprite.opacity; end
|
||||
def opacity=(value); @sprite.opacity = value; end
|
||||
def blend_type; @sprite.blend_type; end
|
||||
def blend_type=(value); @sprite.blend_type = value; end
|
||||
def color; @sprite.color; end
|
||||
def color=(value); @sprite.color = value; end
|
||||
def tone; @sprite.tone; end
|
||||
def tone=(value); @sprite.tone = value; end
|
||||
|
||||
def viewport=(value)
|
||||
return if self.viewport==value
|
||||
bitmap = @sprite.bitmap
|
||||
src_rect = @sprite.src_rect
|
||||
visible = @sprite.visible
|
||||
x = @sprite.x
|
||||
y = @sprite.y
|
||||
z = @sprite.z
|
||||
ox = @sprite.ox
|
||||
oy = @sprite.oy
|
||||
zoom_x = @sprite.zoom_x
|
||||
zoom_y = @sprite.zoom_y
|
||||
angle = @sprite.angle
|
||||
mirror = @sprite.mirror
|
||||
bush_depth = @sprite.bush_depth
|
||||
opacity = @sprite.opacity
|
||||
blend_type = @sprite.blend_type
|
||||
color = @sprite.color
|
||||
tone = @sprite.tone
|
||||
@sprite.dispose
|
||||
@sprite = Sprite.new(value)
|
||||
@sprite.bitmap = bitmap
|
||||
@sprite.src_rect = src_rect
|
||||
@sprite.visible = visible
|
||||
@sprite.x = x
|
||||
@sprite.y = y
|
||||
@sprite.z = z
|
||||
@sprite.ox = ox
|
||||
@sprite.oy = oy
|
||||
@sprite.zoom_x = zoom_x
|
||||
@sprite.zoom_y = zoom_y
|
||||
@sprite.angle = angle
|
||||
@sprite.mirror = mirror
|
||||
@sprite.bush_depth = bush_depth
|
||||
@sprite.opacity = opacity
|
||||
@sprite.blend_type = blend_type
|
||||
@sprite.color = color
|
||||
@sprite.tone = tone
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Sprite class that maintains a bitmap of its own.
|
||||
# This bitmap can't be changed to a different one.
|
||||
#===============================================================================
|
||||
class BitmapSprite < SpriteWrapper
|
||||
def initialize(width,height,viewport=nil)
|
||||
super(viewport)
|
||||
self.bitmap=Bitmap.new(width,height)
|
||||
@initialized=true
|
||||
end
|
||||
|
||||
def bitmap=(value)
|
||||
super(value) if !@initialized
|
||||
end
|
||||
|
||||
def dispose
|
||||
self.bitmap.dispose if !self.disposed?
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class AnimatedSprite < SpriteWrapper
|
||||
attr_reader :frame
|
||||
attr_reader :framewidth
|
||||
attr_reader :frameheight
|
||||
attr_reader :framecount
|
||||
attr_reader :animname
|
||||
|
||||
def initializeLong(animname,framecount,framewidth,frameheight,frameskip)
|
||||
@animname=pbBitmapName(animname)
|
||||
@realframes=0
|
||||
@frameskip=[1,frameskip].max
|
||||
@frameskip *= Graphics.frame_rate/20
|
||||
raise _INTL("Frame width is 0") if framewidth==0
|
||||
raise _INTL("Frame height is 0") if frameheight==0
|
||||
begin
|
||||
@animbitmap=AnimatedBitmap.new(animname).deanimate
|
||||
rescue
|
||||
@animbitmap=Bitmap.new(framewidth,frameheight)
|
||||
end
|
||||
if @animbitmap.width%framewidth!=0
|
||||
raise _INTL("Bitmap's width ({1}) is not a multiple of frame width ({2}) [Bitmap={3}]",
|
||||
@animbitmap.width,framewidth,animname)
|
||||
end
|
||||
if @animbitmap.height%frameheight!=0
|
||||
raise _INTL("Bitmap's height ({1}) is not a multiple of frame height ({2}) [Bitmap={3}]",
|
||||
@animbitmap.height,frameheight,animname)
|
||||
end
|
||||
@framecount=framecount
|
||||
@framewidth=framewidth
|
||||
@frameheight=frameheight
|
||||
@framesperrow=@animbitmap.width/@framewidth
|
||||
@playing=false
|
||||
self.bitmap=@animbitmap
|
||||
self.src_rect.width=@framewidth
|
||||
self.src_rect.height=@frameheight
|
||||
self.frame=0
|
||||
end
|
||||
|
||||
# Shorter version of AnimationSprite. All frames are placed on a single row
|
||||
# of the bitmap, so that the width and height need not be defined beforehand
|
||||
def initializeShort(animname,framecount,frameskip)
|
||||
@animname=pbBitmapName(animname)
|
||||
@realframes=0
|
||||
@frameskip=[1,frameskip].max
|
||||
@frameskip *= Graphics.frame_rate/20
|
||||
begin
|
||||
@animbitmap=AnimatedBitmap.new(animname).deanimate
|
||||
rescue
|
||||
@animbitmap=Bitmap.new(framecount*4,32)
|
||||
end
|
||||
if @animbitmap.width%framecount!=0
|
||||
raise _INTL("Bitmap's width ({1}) is not a multiple of frame count ({2}) [Bitmap={3}]",
|
||||
@animbitmap.width,framewidth,animname)
|
||||
end
|
||||
@framecount=framecount
|
||||
@framewidth=@animbitmap.width/@framecount
|
||||
@frameheight=@animbitmap.height
|
||||
@framesperrow=framecount
|
||||
@playing=false
|
||||
self.bitmap=@animbitmap
|
||||
self.src_rect.width=@framewidth
|
||||
self.src_rect.height=@frameheight
|
||||
self.frame=0
|
||||
end
|
||||
|
||||
def initialize(*args)
|
||||
if args.length==1
|
||||
super(args[0][3])
|
||||
initializeShort(args[0][0],args[0][1],args[0][2])
|
||||
else
|
||||
super(args[5])
|
||||
initializeLong(args[0],args[1],args[2],args[3],args[4])
|
||||
end
|
||||
end
|
||||
|
||||
def self.create(animname,framecount,frameskip,viewport=nil)
|
||||
return self.new([animname,framecount,frameskip,viewport])
|
||||
end
|
||||
|
||||
def dispose
|
||||
return if disposed?
|
||||
@animbitmap.dispose
|
||||
@animbitmap=nil
|
||||
super
|
||||
end
|
||||
|
||||
def playing?
|
||||
return @playing
|
||||
end
|
||||
|
||||
def frame=(value)
|
||||
@frame=value
|
||||
@realframes=0
|
||||
self.src_rect.x=@frame%@framesperrow*@framewidth
|
||||
self.src_rect.y=@frame/@framesperrow*@frameheight
|
||||
end
|
||||
|
||||
def start
|
||||
@playing=true
|
||||
@realframes=0
|
||||
end
|
||||
|
||||
alias play start
|
||||
|
||||
def stop
|
||||
@playing=false
|
||||
end
|
||||
|
||||
def update
|
||||
super
|
||||
if @playing
|
||||
@realframes+=1
|
||||
if @realframes==@frameskip
|
||||
@realframes=0
|
||||
self.frame+=1
|
||||
self.frame%=self.framecount
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Displays an icon bitmap in a sprite. Supports animated images.
|
||||
#===============================================================================
|
||||
class IconSprite < SpriteWrapper
|
||||
attr_reader :name
|
||||
|
||||
def initialize(*args)
|
||||
if args.length==0
|
||||
super(nil)
|
||||
self.bitmap=nil
|
||||
elsif args.length==1
|
||||
super(args[0])
|
||||
self.bitmap=nil
|
||||
elsif args.length==2
|
||||
super(nil)
|
||||
self.x=args[0]
|
||||
self.y=args[1]
|
||||
else
|
||||
super(args[2])
|
||||
self.x=args[0]
|
||||
self.y=args[1]
|
||||
end
|
||||
@name=""
|
||||
@_iconbitmap=nil
|
||||
end
|
||||
|
||||
def dispose
|
||||
clearBitmaps()
|
||||
super
|
||||
end
|
||||
|
||||
# Sets the icon's filename. Alias for setBitmap.
|
||||
def name=(value)
|
||||
setBitmap(value)
|
||||
end
|
||||
|
||||
# Sets the icon's filename.
|
||||
def setBitmap(file,hue=0)
|
||||
oldrc=self.src_rect
|
||||
clearBitmaps()
|
||||
@name=file
|
||||
return if file==nil
|
||||
if file!=""
|
||||
@_iconbitmap=AnimatedBitmap.new(file,hue)
|
||||
# for compatibility
|
||||
self.bitmap=@_iconbitmap ? @_iconbitmap.bitmap : nil
|
||||
self.src_rect=oldrc
|
||||
else
|
||||
@_iconbitmap=nil
|
||||
end
|
||||
end
|
||||
|
||||
def clearBitmaps
|
||||
@_iconbitmap.dispose if @_iconbitmap
|
||||
@_iconbitmap=nil
|
||||
self.bitmap=nil if !self.disposed?
|
||||
end
|
||||
|
||||
def update
|
||||
super
|
||||
return if !@_iconbitmap
|
||||
@_iconbitmap.update
|
||||
if self.bitmap!=@_iconbitmap.bitmap
|
||||
oldrc=self.src_rect
|
||||
self.bitmap=@_iconbitmap.bitmap
|
||||
self.src_rect=oldrc
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Old GifSprite class, retained for compatibility
|
||||
#===============================================================================
|
||||
class GifSprite < IconSprite
|
||||
def initialize(path)
|
||||
super(0,0)
|
||||
setBitmap(path)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# SpriteWrapper that stores multiple bitmaps, and displays only one at once.
|
||||
#===============================================================================
|
||||
class ChangelingSprite < SpriteWrapper
|
||||
def initialize(x=0,y=0,viewport=nil)
|
||||
super(viewport)
|
||||
self.x = x
|
||||
self.y = y
|
||||
@bitmaps = {}
|
||||
@currentBitmap = nil
|
||||
end
|
||||
|
||||
def addBitmap(key,path)
|
||||
@bitmaps[key].dispose if @bitmaps[key]
|
||||
@bitmaps[key] = AnimatedBitmap.new(path)
|
||||
end
|
||||
|
||||
def changeBitmap(key)
|
||||
@currentBitmap = @bitmaps[key]
|
||||
self.bitmap = (@currentBitmap) ? @currentBitmap.bitmap : nil
|
||||
end
|
||||
|
||||
def dispose
|
||||
return if disposed?
|
||||
for bm in @bitmaps.values; bm.dispose; end
|
||||
@bitmaps.clear
|
||||
super
|
||||
end
|
||||
|
||||
def update
|
||||
return if disposed?
|
||||
for bm in @bitmaps.values; bm.update; end
|
||||
self.bitmap = (@currentBitmap) ? @currentBitmap.bitmap : nil
|
||||
end
|
||||
end
|
||||
@@ -5,11 +5,13 @@ class AnimatedBitmap
|
||||
def initialize(file, hue = 0)
|
||||
raise "Filename is nil (missing graphic)." if file.nil?
|
||||
path = file
|
||||
@path = path
|
||||
|
||||
filename = ""
|
||||
if file.last != '/' # Isn't just a directory
|
||||
if file.last != "/" # Isn't just a directory
|
||||
split_file = file.split(/[\\\/]/)
|
||||
filename = split_file.pop
|
||||
path = split_file.join('/') + '/'
|
||||
path = split_file.join("/") + "/"
|
||||
end
|
||||
if filename[/^\[\d+(?:,\d+)?\]/] # Starts with 1 or 2 numbers in square brackets
|
||||
@bitmap = PngAnimatedBitmap.new(path, filename, hue)
|
||||
@@ -31,6 +33,8 @@ class AnimatedBitmap
|
||||
def dispose; @bitmap.dispose; end
|
||||
def deanimate; @bitmap.deanimate; end
|
||||
def copy; @bitmap.copy; end
|
||||
|
||||
def path; @path end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
@@ -43,22 +47,22 @@ class PngAnimatedBitmap
|
||||
def initialize(dir, filename, hue = 0)
|
||||
@frames = []
|
||||
@currentFrame = 0
|
||||
@framecount = 0
|
||||
@timer_start = System.uptime
|
||||
panorama = RPG::Cache.load_bitmap(dir, filename, hue)
|
||||
if filename[/^\[(\d+)(?:,(\d+))?\]/] # Starts with 1 or 2 numbers in brackets
|
||||
# File has a frame count
|
||||
numFrames = $1.to_i
|
||||
delay = $2.to_i
|
||||
delay = 10 if delay == 0
|
||||
duration = $2.to_i # In 1/20ths of a second
|
||||
duration = 5 if duration == 0
|
||||
raise "Invalid frame count in #{filename}" if numFrames <= 0
|
||||
raise "Invalid frame delay in #{filename}" if delay <= 0
|
||||
raise "Invalid frame duration in #{filename}" if duration <= 0
|
||||
if panorama.width % numFrames != 0
|
||||
raise "Bitmap's width (#{panorama.width}) is not divisible by frame count: #{filename}"
|
||||
end
|
||||
@frameDelay = delay
|
||||
@frame_duration = duration / 20.0
|
||||
subWidth = panorama.width / numFrames
|
||||
for i in 0...numFrames
|
||||
subBitmap = BitmapWrapper.new(subWidth, panorama.height)
|
||||
numFrames.times do |i|
|
||||
subBitmap = Bitmap.new(subWidth, panorama.height)
|
||||
subBitmap.blt(0, 0, panorama, Rect.new(subWidth * i, 0, subWidth, panorama.height))
|
||||
@frames.push(subBitmap)
|
||||
end
|
||||
@@ -68,6 +72,16 @@ class PngAnimatedBitmap
|
||||
end
|
||||
end
|
||||
|
||||
def dispose
|
||||
return if @disposed
|
||||
@frames.each { |f| f.dispose }
|
||||
@disposed = true
|
||||
end
|
||||
|
||||
def disposed?
|
||||
return @disposed
|
||||
end
|
||||
|
||||
def [](index)
|
||||
return @frames[index]
|
||||
end
|
||||
@@ -75,15 +89,6 @@ class PngAnimatedBitmap
|
||||
def width; self.bitmap.width; end
|
||||
def height; self.bitmap.height; end
|
||||
|
||||
def deanimate
|
||||
for i in 1...@frames.length
|
||||
@frames[i].dispose
|
||||
end
|
||||
@frames = [@frames[0]]
|
||||
@currentFrame = 0
|
||||
return @frames[0]
|
||||
end
|
||||
|
||||
def bitmap
|
||||
return @frames[@currentFrame]
|
||||
end
|
||||
@@ -92,53 +97,42 @@ class PngAnimatedBitmap
|
||||
return @currentFrame
|
||||
end
|
||||
|
||||
def frameDelay(_index)
|
||||
return @frameDelay
|
||||
end
|
||||
|
||||
def length
|
||||
return @frames.length
|
||||
end
|
||||
|
||||
# Actually returns the total number of 1/20ths of a second this animation lasts.
|
||||
def totalFrames
|
||||
return (@frame_duration * @frames.length * 20).to_i
|
||||
end
|
||||
|
||||
def each
|
||||
@frames.each { |item| yield item }
|
||||
end
|
||||
|
||||
def totalFrames
|
||||
return @frameDelay * @frames.length
|
||||
end
|
||||
|
||||
def disposed?
|
||||
return @disposed
|
||||
end
|
||||
|
||||
def update
|
||||
return if disposed?
|
||||
if @frames.length > 1
|
||||
@framecount += 1
|
||||
if @framecount >= @frameDelay
|
||||
@framecount = 0
|
||||
@currentFrame += 1
|
||||
@currentFrame %= @frames.length
|
||||
end
|
||||
def deanimate
|
||||
(1...@frames.length).each do |i|
|
||||
@frames[i].dispose
|
||||
end
|
||||
end
|
||||
|
||||
def dispose
|
||||
if !@disposed
|
||||
@frames.each { |f| f.dispose }
|
||||
end
|
||||
@disposed = true
|
||||
@frames = [@frames[0]]
|
||||
@currentFrame = 0
|
||||
@frame_duration = 0
|
||||
return @frames[0]
|
||||
end
|
||||
|
||||
def copy
|
||||
x = self.clone
|
||||
x.frames = x.frames.clone
|
||||
for i in 0...x.frames.length
|
||||
x.frames[i] = x.frames[i].copy
|
||||
end
|
||||
x.frames.each_with_index { |frame, i| x.frames[i] = frame.copy }
|
||||
return x
|
||||
end
|
||||
|
||||
def update
|
||||
return if disposed?
|
||||
if @frames.length > 1
|
||||
@currentFrame = ((System.uptime - @timer_start) / @frame_duration).to_i % @frames.length
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
@@ -157,7 +151,7 @@ class GifBitmap
|
||||
rescue
|
||||
@bitmap = nil
|
||||
end
|
||||
@bitmap = BitmapWrapper.new(32, 32) if @bitmap.nil?
|
||||
@bitmap = Bitmap.new(32, 32) if @bitmap.nil?
|
||||
@bitmap.play if @bitmap&.animated?
|
||||
end
|
||||
|
||||
@@ -220,19 +214,19 @@ end
|
||||
#
|
||||
#===============================================================================
|
||||
def pbGetTileBitmap(filename, tile_id, hue, width = 1, height = 1)
|
||||
return RPG::Cache.tileEx(filename, tile_id, hue, width, height) { |f|
|
||||
return RPG::Cache.tileEx(filename, tile_id, hue, width, height) do |f|
|
||||
AnimatedBitmap.new("Graphics/Tilesets/" + filename).deanimate
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def pbGetTileset(name,hue=0)
|
||||
def pbGetTileset(name, hue = 0)
|
||||
return AnimatedBitmap.new("Graphics/Tilesets/" + name, hue).deanimate
|
||||
end
|
||||
|
||||
def pbGetAutotile(name,hue=0)
|
||||
def pbGetAutotile(name, hue = 0)
|
||||
return AnimatedBitmap.new("Graphics/Autotiles/" + name, hue).deanimate
|
||||
end
|
||||
|
||||
def pbGetAnimation(name,hue=0)
|
||||
def pbGetAnimation(name, hue = 0)
|
||||
return AnimatedBitmap.new("Graphics/Animations/" + name, hue).deanimate
|
||||
end
|
||||
|
||||
@@ -6,225 +6,71 @@ class Plane
|
||||
def refresh; end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# This class works around a limitation that planes are always
|
||||
# 640 by 480 pixels in size regardless of the window's size.
|
||||
#===============================================================================
|
||||
class LargePlane < Plane
|
||||
attr_accessor :borderX
|
||||
attr_accessor :borderY
|
||||
|
||||
def initialize(viewport=nil)
|
||||
@__sprite=Sprite.new(viewport)
|
||||
@__disposed=false
|
||||
@__ox=0
|
||||
@__oy=0
|
||||
@__bitmap=nil
|
||||
@__visible=true
|
||||
@__sprite.visible=false
|
||||
@borderX=0
|
||||
@borderY=0
|
||||
end
|
||||
|
||||
def disposed?
|
||||
return @__disposed
|
||||
end
|
||||
|
||||
def dispose
|
||||
if !@__disposed
|
||||
@__sprite.bitmap.dispose if @__sprite.bitmap
|
||||
@__sprite.dispose
|
||||
@__sprite=nil
|
||||
@__bitmap=nil
|
||||
@__disposed=true
|
||||
end
|
||||
#super
|
||||
end
|
||||
|
||||
def ox; @__ox; end
|
||||
def oy; @__oy; end
|
||||
|
||||
def ox=(value);
|
||||
return if @__ox==value
|
||||
@__ox = value
|
||||
refresh
|
||||
end
|
||||
|
||||
def oy=(value);
|
||||
return if @__oy==value
|
||||
@__oy = value
|
||||
refresh
|
||||
end
|
||||
|
||||
def bitmap
|
||||
return @__bitmap
|
||||
end
|
||||
|
||||
def bitmap=(value)
|
||||
if value==nil
|
||||
if @__bitmap!=nil
|
||||
@__bitmap=nil
|
||||
@__sprite.visible=(@__visible && !@__bitmap.nil?)
|
||||
end
|
||||
elsif @__bitmap!=value && !value.disposed?
|
||||
@__bitmap=value
|
||||
refresh
|
||||
elsif value.disposed?
|
||||
if @__bitmap!=nil
|
||||
@__bitmap=nil
|
||||
@__sprite.visible=(@__visible && !@__bitmap.nil?)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def viewport; @__sprite.viewport; end
|
||||
def zoom_x; @__sprite.zoom_x; end
|
||||
def zoom_y; @__sprite.zoom_y; end
|
||||
def opacity; @__sprite.opacity; end
|
||||
def blend_type; @__sprite.blend_type; end
|
||||
def visible; @__visible; end
|
||||
def z; @__sprite.z; end
|
||||
def color; @__sprite.color; end
|
||||
def tone; @__sprite.tone; end
|
||||
|
||||
def zoom_x=(v);
|
||||
return if @__sprite.zoom_x==v
|
||||
@__sprite.zoom_x = v
|
||||
refresh
|
||||
end
|
||||
|
||||
def zoom_y=(v);
|
||||
return if @__sprite.zoom_y==v
|
||||
@__sprite.zoom_y = v
|
||||
refresh
|
||||
end
|
||||
|
||||
def opacity=(v); @__sprite.opacity=(v); end
|
||||
def blend_type=(v); @__sprite.blend_type=(v); end
|
||||
def visible=(v); @__visible=v; @__sprite.visible=(@__visible && !@__bitmap.nil?); end
|
||||
def z=(v); @__sprite.z=(v); end
|
||||
def color=(v); @__sprite.color=(v); end
|
||||
def tone=(v); @__sprite.tone=(v); end
|
||||
def update; ;end
|
||||
|
||||
def refresh
|
||||
@__sprite.visible = (@__visible && !@__bitmap.nil?)
|
||||
if @__bitmap
|
||||
if !@__bitmap.disposed?
|
||||
@__ox += @__bitmap.width*@__sprite.zoom_x if @__ox<0
|
||||
@__oy += @__bitmap.height*@__sprite.zoom_y if @__oy<0
|
||||
@__ox -= @__bitmap.width*@__sprite.zoom_x if @__ox>@__bitmap.width
|
||||
@__oy -= @__bitmap.height*@__sprite.zoom_y if @__oy>@__bitmap.height
|
||||
dwidth = (Graphics.width/@__sprite.zoom_x+@borderX).to_i # +2
|
||||
dheight = (Graphics.height/@__sprite.zoom_y+@borderY).to_i # +2
|
||||
@__sprite.bitmap = ensureBitmap(@__sprite.bitmap,dwidth,dheight)
|
||||
@__sprite.bitmap.clear
|
||||
tileBitmap(@__sprite.bitmap,@__bitmap,@__bitmap.rect)
|
||||
else
|
||||
@__sprite.visible = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensureBitmap(bitmap,dwidth,dheight)
|
||||
if !bitmap || bitmap.disposed? || bitmap.width<dwidth || bitmap.height<dheight
|
||||
bitmap.dispose if bitmap
|
||||
bitmap = Bitmap.new([1,dwidth].max,[1,dheight].max)
|
||||
end
|
||||
return bitmap
|
||||
end
|
||||
|
||||
def tileBitmap(dstbitmap,srcbitmap,srcrect)
|
||||
return if !srcbitmap || srcbitmap.disposed?
|
||||
dstrect = dstbitmap.rect
|
||||
left = (dstrect.x-@__ox/@__sprite.zoom_x).to_i
|
||||
top = (dstrect.y-@__oy/@__sprite.zoom_y).to_i
|
||||
while left>0; left -= srcbitmap.width; end
|
||||
while top>0; top -= srcbitmap.height; end
|
||||
y = top
|
||||
while y<dstrect.height
|
||||
x = left
|
||||
while x<dstrect.width
|
||||
dstbitmap.blt(x+@borderX,y+@borderY,srcbitmap,srcrect)
|
||||
x += srcrect.width
|
||||
end
|
||||
y += srcrect.height
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# A plane class that displays a single color.
|
||||
#===============================================================================
|
||||
class ColoredPlane < LargePlane
|
||||
def initialize(color,viewport=nil)
|
||||
class ColoredPlane < Plane
|
||||
def initialize(color, viewport = nil)
|
||||
super(viewport)
|
||||
self.bitmap=Bitmap.new(32,32)
|
||||
setPlaneColor(color)
|
||||
self.bitmap = Bitmap.new(32, 32)
|
||||
set_plane_color(color)
|
||||
end
|
||||
|
||||
def dispose
|
||||
self.bitmap.dispose if self.bitmap
|
||||
self.bitmap&.dispose
|
||||
super
|
||||
end
|
||||
|
||||
def setPlaneColor(value)
|
||||
self.bitmap.fill_rect(0,0,self.bitmap.width,self.bitmap.height,value)
|
||||
self.refresh
|
||||
def set_plane_color(value)
|
||||
self.bitmap.fill_rect(0, 0, self.bitmap.width, self.bitmap.height, value)
|
||||
refresh
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# A plane class that supports animated images.
|
||||
#===============================================================================
|
||||
class AnimatedPlane < LargePlane
|
||||
class AnimatedPlane < Plane
|
||||
def initialize(viewport)
|
||||
super(viewport)
|
||||
@bitmap=nil
|
||||
@bitmap = nil
|
||||
end
|
||||
|
||||
def dispose
|
||||
clearBitmaps()
|
||||
clear_bitmap
|
||||
super
|
||||
end
|
||||
|
||||
def update
|
||||
super
|
||||
if @bitmap
|
||||
@bitmap.update
|
||||
self.bitmap=@bitmap.bitmap
|
||||
def setBitmap(file, hue = 0)
|
||||
clear_bitmap
|
||||
return if file.nil?
|
||||
@bitmap = AnimatedBitmap.new(file, hue)
|
||||
self.bitmap = @bitmap.bitmap if @bitmap
|
||||
end
|
||||
|
||||
def set_panorama(file, hue = 0)
|
||||
if file.is_a?(String) && file.length > 0
|
||||
setBitmap("Graphics/Panoramas/" + file, hue)
|
||||
else
|
||||
clear_bitmap
|
||||
end
|
||||
end
|
||||
|
||||
def clearBitmaps
|
||||
@bitmap.dispose if @bitmap
|
||||
@bitmap=nil
|
||||
self.bitmap=nil if !self.disposed?
|
||||
def set_fog(file, hue = 0)
|
||||
if file.is_a?(String) && file.length > 0
|
||||
setBitmap("Graphics/Fogs/" + file, hue)
|
||||
else
|
||||
clear_bitmap
|
||||
end
|
||||
end
|
||||
|
||||
def setPanorama(file, hue=0)
|
||||
clearBitmaps()
|
||||
return if file==nil
|
||||
@bitmap=AnimatedBitmap.new("Graphics/Panoramas/"+file,hue)
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def setFog(file, hue=0)
|
||||
clearBitmaps()
|
||||
return if file==nil
|
||||
@bitmap=AnimatedBitmap.new("Graphics/Fogs/"+file,hue)
|
||||
end
|
||||
private
|
||||
|
||||
def setBitmap(file, hue=0)
|
||||
clearBitmaps()
|
||||
return if file==nil
|
||||
@bitmap=AnimatedBitmap.new(file,hue)
|
||||
def clear_bitmap
|
||||
@bitmap&.dispose
|
||||
@bitmap = nil
|
||||
self.bitmap = nil if !self.disposed?
|
||||
end
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,32 +2,28 @@
|
||||
#
|
||||
#===============================================================================
|
||||
class CharacterEntryHelper
|
||||
attr_reader :text
|
||||
attr_accessor :text
|
||||
attr_accessor :maxlength
|
||||
attr_reader :passwordChar
|
||||
attr_accessor :cursor
|
||||
|
||||
def initialize(text)
|
||||
@maxlength=-1
|
||||
@text=text
|
||||
@passwordChar=""
|
||||
@cursor=text.scan(/./m).length
|
||||
end
|
||||
|
||||
def text=(value)
|
||||
@text=value
|
||||
@maxlength = -1
|
||||
@text = text
|
||||
@passwordChar = ""
|
||||
@cursor = text.scan(/./m).length
|
||||
end
|
||||
|
||||
def textChars
|
||||
chars=text.scan(/./m)
|
||||
if @passwordChar!=""
|
||||
chars = text.scan(/./m)
|
||||
if @passwordChar != ""
|
||||
chars.length.times { |i| chars[i] = @passwordChar }
|
||||
end
|
||||
return chars
|
||||
end
|
||||
|
||||
def passwordChar=(value)
|
||||
@passwordChar=value ? value : ""
|
||||
@passwordChar = value || ""
|
||||
end
|
||||
|
||||
def length
|
||||
@@ -35,75 +31,70 @@ class CharacterEntryHelper
|
||||
end
|
||||
|
||||
def canInsert?
|
||||
chars=self.text.scan(/./m)
|
||||
return false if @maxlength>=0 && chars.length>=@maxlength
|
||||
chars = self.text.scan(/./m)
|
||||
return false if @maxlength >= 0 && chars.length >= @maxlength
|
||||
return true
|
||||
end
|
||||
|
||||
def insert(ch)
|
||||
chars=self.text.scan(/./m)
|
||||
return false if @maxlength>=0 && chars.length>=@maxlength
|
||||
chars.insert(@cursor,ch)
|
||||
@text=""
|
||||
for ch in chars
|
||||
@text+=ch if ch
|
||||
end
|
||||
@cursor+=1
|
||||
chars = self.text.scan(/./m)
|
||||
return false if @maxlength >= 0 && chars.length >= @maxlength
|
||||
chars.insert(@cursor, ch)
|
||||
@text = ""
|
||||
chars.each { |char| @text += char if char }
|
||||
@cursor += 1
|
||||
return true
|
||||
end
|
||||
|
||||
def canDelete?
|
||||
chars=self.text.scan(/./m)
|
||||
return false if chars.length<=0 || @cursor<=0
|
||||
chars = self.text.scan(/./m)
|
||||
return false if chars.length <= 0 || @cursor <= 0
|
||||
return true
|
||||
end
|
||||
|
||||
def delete
|
||||
chars=self.text.scan(/./m)
|
||||
return false if chars.length<=0 || @cursor<=0
|
||||
chars.delete_at(@cursor-1)
|
||||
@text=""
|
||||
for ch in chars
|
||||
@text+=ch if ch
|
||||
chars = self.text.scan(/./m)
|
||||
return false if chars.length <= 0 || @cursor <= 0
|
||||
chars.delete_at(@cursor - 1)
|
||||
@text = ""
|
||||
chars.each do |ch|
|
||||
@text += ch if ch
|
||||
end
|
||||
@cursor-=1
|
||||
@cursor -= 1
|
||||
return true
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
private
|
||||
|
||||
def ensure
|
||||
return if @maxlength<0
|
||||
chars=self.text.scan(/./m)
|
||||
if chars.length>@maxlength && @maxlength>=0
|
||||
chars=chars[0,@maxlength]
|
||||
end
|
||||
@text=""
|
||||
for ch in chars
|
||||
@text+=ch if ch
|
||||
return if @maxlength < 0
|
||||
chars = self.text.scan(/./m)
|
||||
chars = chars[0, @maxlength] if chars.length > @maxlength && @maxlength >= 0
|
||||
@text = ""
|
||||
chars.each do |ch|
|
||||
@text += ch if ch
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Window_TextEntry < SpriteWindow_Base
|
||||
def initialize(text,x,y,width,height,heading=nil,usedarkercolor=false)
|
||||
super(x,y,width,height)
|
||||
colors=getDefaultTextColors(self.windowskin)
|
||||
@baseColor=colors[0]
|
||||
@shadowColor=colors[1]
|
||||
def initialize(text, x, y, width, height, heading = nil, usedarkercolor = false)
|
||||
super(x, y, width, height)
|
||||
@baseColor, @shadowColor = getDefaultTextColors(self.windowskin)
|
||||
if usedarkercolor
|
||||
@baseColor=Color.new(16,24,32)
|
||||
@shadowColor=Color.new(168,184,184)
|
||||
@baseColor = Color.new(16, 24, 32)
|
||||
@shadowColor = Color.new(168, 184, 184)
|
||||
end
|
||||
@helper=CharacterEntryHelper.new(text)
|
||||
@heading=heading
|
||||
self.active=true
|
||||
@frame=0
|
||||
@helper = CharacterEntryHelper.new(text)
|
||||
@heading = heading
|
||||
@cursor_timer_start = System.uptime
|
||||
@cursor_shown = true
|
||||
self.active = true
|
||||
refresh
|
||||
end
|
||||
|
||||
@@ -120,23 +111,24 @@ class Window_TextEntry < SpriteWindow_Base
|
||||
end
|
||||
|
||||
def text=(value)
|
||||
@helper.text=value
|
||||
@helper.text = value
|
||||
self.refresh
|
||||
end
|
||||
|
||||
def passwordChar=(value)
|
||||
@helper.passwordChar=value
|
||||
@helper.passwordChar = value
|
||||
refresh
|
||||
end
|
||||
|
||||
def maxlength=(value)
|
||||
@helper.maxlength=value
|
||||
@helper.maxlength = value
|
||||
self.refresh
|
||||
end
|
||||
|
||||
def insert(ch)
|
||||
if @helper.insert(ch)
|
||||
@frame=0
|
||||
@cursor_timer_start = System.uptime
|
||||
@cursor_shown = true
|
||||
self.refresh
|
||||
return true
|
||||
end
|
||||
@@ -145,7 +137,8 @@ class Window_TextEntry < SpriteWindow_Base
|
||||
|
||||
def delete
|
||||
if @helper.delete
|
||||
@frame=0
|
||||
@cursor_timer_start = System.uptime
|
||||
@cursor_shown = true
|
||||
self.refresh
|
||||
return true
|
||||
end
|
||||
@@ -153,21 +146,25 @@ class Window_TextEntry < SpriteWindow_Base
|
||||
end
|
||||
|
||||
def update
|
||||
@frame += 1
|
||||
@frame %= 20
|
||||
self.refresh if (@frame%10)==0
|
||||
cursor_to_show = ((System.uptime - @cursor_timer_start) / 0.35).to_i.even?
|
||||
if cursor_to_show != @cursor_shown
|
||||
@cursor_shown = cursor_to_show
|
||||
refresh
|
||||
end
|
||||
return if !self.active
|
||||
# Moving cursor
|
||||
if Input.repeat?(Input::LEFT) && Input.press?(Input::ACTION)
|
||||
if @helper.cursor > 0
|
||||
@helper.cursor -= 1
|
||||
@frame = 0
|
||||
@cursor_timer_start = System.uptime
|
||||
@cursor_shown = true
|
||||
self.refresh
|
||||
end
|
||||
elsif Input.repeat?(Input::RIGHT) && Input.press?(Input::ACTION)
|
||||
if @helper.cursor < self.text.scan(/./m).length
|
||||
@helper.cursor += 1
|
||||
@frame = 0
|
||||
@cursor_timer_start = System.uptime
|
||||
@cursor_shown = true
|
||||
self.refresh
|
||||
end
|
||||
elsif Input.repeat?(Input::BACK) # Backspace
|
||||
@@ -176,79 +173,81 @@ class Window_TextEntry < SpriteWindow_Base
|
||||
end
|
||||
|
||||
def refresh
|
||||
self.contents=pbDoEnsureBitmap(self.contents,self.width-self.borderX,
|
||||
self.height-self.borderY)
|
||||
bitmap=self.contents
|
||||
self.contents = pbDoEnsureBitmap(self.contents, self.width - self.borderX,
|
||||
self.height - self.borderY)
|
||||
bitmap = self.contents
|
||||
bitmap.clear
|
||||
x=0
|
||||
y=0
|
||||
x = 0
|
||||
y = 0
|
||||
if @heading
|
||||
textwidth=bitmap.text_size(@heading).width
|
||||
pbDrawShadowText(bitmap,x,y, textwidth+4, 32, @heading,@baseColor,@shadowColor)
|
||||
y+=32
|
||||
textwidth = bitmap.text_size(@heading).width
|
||||
pbDrawShadowText(bitmap, x, y, textwidth + 4, 32, @heading, @baseColor, @shadowColor)
|
||||
y += 32
|
||||
end
|
||||
x+=4
|
||||
width=self.width-self.borderX
|
||||
cursorcolor=Color.new(16,24,32)
|
||||
textscan=self.text.scan(/./m)
|
||||
scanlength=textscan.length
|
||||
@helper.cursor=scanlength if @helper.cursor>scanlength
|
||||
@helper.cursor=0 if @helper.cursor<0
|
||||
startpos=@helper.cursor
|
||||
fromcursor=0
|
||||
while (startpos>0)
|
||||
c=(@helper.passwordChar!="") ? @helper.passwordChar : textscan[startpos-1]
|
||||
fromcursor+=bitmap.text_size(c).width
|
||||
break if fromcursor>width-4
|
||||
startpos-=1
|
||||
x += 4
|
||||
width = self.width - self.borderX
|
||||
cursorcolor = Color.new(16, 24, 32)
|
||||
textscan = self.text.scan(/./m)
|
||||
scanlength = textscan.length
|
||||
@helper.cursor = scanlength if @helper.cursor > scanlength
|
||||
@helper.cursor = 0 if @helper.cursor < 0
|
||||
startpos = @helper.cursor
|
||||
fromcursor = 0
|
||||
while startpos > 0
|
||||
c = (@helper.passwordChar != "") ? @helper.passwordChar : textscan[startpos - 1]
|
||||
fromcursor += bitmap.text_size(c).width
|
||||
break if fromcursor > width - 4
|
||||
startpos -= 1
|
||||
end
|
||||
for i in startpos...scanlength
|
||||
c=(@helper.passwordChar!="") ? @helper.passwordChar : textscan[i]
|
||||
textwidth=bitmap.text_size(c).width
|
||||
next if c=="\n"
|
||||
(startpos...scanlength).each do |i|
|
||||
c = (@helper.passwordChar != "") ? @helper.passwordChar : textscan[i]
|
||||
textwidth = bitmap.text_size(c).width
|
||||
next if c == "\n"
|
||||
# Draw text
|
||||
pbDrawShadowText(bitmap,x,y, textwidth+4, 32, c,@baseColor,@shadowColor)
|
||||
pbDrawShadowText(bitmap, x, y, textwidth + 4, 32, c, @baseColor, @shadowColor)
|
||||
# Draw cursor if necessary
|
||||
if ((@frame/10)&1) == 0 && i==@helper.cursor
|
||||
bitmap.fill_rect(x,y+4,2,24,cursorcolor)
|
||||
if i == @helper.cursor && @cursor_shown
|
||||
bitmap.fill_rect(x, y + 4, 2, 24, cursorcolor)
|
||||
end
|
||||
# Add x to drawn text width
|
||||
x += textwidth
|
||||
end
|
||||
if ((@frame/10)&1) == 0 && textscan.length==@helper.cursor
|
||||
bitmap.fill_rect(x,y+4,2,24,cursorcolor)
|
||||
if textscan.length == @helper.cursor && @cursor_shown
|
||||
bitmap.fill_rect(x, y + 4, 2, 24, cursorcolor)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Window_TextEntry_Keyboard < Window_TextEntry
|
||||
def update
|
||||
@frame+=1
|
||||
@frame%=20
|
||||
self.refresh if ((@frame%10)==0)
|
||||
cursor_to_show = ((System.uptime - @cursor_timer_start) / 0.35).to_i.even?
|
||||
if cursor_to_show != @cursor_shown
|
||||
@cursor_shown = cursor_to_show
|
||||
refresh
|
||||
end
|
||||
return if !self.active
|
||||
# Moving cursor
|
||||
if Input.triggerex?(:LEFT) || Input.repeatex?(:LEFT)
|
||||
if @helper.cursor > 0
|
||||
@helper.cursor-=1
|
||||
@frame=0
|
||||
@helper.cursor -= 1
|
||||
@cursor_timer_start = System.uptime
|
||||
@cursor_shown = true
|
||||
self.refresh
|
||||
end
|
||||
return
|
||||
elsif Input.triggerex?(:RIGHT) || Input.repeatex?(:RIGHT)
|
||||
if @helper.cursor < self.text.scan(/./m).length
|
||||
@helper.cursor+=1
|
||||
@frame=0
|
||||
@helper.cursor += 1
|
||||
@cursor_timer_start = System.uptime
|
||||
@cursor_shown = true
|
||||
self.refresh
|
||||
end
|
||||
return
|
||||
elsif Input.triggerex?(:BACKSPACE) || Input.repeatex?(:BACKSPACE)
|
||||
self.delete if @helper.cursor>0
|
||||
self.delete if @helper.cursor > 0
|
||||
return
|
||||
elsif Input.triggerex?(:RETURN) || Input.triggerex?(:ESCAPE)
|
||||
return
|
||||
@@ -257,23 +256,20 @@ class Window_TextEntry_Keyboard < Window_TextEntry
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class Window_MultilineTextEntry < SpriteWindow_Base
|
||||
def initialize(text,x,y,width,height)
|
||||
super(x,y,width,height)
|
||||
colors=getDefaultTextColors(self.windowskin)
|
||||
@baseColor=colors[0]
|
||||
@shadowColor=colors[1]
|
||||
@helper=CharacterEntryHelper.new(text)
|
||||
@firstline=0
|
||||
@cursorLine=0
|
||||
@cursorColumn=0
|
||||
@frame=0
|
||||
self.active=true
|
||||
def initialize(text, x, y, width, height)
|
||||
super(x, y, width, height)
|
||||
@baseColor, @shadowColor = getDefaultTextColors(self.windowskin)
|
||||
@helper = CharacterEntryHelper.new(text)
|
||||
@firstline = 0
|
||||
@cursorLine = 0
|
||||
@cursorColumn = 0
|
||||
@cursor_timer_start = System.uptime
|
||||
@cursor_shown = true
|
||||
self.active = true
|
||||
refresh
|
||||
end
|
||||
|
||||
@@ -281,12 +277,12 @@ class Window_MultilineTextEntry < SpriteWindow_Base
|
||||
attr_reader :shadowColor
|
||||
|
||||
def baseColor=(value)
|
||||
@baseColor=value
|
||||
@baseColor = value
|
||||
refresh
|
||||
end
|
||||
|
||||
def shadowColor=(value)
|
||||
@shadowColor=value
|
||||
@shadowColor = value
|
||||
refresh
|
||||
end
|
||||
|
||||
@@ -299,23 +295,24 @@ class Window_MultilineTextEntry < SpriteWindow_Base
|
||||
end
|
||||
|
||||
def text=(value)
|
||||
@helper.text=value
|
||||
@textchars=nil
|
||||
@helper.text = value
|
||||
@textchars = nil
|
||||
self.refresh
|
||||
end
|
||||
|
||||
def maxlength=(value)
|
||||
@helper.maxlength=value
|
||||
@textchars=nil
|
||||
@helper.maxlength = value
|
||||
@textchars = nil
|
||||
self.refresh
|
||||
end
|
||||
|
||||
def insert(ch)
|
||||
@helper.cursor=getPosFromLineAndColumn(@cursorLine,@cursorColumn)
|
||||
@helper.cursor = getPosFromLineAndColumn(@cursorLine, @cursorColumn)
|
||||
if @helper.insert(ch)
|
||||
@frame=0
|
||||
@textchars=nil
|
||||
moveCursor(0,1)
|
||||
@cursor_timer_start = System.uptime
|
||||
@cursor_shown = true
|
||||
@textchars = nil
|
||||
moveCursor(0, 1)
|
||||
self.refresh
|
||||
return true
|
||||
end
|
||||
@@ -323,11 +320,12 @@ class Window_MultilineTextEntry < SpriteWindow_Base
|
||||
end
|
||||
|
||||
def delete
|
||||
@helper.cursor=getPosFromLineAndColumn(@cursorLine,@cursorColumn)
|
||||
@helper.cursor = getPosFromLineAndColumn(@cursorLine, @cursorColumn)
|
||||
if @helper.delete
|
||||
@frame=0
|
||||
moveCursor(0,-1) # use old textchars
|
||||
@textchars=nil
|
||||
@cursor_timer_start = System.uptime
|
||||
@cursor_shown = true
|
||||
moveCursor(0, -1) # use old textchars
|
||||
@textchars = nil
|
||||
self.refresh
|
||||
return true
|
||||
end
|
||||
@@ -336,163 +334,155 @@ class Window_MultilineTextEntry < SpriteWindow_Base
|
||||
|
||||
def getTextChars
|
||||
if !@textchars
|
||||
@textchars=getLineBrokenText(self.contents,@helper.text,
|
||||
self.contents.width,nil)
|
||||
@textchars = getLineBrokenText(self.contents, @helper.text,
|
||||
self.contents.width, nil)
|
||||
end
|
||||
return @textchars
|
||||
end
|
||||
|
||||
def getTotalLines
|
||||
textchars=getTextChars
|
||||
return 1 if textchars.length==0
|
||||
tchar=textchars[textchars.length-1]
|
||||
return tchar[5]+1
|
||||
textchars = getTextChars
|
||||
return 1 if textchars.length == 0
|
||||
tchar = textchars[textchars.length - 1]
|
||||
return tchar[5] + 1
|
||||
end
|
||||
|
||||
def getLineY(line)
|
||||
textchars=getTextChars
|
||||
return 0 if textchars.length==0
|
||||
totallines=getTotalLines()
|
||||
line=0 if line<0
|
||||
line=totallines-1 if line>=totallines
|
||||
maximumY=0
|
||||
for i in 0...textchars.length
|
||||
thisline=textchars[i][5]
|
||||
y=textchars[i][2]
|
||||
return y if thisline==line
|
||||
maximumY=y if maximumY<y
|
||||
textchars = getTextChars
|
||||
return 0 if textchars.length == 0
|
||||
totallines = getTotalLines
|
||||
line = 0 if line < 0
|
||||
line = totallines - 1 if line >= totallines
|
||||
maximumY = 0
|
||||
textchars.each do |text|
|
||||
thisline = text[5]
|
||||
y = text[2]
|
||||
return y if thisline == line
|
||||
maximumY = y if maximumY < y
|
||||
end
|
||||
return maximumY
|
||||
end
|
||||
|
||||
def getColumnsInLine(line)
|
||||
textchars=getTextChars
|
||||
return 0 if textchars.length==0
|
||||
totallines=getTotalLines()
|
||||
line=0 if line<0
|
||||
line=totallines-1 if line>=totallines
|
||||
endpos=0
|
||||
for i in 0...textchars.length
|
||||
thisline=textchars[i][5]
|
||||
thislength=textchars[i][8]
|
||||
endpos+=thislength if thisline==line
|
||||
textchars = getTextChars
|
||||
return 0 if textchars.length == 0
|
||||
totallines = getTotalLines
|
||||
line = 0 if line < 0
|
||||
line = totallines - 1 if line >= totallines
|
||||
endpos = 0
|
||||
textchars.each do |text|
|
||||
thisline = text[5]
|
||||
thislength = text[8]
|
||||
endpos += thislength if thisline == line
|
||||
end
|
||||
return endpos
|
||||
end
|
||||
|
||||
def getPosFromLineAndColumn(line,column)
|
||||
textchars=getTextChars
|
||||
return 0 if textchars.length==0
|
||||
totallines=getTotalLines()
|
||||
line=0 if line<0
|
||||
line=totallines-1 if line>=totallines
|
||||
endpos=0
|
||||
for i in 0...textchars.length
|
||||
thisline=textchars[i][5]
|
||||
thispos=textchars[i][6]
|
||||
thiscolumn=textchars[i][7]
|
||||
thislength=textchars[i][8]
|
||||
if thisline==line
|
||||
endpos=thispos+thislength
|
||||
# echoln [endpos,thispos+(column-thiscolumn),textchars[i]]
|
||||
if column>=thiscolumn && column<=thiscolumn+thislength && thislength>0
|
||||
return thispos+(column-thiscolumn)
|
||||
end
|
||||
end
|
||||
def getPosFromLineAndColumn(line, column)
|
||||
textchars = getTextChars
|
||||
return 0 if textchars.length == 0
|
||||
totallines = getTotalLines
|
||||
line = 0 if line < 0
|
||||
line = totallines - 1 if line >= totallines
|
||||
endpos = 0
|
||||
textchars.each do |text|
|
||||
thisline = text[5]
|
||||
thispos = text[6]
|
||||
thiscolumn = text[7]
|
||||
thislength = text[8]
|
||||
next if thisline != line
|
||||
endpos = thispos + thislength
|
||||
next if column < thiscolumn || column > thiscolumn + thislength || thislength == 0
|
||||
return thispos + column - thiscolumn
|
||||
end
|
||||
# if endpos==0
|
||||
# echoln [totallines,line,column]
|
||||
# echoln textchars
|
||||
# end
|
||||
# echoln "endpos=#{endpos}"
|
||||
return endpos
|
||||
end
|
||||
|
||||
def getLastVisibleLine
|
||||
getTextChars()
|
||||
textheight=[1,self.contents.text_size("X").height].max
|
||||
lastVisible=@firstline+((self.height-self.borderY)/textheight)-1
|
||||
getTextChars
|
||||
textheight = [1, self.contents.text_size("X").height].max
|
||||
lastVisible = @firstline + ((self.height - self.borderY) / textheight) - 1
|
||||
return lastVisible
|
||||
end
|
||||
|
||||
def updateCursorPos(doRefresh)
|
||||
# Calculate new cursor position
|
||||
@helper.cursor=getPosFromLineAndColumn(@cursorLine,@cursorColumn)
|
||||
@helper.cursor = getPosFromLineAndColumn(@cursorLine, @cursorColumn)
|
||||
if doRefresh
|
||||
@frame=0
|
||||
@cursor_timer_start = System.uptime
|
||||
@cursor_shown = true
|
||||
self.refresh
|
||||
end
|
||||
@firstline=@cursorLine if @cursorLine<@firstline
|
||||
lastVisible=getLastVisibleLine()
|
||||
@firstline+=(@cursorLine-lastVisible) if @cursorLine>lastVisible
|
||||
@firstline = @cursorLine if @cursorLine < @firstline
|
||||
lastVisible = getLastVisibleLine
|
||||
@firstline += (@cursorLine - lastVisible) if @cursorLine > lastVisible
|
||||
end
|
||||
|
||||
def moveCursor(lineOffset, columnOffset)
|
||||
# Move column offset first, then lines (since column offset
|
||||
# can affect line offset)
|
||||
# echoln ["beforemoving",@cursorLine,@cursorColumn]
|
||||
totalColumns=getColumnsInLine(@cursorLine) # check current line
|
||||
totalLines=getTotalLines()
|
||||
oldCursorLine=@cursorLine
|
||||
oldCursorColumn=@cursorColumn
|
||||
@cursorColumn+=columnOffset
|
||||
if @cursorColumn<0 && @cursorLine>0
|
||||
totalColumns = getColumnsInLine(@cursorLine) # check current line
|
||||
totalLines = getTotalLines
|
||||
oldCursorLine = @cursorLine
|
||||
oldCursorColumn = @cursorColumn
|
||||
@cursorColumn += columnOffset
|
||||
if @cursorColumn < 0 && @cursorLine > 0
|
||||
# Will happen if cursor is moved left from the beginning of a line
|
||||
@cursorLine-=1
|
||||
@cursorColumn=getColumnsInLine(@cursorLine)
|
||||
elsif @cursorColumn>totalColumns && @cursorLine<totalLines-1
|
||||
@cursorLine -= 1
|
||||
@cursorColumn = getColumnsInLine(@cursorLine)
|
||||
elsif @cursorColumn > totalColumns && @cursorLine < totalLines - 1
|
||||
# Will happen if cursor is moved right from the end of a line
|
||||
@cursorLine+=1
|
||||
@cursorColumn=0
|
||||
@cursorLine += 1
|
||||
@cursorColumn = 0
|
||||
end
|
||||
# Ensure column bounds
|
||||
totalColumns=getColumnsInLine(@cursorLine)
|
||||
@cursorColumn=totalColumns if @cursorColumn>totalColumns
|
||||
@cursorColumn=0 if @cursorColumn<0 # totalColumns can be 0
|
||||
totalColumns = getColumnsInLine(@cursorLine)
|
||||
@cursorColumn = totalColumns if @cursorColumn > totalColumns
|
||||
@cursorColumn = 0 if @cursorColumn < 0 # totalColumns can be 0
|
||||
# Move line offset
|
||||
@cursorLine+=lineOffset
|
||||
@cursorLine=0 if @cursorLine<0
|
||||
@cursorLine=totalLines-1 if @cursorLine>=totalLines
|
||||
@cursorLine += lineOffset
|
||||
@cursorLine = 0 if @cursorLine < 0
|
||||
@cursorLine = totalLines - 1 if @cursorLine >= totalLines
|
||||
# Ensure column bounds again
|
||||
totalColumns=getColumnsInLine(@cursorLine)
|
||||
@cursorColumn=totalColumns if @cursorColumn>totalColumns
|
||||
@cursorColumn=0 if @cursorColumn<0 # totalColumns can be 0
|
||||
updateCursorPos(
|
||||
oldCursorLine!=@cursorLine ||
|
||||
oldCursorColumn!=@cursorColumn
|
||||
)
|
||||
totalColumns = getColumnsInLine(@cursorLine)
|
||||
@cursorColumn = totalColumns if @cursorColumn > totalColumns
|
||||
@cursorColumn = 0 if @cursorColumn < 0 # totalColumns can be 0
|
||||
updateCursorPos(oldCursorLine != @cursorLine || oldCursorColumn != @cursorColumn)
|
||||
# echoln ["aftermoving",@cursorLine,@cursorColumn]
|
||||
end
|
||||
|
||||
def update
|
||||
@frame+=1
|
||||
@frame%=20
|
||||
self.refresh if ((@frame%10)==0)
|
||||
cursor_to_show = ((System.uptime - @cursor_timer_start) / 0.35).to_i.even?
|
||||
if cursor_to_show != @cursor_shown
|
||||
@cursor_shown = cursor_to_show
|
||||
refresh
|
||||
end
|
||||
return if !self.active
|
||||
# Moving cursor
|
||||
if Input.triggerex?(:UP) || Input.repeatex?(:UP)
|
||||
moveCursor(-1,0)
|
||||
moveCursor(-1, 0)
|
||||
return
|
||||
elsif Input.triggerex?(:DOWN) || Input.repeatex?(:DOWN)
|
||||
moveCursor(1,0)
|
||||
moveCursor(1, 0)
|
||||
return
|
||||
elsif Input.triggerex?(:LEFT) || Input.repeatex?(:LEFT)
|
||||
moveCursor(0,-1)
|
||||
moveCursor(0, -1)
|
||||
return
|
||||
elsif Input.triggerex?(:RIGHT) || Input.repeatex?(:RIGHT)
|
||||
moveCursor(0,1)
|
||||
moveCursor(0, 1)
|
||||
return
|
||||
end
|
||||
if Input.press?(Input::CTRL) && Input.triggerex?(:HOME)
|
||||
# Move cursor to beginning
|
||||
@cursorLine=0
|
||||
@cursorColumn=0
|
||||
@cursorLine = 0
|
||||
@cursorColumn = 0
|
||||
updateCursorPos(true)
|
||||
return
|
||||
elsif Input.press?(Input::CTRL) && Input.triggerex?(:END)
|
||||
# Move cursor to end
|
||||
@cursorLine=getTotalLines()-1
|
||||
@cursorColumn=getColumnsInLine(@cursorLine)
|
||||
@cursorLine = getTotalLines - 1
|
||||
@cursorColumn = getColumnsInLine(@cursorLine)
|
||||
updateCursorPos(true)
|
||||
return
|
||||
elsif Input.triggerex?(:RETURN) || Input.repeatex?(:RETURN)
|
||||
@@ -502,63 +492,61 @@ class Window_MultilineTextEntry < SpriteWindow_Base
|
||||
self.delete
|
||||
return
|
||||
end
|
||||
Input.gets.each_char{|c|insert(c)}
|
||||
Input.gets.each_char { |c| insert(c) }
|
||||
end
|
||||
|
||||
def refresh
|
||||
newContents=pbDoEnsureBitmap(self.contents,self.width-self.borderX,
|
||||
self.height-self.borderY)
|
||||
@textchars=nil if self.contents!=newContents
|
||||
self.contents=newContents
|
||||
bitmap=self.contents
|
||||
newContents = pbDoEnsureBitmap(self.contents, self.width - self.borderX,
|
||||
self.height - self.borderY)
|
||||
@textchars = nil if self.contents != newContents
|
||||
self.contents = newContents
|
||||
bitmap = self.contents
|
||||
bitmap.clear
|
||||
getTextChars
|
||||
height=self.height-self.borderY
|
||||
cursorcolor=Color.new(0,0,0)
|
||||
textchars=getTextChars()
|
||||
startY=getLineY(@firstline)
|
||||
for i in 0...textchars.length
|
||||
thisline=textchars[i][5]
|
||||
thiscolumn=textchars[i][7]
|
||||
thislength=textchars[i][8]
|
||||
textY=textchars[i][2]-startY
|
||||
height = self.height - self.borderY
|
||||
cursorcolor = Color.black
|
||||
textchars = getTextChars
|
||||
startY = getLineY(@firstline)
|
||||
textchars.each do |text|
|
||||
thisline = text[5]
|
||||
thislength = text[8]
|
||||
textY = text[2] - startY
|
||||
# Don't draw lines before the first or zero-length segments
|
||||
next if thisline<@firstline || thislength==0
|
||||
next if thisline < @firstline || thislength == 0
|
||||
# Don't draw lines beyond the window's height
|
||||
break if textY >= height
|
||||
c=textchars[i][0]
|
||||
c = text[0]
|
||||
# Don't draw spaces
|
||||
next if c==" "
|
||||
textwidth=textchars[i][3]+4 # add 4 to prevent draw_text from stretching text
|
||||
textheight=textchars[i][4]
|
||||
next if c == " "
|
||||
textwidth = text[3] + 4 # add 4 to prevent draw_text from stretching text
|
||||
textheight = text[4]
|
||||
# Draw text
|
||||
pbDrawShadowText(bitmap, textchars[i][1], textY, textwidth, textheight, c, @baseColor, @shadowColor)
|
||||
pbDrawShadowText(bitmap, text[1], textY, textwidth, textheight, c, @baseColor, @shadowColor)
|
||||
end
|
||||
# Draw cursor
|
||||
if ((@frame/10)&1) == 0
|
||||
textheight=bitmap.text_size("X").height
|
||||
cursorY=(textheight*@cursorLine)-startY
|
||||
cursorX=0
|
||||
for i in 0...textchars.length
|
||||
thisline=textchars[i][5]
|
||||
thiscolumn=textchars[i][7]
|
||||
thislength=textchars[i][8]
|
||||
if thisline==@cursorLine && @cursorColumn>=thiscolumn &&
|
||||
@cursorColumn<=thiscolumn+thislength
|
||||
cursorY=textchars[i][2]-startY
|
||||
cursorX=textchars[i][1]
|
||||
textheight=textchars[i][4]
|
||||
posToCursor=@cursorColumn-thiscolumn
|
||||
if posToCursor>=0
|
||||
partialString=textchars[i][0].scan(/./m)[0,posToCursor].join("")
|
||||
cursorX+=bitmap.text_size(partialString).width
|
||||
end
|
||||
break
|
||||
if @cursor_shown
|
||||
textheight = bitmap.text_size("X").height
|
||||
cursorY = (textheight * @cursorLine) - startY
|
||||
cursorX = 0
|
||||
textchars.each do |text|
|
||||
thisline = text[5]
|
||||
thiscolumn = text[7]
|
||||
thislength = text[8]
|
||||
next if thisline != @cursorLine || @cursorColumn < thiscolumn ||
|
||||
@cursorColumn > thiscolumn + thislength
|
||||
cursorY = text[2] - startY
|
||||
cursorX = text[1]
|
||||
textheight = text[4]
|
||||
posToCursor = @cursorColumn - thiscolumn
|
||||
if posToCursor >= 0
|
||||
partialString = text[0].scan(/./m)[0, posToCursor].join
|
||||
cursorX += bitmap.text_size(partialString).width
|
||||
end
|
||||
break
|
||||
end
|
||||
cursorY+=4
|
||||
cursorHeight=[4,textheight-4,bitmap.text_size("X").height-4].max
|
||||
bitmap.fill_rect(cursorX,cursorY,2,cursorHeight,cursorcolor)
|
||||
cursorY += 4
|
||||
cursorHeight = [4, textheight - 4, bitmap.text_size("X").height - 4].max
|
||||
bitmap.fill_rect(cursorX, cursorY, 2, cursorHeight, cursorcolor)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,25 +1,9 @@
|
||||
#####################################
|
||||
# Needed because RGSS doesn't call at_exit procs on exit
|
||||
# Exit is not called when game is reset (using F12)
|
||||
$AtExitProcs=[] if !$AtExitProcs
|
||||
|
||||
def exit(code=0)
|
||||
for p in $AtExitProcs
|
||||
p.call
|
||||
end
|
||||
raise SystemExit.new(code)
|
||||
end
|
||||
|
||||
def at_exit(&block)
|
||||
$AtExitProcs.push(Proc.new(&block))
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Methods that determine the duration of an audio file.
|
||||
#===============================================================================
|
||||
def getOggPage(file)
|
||||
fgetdw = proc { |file|
|
||||
(file.eof? ? 0 : (file.read(4).unpack("V")[0] || 0))
|
||||
fgetdw = proc { |f|
|
||||
(f.eof? ? 0 : (f.read(4).unpack("V")[0] || 0))
|
||||
}
|
||||
dw = fgetdw.call(file)
|
||||
return nil if dw != 0x5367674F
|
||||
@@ -35,8 +19,8 @@ end
|
||||
|
||||
# internal function
|
||||
def oggfiletime(file)
|
||||
fgetdw = proc { |file|
|
||||
(file.eof? ? 0 : (file.read(4).unpack("V")[0] || 0))
|
||||
fgetdw = proc { |f|
|
||||
(f.eof? ? 0 : (f.read(4).unpack("V")[0] || 0))
|
||||
}
|
||||
pages = []
|
||||
page = nil
|
||||
@@ -51,8 +35,8 @@ def oggfiletime(file)
|
||||
i = -1
|
||||
pcmlengths = []
|
||||
rates = []
|
||||
for page in pages
|
||||
header = page[0]
|
||||
pages.each do |pg|
|
||||
header = pg[0]
|
||||
serial = header[10, 4].unpack("V")
|
||||
frame = header[2, 8].unpack("C*")
|
||||
frameno = frame[7]
|
||||
@@ -65,7 +49,7 @@ def oggfiletime(file)
|
||||
frameno = (frameno << 8) | frame[0]
|
||||
if serial != curserial
|
||||
curserial = serial
|
||||
file.pos = page[1]
|
||||
file.pos = pg[1]
|
||||
packtype = (file.read(1)[0].ord rescue 0)
|
||||
string = file.read(6)
|
||||
return -1 if string != "vorbis"
|
||||
@@ -78,28 +62,26 @@ def oggfiletime(file)
|
||||
pcmlengths[i] = frameno
|
||||
end
|
||||
ret = 0.0
|
||||
for i in 0...pcmlengths.length
|
||||
ret += pcmlengths[i].to_f / rates[i].to_f
|
||||
end
|
||||
pcmlengths.each_with_index { |length, j| ret += length.to_f / rates[j] }
|
||||
return ret * 256.0
|
||||
end
|
||||
|
||||
# Gets the length of an audio file in seconds. Supports WAV, MP3, and OGG files.
|
||||
def getPlayTime(filename)
|
||||
if safeExists?(filename)
|
||||
if FileTest.exist?(filename)
|
||||
return [getPlayTime2(filename), 0].max
|
||||
elsif safeExists?(filename + ".wav")
|
||||
elsif FileTest.exist?(filename + ".wav")
|
||||
return [getPlayTime2(filename + ".wav"), 0].max
|
||||
elsif safeExists?(filename + ".mp3")
|
||||
elsif FileTest.exist?(filename + ".mp3")
|
||||
return [getPlayTime2(filename + ".mp3"), 0].max
|
||||
elsif safeExists?(filename + ".ogg")
|
||||
elsif FileTest.exist?(filename + ".ogg")
|
||||
return [getPlayTime2(filename + ".ogg"), 0].max
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
def getPlayTime2(filename)
|
||||
return -1 if !safeExists?(filename)
|
||||
return -1 if !FileTest.exist?(filename)
|
||||
time = -1
|
||||
fgetdw = proc { |file|
|
||||
(file.eof? ? 0 : (file.read(4).unpack("V")[0] || 0))
|
||||
@@ -107,39 +89,40 @@ def getPlayTime2(filename)
|
||||
fgetw = proc { |file|
|
||||
(file.eof? ? 0 : (file.read(2).unpack("v")[0] || 0))
|
||||
}
|
||||
File.open(filename, "rb") { |file|
|
||||
File.open(filename, "rb") do |file|
|
||||
file.pos = 0
|
||||
fdw = fgetdw.call(file)
|
||||
if fdw == 0x46464952 # "RIFF"
|
||||
case fdw
|
||||
when 0x46464952 # "RIFF"
|
||||
filesize = fgetdw.call(file)
|
||||
wave = fgetdw.call(file)
|
||||
return -1 if wave != 0x45564157 # "WAVE"
|
||||
fmt = fgetdw.call(file)
|
||||
return -1 if fmt != 0x20746d66 # "fmt "
|
||||
fmtsize = fgetdw.call(file)
|
||||
format = fgetw.call(file)
|
||||
channels = fgetw.call(file)
|
||||
rate = fgetdw.call(file)
|
||||
fgetdw.call(file) # fmtsize
|
||||
fgetw.call(file) # format
|
||||
fgetw.call(file) # channels
|
||||
fgetdw.call(file) # rate
|
||||
bytessec = fgetdw.call(file)
|
||||
return -1 if bytessec == 0
|
||||
bytessample = fgetw.call(file)
|
||||
bitssample = fgetw.call(file)
|
||||
fgetw.call(file) # bytessample
|
||||
fgetw.call(file) # bitssample
|
||||
data = fgetdw.call(file)
|
||||
return -1 if data != 0x61746164 # "data"
|
||||
datasize = fgetdw.call(file)
|
||||
time = (datasize*1.0)/bytessec
|
||||
time = datasize.to_f / bytessec
|
||||
return time
|
||||
elsif fdw == 0x5367674F # "OggS"
|
||||
when 0x5367674F # "OggS"
|
||||
file.pos = 0
|
||||
time = oggfiletime(file)
|
||||
return time
|
||||
end
|
||||
file.pos = 0
|
||||
# Find the length of an MP3 file
|
||||
while true
|
||||
loop do
|
||||
rstr = ""
|
||||
ateof = false
|
||||
while !file.eof?
|
||||
until file.eof?
|
||||
if (file.read(1)[0] rescue 0) == 0xFF
|
||||
begin
|
||||
rstr = file.read(3)
|
||||
@@ -152,20 +135,20 @@ def getPlayTime2(filename)
|
||||
break if ateof || !rstr || rstr.length != 3
|
||||
if rstr[0] == 0xFB
|
||||
t = rstr[1] >> 4
|
||||
next if t == 0 || t == 15
|
||||
freqs = [44100, 22050, 11025, 48000]
|
||||
next if [0, 15].include?(t)
|
||||
freqs = [44_100, 22_050, 11_025, 48_000]
|
||||
bitrates = [32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320]
|
||||
bitrate = bitrates[t]
|
||||
t = (rstr[1] >> 2) & 3
|
||||
freq = freqs[t]
|
||||
t = (rstr[1] >> 1) & 1
|
||||
filesize = FileTest.size(filename)
|
||||
frameLength = ((144000 * bitrate) / freq) + t
|
||||
frameLength = ((144_000 * bitrate) / freq) + t
|
||||
numFrames = filesize / (frameLength + 4)
|
||||
time = (numFrames * 1152.0 / freq)
|
||||
break
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
return time
|
||||
end
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
def pbStringToAudioFile(str)
|
||||
if str[/^(.*)\:\s*(\d+)\s*\:\s*(\d+)\s*$/] # Of the format "XXX: ###: ###"
|
||||
file = $1
|
||||
volume = $2.to_i
|
||||
pitch = $3.to_i
|
||||
return RPG::AudioFile.new(file,volume,pitch)
|
||||
return RPG::AudioFile.new(file, volume, pitch)
|
||||
elsif str[/^(.*)\:\s*(\d+)\s*$/] # Of the format "XXX: ###"
|
||||
file = $1
|
||||
volume = $2.to_i
|
||||
return RPG::AudioFile.new(file,volume,100)
|
||||
return RPG::AudioFile.new(file, volume, 100)
|
||||
else
|
||||
return RPG::AudioFile.new(str,100,100)
|
||||
return RPG::AudioFile.new(str, 100, 100)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -21,7 +24,7 @@ end
|
||||
# filename:volume:pitch
|
||||
# volume -- Volume of the file, up to 100
|
||||
# pitch -- Pitch of the file, normally 100
|
||||
def pbResolveAudioFile(str,volume=nil,pitch=nil)
|
||||
def pbResolveAudioFile(str, volume = nil, pitch = nil)
|
||||
if str.is_a?(String)
|
||||
str = pbStringToAudioFile(str)
|
||||
str.volume = volume || 100
|
||||
@@ -29,8 +32,8 @@ def pbResolveAudioFile(str,volume=nil,pitch=nil)
|
||||
end
|
||||
if str.is_a?(RPG::AudioFile)
|
||||
if volume || pitch
|
||||
return RPG::AudioFile.new(str.name,volume || str.volume || 100 ,
|
||||
pitch || str.pitch || 100)
|
||||
return RPG::AudioFile.new(str.name, volume || str.volume || 100,
|
||||
pitch || str.pitch || 100)
|
||||
else
|
||||
return str
|
||||
end
|
||||
@@ -38,8 +41,9 @@ def pbResolveAudioFile(str,volume=nil,pitch=nil)
|
||||
return str
|
||||
end
|
||||
|
||||
################################################################################
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
# Plays a BGM file.
|
||||
# param -- Either a string showing the filename
|
||||
# (relative to Audio/BGM/) or an RPG::AudioFile object.
|
||||
@@ -49,47 +53,48 @@ end
|
||||
# filename:volume:pitch
|
||||
# volume -- Volume of the file, up to 100
|
||||
# pitch -- Pitch of the file, normally 100
|
||||
def pbBGMPlay(param,volume=nil,pitch=nil)
|
||||
def pbBGMPlay(param, volume = nil, pitch = nil)
|
||||
return if !param
|
||||
param=pbResolveAudioFile(param,volume,pitch)
|
||||
if param.name && param.name!=""
|
||||
if $game_system && $game_system.respond_to?("bgm_play")
|
||||
param = pbResolveAudioFile(param, volume, pitch)
|
||||
if param.name && param.name != ""
|
||||
if $game_system
|
||||
$game_system.bgm_play(param)
|
||||
return
|
||||
elsif (RPG.const_defined?(:BGM) rescue false)
|
||||
b=RPG::BGM.new(param.name,param.volume,param.pitch)
|
||||
if b && b.respond_to?("play")
|
||||
b = RPG::BGM.new(param.name, param.volume, param.pitch)
|
||||
if b.respond_to?("play")
|
||||
b.play
|
||||
return
|
||||
end
|
||||
end
|
||||
Audio.bgm_play(canonicalize("Audio/BGM/"+param.name),param.volume,param.pitch)
|
||||
Audio.bgm_play(canonicalize("Audio/BGM/" + param.name), param.volume, param.pitch)
|
||||
end
|
||||
end
|
||||
|
||||
# Fades out or stops BGM playback. 'x' is the time in seconds to fade out.
|
||||
def pbBGMFade(x=0.0); pbBGMStop(x);end
|
||||
def pbBGMFade(x = 0.0); pbBGMStop(x); end
|
||||
|
||||
# Fades out or stops BGM playback. 'x' is the time in seconds to fade out.
|
||||
def pbBGMStop(timeInSeconds=0.0)
|
||||
if $game_system && timeInSeconds>0.0 && $game_system.respond_to?("bgm_fade")
|
||||
def pbBGMStop(timeInSeconds = 0.0)
|
||||
if $game_system && timeInSeconds > 0.0
|
||||
$game_system.bgm_fade(timeInSeconds)
|
||||
return
|
||||
elsif $game_system && $game_system.respond_to?("bgm_stop")
|
||||
elsif $game_system
|
||||
$game_system.bgm_stop
|
||||
return
|
||||
elsif (RPG.const_defined?(:BGM) rescue false)
|
||||
begin
|
||||
(timeInSeconds>0.0) ? RPG::BGM.fade((timeInSeconds*1000).floor) : RPG::BGM.stop
|
||||
(timeInSeconds > 0.0) ? RPG::BGM.fade((timeInSeconds * 1000).floor) : RPG::BGM.stop
|
||||
return
|
||||
rescue
|
||||
end
|
||||
end
|
||||
(timeInSeconds>0.0) ? Audio.bgm_fade((timeInSeconds*1000).floor) : Audio.bgm_stop
|
||||
(timeInSeconds > 0.0) ? Audio.bgm_fade((timeInSeconds * 1000).floor) : Audio.bgm_stop
|
||||
end
|
||||
|
||||
################################################################################
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
# Plays an ME file.
|
||||
# param -- Either a string showing the filename
|
||||
# (relative to Audio/ME/) or an RPG::AudioFile object.
|
||||
@@ -99,46 +104,48 @@ end
|
||||
# filename:volume:pitch
|
||||
# volume -- Volume of the file, up to 100
|
||||
# pitch -- Pitch of the file, normally 100
|
||||
def pbMEPlay(param,volume=nil,pitch=nil)
|
||||
def pbMEPlay(param, volume = nil, pitch = nil)
|
||||
return if !param
|
||||
param=pbResolveAudioFile(param,volume,pitch)
|
||||
if param.name && param.name!=""
|
||||
if $game_system && $game_system.respond_to?("me_play")
|
||||
param = pbResolveAudioFile(param, volume, pitch)
|
||||
if param.name && param.name != ""
|
||||
if $game_system
|
||||
$game_system.me_play(param)
|
||||
return
|
||||
elsif (RPG.const_defined?(:ME) rescue false)
|
||||
b=RPG::ME.new(param.name,param.volume,param.pitch)
|
||||
if b && b.respond_to?("play")
|
||||
b.play; return
|
||||
b = RPG::ME.new(param.name, param.volume, param.pitch)
|
||||
if b.respond_to?("play")
|
||||
b.play
|
||||
return
|
||||
end
|
||||
end
|
||||
Audio.me_play(canonicalize("Audio/ME/"+param.name),param.volume,param.pitch)
|
||||
Audio.me_play(canonicalize("Audio/ME/" + param.name), param.volume, param.pitch)
|
||||
end
|
||||
end
|
||||
|
||||
# Fades out or stops ME playback. 'x' is the time in seconds to fade out.
|
||||
def pbMEFade(x=0.0); pbMEStop(x);end
|
||||
def pbMEFade(x = 0.0); pbMEStop(x); end
|
||||
|
||||
# Fades out or stops ME playback. 'x' is the time in seconds to fade out.
|
||||
def pbMEStop(timeInSeconds=0.0)
|
||||
if $game_system && timeInSeconds>0.0 && $game_system.respond_to?("me_fade")
|
||||
def pbMEStop(timeInSeconds = 0.0)
|
||||
if $game_system && timeInSeconds > 0.0 && $game_system.respond_to?("me_fade")
|
||||
$game_system.me_fade(timeInSeconds)
|
||||
return
|
||||
elsif $game_system && $game_system.respond_to?("me_stop")
|
||||
elsif $game_system.respond_to?("me_stop")
|
||||
$game_system.me_stop(nil)
|
||||
return
|
||||
elsif (RPG.const_defined?(:ME) rescue false)
|
||||
begin
|
||||
(timeInSeconds>0.0) ? RPG::ME.fade((timeInSeconds*1000).floor) : RPG::ME.stop
|
||||
(timeInSeconds > 0.0) ? RPG::ME.fade((timeInSeconds * 1000).floor) : RPG::ME.stop
|
||||
return
|
||||
rescue
|
||||
end
|
||||
end
|
||||
(timeInSeconds>0.0) ? Audio.me_fade((timeInSeconds*1000).floor) : Audio.me_stop
|
||||
(timeInSeconds > 0.0) ? Audio.me_fade((timeInSeconds * 1000).floor) : Audio.me_stop
|
||||
end
|
||||
|
||||
################################################################################
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
# Plays a BGS file.
|
||||
# param -- Either a string showing the filename
|
||||
# (relative to Audio/BGS/) or an RPG::AudioFile object.
|
||||
@@ -148,46 +155,48 @@ end
|
||||
# filename:volume:pitch
|
||||
# volume -- Volume of the file, up to 100
|
||||
# pitch -- Pitch of the file, normally 100
|
||||
def pbBGSPlay(param,volume=nil,pitch=nil)
|
||||
def pbBGSPlay(param, volume = nil, pitch = nil)
|
||||
return if !param
|
||||
param=pbResolveAudioFile(param,volume,pitch)
|
||||
if param.name && param.name!=""
|
||||
if $game_system && $game_system.respond_to?("bgs_play")
|
||||
param = pbResolveAudioFile(param, volume, pitch)
|
||||
if param.name && param.name != ""
|
||||
if $game_system
|
||||
$game_system.bgs_play(param)
|
||||
return
|
||||
elsif (RPG.const_defined?(:BGS) rescue false)
|
||||
b=RPG::BGS.new(param.name,param.volume,param.pitch)
|
||||
if b && b.respond_to?("play")
|
||||
b.play; return
|
||||
b = RPG::BGS.new(param.name, param.volume, param.pitch)
|
||||
if b.respond_to?("play")
|
||||
b.play
|
||||
return
|
||||
end
|
||||
end
|
||||
Audio.bgs_play(canonicalize("Audio/BGS/"+param.name),param.volume,param.pitch)
|
||||
Audio.bgs_play(canonicalize("Audio/BGS/" + param.name), param.volume, param.pitch)
|
||||
end
|
||||
end
|
||||
|
||||
# Fades out or stops BGS playback. 'x' is the time in seconds to fade out.
|
||||
def pbBGSFade(x=0.0); pbBGSStop(x);end
|
||||
def pbBGSFade(x = 0.0); pbBGSStop(x); end
|
||||
|
||||
# Fades out or stops BGS playback. 'x' is the time in seconds to fade out.
|
||||
def pbBGSStop(timeInSeconds=0.0)
|
||||
if $game_system && timeInSeconds>0.0 && $game_system.respond_to?("bgs_fade")
|
||||
def pbBGSStop(timeInSeconds = 0.0)
|
||||
if $game_system && timeInSeconds > 0.0
|
||||
$game_system.bgs_fade(timeInSeconds)
|
||||
return
|
||||
elsif $game_system && $game_system.respond_to?("bgs_play")
|
||||
elsif $game_system
|
||||
$game_system.bgs_play(nil)
|
||||
return
|
||||
elsif (RPG.const_defined?(:BGS) rescue false)
|
||||
begin
|
||||
(timeInSeconds>0.0) ? RPG::BGS.fade((timeInSeconds*1000).floor) : RPG::BGS.stop
|
||||
(timeInSeconds > 0.0) ? RPG::BGS.fade((timeInSeconds * 1000).floor) : RPG::BGS.stop
|
||||
return
|
||||
rescue
|
||||
end
|
||||
end
|
||||
(timeInSeconds>0.0) ? Audio.bgs_fade((timeInSeconds*1000).floor) : Audio.bgs_stop
|
||||
(timeInSeconds > 0.0) ? Audio.bgs_fade((timeInSeconds * 1000).floor) : Audio.bgs_stop
|
||||
end
|
||||
|
||||
################################################################################
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
# Plays an SE file.
|
||||
# param -- Either a string showing the filename
|
||||
# (relative to Audio/SE/) or an RPG::AudioFile object.
|
||||
@@ -197,30 +206,30 @@ end
|
||||
# filename:volume:pitch
|
||||
# volume -- Volume of the file, up to 100
|
||||
# pitch -- Pitch of the file, normally 100
|
||||
def pbSEPlay(param,volume=nil,pitch=nil)
|
||||
def pbSEPlay(param, volume = nil, pitch = nil)
|
||||
return if !param
|
||||
param = pbResolveAudioFile(param,volume,pitch)
|
||||
if param.name && param.name!=""
|
||||
if $game_system && $game_system.respond_to?("se_play")
|
||||
param = pbResolveAudioFile(param, volume, pitch)
|
||||
if param.name && param.name != ""
|
||||
if $game_system
|
||||
$game_system.se_play(param)
|
||||
return
|
||||
end
|
||||
if (RPG.const_defined?(:SE) rescue false)
|
||||
b = RPG::SE.new(param.name,param.volume,param.pitch)
|
||||
if b && b.respond_to?("play")
|
||||
b = RPG::SE.new(param.name, param.volume, param.pitch)
|
||||
if b.respond_to?("play")
|
||||
b.play
|
||||
return
|
||||
end
|
||||
end
|
||||
Audio.se_play(canonicalize("Audio/SE/"+param.name),param.volume,param.pitch)
|
||||
Audio.se_play(canonicalize("Audio/SE/" + param.name), param.volume, param.pitch)
|
||||
end
|
||||
end
|
||||
|
||||
# Stops SE playback.
|
||||
def pbSEFade(x=0.0); pbSEStop(x);end
|
||||
def pbSEFade(x = 0.0); pbSEStop(x); end
|
||||
|
||||
# Stops SE playback.
|
||||
def pbSEStop(_timeInSeconds=0.0)
|
||||
def pbSEStop(_timeInSeconds = 0.0)
|
||||
if $game_system
|
||||
$game_system.se_stop
|
||||
elsif (RPG.const_defined?(:SE) rescue false)
|
||||
@@ -230,63 +239,45 @@ def pbSEStop(_timeInSeconds=0.0)
|
||||
end
|
||||
end
|
||||
|
||||
################################################################################
|
||||
|
||||
# Plays a sound effect that plays when the player moves the cursor.
|
||||
def pbPlayCursorSE
|
||||
if $data_system && $data_system.respond_to?("cursor_se") &&
|
||||
$data_system.cursor_se && $data_system.cursor_se.name!=""
|
||||
if !nil_or_empty?($data_system&.cursor_se&.name)
|
||||
pbSEPlay($data_system.cursor_se)
|
||||
elsif $data_system && $data_system.respond_to?("sounds") &&
|
||||
$data_system.sounds && $data_system.sounds[0] && $data_system.sounds[0].name!=""
|
||||
pbSEPlay($data_system.sounds[0])
|
||||
elsif FileTest.audio_exist?("Audio/SE/GUI sel cursor")
|
||||
pbSEPlay("GUI sel cursor",80)
|
||||
pbSEPlay("GUI sel cursor", 80)
|
||||
end
|
||||
end
|
||||
|
||||
# Plays a sound effect that plays when a decision is confirmed or a choice is made.
|
||||
def pbPlayDecisionSE
|
||||
if $data_system && $data_system.respond_to?("decision_se") &&
|
||||
$data_system.decision_se && $data_system.decision_se.name!=""
|
||||
if !nil_or_empty?($data_system&.decision_se&.name)
|
||||
pbSEPlay($data_system.decision_se)
|
||||
elsif $data_system && $data_system.respond_to?("sounds") &&
|
||||
$data_system.sounds && $data_system.sounds[1] && $data_system.sounds[1].name!=""
|
||||
pbSEPlay($data_system.sounds[1])
|
||||
elsif FileTest.audio_exist?("Audio/SE/GUI sel decision")
|
||||
pbSEPlay("GUI sel decision",80)
|
||||
pbSEPlay("GUI sel decision", 80)
|
||||
end
|
||||
end
|
||||
|
||||
# Plays a sound effect that plays when a choice is canceled.
|
||||
def pbPlayCancelSE
|
||||
if $data_system && $data_system.respond_to?("cancel_se") &&
|
||||
$data_system.cancel_se && $data_system.cancel_se.name!=""
|
||||
if !nil_or_empty?($data_system&.cancel_se&.name)
|
||||
pbSEPlay($data_system.cancel_se)
|
||||
elsif $data_system && $data_system.respond_to?("sounds") &&
|
||||
$data_system.sounds && $data_system.sounds[2] && $data_system.sounds[2].name!=""
|
||||
pbSEPlay($data_system.sounds[2])
|
||||
elsif FileTest.audio_exist?("Audio/SE/GUI sel cancel")
|
||||
pbSEPlay("GUI sel cancel",80)
|
||||
pbSEPlay("GUI sel cancel", 80)
|
||||
end
|
||||
end
|
||||
|
||||
# Plays a buzzer sound effect.
|
||||
def pbPlayBuzzerSE
|
||||
if $data_system && $data_system.respond_to?("buzzer_se") &&
|
||||
$data_system.buzzer_se && $data_system.buzzer_se.name!=""
|
||||
if !nil_or_empty?($data_system&.buzzer_se&.name)
|
||||
pbSEPlay($data_system.buzzer_se)
|
||||
elsif $data_system && $data_system.respond_to?("sounds") &&
|
||||
$data_system.sounds && $data_system.sounds[3] && $data_system.sounds[3].name!=""
|
||||
pbSEPlay($data_system.sounds[3])
|
||||
elsif FileTest.audio_exist?("Audio/SE/GUI sel buzzer")
|
||||
pbSEPlay("GUI sel buzzer",80)
|
||||
pbSEPlay("GUI sel buzzer", 80)
|
||||
end
|
||||
end
|
||||
|
||||
# Plays a sound effect that plays when the player moves the cursor.
|
||||
# Plays a sound effect that plays when the player closes a menu.
|
||||
def pbPlayCloseMenuSE
|
||||
if FileTest.audio_exist?("Audio/SE/GUI menu close")
|
||||
pbSEPlay("GUI menu close",80)
|
||||
pbSEPlay("GUI menu close", 80)
|
||||
end
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,7 @@
|
||||
class PictureSprite < SpriteWrapper
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class PictureSprite < Sprite
|
||||
def initialize(viewport, picture)
|
||||
super(viewport)
|
||||
@picture = picture
|
||||
@@ -10,7 +13,7 @@ class PictureSprite < SpriteWrapper
|
||||
end
|
||||
|
||||
def dispose
|
||||
@pictureBitmap.dispose if @pictureBitmap
|
||||
@pictureBitmap&.dispose
|
||||
super
|
||||
end
|
||||
|
||||
@@ -22,23 +25,23 @@ class PictureSprite < SpriteWrapper
|
||||
|
||||
def update
|
||||
super
|
||||
@pictureBitmap.update if @pictureBitmap
|
||||
@pictureBitmap&.update
|
||||
# If picture file name is different from current one
|
||||
if @customBitmap && @picture.name==""
|
||||
if @customBitmap && @picture.name == ""
|
||||
self.bitmap = (@customBitmapIsBitmap) ? @customBitmap : @customBitmap.bitmap
|
||||
elsif @picture_name != @picture.name || @picture.hue.to_i != @hue.to_i
|
||||
elsif @picture_name != @picture.name || @picture.hue.to_i != @hue.to_i
|
||||
# Remember file name to instance variables
|
||||
@picture_name = @picture.name
|
||||
@hue = @picture.hue.to_i
|
||||
# If file name is not empty
|
||||
if @picture_name == ""
|
||||
@pictureBitmap.dispose if @pictureBitmap
|
||||
@pictureBitmap&.dispose
|
||||
@pictureBitmap = nil
|
||||
self.visible = false
|
||||
return
|
||||
end
|
||||
# Get picture graphic
|
||||
@pictureBitmap.dispose if @pictureBitmap
|
||||
@pictureBitmap&.dispose
|
||||
@pictureBitmap = AnimatedBitmap.new(@picture_name, @hue)
|
||||
self.bitmap = (@pictureBitmap) ? @pictureBitmap.bitmap : nil
|
||||
elsif @picture_name == ""
|
||||
@@ -46,28 +49,24 @@ class PictureSprite < SpriteWrapper
|
||||
self.visible = false
|
||||
return
|
||||
end
|
||||
setPictureSprite(self,@picture)
|
||||
setPictureSprite(self, @picture)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def pbTextBitmap(text, maxwidth=Graphics.width)
|
||||
tmp = Bitmap.new(maxwidth,Graphics.height)
|
||||
def pbTextBitmap(text, maxwidth = Graphics.width)
|
||||
tmp = Bitmap.new(maxwidth, Graphics.height)
|
||||
pbSetSystemFont(tmp)
|
||||
drawFormattedTextEx(tmp,0,0,maxwidth,text,Color.new(248,248,248),Color.new(168,184,184))
|
||||
drawFormattedTextEx(tmp, 0, 4, maxwidth, text, Color.new(248, 248, 248), Color.new(168, 184, 184))
|
||||
return tmp
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# EventScene
|
||||
#
|
||||
#===============================================================================
|
||||
class EventScene
|
||||
attr_accessor :onCTrigger,:onBTrigger,:onUpdate
|
||||
attr_accessor :onCTrigger, :onBTrigger, :onUpdate
|
||||
|
||||
def initialize(viewport=nil)
|
||||
def initialize(viewport = nil)
|
||||
@viewport = viewport
|
||||
@onCTrigger = Event.new
|
||||
@onBTrigger = Event.new
|
||||
@@ -80,12 +79,8 @@ class EventScene
|
||||
|
||||
def dispose
|
||||
return if disposed?
|
||||
for sprite in @picturesprites
|
||||
sprite.dispose
|
||||
end
|
||||
for sprite in @usersprites
|
||||
sprite.dispose
|
||||
end
|
||||
@picturesprites.each { |sprite| sprite.dispose }
|
||||
@usersprites.each { |sprite| sprite.dispose }
|
||||
@onCTrigger.clear
|
||||
@onBTrigger.clear
|
||||
@onUpdate.clear
|
||||
@@ -105,26 +100,26 @@ class EventScene
|
||||
# EventScene doesn't take ownership of the passed-in bitmap
|
||||
num = @pictures.length
|
||||
picture = PictureEx.new(num)
|
||||
picture.setXY(0,x,y)
|
||||
picture.setVisible(0,true)
|
||||
picture.setXY(0, x, y)
|
||||
picture.setVisible(0, true)
|
||||
@pictures[num] = picture
|
||||
@picturesprites[num] = PictureSprite.new(@viewport,picture)
|
||||
@picturesprites[num] = PictureSprite.new(@viewport, picture)
|
||||
@picturesprites[num].setCustomBitmap(bitmap)
|
||||
return picture
|
||||
end
|
||||
|
||||
def addLabel(x, y, width, text)
|
||||
addBitmap(x,y,pbTextBitmap(text,width))
|
||||
addBitmap(x, y, pbTextBitmap(text, width))
|
||||
end
|
||||
|
||||
def addImage(x, y, name)
|
||||
num = @pictures.length
|
||||
picture = PictureEx.new(num)
|
||||
picture.name = name
|
||||
picture.setXY(0,x,y)
|
||||
picture.setVisible(0,true)
|
||||
picture.setXY(0, x, y)
|
||||
picture.setVisible(0, true)
|
||||
@pictures[num] = picture
|
||||
@picturesprites[num] = PictureSprite.new(@viewport,picture)
|
||||
@picturesprites[num] = PictureSprite.new(@viewport, picture)
|
||||
return picture
|
||||
end
|
||||
|
||||
@@ -136,36 +131,38 @@ class EventScene
|
||||
return @pictures[num]
|
||||
end
|
||||
|
||||
def wait(frames)
|
||||
frames.times { update }
|
||||
# ticks is in 1/20ths of a second.
|
||||
def wait(ticks)
|
||||
return if ticks <= 0
|
||||
timer_start = System.uptime
|
||||
loop do
|
||||
update
|
||||
break if System.uptime - timer_start >= ticks / 20.0
|
||||
end
|
||||
end
|
||||
|
||||
def pictureWait(extraframes=0)
|
||||
# extra_ticks is in 1/20ths of a second.
|
||||
def pictureWait(extra_ticks = 0)
|
||||
loop do
|
||||
hasRunning = false
|
||||
for pic in @pictures
|
||||
hasRunning = true if pic.running?
|
||||
end
|
||||
@pictures.each { |pic| hasRunning = true if pic.running? }
|
||||
break if !hasRunning
|
||||
update
|
||||
end
|
||||
extraframes.times { update }
|
||||
wait(extra_ticks)
|
||||
end
|
||||
|
||||
def update
|
||||
return if disposed?
|
||||
Graphics.update
|
||||
Input.update
|
||||
for picture in @pictures
|
||||
picture.update
|
||||
end
|
||||
for sprite in @picturesprites
|
||||
sprite.update
|
||||
end
|
||||
for sprite in @usersprites
|
||||
@pictures.each { |picture| picture.update }
|
||||
@picturesprites.each { |sprite| sprite.update }
|
||||
@usersprites.each do |sprite|
|
||||
next if !sprite || sprite.disposed? || !sprite.is_a?(Sprite)
|
||||
sprite.update
|
||||
end
|
||||
@usersprites.delete_if { |sprite| sprite.disposed? }
|
||||
@onUpdate.trigger(self)
|
||||
if Input.trigger?(Input::BACK)
|
||||
@onBTrigger.trigger(self)
|
||||
@@ -175,24 +172,21 @@ class EventScene
|
||||
end
|
||||
|
||||
def main
|
||||
while !disposed?
|
||||
loop do
|
||||
update
|
||||
break if disposed?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
def pbEventScreen(cls)
|
||||
pbFadeOutIn {
|
||||
viewport = Viewport.new(0,0,Graphics.width,Graphics.height)
|
||||
pbFadeOutIn do
|
||||
viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
|
||||
viewport.z = 99999
|
||||
PBDebug.logonerr {
|
||||
cls.new(viewport).main
|
||||
}
|
||||
PBDebug.logonerr { cls.new(viewport).main }
|
||||
viewport.dispose
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module GameData
|
||||
#=============================================================================
|
||||
# A mixin module for data classes which provides common class methods (called
|
||||
@@ -6,6 +9,10 @@ module GameData
|
||||
# For data that is known by a symbol or an ID number.
|
||||
#=============================================================================
|
||||
module ClassMethods
|
||||
def schema
|
||||
return self::SCHEMA
|
||||
end
|
||||
|
||||
def register(hash)
|
||||
self::DATA[hash[:id]] = self::DATA[hash[:id_number]] = self.new(hash)
|
||||
end
|
||||
@@ -26,9 +33,6 @@ module GameData
|
||||
validate other => [Symbol, self, String, Integer]
|
||||
return other if other.is_a?(self)
|
||||
other = other.to_sym if other.is_a?(String)
|
||||
# if other.is_a?(Integer)
|
||||
# p "Please switch to symbols, thanks."
|
||||
# end
|
||||
raise "Unknown ID #{other}." unless self::DATA.has_key?(other)
|
||||
return self::DATA[other]
|
||||
end
|
||||
@@ -40,9 +44,6 @@ module GameData
|
||||
validate other => [Symbol, self, String, Integer]
|
||||
return other if other.is_a?(self)
|
||||
other = other.to_sym if other.is_a?(String)
|
||||
# if other.is_a?(Integer)
|
||||
# p "Please switch to symbols, thanks."
|
||||
# end
|
||||
return (self::DATA.has_key?(other)) ? self::DATA[other] : nil
|
||||
end
|
||||
|
||||
@@ -54,8 +55,12 @@ module GameData
|
||||
|
||||
# Yields all data in order of their id_number.
|
||||
def each
|
||||
keys = self::DATA.keys.sort { |a, b| self::DATA[a].id_number <=> self::DATA[b].id_number }
|
||||
keys.each { |key| yield self::DATA[key] if !key.is_a?(Integer) }
|
||||
sorted_keys = self::DATA.keys.sort { |a, b| self::DATA[a].id_number <=> self::DATA[b].id_number }
|
||||
sorted_keys.each { |key| yield self::DATA[key] if !key.is_a?(Integer) }
|
||||
end
|
||||
|
||||
def count
|
||||
return self::DATA.length / 2
|
||||
end
|
||||
|
||||
def load
|
||||
@@ -74,6 +79,10 @@ module GameData
|
||||
# For data that is only known by a symbol.
|
||||
#=============================================================================
|
||||
module ClassMethodsSymbols
|
||||
def schema
|
||||
return self::SCHEMA
|
||||
end
|
||||
|
||||
def register(hash)
|
||||
self::DATA[hash[:id]] = self.new(hash)
|
||||
end
|
||||
@@ -114,12 +123,21 @@ module GameData
|
||||
return self::DATA.keys
|
||||
end
|
||||
|
||||
# Yields all data in alphabetical order.
|
||||
# Yields all data in the order they were defined.
|
||||
def each
|
||||
self::DATA.each_value { |value| yield value }
|
||||
end
|
||||
|
||||
# Yields all data in alphabetical order.
|
||||
def each_alphabetically
|
||||
keys = self::DATA.keys.sort { |a, b| self::DATA[a].real_name <=> self::DATA[b].real_name }
|
||||
keys.each { |key| yield self::DATA[key] }
|
||||
end
|
||||
|
||||
def count
|
||||
return self::DATA.length
|
||||
end
|
||||
|
||||
def load
|
||||
const_set(:DATA, load_data("Data/#{self::DATA_FILENAME}"))
|
||||
end
|
||||
@@ -136,6 +154,10 @@ module GameData
|
||||
# For data that is only known by an ID number.
|
||||
#=============================================================================
|
||||
module ClassMethodsIDNumbers
|
||||
def schema
|
||||
return self::SCHEMA
|
||||
end
|
||||
|
||||
def register(hash)
|
||||
self::DATA[hash[:id]] = self.new(hash)
|
||||
end
|
||||
@@ -171,12 +193,16 @@ module GameData
|
||||
return self::DATA.keys
|
||||
end
|
||||
|
||||
# Yields all data in numberical order.
|
||||
# Yields all data in numerical order.
|
||||
def each
|
||||
keys = self::DATA.keys.sort
|
||||
keys.each { |key| yield self::DATA[key] }
|
||||
end
|
||||
|
||||
def count
|
||||
return self::DATA.length
|
||||
end
|
||||
|
||||
def load
|
||||
const_set(:DATA, load_data("Data/#{self::DATA_FILENAME}"))
|
||||
end
|
||||
@@ -196,34 +222,65 @@ module GameData
|
||||
# @return [Boolean] whether other represents the same thing as this thing
|
||||
def ==(other)
|
||||
return false if other.nil?
|
||||
if other.is_a?(Symbol)
|
||||
case other
|
||||
when Symbol
|
||||
return @id == other
|
||||
elsif other.is_a?(self.class)
|
||||
when self.class
|
||||
return @id == other.id
|
||||
elsif other.is_a?(String)
|
||||
return @id_number == other.to_sym
|
||||
elsif other.is_a?(Integer)
|
||||
when String
|
||||
return @id == other.to_sym
|
||||
when Integer
|
||||
return @id_number == other
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def get_property_for_PBS(key)
|
||||
ret = nil
|
||||
if self.class::SCHEMA.include?(key) && self.respond_to?(self.class::SCHEMA[key][0])
|
||||
ret = self.send(self.class::SCHEMA[key][0])
|
||||
ret = nil if ret == false || (ret.is_a?(Array) && ret.length == 0)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# A bulk loader method for all data stored in .dat files in the Data folder.
|
||||
#=============================================================================
|
||||
def self.load_all
|
||||
Type.load
|
||||
Ability.load
|
||||
Move.load
|
||||
Item.load
|
||||
BerryPlant.load
|
||||
Species.load
|
||||
Ribbon.load
|
||||
Encounter.load
|
||||
TrainerType.load
|
||||
Trainer.load
|
||||
Metadata.load
|
||||
MapMetadata.load
|
||||
self.constants.each do |c|
|
||||
next if !self.const_get(c).is_a?(Class)
|
||||
self.const_get(c).load if self.const_get(c).const_defined?(:DATA_FILENAME)
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_all_data_filenames
|
||||
ret = []
|
||||
self.constants.each do |c|
|
||||
next if !self.const_get(c).is_a?(Class)
|
||||
next if !self.const_get(c).const_defined?(:DATA_FILENAME)
|
||||
if self.const_get(c).const_defined?(:OPTIONAL) && self.const_get(c)::OPTIONAL
|
||||
ret.push([self.const_get(c)::DATA_FILENAME, false])
|
||||
else
|
||||
ret.push([self.const_get(c)::DATA_FILENAME, true])
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def self.get_all_pbs_base_filenames
|
||||
ret = {}
|
||||
self.constants.each do |c|
|
||||
next if !self.const_get(c).is_a?(Class)
|
||||
ret[c] = self.const_get(c)::PBS_BASE_FILENAME if self.const_get(c).const_defined?(:PBS_BASE_FILENAME)
|
||||
next if !ret[c].is_a?(Array)
|
||||
ret[c].length.times do |i|
|
||||
next if i == 0
|
||||
ret[(c.to_s + i.to_s).to_sym] = ret[c][i] # :Species1 => "pokemon_forms"
|
||||
end
|
||||
ret[c] = ret[c][0] # :Species => "pokemon"
|
||||
end
|
||||
return ret
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module GameData
|
||||
class GrowthRate
|
||||
attr_reader :id
|
||||
@@ -24,6 +27,8 @@ module GameData
|
||||
return Settings::MAXIMUM_LEVEL
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def initialize(hash)
|
||||
@id = hash[:id]
|
||||
@real_name = hash[:name] || "Unnamed"
|
||||
@@ -64,7 +69,7 @@ module GameData
|
||||
return ArgumentError.new("Exp amount #{level} is invalid.") if !exp || exp < 0
|
||||
max = GrowthRate.max_level
|
||||
return max if exp >= maximum_exp
|
||||
for level in 1..max
|
||||
(1..max).each do |level|
|
||||
return level - 1 if exp < minimum_exp_for_level(level)
|
||||
end
|
||||
return max
|
||||
@@ -72,46 +77,47 @@ module GameData
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
GameData::GrowthRate.register({
|
||||
:id => :Medium, # Also known as Medium Fast
|
||||
:name => _INTL("Medium"),
|
||||
:exp_values => [-1,
|
||||
0, 8, 27, 64, 125, 216, 343, 512, 729, 1000,
|
||||
1331, 1728, 2197, 2744, 3375, 4096, 4913, 5832, 6859, 8000,
|
||||
9261, 10648, 12167, 13824, 15625, 17576, 19683, 21952, 24389, 27000,
|
||||
29791, 32768, 35937, 39304, 42875, 46656, 50653, 54872, 59319, 64000,
|
||||
68921, 74088, 79507, 85184, 91125, 97336, 103823, 110592, 117649, 125000,
|
||||
132651, 140608, 148877, 157464, 166375, 175616, 185193, 195112, 205379, 216000,
|
||||
226981, 238328, 250047, 262144, 274625, 287496, 300763, 314432, 328509, 343000,
|
||||
357911, 373248, 389017, 405224, 421875, 438976, 456533, 474552, 493039, 512000,
|
||||
531441, 551368, 571787, 592704, 614125, 636056, 658503, 681472, 704969, 729000,
|
||||
753571, 778688, 804357, 830584, 857375, 884736, 912673, 941192, 970299, 1000000],
|
||||
:exp_formula => proc { |level| next level ** 3 }
|
||||
0, 8, 27, 64, 125, 216, 343, 512, 729, 1000,
|
||||
1331, 1728, 2197, 2744, 3375, 4096, 4913, 5832, 6859, 8000,
|
||||
9261, 10648, 12167, 13824, 15625, 17576, 19683, 21952, 24389, 27000,
|
||||
29791, 32768, 35937, 39304, 42875, 46656, 50653, 54872, 59319, 64000,
|
||||
68921, 74088, 79507, 85184, 91125, 97336, 103823, 110592, 117649, 125000,
|
||||
132651, 140608, 148877, 157464, 166375, 175616, 185193, 195112, 205379, 216000,
|
||||
226981, 238328, 250047, 262144, 274625, 287496, 300763, 314432, 328509, 343000,
|
||||
357911, 373248, 389017, 405224, 421875, 438976, 456533, 474552, 493039, 512000,
|
||||
531441, 551368, 571787, 592704, 614125, 636056, 658503, 681472, 704969, 729000,
|
||||
753571, 778688, 804357, 830584, 857375, 884736, 912673, 941192, 970299, 1000000],
|
||||
:exp_formula => proc { |level| next level**3 }
|
||||
})
|
||||
|
||||
# Erratic (600000):
|
||||
# For levels 0-50: n**3 * (100 - n) / 50
|
||||
# For levels 51-68: n**3 * (150 - n) / 100
|
||||
# For levels 69-98: n**3 * 1.274 - (n / 150) - p(n mod 3)
|
||||
# where p(x) = array(0.000, 0.008, 0.014)[x]
|
||||
# For levels 69-98: n**3 * ((1911 - (10 * level)) / 3).floor / 500
|
||||
# For levels 99-100: n**3 * (160 - n) / 100
|
||||
GameData::GrowthRate.register({
|
||||
:id => :Erratic,
|
||||
:name => _INTL("Erratic"),
|
||||
:exp_values => [-1,
|
||||
0, 15, 52, 122, 237, 406, 637, 942, 1326, 1800,
|
||||
2369, 3041, 3822, 4719, 5737, 6881, 8155, 9564, 11111, 12800,
|
||||
14632, 16610, 18737, 21012, 23437, 26012, 28737, 31610, 34632, 37800,
|
||||
41111, 44564, 48155, 51881, 55737, 59719, 63822, 68041, 72369, 76800,
|
||||
81326, 85942, 90637, 95406, 100237, 105122, 110052, 115015, 120001, 125000,
|
||||
131324, 137795, 144410, 151165, 158056, 165079, 172229, 179503, 186894, 194400,
|
||||
202013, 209728, 217540, 225443, 233431, 241496, 249633, 257834, 267406, 276458,
|
||||
286328, 296358, 305767, 316074, 326531, 336255, 346965, 357812, 367807, 378880,
|
||||
390077, 400293, 411686, 423190, 433572, 445239, 457001, 467489, 479378, 491346,
|
||||
501878, 513934, 526049, 536557, 548720, 560922, 571333, 583539, 591882, 600000],
|
||||
:exp_formula => proc { |level| next (level ** 4) * 3 / 500 }
|
||||
0, 15, 52, 122, 237, 406, 637, 942, 1326, 1800,
|
||||
2369, 3041, 3822, 4719, 5737, 6881, 8155, 9564, 11111, 12800,
|
||||
14632, 16610, 18737, 21012, 23437, 26012, 28737, 31610, 34632, 37800,
|
||||
41111, 44564, 48155, 51881, 55737, 59719, 63822, 68041, 72369, 76800,
|
||||
81326, 85942, 90637, 95406, 100237, 105122, 110052, 115015, 120001, 125000,
|
||||
131324, 137795, 144410, 151165, 158056, 165079, 172229, 179503, 186894, 194400,
|
||||
202013, 209728, 217540, 225443, 233431, 241496, 249633, 257834, 267406, 276458,
|
||||
286328, 296358, 305767, 316074, 326531, 336255, 346965, 357812, 367807, 378880,
|
||||
390077, 400293, 411686, 423190, 433572, 445239, 457001, 467489, 479378, 491346,
|
||||
501878, 513934, 526049, 536557, 548720, 560922, 571333, 583539, 591882, 600000],
|
||||
:exp_formula => proc { |level| next ((level**4) + ((level**3) * 2000)) / 3500 }
|
||||
})
|
||||
|
||||
# Fluctuating (1640000):
|
||||
@@ -122,19 +128,18 @@ GameData::GrowthRate.register({
|
||||
:id => :Fluctuating,
|
||||
:name => _INTL("Fluctuating"),
|
||||
:exp_values => [-1,
|
||||
0, 4, 13, 32, 65, 112, 178, 276, 393, 540,
|
||||
745, 967, 1230, 1591, 1957, 2457, 3046, 3732, 4526, 5440,
|
||||
6482, 7666, 9003, 10506, 12187, 14060, 16140, 18439, 20974, 23760,
|
||||
26811, 30146, 33780, 37731, 42017, 46656, 50653, 55969, 60505, 66560,
|
||||
71677, 78533, 84277, 91998, 98415, 107069, 114205, 123863, 131766, 142500,
|
||||
151222, 163105, 172697, 185807, 196322, 210739, 222231, 238036, 250562, 267840,
|
||||
281456, 300293, 315059, 335544, 351520, 373744, 390991, 415050, 433631, 459620,
|
||||
479600, 507617, 529063, 559209, 582187, 614566, 639146, 673863, 700115, 737280,
|
||||
765275, 804997, 834809, 877201, 908905, 954084, 987754, 1035837, 1071552, 1122660,
|
||||
1160499, 1214753, 1254796, 1312322, 1354652, 1415577, 1460276, 1524731, 1571884, 1640000],
|
||||
0, 4, 13, 32, 65, 112, 178, 276, 393, 540,
|
||||
745, 967, 1230, 1591, 1957, 2457, 3046, 3732, 4526, 5440,
|
||||
6482, 7666, 9003, 10506, 12187, 14060, 16140, 18439, 20974, 23760,
|
||||
26811, 30146, 33780, 37731, 42017, 46656, 50653, 55969, 60505, 66560,
|
||||
71677, 78533, 84277, 91998, 98415, 107069, 114205, 123863, 131766, 142500,
|
||||
151222, 163105, 172697, 185807, 196322, 210739, 222231, 238036, 250562, 267840,
|
||||
281456, 300293, 315059, 335544, 351520, 373744, 390991, 415050, 433631, 459620,
|
||||
479600, 507617, 529063, 559209, 582187, 614566, 639146, 673863, 700115, 737280,
|
||||
765275, 804997, 834809, 877201, 908905, 954084, 987754, 1035837, 1071552, 1122660,
|
||||
1160499, 1214753, 1254796, 1312322, 1354652, 1415577, 1460276, 1524731, 1571884, 1640000],
|
||||
:exp_formula => proc { |level|
|
||||
rate = [82 - (level - 100) / 2.0, 40].max
|
||||
next (level ** 4) * rate / 5000
|
||||
next ((level**3) * ((level / 2) + 32)) * 4 / (100 + level)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -142,49 +147,49 @@ GameData::GrowthRate.register({
|
||||
:id => :Parabolic, # Also known as Medium Slow
|
||||
:name => _INTL("Parabolic"),
|
||||
:exp_values => [-1,
|
||||
0, 9, 57, 96, 135, 179, 236, 314, 419, 560,
|
||||
742, 973, 1261, 1612, 2035, 2535, 3120, 3798, 4575, 5460,
|
||||
6458, 7577, 8825, 10208, 11735, 13411, 15244, 17242, 19411, 21760,
|
||||
24294, 27021, 29949, 33084, 36435, 40007, 43808, 47846, 52127, 56660,
|
||||
61450, 66505, 71833, 77440, 83335, 89523, 96012, 102810, 109923, 117360,
|
||||
125126, 133229, 141677, 150476, 159635, 169159, 179056, 189334, 199999, 211060,
|
||||
222522, 234393, 246681, 259392, 272535, 286115, 300140, 314618, 329555, 344960,
|
||||
360838, 377197, 394045, 411388, 429235, 447591, 466464, 485862, 505791, 526260,
|
||||
547274, 568841, 590969, 613664, 636935, 660787, 685228, 710266, 735907, 762160,
|
||||
789030, 816525, 844653, 873420, 902835, 932903, 963632, 995030, 1027103, 1059860],
|
||||
:exp_formula => proc { |level| next ((level ** 3) * 6 / 5) - 15 * (level ** 2) + 100 * level - 140 }
|
||||
0, 9, 57, 96, 135, 179, 236, 314, 419, 560,
|
||||
742, 973, 1261, 1612, 2035, 2535, 3120, 3798, 4575, 5460,
|
||||
6458, 7577, 8825, 10208, 11735, 13411, 15244, 17242, 19411, 21760,
|
||||
24294, 27021, 29949, 33084, 36435, 40007, 43808, 47846, 52127, 56660,
|
||||
61450, 66505, 71833, 77440, 83335, 89523, 96012, 102810, 109923, 117360,
|
||||
125126, 133229, 141677, 150476, 159635, 169159, 179056, 189334, 199999, 211060,
|
||||
222522, 234393, 246681, 259392, 272535, 286115, 300140, 314618, 329555, 344960,
|
||||
360838, 377197, 394045, 411388, 429235, 447591, 466464, 485862, 505791, 526260,
|
||||
547274, 568841, 590969, 613664, 636935, 660787, 685228, 710266, 735907, 762160,
|
||||
789030, 816525, 844653, 873420, 902835, 932903, 963632, 995030, 1027103, 1059860],
|
||||
:exp_formula => proc { |level| next ((level**3) * 6 / 5) - (15 * (level**2)) + (100 * level) - 140 }
|
||||
})
|
||||
|
||||
GameData::GrowthRate.register({
|
||||
:id => :Fast,
|
||||
:name => _INTL("Fast"),
|
||||
:exp_values => [-1,
|
||||
0, 6, 21, 51, 100, 172, 274, 409, 583, 800,
|
||||
1064, 1382, 1757, 2195, 2700, 3276, 3930, 4665, 5487, 6400,
|
||||
7408, 8518, 9733, 11059, 12500, 14060, 15746, 17561, 19511, 21600,
|
||||
23832, 26214, 28749, 31443, 34300, 37324, 40522, 43897, 47455, 51200,
|
||||
55136, 59270, 63605, 68147, 72900, 77868, 83058, 88473, 94119, 100000,
|
||||
106120, 112486, 119101, 125971, 133100, 140492, 148154, 156089, 164303, 172800,
|
||||
181584, 190662, 200037, 209715, 219700, 229996, 240610, 251545, 262807, 274400,
|
||||
286328, 298598, 311213, 324179, 337500, 351180, 365226, 379641, 394431, 409600,
|
||||
425152, 441094, 457429, 474163, 491300, 508844, 526802, 545177, 563975, 583200,
|
||||
602856, 622950, 643485, 664467, 685900, 707788, 730138, 752953, 776239, 800000],
|
||||
:exp_formula => proc { |level| (level ** 3) * 4 / 5 }
|
||||
0, 6, 21, 51, 100, 172, 274, 409, 583, 800,
|
||||
1064, 1382, 1757, 2195, 2700, 3276, 3930, 4665, 5487, 6400,
|
||||
7408, 8518, 9733, 11059, 12500, 14060, 15746, 17561, 19511, 21600,
|
||||
23832, 26214, 28749, 31443, 34300, 37324, 40522, 43897, 47455, 51200,
|
||||
55136, 59270, 63605, 68147, 72900, 77868, 83058, 88473, 94119, 100000,
|
||||
106120, 112486, 119101, 125971, 133100, 140492, 148154, 156089, 164303, 172800,
|
||||
181584, 190662, 200037, 209715, 219700, 229996, 240610, 251545, 262807, 274400,
|
||||
286328, 298598, 311213, 324179, 337500, 351180, 365226, 379641, 394431, 409600,
|
||||
425152, 441094, 457429, 474163, 491300, 508844, 526802, 545177, 563975, 583200,
|
||||
602856, 622950, 643485, 664467, 685900, 707788, 730138, 752953, 776239, 800000],
|
||||
:exp_formula => proc { |level| (level**3) * 4 / 5 }
|
||||
})
|
||||
|
||||
GameData::GrowthRate.register({
|
||||
:id => :Slow,
|
||||
:name => _INTL("Slow"),
|
||||
:exp_values => [-1,
|
||||
0, 10, 33, 80, 156, 270, 428, 640, 911, 1250,
|
||||
1663, 2160, 2746, 3430, 4218, 5120, 6141, 7290, 8573, 10000,
|
||||
11576, 13310, 15208, 17280, 19531, 21970, 24603, 27440, 30486, 33750,
|
||||
37238, 40960, 44921, 49130, 53593, 58320, 63316, 68590, 74148, 80000,
|
||||
86151, 92610, 99383, 106480, 113906, 121670, 129778, 138240, 147061, 156250,
|
||||
165813, 175760, 186096, 196830, 207968, 219520, 231491, 243890, 256723, 270000,
|
||||
283726, 297910, 312558, 327680, 343281, 359370, 375953, 393040, 410636, 428750,
|
||||
447388, 466560, 486271, 506530, 527343, 548720, 570666, 593190, 616298, 640000,
|
||||
664301, 689210, 714733, 740880, 767656, 795070, 823128, 851840, 881211, 911250,
|
||||
941963, 973360, 1005446, 1038230, 1071718, 1105920, 1140841, 1176490, 1212873, 1250000],
|
||||
:exp_formula => proc { |level| (level ** 3) * 5 / 4 }
|
||||
0, 10, 33, 80, 156, 270, 428, 640, 911, 1250,
|
||||
1663, 2160, 2746, 3430, 4218, 5120, 6141, 7290, 8573, 10000,
|
||||
11576, 13310, 15208, 17280, 19531, 21970, 24603, 27440, 30486, 33750,
|
||||
37238, 40960, 44921, 49130, 53593, 58320, 63316, 68590, 74148, 80000,
|
||||
86151, 92610, 99383, 106480, 113906, 121670, 129778, 138240, 147061, 156250,
|
||||
165813, 175760, 186096, 196830, 207968, 219520, 231491, 243890, 256723, 270000,
|
||||
283726, 297910, 312558, 327680, 343281, 359370, 375953, 393040, 410636, 428750,
|
||||
447388, 466560, 486271, 506530, 527343, 548720, 570666, 593190, 616298, 640000,
|
||||
664301, 689210, 714733, 740880, 767656, 795070, 823128, 851840, 881211, 911250,
|
||||
941963, 973360, 1005446, 1038230, 1071718, 1105920, 1140841, 1176490, 1212873, 1250000],
|
||||
:exp_formula => proc { |level| (level**3) * 5 / 4 }
|
||||
})
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#===============================================================================
|
||||
# If a Pokémon's gender ratio is none of :AlwaysMale, :AlwaysFemale or
|
||||
# :Genderless, then it will choose a random number between 0 and 255 inclusive,
|
||||
# and compare it to the @female_chance. If the random number is lower than this
|
||||
# chance, it will be female; otherwise, it will be male.
|
||||
#===============================================================================
|
||||
module GameData
|
||||
class GenderRatio
|
||||
attr_reader :id
|
||||
@@ -16,6 +18,8 @@ module GameData
|
||||
def self.load; end
|
||||
def self.save; end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def initialize(hash)
|
||||
@id = hash[:id]
|
||||
@real_name = hash[:name] || "Unnamed"
|
||||
@@ -26,9 +30,17 @@ module GameData
|
||||
def name
|
||||
return _INTL(@real_name)
|
||||
end
|
||||
|
||||
# @return [Boolean] whether a Pokémon with this gender ratio can only ever
|
||||
# be a single gender
|
||||
def single_gendered?
|
||||
return @female_chance.nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
GameData::GenderRatio.register({
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module GameData
|
||||
class EggGroup
|
||||
attr_reader :id
|
||||
@@ -11,6 +14,8 @@ module GameData
|
||||
def self.load; end
|
||||
def self.save; end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def initialize(hash)
|
||||
@id = hash[:id]
|
||||
@real_name = hash[:name] || "Unnamed"
|
||||
@@ -23,6 +28,8 @@ module GameData
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
GameData::EggGroup.register({
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
# NOTE: The id_number is only used to determine the order that body shapes are
|
||||
# listed in the Pokédex search screen. Number 0 (:None) is ignored; they
|
||||
# start with shape 1.
|
||||
# "Graphics/Pictures/Pokedex/icon_shapes.png" contains icons for these
|
||||
#===============================================================================
|
||||
# NOTE: The order these shapes are registered are the order they are listed in
|
||||
# the Pokédex search screen.
|
||||
# "Graphics/UI/Pokedex/icon_shapes.png" contains icons for these
|
||||
# shapes.
|
||||
#===============================================================================
|
||||
module GameData
|
||||
class BodyShape
|
||||
attr_reader :id
|
||||
attr_reader :id_number
|
||||
attr_reader :real_name
|
||||
attr_reader :icon_position # Where this shape's icon is within icon_shapes.png
|
||||
|
||||
DATA = {}
|
||||
|
||||
extend ClassMethods
|
||||
extend ClassMethodsSymbols
|
||||
include InstanceMethods
|
||||
|
||||
def self.load; end
|
||||
def self.save; end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def initialize(hash)
|
||||
@id = hash[:id]
|
||||
@id_number = hash[:id_number] || -1
|
||||
@real_name = hash[:name] || "Unnamed"
|
||||
@id = hash[:id]
|
||||
@real_name = hash[:name] || "Unnamed"
|
||||
@icon_position = hash[:icon_position] || 0
|
||||
end
|
||||
|
||||
# @return [String] the translated name of this body shape
|
||||
@@ -30,88 +33,90 @@ module GameData
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
GameData::BodyShape.register({
|
||||
:id => :Head,
|
||||
:id_number => 1,
|
||||
:name => _INTL("Head")
|
||||
:id => :Head,
|
||||
:name => _INTL("Head"),
|
||||
:icon_position => 0
|
||||
})
|
||||
|
||||
GameData::BodyShape.register({
|
||||
:id => :Serpentine,
|
||||
:id_number => 2,
|
||||
:name => _INTL("Serpentine")
|
||||
:id => :Serpentine,
|
||||
:name => _INTL("Serpentine"),
|
||||
:icon_position => 1
|
||||
})
|
||||
|
||||
GameData::BodyShape.register({
|
||||
:id => :Finned,
|
||||
:id_number => 3,
|
||||
:name => _INTL("Finned")
|
||||
:id => :Finned,
|
||||
:name => _INTL("Finned"),
|
||||
:icon_position => 2
|
||||
})
|
||||
|
||||
GameData::BodyShape.register({
|
||||
:id => :HeadArms,
|
||||
:id_number => 4,
|
||||
:name => _INTL("Head and arms")
|
||||
:id => :HeadArms,
|
||||
:name => _INTL("Head and arms"),
|
||||
:icon_position => 3
|
||||
})
|
||||
|
||||
GameData::BodyShape.register({
|
||||
:id => :HeadBase,
|
||||
:id_number => 5,
|
||||
:name => _INTL("Head and base")
|
||||
:id => :HeadBase,
|
||||
:name => _INTL("Head and base"),
|
||||
:icon_position => 4
|
||||
})
|
||||
|
||||
GameData::BodyShape.register({
|
||||
:id => :BipedalTail,
|
||||
:id_number => 6,
|
||||
:name => _INTL("Bipedal with tail")
|
||||
:id => :BipedalTail,
|
||||
:name => _INTL("Bipedal with tail"),
|
||||
:icon_position => 5
|
||||
})
|
||||
|
||||
GameData::BodyShape.register({
|
||||
:id => :HeadLegs,
|
||||
:id_number => 7,
|
||||
:name => _INTL("Head and legs")
|
||||
:id => :HeadLegs,
|
||||
:name => _INTL("Head and legs"),
|
||||
:icon_position => 6
|
||||
})
|
||||
|
||||
GameData::BodyShape.register({
|
||||
:id => :Quadruped,
|
||||
:id_number => 8,
|
||||
:name => _INTL("Quadruped")
|
||||
:id => :Quadruped,
|
||||
:name => _INTL("Quadruped"),
|
||||
:icon_position => 7
|
||||
})
|
||||
|
||||
GameData::BodyShape.register({
|
||||
:id => :Winged,
|
||||
:id_number => 9,
|
||||
:name => _INTL("Winged")
|
||||
:id => :Winged,
|
||||
:name => _INTL("Winged"),
|
||||
:icon_position => 8
|
||||
})
|
||||
|
||||
GameData::BodyShape.register({
|
||||
:id => :Multiped,
|
||||
:id_number => 10,
|
||||
:name => _INTL("Multiped")
|
||||
:id => :Multiped,
|
||||
:name => _INTL("Multiped"),
|
||||
:icon_position => 9
|
||||
})
|
||||
|
||||
GameData::BodyShape.register({
|
||||
:id => :MultiBody,
|
||||
:id_number => 11,
|
||||
:name => _INTL("Multi Body")
|
||||
:id => :MultiBody,
|
||||
:name => _INTL("Multi Body"),
|
||||
:icon_position => 10
|
||||
})
|
||||
|
||||
GameData::BodyShape.register({
|
||||
:id => :Bipedal,
|
||||
:id_number => 12,
|
||||
:name => _INTL("Bipedal")
|
||||
:id => :Bipedal,
|
||||
:name => _INTL("Bipedal"),
|
||||
:icon_position => 11
|
||||
})
|
||||
|
||||
GameData::BodyShape.register({
|
||||
:id => :MultiWinged,
|
||||
:id_number => 13,
|
||||
:name => _INTL("Multi Winged")
|
||||
:id => :MultiWinged,
|
||||
:name => _INTL("Multi Winged"),
|
||||
:icon_position => 12
|
||||
})
|
||||
|
||||
GameData::BodyShape.register({
|
||||
:id => :Insectoid,
|
||||
:id_number => 14,
|
||||
:name => _INTL("Insectoid")
|
||||
:id => :Insectoid,
|
||||
:name => _INTL("Insectoid"),
|
||||
:icon_position => 13
|
||||
})
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
# NOTE: The id_number is only used to determine the order that body colors are
|
||||
# listed in the Pokédex search screen.
|
||||
#===============================================================================
|
||||
# NOTE: The order these colors are registered are the order they are listed in
|
||||
# the Pokédex search screen.
|
||||
#===============================================================================
|
||||
module GameData
|
||||
class BodyColor
|
||||
attr_reader :id
|
||||
attr_reader :id_number
|
||||
attr_reader :real_name
|
||||
|
||||
DATA = {}
|
||||
|
||||
extend ClassMethods
|
||||
extend ClassMethodsSymbols
|
||||
include InstanceMethods
|
||||
|
||||
def self.load; end
|
||||
def self.save; end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def initialize(hash)
|
||||
@id = hash[:id]
|
||||
@id_number = hash[:id_number] || -1
|
||||
@real_name = hash[:name] || "Unnamed"
|
||||
@real_name = hash[:name] || "Unnamed"
|
||||
end
|
||||
|
||||
# @return [String] the translated name of this body color
|
||||
@@ -27,64 +29,56 @@ module GameData
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
GameData::BodyColor.register({
|
||||
:id => :Red,
|
||||
:id_number => 0,
|
||||
:name => _INTL("Red")
|
||||
:id => :Red,
|
||||
:name => _INTL("Red")
|
||||
})
|
||||
|
||||
GameData::BodyColor.register({
|
||||
:id => :Blue,
|
||||
:id_number => 1,
|
||||
:name => _INTL("Blue")
|
||||
:id => :Blue,
|
||||
:name => _INTL("Blue")
|
||||
})
|
||||
|
||||
GameData::BodyColor.register({
|
||||
:id => :Yellow,
|
||||
:id_number => 2,
|
||||
:name => _INTL("Yellow")
|
||||
:id => :Yellow,
|
||||
:name => _INTL("Yellow")
|
||||
})
|
||||
|
||||
GameData::BodyColor.register({
|
||||
:id => :Green,
|
||||
:id_number => 3,
|
||||
:name => _INTL("Green")
|
||||
:id => :Green,
|
||||
:name => _INTL("Green")
|
||||
})
|
||||
|
||||
GameData::BodyColor.register({
|
||||
:id => :Black,
|
||||
:id_number => 4,
|
||||
:name => _INTL("Black")
|
||||
:id => :Black,
|
||||
:name => _INTL("Black")
|
||||
})
|
||||
|
||||
GameData::BodyColor.register({
|
||||
:id => :Brown,
|
||||
:id_number => 5,
|
||||
:name => _INTL("Brown")
|
||||
:id => :Brown,
|
||||
:name => _INTL("Brown")
|
||||
})
|
||||
|
||||
GameData::BodyColor.register({
|
||||
:id => :Purple,
|
||||
:id_number => 6,
|
||||
:name => _INTL("Purple")
|
||||
:id => :Purple,
|
||||
:name => _INTL("Purple")
|
||||
})
|
||||
|
||||
GameData::BodyColor.register({
|
||||
:id => :Gray,
|
||||
:id_number => 7,
|
||||
:name => _INTL("Gray")
|
||||
:id => :Gray,
|
||||
:name => _INTL("Gray")
|
||||
})
|
||||
|
||||
GameData::BodyColor.register({
|
||||
:id => :White,
|
||||
:id_number => 8,
|
||||
:name => _INTL("White")
|
||||
:id => :White,
|
||||
:name => _INTL("White")
|
||||
})
|
||||
|
||||
GameData::BodyColor.register({
|
||||
:id => :Pink,
|
||||
:id_number => 9,
|
||||
:name => _INTL("Pink")
|
||||
:id => :Pink,
|
||||
:name => _INTL("Pink")
|
||||
})
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module GameData
|
||||
class Habitat
|
||||
attr_reader :id
|
||||
@@ -11,6 +14,8 @@ module GameData
|
||||
def self.load; end
|
||||
def self.save; end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def initialize(hash)
|
||||
@id = hash[:id]
|
||||
@real_name = hash[:name] || "Unnamed"
|
||||
@@ -23,6 +28,8 @@ module GameData
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
GameData::Habitat.register({
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module GameData
|
||||
class Evolution
|
||||
attr_reader :id
|
||||
attr_reader :real_name
|
||||
attr_reader :parameter
|
||||
attr_reader :minimum_level # 0 means parameter is the minimum level
|
||||
attr_reader :any_level_up # false means parameter is the minimum level
|
||||
attr_reader :level_up_proc
|
||||
attr_reader :battle_level_up_proc
|
||||
attr_reader :use_item_proc
|
||||
attr_reader :on_trade_proc
|
||||
attr_reader :after_battle_proc
|
||||
attr_reader :event_proc
|
||||
attr_reader :after_evolution_proc
|
||||
|
||||
DATA = {}
|
||||
@@ -17,21 +23,37 @@ module GameData
|
||||
def self.load; end
|
||||
def self.save; end
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def initialize(hash)
|
||||
@id = hash[:id]
|
||||
@real_name = hash[:id].to_s || "Unnamed"
|
||||
@real_name = hash[:id].to_s || "Unnamed"
|
||||
@parameter = hash[:parameter]
|
||||
@minimum_level = hash[:minimum_level] || 0
|
||||
@any_level_up = hash[:any_level_up] || false
|
||||
@level_up_proc = hash[:level_up_proc]
|
||||
@battle_level_up_proc = hash[:battle_level_up_proc]
|
||||
@use_item_proc = hash[:use_item_proc]
|
||||
@on_trade_proc = hash[:on_trade_proc]
|
||||
@after_battle_proc = hash[:after_battle_proc]
|
||||
@event_proc = hash[:event_proc]
|
||||
@after_evolution_proc = hash[:after_evolution_proc]
|
||||
end
|
||||
|
||||
alias name real_name
|
||||
|
||||
def call_level_up(*args)
|
||||
return (@level_up_proc) ? @level_up_proc.call(*args) : nil
|
||||
end
|
||||
|
||||
def call_battle_level_up(*args)
|
||||
if @battle_level_up_proc
|
||||
return @battle_level_up_proc.call(*args)
|
||||
elsif @level_up_proc
|
||||
return @level_up_proc.call(*args)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def call_use_item(*args)
|
||||
return (@use_item_proc) ? @use_item_proc.call(*args) : nil
|
||||
end
|
||||
@@ -40,18 +62,32 @@ module GameData
|
||||
return (@on_trade_proc) ? @on_trade_proc.call(*args) : nil
|
||||
end
|
||||
|
||||
def call_after_battle(*args)
|
||||
return (@after_battle_proc) ? @after_battle_proc.call(*args) : nil
|
||||
end
|
||||
|
||||
def call_event(*args)
|
||||
return (@event_proc) ? @event_proc.call(*args) : nil
|
||||
end
|
||||
|
||||
def call_after_evolution(*args)
|
||||
@after_evolution_proc.call(*args) if @after_evolution_proc
|
||||
@after_evolution_proc&.call(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :None
|
||||
})
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :Level,
|
||||
:parameter => Integer,
|
||||
@@ -184,12 +220,23 @@ GameData::Evolution.register({
|
||||
}
|
||||
})
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :LevelCoins,
|
||||
:parameter => Integer,
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next $player.coins >= parameter
|
||||
},
|
||||
:after_evolution_proc => proc { |pkmn, new_species, parameter, evo_species|
|
||||
$player.coins -= parameter
|
||||
next true
|
||||
}
|
||||
})
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :LevelDarkness,
|
||||
:parameter => Integer,
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
map_metadata = GameData::MapMetadata.try_get($game_map.map_id)
|
||||
next pkmn.level >= parameter && map_metadata && map_metadata.dark_map
|
||||
next pkmn.level >= parameter && $game_map.metadata&.dark_map
|
||||
}
|
||||
})
|
||||
|
||||
@@ -197,7 +244,7 @@ GameData::Evolution.register({
|
||||
:id => :LevelDarkInParty,
|
||||
:parameter => Integer,
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.level >= parameter && $Trainer.has_pokemon_of_type?(:DARK)
|
||||
next pkmn.level >= parameter && $player.has_pokemon_of_type?(:DARK, [pkmn])
|
||||
}
|
||||
})
|
||||
|
||||
@@ -252,64 +299,61 @@ GameData::Evolution.register({
|
||||
GameData::Evolution.register({
|
||||
:id => :Shedinja,
|
||||
:parameter => Integer,
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next false # This is a dummy proc and shouldn't next true
|
||||
},
|
||||
:after_evolution_proc => proc { |pkmn, new_species, parameter, evo_species|
|
||||
next false if $Trainer.party_full?
|
||||
next false if !$PokemonBag.pbHasItem?(:POKEBALL)
|
||||
next false if $player.party_full?
|
||||
next false if !$bag.has?(:POKEBALL)
|
||||
PokemonEvolutionScene.pbDuplicatePokemon(pkmn, new_species)
|
||||
$PokemonBag.pbDeleteItem(:POKEBALL)
|
||||
$bag.remove(:POKEBALL)
|
||||
next true
|
||||
}
|
||||
})
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :Happiness,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.happiness >= 220
|
||||
next pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220)
|
||||
}
|
||||
})
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :HappinessMale,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.happiness >= 220 && pkmn.male?
|
||||
next pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220) && pkmn.male?
|
||||
}
|
||||
})
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :HappinessFemale,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.happiness >= 220 && pkmn.female?
|
||||
next pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220) && pkmn.female?
|
||||
}
|
||||
})
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :HappinessDay,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.happiness >= 220 && PBDayNight.isDay?
|
||||
next pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220) && PBDayNight.isDay?
|
||||
}
|
||||
})
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :HappinessNight,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.happiness >= 220 && PBDayNight.isNight?
|
||||
next pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220) && PBDayNight.isNight?
|
||||
}
|
||||
})
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :HappinessMove,
|
||||
:parameter => :Move,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
if pkmn.happiness >= 220
|
||||
if pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220)
|
||||
next pkmn.moves.any? { |m| m && m.id == parameter }
|
||||
end
|
||||
}
|
||||
@@ -318,10 +362,10 @@ GameData::Evolution.register({
|
||||
GameData::Evolution.register({
|
||||
:id => :HappinessMoveType,
|
||||
:parameter => :Type,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
if pkmn.happiness >= 220
|
||||
next pkmn.moves.any? { |m| m && m.id > 0 && m.type == parameter }
|
||||
if pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220)
|
||||
next pkmn.moves.any? { |m| m && m.type == parameter }
|
||||
end
|
||||
}
|
||||
})
|
||||
@@ -329,9 +373,9 @@ GameData::Evolution.register({
|
||||
GameData::Evolution.register({
|
||||
:id => :HappinessHoldItem,
|
||||
:parameter => :Item,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.item == parameter && pkmn.happiness >= 220
|
||||
next pkmn.item == parameter && pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220)
|
||||
},
|
||||
:after_evolution_proc => proc { |pkmn, new_species, parameter, evo_species|
|
||||
next false if evo_species != new_species || !pkmn.hasItem?(parameter)
|
||||
@@ -342,7 +386,7 @@ GameData::Evolution.register({
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :MaxHappiness,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.happiness == 255
|
||||
}
|
||||
@@ -351,7 +395,7 @@ GameData::Evolution.register({
|
||||
GameData::Evolution.register({
|
||||
:id => :Beauty, # Feebas
|
||||
:parameter => Integer,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.beauty >= parameter
|
||||
}
|
||||
@@ -360,7 +404,7 @@ GameData::Evolution.register({
|
||||
GameData::Evolution.register({
|
||||
:id => :HoldItem,
|
||||
:parameter => :Item,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.item == parameter
|
||||
},
|
||||
@@ -374,7 +418,7 @@ GameData::Evolution.register({
|
||||
GameData::Evolution.register({
|
||||
:id => :HoldItemMale,
|
||||
:parameter => :Item,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.item == parameter && pkmn.male?
|
||||
},
|
||||
@@ -388,7 +432,7 @@ GameData::Evolution.register({
|
||||
GameData::Evolution.register({
|
||||
:id => :HoldItemFemale,
|
||||
:parameter => :Item,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.item == parameter && pkmn.female?
|
||||
},
|
||||
@@ -402,7 +446,7 @@ GameData::Evolution.register({
|
||||
GameData::Evolution.register({
|
||||
:id => :DayHoldItem,
|
||||
:parameter => :Item,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.item == parameter && PBDayNight.isDay?
|
||||
},
|
||||
@@ -416,7 +460,7 @@ GameData::Evolution.register({
|
||||
GameData::Evolution.register({
|
||||
:id => :NightHoldItem,
|
||||
:parameter => :Item,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.item == parameter && PBDayNight.isNight?
|
||||
},
|
||||
@@ -430,9 +474,9 @@ GameData::Evolution.register({
|
||||
GameData::Evolution.register({
|
||||
:id => :HoldItemHappiness,
|
||||
:parameter => :Item,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.item == parameter && pkmn.happiness >= 220
|
||||
next pkmn.item == parameter && pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220)
|
||||
},
|
||||
:after_evolution_proc => proc { |pkmn, new_species, parameter, evo_species|
|
||||
next false if evo_species != new_species || !pkmn.hasItem?(parameter)
|
||||
@@ -444,7 +488,7 @@ GameData::Evolution.register({
|
||||
GameData::Evolution.register({
|
||||
:id => :HasMove,
|
||||
:parameter => :Move,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.moves.any? { |m| m && m.id == parameter }
|
||||
}
|
||||
@@ -453,7 +497,7 @@ GameData::Evolution.register({
|
||||
GameData::Evolution.register({
|
||||
:id => :HasMoveType,
|
||||
:parameter => :Type,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.moves.any? { |m| m && m.type == parameter }
|
||||
}
|
||||
@@ -462,35 +506,69 @@ GameData::Evolution.register({
|
||||
GameData::Evolution.register({
|
||||
:id => :HasInParty,
|
||||
:parameter => :Species,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next $Trainer.has_species?(parameter)
|
||||
next $player.has_species?(parameter)
|
||||
}
|
||||
})
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :Location,
|
||||
:parameter => Integer,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next $game_map.map_id == parameter
|
||||
}
|
||||
})
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :LocationFlag,
|
||||
:parameter => String,
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next $game_map.metadata&.has_flag?(parameter)
|
||||
}
|
||||
})
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :Region,
|
||||
:parameter => Integer,
|
||||
:minimum_level => 1, # Needs any level up
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
map_metadata = GameData::MapMetadata.try_get($game_map.map_id)
|
||||
next map_metadata && map_metadata.town_map_position &&
|
||||
map_metadata.town_map_position[0] == parameter
|
||||
map_metadata = $game_map.metadata
|
||||
next map_metadata&.town_map_position && map_metadata.town_map_position[0] == parameter
|
||||
}
|
||||
})
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :Counter,
|
||||
:parameter => Integer,
|
||||
:any_level_up => true, # Needs any level up
|
||||
:level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.evolution_counter >= parameter
|
||||
},
|
||||
:after_evolution_proc => proc { |pkmn, new_species, parameter, evo_species|
|
||||
pkmn.evolution_counter = 0
|
||||
next true
|
||||
}
|
||||
})
|
||||
|
||||
#===============================================================================
|
||||
# Evolution methods that trigger when using an item on the Pokémon
|
||||
# Evolution methods that trigger when levelling up in battle.
|
||||
#===============================================================================
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :LevelBattle,
|
||||
:parameter => Integer,
|
||||
:battle_level_up_proc => proc { |pkmn, parameter|
|
||||
next pkmn.level >= parameter
|
||||
}
|
||||
})
|
||||
|
||||
#===============================================================================
|
||||
# Evolution methods that trigger when using an item on the Pokémon.
|
||||
#===============================================================================
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :Item,
|
||||
:parameter => :Item,
|
||||
@@ -535,13 +613,14 @@ GameData::Evolution.register({
|
||||
:id => :ItemHappiness,
|
||||
:parameter => :Item,
|
||||
:use_item_proc => proc { |pkmn, parameter, item|
|
||||
next item == parameter && pkmn.happiness >= 220
|
||||
next item == parameter && pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220)
|
||||
}
|
||||
})
|
||||
|
||||
#===============================================================================
|
||||
# Evolution methods that trigger when the Pokémon is obtained in a trade
|
||||
# Evolution methods that trigger when the Pokémon is obtained in a trade.
|
||||
#===============================================================================
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :Trade,
|
||||
:on_trade_proc => proc { |pkmn, parameter, other_pkmn|
|
||||
@@ -594,6 +673,72 @@ GameData::Evolution.register({
|
||||
:id => :TradeSpecies,
|
||||
:parameter => :Species,
|
||||
:on_trade_proc => proc { |pkmn, parameter, other_pkmn|
|
||||
next pkmn.species == parameter && !other_pkmn.hasItem?(:EVERSTONE)
|
||||
next other_pkmn.species == parameter && !other_pkmn.hasItem?(:EVERSTONE)
|
||||
}
|
||||
})
|
||||
|
||||
#===============================================================================
|
||||
# Evolution methods that are triggered after any battle.
|
||||
#===============================================================================
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :AfterBattleCounter,
|
||||
:parameter => Integer,
|
||||
:any_level_up => true, # Needs any level up
|
||||
:after_battle_proc => proc { |pkmn, party_index, parameter|
|
||||
ret = pkmn.evolution_counter >= parameter
|
||||
pkmn.evolution_counter = 0 # Always resets after battle
|
||||
next ret
|
||||
}
|
||||
})
|
||||
|
||||
# Doesn't cause an evolution itself. Just makes the Pokémon ready to evolve by
|
||||
# another means (e.g. via an event). Note that pkmn.evolution_counter is not
|
||||
# reset after the battle.
|
||||
GameData::Evolution.register({
|
||||
:id => :AfterBattleCounterMakeReady,
|
||||
:parameter => Integer,
|
||||
:any_level_up => true, # Needs any level up
|
||||
:after_battle_proc => proc { |pkmn, party_index, parameter|
|
||||
pkmn.ready_to_evolve = true if pkmn.evolution_counter >= parameter
|
||||
next false
|
||||
}
|
||||
})
|
||||
|
||||
#===============================================================================
|
||||
# Evolution methods that are triggered by an event.
|
||||
# Each event has its own number, which is the value of the parameter as defined
|
||||
# in pokemon.txt/pokemon_forms.txt. It is also 'number' in def pbEvolutionEvent,
|
||||
# which triggers evolution checks for a particular event number. 'value' in an
|
||||
# event_proc is the number of the evolution event currently being triggered.
|
||||
# Evolutions caused by different events should have different numbers. Used
|
||||
# event numbers are:
|
||||
# 1: Kubfu -> Urshifu
|
||||
# 2: Galarian Yamask -> Runerigus
|
||||
# These used event numbers are only used in pokemon.txt/pokemon_forms.txt and in
|
||||
# map events that call pbEvolutionEvent, so they are relatively easy to change
|
||||
# if you need to (no script changes are required). However, you could just
|
||||
# ignore them instead if you don't want to use them.
|
||||
#===============================================================================
|
||||
def pbEvolutionEvent(number)
|
||||
return if !$player
|
||||
$player.able_party.each do |pkmn|
|
||||
pkmn.trigger_event_evolution(number)
|
||||
end
|
||||
end
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :Event,
|
||||
:parameter => Integer,
|
||||
:event_proc => proc { |pkmn, parameter, value|
|
||||
next value == parameter
|
||||
}
|
||||
})
|
||||
|
||||
GameData::Evolution.register({
|
||||
:id => :EventReady,
|
||||
:parameter => Integer,
|
||||
:event_proc => proc { |pkmn, parameter, value|
|
||||
next value == parameter && pkmn.ready_to_evolve
|
||||
}
|
||||
})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user