mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-06 16:44:05 +09:00
Compare commits
622 Commits
gradle-mig
...
delta_t_aw
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aef601e9b8 | ||
|
|
88db71f780 | ||
|
|
ded9cb1a10 | ||
|
|
afba402c6c | ||
|
|
b027f662ce | ||
|
|
c60b0b42ad | ||
|
|
40580a57cd | ||
|
|
09b4a34d14 | ||
|
|
613b69a20f | ||
|
|
5738418f39 | ||
|
|
10cf3fb007 | ||
|
|
be20fd8328 | ||
|
|
d1a2e6b8f2 | ||
|
|
5bf8b6cad7 | ||
|
|
2c59d60a15 | ||
|
|
68df2a223e | ||
|
|
784a6a13e3 | ||
|
|
9040ff2c87 | ||
|
|
c4510f9c3b | ||
|
|
ebce90aa4b | ||
|
|
25d0e195c3 | ||
|
|
e209967730 | ||
|
|
f689e1de99 | ||
|
|
6e33dbdfaf | ||
|
|
b10e8aa777 | ||
|
|
6a343ae382 | ||
|
|
17b6738308 | ||
|
|
078cdfefa4 | ||
|
|
81f9c92e48 | ||
|
|
8237188dc3 | ||
|
|
7b120020e4 | ||
|
|
f4cd4f49b2 | ||
|
|
09b039c62f | ||
|
|
ff8791f48a | ||
|
|
43bc99548c | ||
|
|
380a14492f | ||
|
|
692e08fc1e | ||
|
|
33ad8520f8 | ||
|
|
9aa8eb395d | ||
|
|
34d50b8d70 | ||
|
|
07e8e21eae | ||
|
|
525273e37f | ||
|
|
34a8113d53 | ||
|
|
4f8cf2cb02 | ||
|
|
8a0abf22da | ||
|
|
9140d6d8b0 | ||
|
|
9133f05b5e | ||
|
|
790d16b85d | ||
|
|
adf60e357e | ||
|
|
f81db26e60 | ||
|
|
655eccbe19 | ||
|
|
5b31b4768f | ||
|
|
425cb82133 | ||
|
|
344e4ebdab | ||
|
|
32afb2e2e5 | ||
|
|
3100a093fd | ||
|
|
fb06200d26 | ||
|
|
1696cc8601 | ||
|
|
4072b9fb09 | ||
|
|
36160a6579 | ||
|
|
4986d570a0 | ||
|
|
1965eabaa3 | ||
|
|
90784afd48 | ||
|
|
258364f37e | ||
|
|
f99531c9d4 | ||
|
|
74cfc05fba | ||
|
|
15868a5a2d | ||
|
|
3abca8989a | ||
|
|
ae9a1ebcb4 | ||
|
|
18a05ace64 | ||
|
|
3b2c38cf0b | ||
|
|
6ecbb672fb | ||
|
|
30954d239a | ||
|
|
edd15a4f79 | ||
|
|
db110d1ca4 | ||
|
|
e3e97000a7 | ||
|
|
ce2d9a271a | ||
|
|
222aef7e3d | ||
|
|
08bbdaf70b | ||
|
|
7300b05442 | ||
|
|
cd13e04658 | ||
|
|
48de42d98b | ||
|
|
35c0c45500 | ||
|
|
6c01aa9b0b | ||
|
|
2335312081 | ||
|
|
abfd9b68fc | ||
|
|
500c72ebc9 | ||
|
|
00fc4f1b8c | ||
|
|
98755fab61 | ||
|
|
09d8702089 | ||
|
|
9080127d38 | ||
|
|
d7664c7f46 | ||
|
|
47da7d5b81 | ||
|
|
ef3690765d | ||
|
|
33c333e7fa | ||
|
|
10128a20a0 | ||
|
|
764945fc30 | ||
|
|
3098c0afd2 | ||
|
|
101c67a107 | ||
|
|
a1661fbb4e | ||
|
|
04c5e32ddf | ||
|
|
b78d488044 | ||
|
|
832e296bc5 | ||
|
|
46e5860143 | ||
|
|
4fa44abd3e | ||
|
|
191a91cb81 | ||
|
|
388d3d6f2f | ||
|
|
b1b29387e3 | ||
|
|
764edea832 | ||
|
|
16e4067d89 | ||
|
|
05a8f47006 | ||
|
|
1f1d6f1eda | ||
|
|
27f79238a1 | ||
|
|
6d553ea583 | ||
|
|
ad8d3ba210 | ||
|
|
e441cdf5f0 | ||
|
|
9c3c35067d | ||
|
|
7a60ae0629 | ||
|
|
258273fd25 | ||
|
|
dc502b2f12 | ||
|
|
803e59a0ee | ||
|
|
e31eaf0241 | ||
|
|
8181bec481 | ||
|
|
7c1d6e6b88 | ||
|
|
7e7e54eed7 | ||
|
|
57c9b7b277 | ||
|
|
984eb4de00 | ||
|
|
c4b4bfd2fc | ||
|
|
cf9bce5bac | ||
|
|
16a7d2abe7 | ||
|
|
a690b46456 | ||
|
|
b55cd415f2 | ||
|
|
4c2b73197d | ||
|
|
1c1ae37f41 | ||
|
|
57fa6de62a | ||
|
|
6f0a923df7 | ||
|
|
4b04bf3781 | ||
|
|
eca0469f32 | ||
|
|
d588f73ed6 | ||
|
|
b40a78b706 | ||
|
|
93a43899e7 | ||
|
|
155ba9eb56 | ||
|
|
4224d56b25 | ||
|
|
cc14218dd5 | ||
|
|
b856829ca9 | ||
|
|
a9bc4f47f8 | ||
|
|
bf9c172206 | ||
|
|
fa86ca2e05 | ||
|
|
9cc0a62188 | ||
|
|
f3b0044d5f | ||
|
|
f5d36e2c92 | ||
|
|
8da80e88a3 | ||
|
|
f21ed3bf0d | ||
|
|
4d0c772dd8 | ||
|
|
f4f0e59811 | ||
|
|
d9f576e4dc | ||
|
|
091f79c7f8 | ||
|
|
8942f352a1 | ||
|
|
1aa90077a4 | ||
|
|
3360ab0dfe | ||
|
|
4eee5ee2b1 | ||
|
|
c7c68187eb | ||
|
|
5c8cdd3162 | ||
|
|
73d1a1bdc5 | ||
|
|
ee3d98662c | ||
|
|
d77b552518 | ||
|
|
5f75288dc7 | ||
|
|
74d76440ee | ||
|
|
e072aff897 | ||
|
|
397b2a8795 | ||
|
|
ae1e99aa3e | ||
|
|
17e550a6a0 | ||
|
|
292de8d56a | ||
|
|
626aa710c1 | ||
|
|
78fc6fc657 | ||
|
|
d2b7c76734 | ||
|
|
4cfd3b8c45 | ||
|
|
e645eaade9 | ||
|
|
af34d94e6a | ||
|
|
98539e698f | ||
|
|
03b642ddd3 | ||
|
|
967eafe8a3 | ||
|
|
69eb2d7a3b | ||
|
|
6d4ac92133 | ||
|
|
b40af8e1b3 | ||
|
|
c381250665 | ||
|
|
497a88c8de | ||
|
|
0bad86bb9d | ||
|
|
eee8a18875 | ||
|
|
24b2e2a2af | ||
|
|
e48731b2e3 | ||
|
|
8f9022827c | ||
|
|
de19f49d26 | ||
|
|
9ade08013f | ||
|
|
6b929ac107 | ||
|
|
108a3e6188 | ||
|
|
07681110c7 | ||
|
|
abd1827182 | ||
|
|
9736d39e04 | ||
|
|
8daf0a2c38 | ||
|
|
6bbfd5d167 | ||
|
|
4664c9ba0d | ||
|
|
fded7f1dfb | ||
|
|
d11fd281f4 | ||
|
|
40423ede52 | ||
|
|
941d9fa107 | ||
|
|
c5fa83b2f4 | ||
|
|
51a2e47430 | ||
|
|
6715308f88 | ||
|
|
35f2cf6b4d | ||
|
|
f45a3d252a | ||
|
|
ade77473c4 | ||
|
|
7cd7b4047f | ||
|
|
f5636fe0d3 | ||
|
|
948f922041 | ||
|
|
6c72bef0de | ||
|
|
fe21340186 | ||
|
|
516314c47f | ||
|
|
55cdac9269 | ||
|
|
a506269906 | ||
|
|
77b563396e | ||
|
|
98a67c80c6 | ||
|
|
a8398765c6 | ||
|
|
6df79b96dd | ||
|
|
83b9f74100 | ||
|
|
d9a01a70c3 | ||
|
|
06949848f8 | ||
|
|
0e1c46f18d | ||
|
|
fe8163c1e4 | ||
|
|
e3ac877c3d | ||
|
|
b560011d2f | ||
|
|
e76458bff6 | ||
|
|
558430b4f3 | ||
|
|
1149311076 | ||
|
|
ef176909b4 | ||
|
|
1d8e66a9cc | ||
|
|
cdf961df09 | ||
|
|
01a32ad00c | ||
|
|
7ffb417618 | ||
|
|
82ddfeb6ee | ||
|
|
e67b97257c | ||
|
|
e6e962ecf7 | ||
|
|
749a82bcf7 | ||
|
|
f9897bc439 | ||
|
|
1c6560797d | ||
|
|
75192bef17 | ||
|
|
05560cf04c | ||
|
|
ee7d51c21b | ||
|
|
2928aa2eb7 | ||
|
|
d0702c9159 | ||
|
|
2bf9acb07a | ||
|
|
25ce7958ae | ||
|
|
64f36d2d7c | ||
|
|
65bc67710c | ||
|
|
86d3a4a08d | ||
|
|
33da9777ea | ||
|
|
07ee987411 | ||
|
|
72b7adcf39 | ||
|
|
c595270faa | ||
|
|
d753365e54 | ||
|
|
116b4cc390 | ||
|
|
a5dd5b9e98 | ||
|
|
f51417e709 | ||
|
|
fd7d724f39 | ||
|
|
528fdc9fc5 | ||
|
|
33a774b5b7 | ||
|
|
58205e5eb5 | ||
|
|
31b7203d01 | ||
|
|
c9932fc81b | ||
|
|
145a4e5e71 | ||
|
|
81529eb215 | ||
|
|
057df6632a | ||
|
|
5499ded796 | ||
|
|
61427b849a | ||
|
|
a53f818ba6 | ||
|
|
d9a3318768 | ||
|
|
d241e5cbb0 | ||
|
|
49a9278c59 | ||
|
|
fc9516fd39 | ||
|
|
6bff02d91e | ||
|
|
bad6ff296a | ||
|
|
1e9c04d7c0 | ||
|
|
3ffdd7233f | ||
|
|
5a5fb45c3b | ||
|
|
1a33c3be5a | ||
|
|
0ad7db3b51 | ||
|
|
8504337da9 | ||
|
|
f2f5cd7daf | ||
|
|
464d30a384 | ||
|
|
009b55481b | ||
|
|
72e7931f4d | ||
|
|
0e4dd79cc1 | ||
|
|
f676938176 | ||
|
|
8a759cb178 | ||
|
|
66e4dcd1c4 | ||
|
|
d9381fc58e | ||
|
|
039ccea58f | ||
|
|
b592b8fa0f | ||
|
|
b82d172d58 | ||
|
|
41f9f4032d | ||
|
|
7b2b6caf82 | ||
|
|
b7fb8ff4da | ||
|
|
2ea3ce0c67 | ||
|
|
9b32cf63ff | ||
|
|
2129cce7f3 | ||
|
|
c8c1bdf836 | ||
|
|
4a54c87826 | ||
|
|
7248616e58 | ||
|
|
33b5a21c26 | ||
|
|
1095cb451f | ||
|
|
4472722c5d | ||
|
|
ab846ad805 | ||
|
|
187277d6a8 | ||
|
|
ad481853bb | ||
|
|
1ecbc57f83 | ||
|
|
41791af764 | ||
|
|
c664755ad8 | ||
|
|
984881421c | ||
|
|
e07e321ee3 | ||
|
|
6e403f97f8 | ||
|
|
87242da9cc | ||
|
|
12c6f6fd04 | ||
|
|
980c92f213 | ||
|
|
8a3c4fd65e | ||
|
|
67ca216243 | ||
|
|
7bd7a6532d | ||
|
|
c5765fc08a | ||
|
|
7f909e3796 | ||
|
|
b4042f0060 | ||
|
|
da2452c84e | ||
|
|
f0a6c36f8a | ||
|
|
fdb9d38e03 | ||
|
|
799a77c929 | ||
|
|
41050337f4 | ||
|
|
85ab2a2066 | ||
|
|
06cbac1cc5 | ||
|
|
50b597de5f | ||
|
|
b96daa7d3d | ||
|
|
80777fcccb | ||
|
|
a601d4c57b | ||
|
|
f7eaa4c4f0 | ||
|
|
f466f6f001 | ||
|
|
5255ae60af | ||
|
|
2a575351d3 | ||
|
|
58b229a7fa | ||
|
|
905ab1004c | ||
|
|
b7ed3dd814 | ||
|
|
ccbf56b322 | ||
|
|
87213e8fbd | ||
|
|
40e48eec21 | ||
|
|
b421dcf187 | ||
|
|
2eb6e7c0a2 | ||
|
|
3de9cedec3 | ||
|
|
f45dc6fde2 | ||
|
|
31954f3ca7 | ||
|
|
4262b02faf | ||
|
|
46fe5fb1e2 | ||
|
|
23cc28d3bd | ||
|
|
9732c6d66f | ||
|
|
566c76c1a2 | ||
|
|
81220fa542 | ||
|
|
572fbb4b9c | ||
|
|
10a99b7db6 | ||
|
|
959873413d | ||
|
|
14dfb5c963 | ||
|
|
86821d2d98 | ||
|
|
c9d786390c | ||
|
|
ade9592d67 | ||
|
|
22ad180e04 | ||
|
|
479c0ce91f | ||
|
|
a9d35678c5 | ||
|
|
cbb4eaad94 | ||
|
|
165ae1777b | ||
|
|
ecf775c664 | ||
|
|
1375f91505 | ||
|
|
c9c761598a | ||
|
|
9a7885fc80 | ||
|
|
9508249533 | ||
|
|
3498a100a4 | ||
|
|
7a3e7546de | ||
|
|
93939f22bf | ||
|
|
253260de6f | ||
|
|
a7dea93744 | ||
|
|
26cbe6970a | ||
|
|
3e54dcab2c | ||
|
|
56b77d1838 | ||
|
|
f4db93ca9e | ||
|
|
a9eb1f579e | ||
|
|
36a7983024 | ||
|
|
ab8f019109 | ||
|
|
ebc8174d2c | ||
|
|
c35ba8201a | ||
|
|
5cd5ebbea3 | ||
|
|
6399c2d66b | ||
|
|
b342e7d042 | ||
|
|
c6e42ffbbe | ||
|
|
e0a23f6089 | ||
|
|
c779baa72d | ||
|
|
aa4fbba711 | ||
|
|
2895f4be6d | ||
|
|
fcd378c51a | ||
|
|
fe94ebbe4a | ||
|
|
8689ab1565 | ||
|
|
4f43fdbd27 | ||
|
|
5fe604cf45 | ||
|
|
f840dbe7de | ||
|
|
532c836553 | ||
|
|
7ebb21124c | ||
|
|
f2ae2d9449 | ||
|
|
6087072d3d | ||
|
|
a47eb41d9a | ||
|
|
47b9b92797 | ||
|
|
037e84d6e2 | ||
|
|
1301121aa9 | ||
|
|
d20190b2bd | ||
|
|
bb797a0910 | ||
|
|
d33d25f384 | ||
|
|
12015669c6 | ||
|
|
671048e1e1 | ||
|
|
c5367f8f1c | ||
|
|
2332239ef2 | ||
|
|
25128d45e5 | ||
|
|
207c90d35e | ||
|
|
1057e7d442 | ||
|
|
5bfc5c3a38 | ||
|
|
84f91e6a7a | ||
|
|
4363bd4ba2 | ||
|
|
48315daa7d | ||
|
|
cd710de280 | ||
|
|
816502df3d | ||
|
|
b6290134a9 | ||
|
|
1e3ffd2272 | ||
|
|
1f59082c15 | ||
|
|
2e11676ee6 | ||
|
|
f919b45e18 | ||
|
|
24de647284 | ||
|
|
accf1cf584 | ||
|
|
6bea8af9db | ||
|
|
d3547e47ca | ||
|
|
208fd2ba15 | ||
|
|
72204fd5cd | ||
|
|
41da296bce | ||
|
|
114bfe395f | ||
|
|
2491a03c99 | ||
|
|
3d91023011 | ||
|
|
ff817c25e6 | ||
|
|
f47c66db44 | ||
|
|
bc4fd8866a | ||
|
|
0113ca5d09 | ||
|
|
920d8085cd | ||
|
|
a10134db2e | ||
|
|
edb2f5ce11 | ||
|
|
a22d27408c | ||
|
|
dac69f504c | ||
|
|
dfd71435de | ||
|
|
76fcb5b12f | ||
|
|
e9572488be | ||
|
|
08417be027 | ||
|
|
edd97b45a7 | ||
|
|
0a0aea9589 | ||
|
|
f5db4cb2fb | ||
|
|
75ab8c6558 | ||
|
|
63ec3a8917 | ||
|
|
4c8ceaf301 | ||
|
|
6d8f9d2901 | ||
|
|
efd3284e30 | ||
|
|
b29e6af643 | ||
|
|
96c6cb2cc6 | ||
|
|
bdba27d776 | ||
|
|
71091cce98 | ||
|
|
679a65a12e | ||
|
|
a3445d631a | ||
|
|
b23f848d95 | ||
|
|
3b7e88b0af | ||
|
|
d7b49b0f9d | ||
|
|
0180c7cf0a | ||
|
|
b33f179a9b | ||
|
|
c48308efe1 | ||
|
|
076c5ba1f1 | ||
|
|
d7576ce844 | ||
|
|
1c0b969078 | ||
|
|
5d7349386e | ||
|
|
3065d642b5 | ||
|
|
d028593842 | ||
|
|
5c4036e73f | ||
|
|
a9b00bd909 | ||
|
|
add2be7109 | ||
|
|
226ae77ab4 | ||
|
|
5799cc39ce | ||
|
|
afe197caf7 | ||
|
|
cc01ff62e6 | ||
|
|
bd58c9e40b | ||
|
|
9ddf0dee63 | ||
|
|
ad68309bc5 | ||
|
|
0a2bf64bff | ||
|
|
e66304bea0 | ||
|
|
8e7b61ea0c | ||
|
|
bb33d9e381 | ||
|
|
65dec9661c | ||
|
|
2c9906888b | ||
|
|
2f7eaea6b8 | ||
|
|
abad2eb1a6 | ||
|
|
12b04fabdf | ||
|
|
dbdee14481 | ||
|
|
172e5752ca | ||
|
|
c60a967050 | ||
|
|
361f322d78 | ||
|
|
8b111ef262 | ||
|
|
df5f4771a1 | ||
|
|
2d34db3022 | ||
|
|
5a76b1cc13 | ||
|
|
9aab3d3664 | ||
|
|
c5b452f779 | ||
|
|
95ea8d9b7c | ||
|
|
f02c931715 | ||
|
|
225f2f2235 | ||
|
|
1b83e7deb7 | ||
|
|
e951a6285e | ||
|
|
0717b883b4 | ||
|
|
6c94dc9632 | ||
|
|
54b52b1b6e | ||
|
|
4acc797fee | ||
|
|
5db3aadaf4 | ||
|
|
02f38eab3c | ||
|
|
b08060bffc | ||
|
|
fdecb83ebf | ||
|
|
e139fb891f | ||
|
|
efbb654b45 | ||
|
|
ea4c4bdb2b | ||
|
|
e9c7ef4930 | ||
|
|
1f1e2f6899 | ||
|
|
e7276513d7 | ||
|
|
8ae07c8d20 | ||
|
|
bac246cd9a | ||
|
|
ec73d2ea1e | ||
|
|
213831ad31 | ||
|
|
b52d6f89f7 | ||
|
|
dfb769c982 | ||
|
|
9e9bca3442 | ||
|
|
b1686ec5ab | ||
|
|
d076676a2f | ||
|
|
1e89ddfec7 | ||
|
|
1c5ee6f32c | ||
|
|
083197f4cb | ||
|
|
135f8f86e8 | ||
|
|
f7d055806b | ||
|
|
5944a215df | ||
|
|
0f8f64cddf | ||
|
|
0b7485fd57 | ||
|
|
e499c24c0d | ||
|
|
aab8da6ac7 | ||
|
|
ea73ff3153 | ||
|
|
4b54fb3b67 | ||
|
|
4d8ff11ece | ||
|
|
3eb1fe98cd | ||
|
|
df8c0813c3 | ||
|
|
ae97310bf7 | ||
|
|
0c2cb48135 | ||
|
|
f5f0fcb077 | ||
|
|
d3080ffb78 | ||
|
|
d1f01a203d | ||
|
|
da06e0fa93 | ||
|
|
0b024dcf70 | ||
|
|
ac05b5edf1 | ||
|
|
9a8090038e | ||
|
|
0e60380718 | ||
|
|
71294a6bd1 | ||
|
|
f4332afd3c | ||
|
|
f7365ea47b | ||
|
|
63bc018550 | ||
|
|
bc36cc946d | ||
|
|
767802e75f | ||
|
|
a6bbf256f0 | ||
|
|
e253641471 | ||
|
|
2e2e4a0281 | ||
|
|
433612ebdb | ||
|
|
f06c6f7502 | ||
|
|
81e9539381 | ||
|
|
e88124f065 | ||
|
|
35a723ee0f | ||
|
|
d0109a88af | ||
|
|
5e2cb526ee | ||
|
|
8e6fc55f46 | ||
|
|
ae45cf32a7 | ||
|
|
a9a2b93341 | ||
|
|
639f1c158e | ||
|
|
1362f6921e | ||
|
|
611b78ffa5 | ||
|
|
c1e7b3537d | ||
|
|
72e348b5e5 | ||
|
|
e76f8840ba | ||
|
|
656aa07e8b | ||
|
|
4548a2fe3d | ||
|
|
70d85398ce | ||
|
|
dd60448cae | ||
|
|
8c8a0cbb23 | ||
|
|
e0665db121 | ||
|
|
aeb377a857 | ||
|
|
e501b356cd | ||
|
|
01def757e9 | ||
|
|
ea1e90b035 | ||
|
|
0db1130b41 | ||
|
|
1ad9f2611d | ||
|
|
9c7e7ed266 | ||
|
|
56530a6041 | ||
|
|
af8516be68 | ||
|
|
9df31df54f | ||
|
|
b66b02ceeb | ||
|
|
7a7fac776a | ||
|
|
d179d090c5 | ||
|
|
174a0f9101 | ||
|
|
fd7a629757 | ||
|
|
a5ca82f2c7 | ||
|
|
4552d7b7db | ||
|
|
fe994621c0 | ||
|
|
5dc99f5612 | ||
|
|
1d1769a2c3 | ||
|
|
7078ecfed4 | ||
|
|
1dd156d172 | ||
|
|
22bb5d83e1 | ||
|
|
e1642c799c | ||
|
|
870c9b36ff |
22
.gitignore
vendored
22
.gitignore
vendored
@@ -1,15 +1,33 @@
|
||||
# Build-related
|
||||
out/*
|
||||
bin/*
|
||||
build/*
|
||||
.gradle/*
|
||||
|
||||
# Java native errors
|
||||
hs_err_pid*
|
||||
|
||||
# OS files
|
||||
Thumbs.db
|
||||
*.jar
|
||||
.DS_Store
|
||||
~$*
|
||||
|
||||
# Resources that should not be tracked
|
||||
*.jar
|
||||
assets/mods/basegame/demoworld
|
||||
assets/mods/basegame/demoworld.gz
|
||||
external_resource_packs.zip
|
||||
|
||||
# IntelliJ
|
||||
workspace.xml
|
||||
|
||||
# Temporary files
|
||||
.tmp*
|
||||
tmp_*
|
||||
~$*
|
||||
|
||||
# Eclipse MAT heap files
|
||||
*.hprof
|
||||
*.bin
|
||||
*.index
|
||||
*.threads
|
||||
*_Leak_Suspects.zip
|
||||
@@ -1,6 +1,6 @@
|
||||
*Terrarum*
|
||||
|
||||
Copyright (C) 2013-2018 Minjaesong (Torvald)
|
||||
Copyright (C) 2013-2019 Minjaesong (Torvald)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*Terrarum Sans Bitmap*
|
||||
|
||||
Copyright (c) 2017 Minjae Song (Torvald) and the contributors
|
||||
Copyright (c) 2017-2019 Minjae Song (Torvald) and the contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|0..4095|Tiles (4096 possible)|
|
||||
|4096..8191|Walls (4096 possible)|
|
||||
|8192..8447|Wires (256 possible)|
|
||||
|8448..32767|Items (static) (24320 possible)|
|
||||
|32768..0x0FFF_FFFF|Items (dynamic\*) (268M possible)|
|
||||
|0x1000_0000..0x7FFF_FFFF|Actors|
|
||||
|-2147483648..-1 (all negative numbers)|Faction|
|
||||
|8448..0x0F_FFFF|Items (static) (1M possible)|
|
||||
|0x10_0000..0x0FFF_FFFF|Items (dynamic\*) (267M possible)|
|
||||
|0x1000_0000..0x7FFF_FFFF|Actors (1879M possible)|
|
||||
|-2147483648..-1 (all negative numbers)|Faction (2147M possible)|
|
||||
|
||||
* dynamic items have own properties that will persist through savegame.
|
||||
|
||||
@@ -14,7 +14,8 @@ Actors range in-depth
|
||||
|
||||
|Range|Description|
|
||||
|-----|-----------|
|
||||
|0x1000_0000..0x1FFF_FFFF|Rendered behind (e.g. tapestries)
|
||||
|0x2000_0000..0x5FFF_FFFF|Regular actors (e.g. almost all of them)
|
||||
|0x6000_0000..0x6FFF_FFFF|Special (e.g. weapon swung, bullets, dropped item, particles)
|
||||
|0x7000_0000..0x7FFF_FFFF|Rendered front (e.g. fake tile)
|
||||
|0x1000_0000..0x1FFF_FFFF|Rendered behind (e.g. tapestries)|
|
||||
|0x2000_0000..0x4FFF_FFFF|Regular actors (e.g. almost all of them)|
|
||||
|0x5000_0000..0x5FFF_FFFF|Special (e.g. weapon swung, bullets, dropped item, particles)|
|
||||
|0x6000_0000..0x6FFF_FFFF|Rendered front (e.g. fake tile)|
|
||||
|0x7000_0000..0x7FFF_FFFF|Rendered as screen overlay, not affected by light nor environment overlays|
|
||||
@@ -1,4 +1,4 @@
|
||||
#version 100
|
||||
#version 120
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
|
||||
Binary file not shown.
@@ -10,9 +10,9 @@ uniform sampler2D u_texture;
|
||||
|
||||
|
||||
// "steps" of R, G and B. Must be integer && equal or greater than 2
|
||||
uniform float rcount = 32.0;
|
||||
uniform float gcount = 32.0;
|
||||
uniform float bcount = 32.0;
|
||||
uniform float rcount = 64.0;
|
||||
uniform float gcount = 64.0;
|
||||
uniform float bcount = 64.0;
|
||||
uniform float acount = 1.0;
|
||||
|
||||
int bayer[14 * 14] = int[](131,187,8,78,50,18,134,89,155,102,29,95,184,73,22,86,113,171,142,105,34,166,9,60,151,128,40,110,168,137,45,28,64,188,82,54,124,189,80,13,156,56,7,61,186,121,154,6,108,177,24,100,38,176,93,123,83,148,96,17,88,133,44,145,69,161,139,72,30,181,115,27,163,47,178,65,164,14,120,48,5,127,153,52,190,58,126,81,116,21,106,77,173,92,191,63,99,12,76,144,4,185,37,149,192,39,135,23,117,31,170,132,35,172,103,66,129,79,3,97,57,159,70,141,53,94,114,20,49,158,19,146,169,122,183,11,104,180,2,165,152,87,182,118,91,42,67,25,84,147,43,85,125,68,16,136,71,10,193,112,160,138,51,111,162,26,194,46,174,107,41,143,33,74,1,101,195,15,75,140,109,90,32,62,157,98,167,119,179,59,36,130,175,55,0,150);
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
Air tile (tile 0,0) must have colour of 0x00000000, NOT 0xFFFFFF00. You can modify the tga file directly to correct bad exporter behaviour.
|
||||
Air tile (tile 0,0) must have colour of 0x00000000, NOT 0xFFFFFF00. You can modify the tga file directly to correct bad exporter behaviour.
|
||||
|
||||
All TGA must have alpha premultiplied.
|
||||
@@ -1,182 +1,158 @@
|
||||
"id";"drop";"name" ; "shdr"; "shdg"; "shdb"; "shduv";"strength";"dsty";"mate";"fluid";"solid";"clear";"wall"; "lumr"; "lumg"; "lumb";"lumuv";"fall";"dlfn";"vscs";"fv";"friction"
|
||||
"0"; "0";"BLOCK_AIR" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "1";"null"; "0"; "0"; "1"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"4"
|
||||
"16"; "17";"BLOCK_STONE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"17"; "17";"BLOCK_STONE_QUARRIED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"18"; "18";"BLOCK_STONE_TILE_WHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"19"; "19";"BLOCK_STONE_BRICKS" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"32"; "32";"BLOCK_DIRT" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"dirt"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"33"; "32";"BLOCK_GRASS" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"grss"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"34"; "34";"BLOCK_GRASSWALL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"grss"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"35"; "35";"BLOCK_FOLIAGE_GREEN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"grss"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"36"; "36";"BLOCK_FOLIAGE_LIME" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"grss"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"37"; "37";"BLOCK_FOLIAGE_GOLD" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"grss"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"38"; "38";"BLOCK_FOLIAGE_RED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"grss"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"39"; "39";"BLOCK_FOLIAGE_ICEBLUE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"grss"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"40"; "40";"BLOCK_FOLIAGE_PURPLE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"grss"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"48"; "48";"BLOCK_PLANK_NORMAL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "16"; "740";"wood"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"49"; "49";"BLOCK_PLANK_EBONY" ;"0.1252";"0.1252";"0.1252";"0.1252"; "19";"1200";"wood"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"50"; "50";"BLOCK_PLANK_BIRCH" ;"0.1252";"0.1252";"0.1252";"0.1252"; "15"; "670";"wood"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"51"; "51";"BLOCK_PLANK_BLOODROSE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "17"; "900";"wood"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"64"; "64";"BLOCK_TRUNK_NORMAL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "16"; "740";"wood"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"65"; "65";"BLOCK_TRUNK_EBONY" ;"0.1252";"0.1252";"0.1252";"0.1252"; "19";"1200";"wood"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"66"; "66";"BLOCK_TRUNK_BIRCH" ;"0.1252";"0.1252";"0.1252";"0.1252"; "15"; "670";"wood"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"67"; "67";"BLOCK_TRUNK_BLOODROSE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "17"; "900";"wood"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"80"; "80";"BLOCK_SAND" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"sand"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "1"; "0"; "N/A"; "0";"16"
|
||||
"81"; "81";"BLOCK_SAND_WHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"sand"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "1"; "0"; "N/A"; "0";"16"
|
||||
"82"; "82";"BLOCK_SAND_RED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"sand"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "1"; "0"; "N/A"; "0";"16"
|
||||
"83"; "83";"BLOCK_SAND_DESERT" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"sand"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "1"; "0"; "N/A"; "0";"16"
|
||||
"84"; "84";"BLOCK_SAND_BLACK" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"sand"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "1"; "0"; "N/A"; "0";"16"
|
||||
"85"; "85";"BLOCK_SAND_GREEN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"sand"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "1"; "0"; "N/A"; "0";"16"
|
||||
"96"; "96";"BLOCK_GRAVEL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"grvl"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "1"; "0"; "N/A"; "0";"16"
|
||||
"97"; "97";"BLOCK_GRAVEL_GREY" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"grvl"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "1"; "0"; "N/A"; "0";"16"
|
||||
"112"; "112";"BLOCK_ORE_MALACHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"113"; "113";"BLOCK_ORE_HEMATITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"114"; "114";"BLOCK_ORE_NATURAL_GOLD" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"115"; "115";"BLOCK_ORE_NATURAL_SILVER" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"116"; "116";"BLOCK_ORE_RUTILE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"117"; "117";"BLOCK_ORE_AURICHALCUMITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"128"; "128";"BLOCK_GEM_RUBY" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"129"; "129";"BLOCK_GEM_EMERALD" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"130"; "130";"BLOCK_GEM_SAPPHIRE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"131"; "131";"BLOCK_GEM_TOPAZ" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"132"; "132";"BLOCK_GEM_DIAMOND" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"133"; "133";"BLOCK_GEM_AMETHYST" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"rock"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"144"; "144";"BLOCK_SNOW" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24"; "500";"snow"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"145"; "0";"BLOCK_ICE_FRAGILE" ;"0.0508";"0.0508";"0.0508";"0.0508"; "5"; "930";"icei"; "0"; "1"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0"; "4"
|
||||
"146"; "146";"BLOCK_ICE_NATURAL" ;"0.1016";"0.1016";"0.1016";"0.1016"; "35"; "930";"icei"; "0"; "1"; "1"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0"; "4"
|
||||
"147"; "147";"BLOCK_ICE_CLEAR_MAGICAL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"3720";"icex"; "0"; "1"; "1"; "1";"0.0744";"0.1252";"0.2268";"0.0000"; "0"; "0"; "N/A"; "0"; "4"
|
||||
"148"; "148";"BLOCK_GLASS_CRUDE" ;"0.0120";"0.0040";"0.0120";"0.0080"; "5";"2500";"glas"; "0"; "1"; "1"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"149"; "149";"BLOCK_GLASS_CLEAN" ;"0.0040";"0.0040";"0.0040";"0.0020"; "5";"2203";"glas"; "0"; "1"; "1"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"160"; "160";"BLOCK_PLATFORM_STONE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"rock"; "0"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"161"; "161";"BLOCK_PLATFORM_WOODEN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"wood"; "0"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"162"; "162";"BLOCK_PLATFORM_EBONY" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"wood"; "0"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"163"; "163";"BLOCK_PLATFORM_BIRCH" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"wood"; "0"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"164"; "164";"BLOCK_PLATFORM_BLOODROSE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"wood"; "0"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"176"; "176";"BLOCK_TORCH" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"fxtr"; "0"; "0"; "1"; "0";"1.0000";"0.6372";"0.0000";"0.0000"; "0"; "1"; "N/A"; "0";"16"
|
||||
"177"; "177";"BLOCK_TORCH_FROST" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"fxtr"; "0"; "0"; "1"; "0";"0.3048";"0.4848";"1.0000";"0.0000"; "0"; "1"; "N/A"; "0";"16"
|
||||
"192"; "176";"BLOCK_TORCH" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"fxtr"; "0"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"193"; "177";"BLOCK_TORCH_FROST" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"fxtr"; "0"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"208"; "208";"BLOCK_ILLUMINATOR_WHITE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.9270";"0.9414";"0.8519";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"209"; "209";"BLOCK_ILLUMINATOR_YELLOW" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"1.0000";"0.8408";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"210"; "210";"BLOCK_ILLUMINATOR_ORANGE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"1.0000";"0.5294";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"211"; "211";"BLOCK_ILLUMINATOR_RED" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.9188";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"212"; "212";"BLOCK_ILLUMINATOR_FUCHSIA" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.9188";"0.0000";"0.7156";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"213"; "213";"BLOCK_ILLUMINATOR_PURPLE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.7156";"0.0000";"0.9188";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"214"; "214";"BLOCK_ILLUMINATOR_BLUE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.1996";"0.9188";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"215"; "215";"BLOCK_ILLUMINATOR_CYAN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.4621";"1.4188";"1.2368";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"216"; "216";"BLOCK_ILLUMINATOR_GREEN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.2112";"1.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"217"; "217";"BLOCK_ILLUMINATOR_GREEN_DARK";"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.1252";"0.4068";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"218"; "218";"BLOCK_ILLUMINATOR_BROWN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.3324";"0.1252";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"219"; "219";"BLOCK_ILLUMINATOR_TAN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.5864";"0.4068";"0.2032";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"220"; "220";"BLOCK_ILLUMINATOR_GREY_LIGHT";"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.7392";"0.7392";"0.7392";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"221"; "221";"BLOCK_ILLUMINATOR_GREY_MED" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.4576";"0.4576";"0.4576";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"222"; "222";"BLOCK_ILLUMINATOR_GREY_DARK" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.2540";"0.2540";"0.2540";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"223"; "223";"BLOCK_ILLUMINATOR_BLACK" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.2140";"0.0000";"0.4932";"3.7499"; "0"; "0"; "N/A"; "0";"16"
|
||||
"224"; "208";"BLOCK_ILLUMINATOR_WHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"225"; "209";"BLOCK_ILLUMINATOR_YELLOW" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"226"; "210";"BLOCK_ILLUMINATOR_ORANGE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"227"; "211";"BLOCK_ILLUMINATOR_RED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"228"; "212";"BLOCK_ILLUMINATOR_FUCHSIA" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"229"; "213";"BLOCK_ILLUMINATOR_PURPLE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"230"; "214";"BLOCK_ILLUMINATOR_BLUE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"231"; "215";"BLOCK_ILLUMINATOR_CYAN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"232"; "216";"BLOCK_ILLUMINATOR_GREEN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"233"; "217";"BLOCK_ILLUMINATOR_GREEN_DARK";"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"234"; "218";"BLOCK_ILLUMINATOR_BROWN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"235"; "219";"BLOCK_ILLUMINATOR_TAN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"236"; "220";"BLOCK_ILLUMINATOR_GREY_LIGHT";"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"237"; "221";"BLOCK_ILLUMINATOR_GREY_MED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"238"; "222";"BLOCK_ILLUMINATOR_GREY_DARK" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"239"; "223";"BLOCK_ILLUMINATOR_BLACK" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"240"; "240";"BLOCK_SANDSTONE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"rock"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"241"; "241";"BLOCK_SANDSTONE_WHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"rock"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"242"; "242";"BLOCK_SANDSTONE_RED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"rock"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"243"; "243";"BLOCK_SANDSTONE_DESERT" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"rock"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"244"; "244";"BLOCK_SANDSTONE_BLACK" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"rock"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"245"; "245";"BLOCK_SANDSTONE_GREEN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"rock"; "0"; "1"; "0"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"256"; "256";"BLOCK_LANTERN_IRON_REGULAR" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"fxtr"; "0"; "0"; "1"; "0";"1.0000";"0.6372";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"257"; "257";"BLOCK_SUNSTONE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"rock"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "2"; "N/A"; "0";"16"
|
||||
"258"; "258";"BLOCK_DAYLIGHT_CAPACITOR" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"glas"; "0"; "1"; "0"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "3"; "N/A"; "0";"16"
|
||||
"4064"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4065"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4066"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4067"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4068"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4069"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4070"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4071"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4072"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4073"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4074"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4075"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4076"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4077"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4078"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4079"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696"; "100";"2600";"rock"; "1"; "0"; "1"; "0";"0.7664";"0.2032";"0.0000";"0.0000"; "0"; "0"; "32"; "0";"16"
|
||||
"4080"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4081"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4082"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4083"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4084"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4085"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4086"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4087"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4088"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4089"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4090"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4091"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4092"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4093"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4094"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"4095"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508"; "100";"1000";"watr"; "1"; "0"; "1"; "0";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "16"; "0";"16"
|
||||
"-1"; "0";"BLOCK_NULL" ;"4.0000";"4.0000";"4.0000";"4.0000"; "-1";"2600";"null"; "0"; "0"; "1"; "1";"0.0000";"0.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16"
|
||||
"id";"drop";"name" ; "shdr"; "shdg"; "shdb"; "shduv";"str";"dsty";"mate";"solid";"plat";"clear";"wall";"fall";"dlfn";"vscs";"fv";"fr"; "lumr"; "lumg"; "lumb"; "lumuv"
|
||||
"0"; "0";"BLOCK_AIR" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "1";"NULL"; "0"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0"; "4";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"1"; "1";"BLOCK_MIASMA" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "1";"NULL"; "0"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0"; "4";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"16"; "17";"BLOCK_STONE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"17"; "17";"BLOCK_STONE_QUARRIED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"18"; "18";"BLOCK_STONE_TILE_WHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"19"; "19";"BLOCK_STONE_BRICKS" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"32"; "32";"BLOCK_DIRT" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"DIRT"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"33"; "32";"BLOCK_GRASS" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"34"; "34";"BLOCK_GRASSWALL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"35"; "35";"BLOCK_FOLIAGE_GREEN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"36"; "36";"BLOCK_FOLIAGE_LIME" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"37"; "37";"BLOCK_FOLIAGE_GOLD" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"38"; "38";"BLOCK_FOLIAGE_RED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"39"; "39";"BLOCK_FOLIAGE_ICEBLUE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"40"; "40";"BLOCK_FOLIAGE_PURPLE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"48"; "48";"BLOCK_PLANK_NORMAL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "16"; "740";"WOOD"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"49"; "49";"BLOCK_PLANK_EBONY" ;"0.1252";"0.1252";"0.1252";"0.1252"; "19";"1200";"WOOD"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"50"; "50";"BLOCK_PLANK_BIRCH" ;"0.1252";"0.1252";"0.1252";"0.1252"; "15"; "670";"WOOD"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"51"; "51";"BLOCK_PLANK_BLOODROSE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "17"; "900";"WOOD"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"64"; "64";"BLOCK_TRUNK_NORMAL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "16"; "740";"WOOD"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"65"; "65";"BLOCK_TRUNK_EBONY" ;"0.1252";"0.1252";"0.1252";"0.1252"; "19";"1200";"WOOD"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"66"; "66";"BLOCK_TRUNK_BIRCH" ;"0.1252";"0.1252";"0.1252";"0.1252"; "15"; "670";"WOOD"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"67"; "67";"BLOCK_TRUNK_BLOODROSE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "17"; "900";"WOOD"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"80"; "80";"BLOCK_SAND" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"SAND"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"81"; "81";"BLOCK_SAND_WHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"SAND"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"82"; "82";"BLOCK_SAND_RED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"SAND"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"83"; "83";"BLOCK_SAND_DESERT" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"SAND"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"84"; "84";"BLOCK_SAND_BLACK" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"SAND"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"85"; "85";"BLOCK_SAND_GREEN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"SAND"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"96"; "96";"BLOCK_GRAVEL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"GRVL"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"97"; "97";"BLOCK_GRAVEL_GREY" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"GRVL"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"112"; "112";"BLOCK_ORE_MALACHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"113"; "113";"BLOCK_ORE_HEMATITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"114"; "114";"BLOCK_ORE_NATURAL_GOLD" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"115"; "115";"BLOCK_ORE_NATURAL_SILVER" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"116"; "116";"BLOCK_ORE_RUTILE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"117"; "117";"BLOCK_ORE_AURICHALCUMITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"128"; "128";"BLOCK_GEM_RUBY" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"129"; "129";"BLOCK_GEM_EMERALD" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"130"; "130";"BLOCK_GEM_SAPPHIRE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"131"; "131";"BLOCK_GEM_TOPAZ" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"132"; "132";"BLOCK_GEM_DIAMOND" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"133"; "133";"BLOCK_GEM_AMETHYST" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"144"; "144";"BLOCK_SNOW" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24"; "500";"SNOW"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"145"; "0";"BLOCK_ICE_FRAGILE" ;"0.0508";"0.0508";"0.0508";"0.0508"; "5"; "930";"ICEI"; "1"; "0"; "1"; "0"; "0"; "0"; "N/A"; "0"; "4";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"146"; "146";"BLOCK_ICE_NATURAL" ;"0.1016";"0.1016";"0.1016";"0.1016"; "35"; "930";"ICEI"; "1"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0"; "4";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"147"; "147";"BLOCK_ICE_CLEAR_MAGICAL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"3720";"ICEX"; "1"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0"; "4";"0.0744";"0.1252";"0.2268";"0.0000"
|
||||
"148"; "148";"BLOCK_GLASS_CRUDE" ;"0.0120";"0.0040";"0.0120";"0.0080"; "5";"2500";"GLAS"; "1"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"149"; "149";"BLOCK_GLASS_CLEAN" ;"0.0040";"0.0040";"0.0040";"0.0020"; "5";"2203";"GLAS"; "1"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"160"; "160";"BLOCK_PLATFORM_STONE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"ROCK"; "0"; "1"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"161"; "161";"BLOCK_PLATFORM_WOODEN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"WOOD"; "0"; "1"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"162"; "162";"BLOCK_PLATFORM_EBONY" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"WOOD"; "0"; "1"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"163"; "163";"BLOCK_PLATFORM_BIRCH" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"WOOD"; "0"; "1"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"164"; "164";"BLOCK_PLATFORM_BLOODROSE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"WOOD"; "0"; "1"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"176"; "176";"BLOCK_TORCH" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"FXTR"; "0"; "0"; "1"; "0"; "0"; "1"; "N/A"; "0";"16";"1.0000";"0.6372";"0.0000";"0.0000"
|
||||
"177"; "177";"BLOCK_TORCH_FROST" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"FXTR"; "0"; "0"; "1"; "0"; "0"; "1"; "N/A"; "0";"16";"0.3048";"0.4848";"1.0000";"0.0000"
|
||||
"192"; "176";"BLOCK_TORCH" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"FXTR"; "0"; "0"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"193"; "177";"BLOCK_TORCH_FROST" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"FXTR"; "0"; "0"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"208"; "208";"BLOCK_ILLUMINATOR_WHITE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.9270";"0.9414";"0.8519";"0.0000"
|
||||
"209"; "209";"BLOCK_ILLUMINATOR_YELLOW" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"1.0000";"0.8408";"0.0000";"0.0000"
|
||||
"210"; "210";"BLOCK_ILLUMINATOR_ORANGE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"1.0000";"0.5294";"0.0000";"0.0000"
|
||||
"211"; "211";"BLOCK_ILLUMINATOR_RED" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.9188";"0.0000";"0.0000";"0.0000"
|
||||
"212"; "212";"BLOCK_ILLUMINATOR_FUCHSIA" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.9188";"0.0000";"0.7156";"0.0000"
|
||||
"213"; "213";"BLOCK_ILLUMINATOR_PURPLE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.7156";"0.0000";"0.9188";"0.0000"
|
||||
"214"; "214";"BLOCK_ILLUMINATOR_BLUE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.1996";"0.9188";"0.0000"
|
||||
"215"; "215";"BLOCK_ILLUMINATOR_CYAN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.4621";"1.4188";"1.2368";"0.0000"
|
||||
"216"; "216";"BLOCK_ILLUMINATOR_GREEN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.2112";"1.0000";"0.0000";"0.0000"
|
||||
"217"; "217";"BLOCK_ILLUMINATOR_GREEN_DARK";"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.1252";"0.4068";"0.0000";"0.0000"
|
||||
"218"; "218";"BLOCK_ILLUMINATOR_BROWN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.3324";"0.1252";"0.0000";"0.0000"
|
||||
"219"; "219";"BLOCK_ILLUMINATOR_TAN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.5864";"0.4068";"0.2032";"0.0000"
|
||||
"220"; "220";"BLOCK_ILLUMINATOR_GREY_LIGHT";"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.7392";"0.7392";"0.7392";"0.0000"
|
||||
"221"; "221";"BLOCK_ILLUMINATOR_GREY_MED" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.4576";"0.4576";"0.4576";"0.0000"
|
||||
"222"; "222";"BLOCK_ILLUMINATOR_GREY_DARK" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.2540";"0.2540";"0.2540";"0.0000"
|
||||
"223"; "223";"BLOCK_ILLUMINATOR_BLACK" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.2140";"0.0000";"0.4932";"3.7499"
|
||||
"224"; "208";"BLOCK_ILLUMINATOR_WHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"225"; "209";"BLOCK_ILLUMINATOR_YELLOW" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"226"; "210";"BLOCK_ILLUMINATOR_ORANGE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"227"; "211";"BLOCK_ILLUMINATOR_RED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"228"; "212";"BLOCK_ILLUMINATOR_FUCHSIA" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"229"; "213";"BLOCK_ILLUMINATOR_PURPLE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"230"; "214";"BLOCK_ILLUMINATOR_BLUE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"231"; "215";"BLOCK_ILLUMINATOR_CYAN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"232"; "216";"BLOCK_ILLUMINATOR_GREEN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"233"; "217";"BLOCK_ILLUMINATOR_GREEN_DARK";"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"234"; "218";"BLOCK_ILLUMINATOR_BROWN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"235"; "219";"BLOCK_ILLUMINATOR_TAN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"236"; "220";"BLOCK_ILLUMINATOR_GREY_LIGHT";"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"237"; "221";"BLOCK_ILLUMINATOR_GREY_MED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"238"; "222";"BLOCK_ILLUMINATOR_GREY_DARK" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"239"; "223";"BLOCK_ILLUMINATOR_BLACK" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"240"; "240";"BLOCK_SANDSTONE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"241"; "241";"BLOCK_SANDSTONE_WHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"242"; "242";"BLOCK_SANDSTONE_RED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"243"; "243";"BLOCK_SANDSTONE_DESERT" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"244"; "244";"BLOCK_SANDSTONE_BLACK" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"245"; "245";"BLOCK_SANDSTONE_GREEN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"256"; "256";"BLOCK_LANTERN_IRON_REGULAR" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"FXTR"; "0"; "0"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"1.0000";"0.6372";"0.0000";"0.0000"
|
||||
"257"; "257";"BLOCK_SUNSTONE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"ROCK"; "1"; "0"; "0"; "0"; "0"; "2"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"258"; "258";"BLOCK_DAYLIGHT_CAPACITOR" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "0"; "0"; "3"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"4094"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696";"100";"2600";"ROCK"; "0"; "0"; "1"; "0"; "0"; "0"; "32"; "0";"16";"0.7664";"0.2032";"0.0000";"0.0000"
|
||||
"4095"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508";"100";"1000";"WATR"; "0"; "0"; "1"; "0"; "0"; "0"; "16"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"-1"; "0";"BLOCK_NULL" ;"4.0000";"4.0000";"4.0000";"4.0000"; "-1";"2600";"NULL"; "0"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
|
||||
## Notes ##
|
||||
|
||||
#
|
||||
# Lava/Water props are left for future references, do not delete them until FluidCodex is built #
|
||||
#
|
||||
# id: Block ID
|
||||
# drop: Drop ID
|
||||
|
||||
#
|
||||
# shdr/g/b, lumr/g/b: Shade RGB/ Lum RGB.
|
||||
# valid range: float of 0..4; 1.0 for 255
|
||||
|
||||
# Friction: 0: frictionless, <16: slippery, 16: regular, >16: sticky
|
||||
|
||||
#
|
||||
# solid: whether the tile has full collision (affects physics; flowers are not solid, glass is solid)
|
||||
# clear: whether the tile has trnasparency (affects render; flowers AND glass is clear)
|
||||
|
||||
# clear: [PENDING FOR REMOVAL] whether the tile has trnasparency (affects render; flowers AND glass is clear)
|
||||
# plat: if the block is a Platform (applicable target: actual platforms, furniture filler block that collision == PLATFORM)
|
||||
#
|
||||
# vscs: viscosity, (velocity) / (1 + (n/16)), 16 halves movement speed, can be used to non-fluid tiles (sticky hazard, tarmac road in Terraria)
|
||||
|
||||
#
|
||||
# str: strength
|
||||
#
|
||||
# dsty: density. As we are putting water an 1000, it is identical to specific gravity. [g/l]
|
||||
|
||||
#
|
||||
# dlfn: dynamic luminosity function.
|
||||
# 0-static, 1-torch flicker, 2-current global light (sun, star, moon), 3-daylight at noon,
|
||||
# 4-slow breath, 5-pulsate
|
||||
|
||||
#
|
||||
# mate: material, four-letter code
|
||||
|
||||
#
|
||||
# fv: vertical friction (boolean)
|
||||
|
||||
|
||||
# fr: horizontal friction. 0: frictionless, <16: slippery, 16: regular, >16: sticky
|
||||
#
|
||||
#
|
||||
## Illuminators ##
|
||||
|
||||
# Illuminator white: Mercury Lamp; CIELAB of (94, -5.131, 10.613), which is made out of CIEXYZ of (0.947638, 1.146481, 0.482263), measured with ColorMunki Spectrometer (If you want high CRI lamp, collect a daylight!)
|
||||
#
|
||||
# Illuminator white: Mercury Lamp; CIELAB of (94, -5.131, 10.613), which is made out of CIEXYZ of (0.947638, 1.146481, 0.482263), measured with ColorMunki Spectrometer (If you don't want green tinge, collect a daylight!)
|
||||
# Illuminator orange: Sodium Lamp; CIE xy of (0.5375, 0.4153), CIEXYZ of (352.531139, 272.379377, 30.980339), measured with ColorMunki Spectrometer
|
||||
# Defalut torch : Y 64 x 0.55183 y 0.40966 (Planckian ~1 770 K); real candlelight colour taken from Spyder5 colorimeter (for I couldn't afford i1DisplayPro/Colormunki)
|
||||
# Defalut torch : Y 64 x 0.55183 y 0.40966 (Planckian ~1 770 K); real candlelight colour taken from Spyder5 colorimeter (for I couldn't afford i1DisplayPro/Colormunki -- at least back then!)
|
||||
# Sunstone: Artificial sunlight, change colour over time in sync with sunlight. The light is set by game's code.
|
||||
# Sunlight capacitor: daylight at noon. Set by game's code.
|
||||
|
||||
#
|
||||
# BLOCK_ILLUMINATOR_CYAN is actually a SUPER_LUMINATOR, cyan colour is used as:
|
||||
# 1. It has quite a brightness on RGB colour space
|
||||
# 2. Helmholz-Kohlraush effect
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
## Tiles ##
|
||||
|
||||
#
|
||||
# 16 colour palette : games's 16-colour palette
|
||||
# Magical ice: theoretical __metallic__ ice that might form under super-high pressure (> 5 TPa). Its density is a wild guess.
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
## References ##
|
||||
|
||||
#
|
||||
# * Density of various woods : http://www.engineeringtoolbox.com/wood-density-d_40.html
|
||||
# * Density of various phases of ice : http://www1.lsbu.ac.uk/water/ice_phases.html
|
||||
#
|
||||
|
Can't render this file because it contains an unexpected character in line 1 and column 20.
|
157
assets/mods/basegame/blocks/blocks_old.csv
Normal file
157
assets/mods/basegame/blocks/blocks_old.csv
Normal file
@@ -0,0 +1,157 @@
|
||||
"id";"drop";"name" ; "shdr"; "shdg"; "shdb"; "shduv";"str";"dsty";"mate";"solid";"plat";"clear";"wall";"fall";"dlfn";"vscs";"fv";"fr"; "lumr"; "lumg"; "lumb"; "lumuv"
|
||||
"0"; "0";"BLOCK_AIR" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "1";"NULL"; "0"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0"; "4";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"16"; "17";"BLOCK_STONE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"17"; "17";"BLOCK_STONE_QUARRIED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"18"; "18";"BLOCK_STONE_TILE_WHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"19"; "19";"BLOCK_STONE_BRICKS" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"32"; "32";"BLOCK_DIRT" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"DIRT"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"33"; "32";"BLOCK_GRASS" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"34"; "34";"BLOCK_GRASSWALL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"35"; "35";"BLOCK_FOLIAGE_GREEN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"36"; "36";"BLOCK_FOLIAGE_LIME" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"37"; "37";"BLOCK_FOLIAGE_GOLD" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"38"; "38";"BLOCK_FOLIAGE_RED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"39"; "39";"BLOCK_FOLIAGE_ICEBLUE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"40"; "40";"BLOCK_FOLIAGE_PURPLE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"1400";"GRSS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"48"; "48";"BLOCK_PLANK_NORMAL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "16"; "740";"WOOD"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"49"; "49";"BLOCK_PLANK_EBONY" ;"0.1252";"0.1252";"0.1252";"0.1252"; "19";"1200";"WOOD"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"50"; "50";"BLOCK_PLANK_BIRCH" ;"0.1252";"0.1252";"0.1252";"0.1252"; "15"; "670";"WOOD"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"51"; "51";"BLOCK_PLANK_BLOODROSE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "17"; "900";"WOOD"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"64"; "64";"BLOCK_TRUNK_NORMAL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "16"; "740";"WOOD"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"65"; "65";"BLOCK_TRUNK_EBONY" ;"0.1252";"0.1252";"0.1252";"0.1252"; "19";"1200";"WOOD"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"66"; "66";"BLOCK_TRUNK_BIRCH" ;"0.1252";"0.1252";"0.1252";"0.1252"; "15"; "670";"WOOD"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"67"; "67";"BLOCK_TRUNK_BLOODROSE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "17"; "900";"WOOD"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"80"; "80";"BLOCK_SAND" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"SAND"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"81"; "81";"BLOCK_SAND_WHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"SAND"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"82"; "82";"BLOCK_SAND_RED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"SAND"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"83"; "83";"BLOCK_SAND_DESERT" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"SAND"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"84"; "84";"BLOCK_SAND_BLACK" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"SAND"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"85"; "85";"BLOCK_SAND_GREEN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"SAND"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"96"; "96";"BLOCK_GRAVEL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"GRVL"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"97"; "97";"BLOCK_GRAVEL_GREY" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24";"2400";"GRVL"; "1"; "0"; "0"; "0"; "1"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"112"; "112";"BLOCK_ORE_MALACHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"113"; "113";"BLOCK_ORE_HEMATITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"114"; "114";"BLOCK_ORE_NATURAL_GOLD" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"115"; "115";"BLOCK_ORE_NATURAL_SILVER" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"116"; "116";"BLOCK_ORE_RUTILE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"117"; "117";"BLOCK_ORE_AURICHALCUMITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"128"; "128";"BLOCK_GEM_RUBY" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"129"; "129";"BLOCK_GEM_EMERALD" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"130"; "130";"BLOCK_GEM_SAPPHIRE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"131"; "131";"BLOCK_GEM_TOPAZ" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"132"; "132";"BLOCK_GEM_DIAMOND" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"133"; "133";"BLOCK_GEM_AMETHYST" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"2400";"ROCK"; "1"; "0"; "0"; "0"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"144"; "144";"BLOCK_SNOW" ;"0.1252";"0.1252";"0.1252";"0.1252"; "24"; "500";"SNOW"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "4";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"145"; "0";"BLOCK_ICE_FRAGILE" ;"0.0508";"0.0508";"0.0508";"0.0508"; "5"; "930";"ICEI"; "1"; "0"; "1"; "0"; "0"; "0"; "N/A"; "0"; "4";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"146"; "146";"BLOCK_ICE_NATURAL" ;"0.1016";"0.1016";"0.1016";"0.1016"; "35"; "930";"ICEI"; "1"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0"; "4";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"147"; "147";"BLOCK_ICE_CLEAR_MAGICAL" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"3720";"ICEX"; "1"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0"; "4";"0.0744";"0.1252";"0.2268";"0.0000"
|
||||
"148"; "148";"BLOCK_GLASS_CRUDE" ;"0.0120";"0.0040";"0.0120";"0.0080"; "5";"2500";"GLAS"; "1"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"149"; "149";"BLOCK_GLASS_CLEAN" ;"0.0040";"0.0040";"0.0040";"0.0020"; "5";"2203";"GLAS"; "1"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"160"; "160";"BLOCK_PLATFORM_STONE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"ROCK"; "0"; "1"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"161"; "161";"BLOCK_PLATFORM_WOODEN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"WOOD"; "0"; "1"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"162"; "162";"BLOCK_PLATFORM_EBONY" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"WOOD"; "0"; "1"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"163"; "163";"BLOCK_PLATFORM_BIRCH" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"WOOD"; "0"; "1"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"164"; "164";"BLOCK_PLATFORM_BLOODROSE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "5"; "N/A";"WOOD"; "0"; "1"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"176"; "176";"BLOCK_TORCH" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"FXTR"; "0"; "0"; "1"; "0"; "0"; "1"; "N/A"; "0";"16";"1.0000";"0.6372";"0.0000";"0.0000"
|
||||
"177"; "177";"BLOCK_TORCH_FROST" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"FXTR"; "0"; "0"; "1"; "0"; "0"; "1"; "N/A"; "0";"16";"0.3048";"0.4848";"1.0000";"0.0000"
|
||||
"192"; "176";"BLOCK_TORCH" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"FXTR"; "0"; "0"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"193"; "177";"BLOCK_TORCH_FROST" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"FXTR"; "0"; "0"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"208"; "208";"BLOCK_ILLUMINATOR_WHITE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.9270";"0.9414";"0.8519";"0.0000"
|
||||
"209"; "209";"BLOCK_ILLUMINATOR_YELLOW" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"1.0000";"0.8408";"0.0000";"0.0000"
|
||||
"210"; "210";"BLOCK_ILLUMINATOR_ORANGE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"1.0000";"0.5294";"0.0000";"0.0000"
|
||||
"211"; "211";"BLOCK_ILLUMINATOR_RED" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.9188";"0.0000";"0.0000";"0.0000"
|
||||
"212"; "212";"BLOCK_ILLUMINATOR_FUCHSIA" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.9188";"0.0000";"0.7156";"0.0000"
|
||||
"213"; "213";"BLOCK_ILLUMINATOR_PURPLE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.7156";"0.0000";"0.9188";"0.0000"
|
||||
"214"; "214";"BLOCK_ILLUMINATOR_BLUE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.1996";"0.9188";"0.0000"
|
||||
"215"; "215";"BLOCK_ILLUMINATOR_CYAN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.4621";"1.4188";"1.2368";"0.0000"
|
||||
"216"; "216";"BLOCK_ILLUMINATOR_GREEN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.2112";"1.0000";"0.0000";"0.0000"
|
||||
"217"; "217";"BLOCK_ILLUMINATOR_GREEN_DARK";"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.1252";"0.4068";"0.0000";"0.0000"
|
||||
"218"; "218";"BLOCK_ILLUMINATOR_BROWN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.3324";"0.1252";"0.0000";"0.0000"
|
||||
"219"; "219";"BLOCK_ILLUMINATOR_TAN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.5864";"0.4068";"0.2032";"0.0000"
|
||||
"220"; "220";"BLOCK_ILLUMINATOR_GREY_LIGHT";"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.7392";"0.7392";"0.7392";"0.0000"
|
||||
"221"; "221";"BLOCK_ILLUMINATOR_GREY_MED" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.4576";"0.4576";"0.4576";"0.0000"
|
||||
"222"; "222";"BLOCK_ILLUMINATOR_GREY_DARK" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.2540";"0.2540";"0.2540";"0.0000"
|
||||
"223"; "223";"BLOCK_ILLUMINATOR_BLACK" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.2140";"0.0000";"0.4932";"3.7499"
|
||||
"224"; "208";"BLOCK_ILLUMINATOR_WHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"225"; "209";"BLOCK_ILLUMINATOR_YELLOW" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"226"; "210";"BLOCK_ILLUMINATOR_ORANGE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"227"; "211";"BLOCK_ILLUMINATOR_RED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"228"; "212";"BLOCK_ILLUMINATOR_FUCHSIA" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"229"; "213";"BLOCK_ILLUMINATOR_PURPLE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"230"; "214";"BLOCK_ILLUMINATOR_BLUE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"231"; "215";"BLOCK_ILLUMINATOR_CYAN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"232"; "216";"BLOCK_ILLUMINATOR_GREEN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"233"; "217";"BLOCK_ILLUMINATOR_GREEN_DARK";"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"234"; "218";"BLOCK_ILLUMINATOR_BROWN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"235"; "219";"BLOCK_ILLUMINATOR_TAN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"236"; "220";"BLOCK_ILLUMINATOR_GREY_LIGHT";"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"237"; "221";"BLOCK_ILLUMINATOR_GREY_MED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"238"; "222";"BLOCK_ILLUMINATOR_GREY_DARK" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"239"; "223";"BLOCK_ILLUMINATOR_BLACK" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"240"; "240";"BLOCK_SANDSTONE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"241"; "241";"BLOCK_SANDSTONE_WHITE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"242"; "242";"BLOCK_SANDSTONE_RED" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"243"; "243";"BLOCK_SANDSTONE_DESERT" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"244"; "244";"BLOCK_SANDSTONE_BLACK" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"245"; "245";"BLOCK_SANDSTONE_GREEN" ;"0.1252";"0.1252";"0.1252";"0.1252"; "48";"1900";"ROCK"; "1"; "0"; "0"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"256"; "256";"BLOCK_LANTERN_IRON_REGULAR" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"FXTR"; "0"; "0"; "1"; "0"; "0"; "0"; "N/A"; "0";"16";"1.0000";"0.6372";"0.0000";"0.0000"
|
||||
"257"; "257";"BLOCK_SUNSTONE" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"ROCK"; "1"; "0"; "0"; "0"; "0"; "2"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"258"; "258";"BLOCK_DAYLIGHT_CAPACITOR" ;"0.1252";"0.1252";"0.1252";"0.1252"; "1"; "N/A";"GLAS"; "1"; "0"; "0"; "0"; "0"; "3"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"4094"; "0";"BLOCK_LAVA" ;"0.9696";"0.9696";"0.9696";"0.9696";"100";"2600";"ROCK"; "0"; "0"; "1"; "0"; "0"; "0"; "32"; "0";"16";"0.7664";"0.2032";"0.0000";"0.0000"
|
||||
"4095"; "0";"BLOCK_WATER" ;"0.1016";"0.0744";"0.0508";"0.0508";"100";"1000";"WATR"; "0"; "0"; "1"; "0"; "0"; "0"; "16"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
"-1"; "0";"BLOCK_NULL" ;"4.0000";"4.0000";"4.0000";"4.0000"; "-1";"2600";"NULL"; "0"; "0"; "1"; "1"; "0"; "0"; "N/A"; "0";"16";"0.0000";"0.0000";"0.0000";"0.0000"
|
||||
|
||||
## Notes ##
|
||||
#
|
||||
# Lava/Water props are left for future references, do not delete them until FluidCodex is built #
|
||||
#
|
||||
# id: Block ID
|
||||
# drop: Drop ID
|
||||
#
|
||||
# shdr/g/b, lumr/g/b: Shade RGB/ Lum RGB.
|
||||
# valid range: float of 0..4; 1.0 for 255
|
||||
#
|
||||
# solid: whether the tile has full collision (affects physics; flowers are not solid, glass is solid)
|
||||
# clear: [PENDING FOR REMOVAL] whether the tile has trnasparency (affects render; flowers AND glass is clear)
|
||||
# plat: if the block is a Platform (applicable target: actual platforms, furniture filler block that collision == PLATFORM)
|
||||
#
|
||||
# vscs: viscosity, (velocity) / (1 + (n/16)), 16 halves movement speed, can be used to non-fluid tiles (sticky hazard, tarmac road in Terraria)
|
||||
#
|
||||
# str: strength
|
||||
#
|
||||
# dsty: density. As we are putting water an 1000, it is identical to specific gravity. [g/l]
|
||||
#
|
||||
# dlfn: dynamic luminosity function.
|
||||
# 0-static, 1-torch flicker, 2-current global light (sun, star, moon), 3-daylight at noon,
|
||||
# 4-slow breath, 5-pulsate
|
||||
#
|
||||
# mate: material, four-letter code
|
||||
#
|
||||
# fv: vertical friction (boolean)
|
||||
# fr: horizontal friction. 0: frictionless, <16: slippery, 16: regular, >16: sticky
|
||||
#
|
||||
#
|
||||
## Illuminators ##
|
||||
#
|
||||
# Illuminator white: Mercury Lamp; CIELAB of (94, -5.131, 10.613), which is made out of CIEXYZ of (0.947638, 1.146481, 0.482263), measured with ColorMunki Spectrometer (If you don't want green tinge, collect a daylight!)
|
||||
# Illuminator orange: Sodium Lamp; CIE xy of (0.5375, 0.4153), CIEXYZ of (352.531139, 272.379377, 30.980339), measured with ColorMunki Spectrometer
|
||||
# Defalut torch : Y 64 x 0.55183 y 0.40966 (Planckian ~1 770 K); real candlelight colour taken from Spyder5 colorimeter (for I couldn't afford i1DisplayPro/Colormunki -- at least back then!)
|
||||
# Sunstone: Artificial sunlight, change colour over time in sync with sunlight. The light is set by game's code.
|
||||
# Sunlight capacitor: daylight at noon. Set by game's code.
|
||||
#
|
||||
# BLOCK_ILLUMINATOR_CYAN is actually a SUPER_LUMINATOR, cyan colour is used as:
|
||||
# 1. It has quite a brightness on RGB colour space
|
||||
# 2. Helmholz-Kohlraush effect
|
||||
#
|
||||
#
|
||||
## Tiles ##
|
||||
#
|
||||
# 16 colour palette : games's 16-colour palette
|
||||
# Magical ice: theoretical __metallic__ ice that might form under super-high pressure (> 5 TPa). Its density is a wild guess.
|
||||
#
|
||||
#
|
||||
## References ##
|
||||
#
|
||||
# * Density of various woods : http://www.engineeringtoolbox.com/wood-density-d_40.html
|
||||
# * Density of various phases of ice : http://www1.lsbu.ac.uk/water/ice_phases.html
|
||||
#
|
||||
|
Can't render this file because it contains an unexpected character in line 1 and column 20.
|
BIN
assets/mods/basegame/blocks/fluids.tga.gz
LFS
Normal file
BIN
assets/mods/basegame/blocks/fluids.tga.gz
LFS
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/mods/basegame/blocks/terrain_autumn.tga.gz
LFS
Normal file
BIN
assets/mods/basegame/blocks/terrain_autumn.tga.gz
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/blocks/terrain_spring.tga.gz
LFS
Normal file
BIN
assets/mods/basegame/blocks/terrain_spring.tga.gz
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/blocks/terrain_winter.tga.gz
LFS
Normal file
BIN
assets/mods/basegame/blocks/terrain_winter.tga.gz
LFS
Normal file
Binary file not shown.
@@ -1,13 +1,13 @@
|
||||
"idst";"dsty";"forcemod";"endurance";"comments"
|
||||
"rock";"2400"; "1"; "0.42";
|
||||
"cupr";"1000"; "2"; "1.00";"copper"
|
||||
"egls";"2500"; "4"; "0.82";"elven glass"
|
||||
"iron";"1000"; "5"; "1.42";
|
||||
"argn";"1000"; "9"; "0.91";"argentum/silver"
|
||||
"stal";"1000"; "14"; "1.73";"steel"
|
||||
"eaur";"1000"; "21"; "1.36";"elven aurichalcum"
|
||||
"tial";"1000"; "33"; "2.16";"titanium alloy (Ti6Al4V)"
|
||||
"admt";"1000"; "71"; "3.42";"adamant"
|
||||
"ROCK";"2400"; "1"; "0.42";
|
||||
"CUPR";"1000"; "2"; "1.00";"copper"
|
||||
"EGLS";"2500"; "4"; "0.82";"elven glass"
|
||||
"IRON";"1000"; "5"; "1.42";
|
||||
"ARGN";"1000"; "9"; "0.91";"argentum/silver"
|
||||
"STAL";"1000"; "14"; "1.73";"steel"
|
||||
"EAUR";"1000"; "21"; "1.36";"elven aurichalcum"
|
||||
"TIAL";"1000"; "33"; "2.16";"titanium alloy (Ti6Al4V)"
|
||||
"ADMT";"1000"; "71"; "3.42";"adamant"
|
||||
|
||||
# idst: ID_STRING
|
||||
|
||||
|
||||
|
Binary file not shown.
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_arm_rest_left.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_arm_rest_left.tga
LFS
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_foot_left.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_foot_left.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_foot_right.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_foot_right.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_hair.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_hair.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_hair_fore.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_hair_fore.tga
LFS
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_head.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_head.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_leg_rest_left.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_leg_rest_left.tga
LFS
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_lower_torso.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_lower_torso.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_upper_torso.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/sprite_assembler_test_assets/test_upper_torso.tga
LFS
Normal file
Binary file not shown.
35
assets/mods/basegame/sprites/test_sprite.properties
Normal file
35
assets/mods/basegame/sprites/test_sprite.properties
Normal file
@@ -0,0 +1,35 @@
|
||||
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
|
||||
SPRITESHEET=mods/basegame/sprites/sprite_assembler_test_assets/test_
|
||||
EXTENSION=.tga
|
||||
# defines frame size and origin point. Origin point is given as: (originx, size.y - 1)
|
||||
CONFIG=SIZE 48,56;ORIGINX 29
|
||||
|
||||
# note to self: don't implement skeleton hierarchy: there's too many exceptions
|
||||
# besides, you have "ALL" key.
|
||||
|
||||
! a skeleton also defines what body parts (images) be used.
|
||||
! you can also write multiline text using reverse solidus; this is a feature of .properties
|
||||
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
|
||||
! are painted first, and any object that comes before it will paint over it. In other words, this list is
|
||||
! first reversed then being iterated.
|
||||
! Joints' original point is defined in the document sprite_joints.psd. It also has visual representations.
|
||||
# TODO right now accessory points are explicitly defined. Should they be injected in run-time?
|
||||
SKELETON_STAND=HEADGEAR 0,32;HAIR_FORE 0,32;\
|
||||
ARM_REST_RIGHT -7,23;HAND_REST_RIGHT -6,11;HELD_ITEM -6,11;\
|
||||
HAIR 0,32;HEAD 0,32;\
|
||||
UPPER_TORSO 0,23;LOWER_TORSO 0,15;\
|
||||
FOOT_RIGHT -2,2;LEG_REST_RIGHT -2,7;\
|
||||
FOOT_LEFT 2,2;LEG_REST_LEFT 2,7;\
|
||||
ARM_REST_LEFT 5,24;HAND_REST_LEFT 6,12
|
||||
|
||||
# skeleton_stand is used for testing purpose
|
||||
ANIM_RUN=DELAY 0.15;ROW 2;SKELETON SKELETON_STAND
|
||||
ANIM_RUN_1=LEG_REST_RIGHT 1,1;FOOT_RIGHT 1,1;LEG_REST_LEFT -1,0;FOOT_LEFT -1,0
|
||||
ANIM_RUN_2=ALL 0,1;LEG_REST_RIGHT 0,-1;FOOT_RIGHT 0,-1;LEG_REST_LEFT 0,1;FOOT_LEFT 0,1
|
||||
ANIM_RUN_3=LEG_REST_RIGHT -1,0;FOOT_RIGHT -1,0;LEG_REST_LEFT 1,1;FOOT_LEFT 1,1
|
||||
ANIM_RUN_4=ALL 0,1;LEG_REST_RIGHT 0,1;FOOT_RIGHT 0,1;LEG_REST_LEFT 0,-1;FOOT_LEFT 0,-1
|
||||
|
||||
ANIM_IDLE=DELAY 2;ROW 1;SKELETON SKELETON_STAND
|
||||
ANIM_IDLE_1=
|
||||
! ANIM_IDLE_1 will not make any transformation
|
||||
ANIM_IDLE_2=UPPER_TORSO 0,-1;HEAD 0,-1;HAIR 0,-1;HELD_ITEM 0,-1;ARM_REST_LEFT 0,-1;ARM_REST_RIGHT 0,-1;HAND_REST_LEFT 0,-1;HAND_REST_RIGHT 0,-1;HAIR_FORE 0,-1;HEADGEAR 0,-1
|
||||
@@ -1,3 +1,13 @@
|
||||
/*
|
||||
|
||||
Texture binding:
|
||||
|
||||
0 <- Tiles atlas
|
||||
1 <- Tiles buffer that holds tiles to be drawn
|
||||
2 <- Fluid tiles atlas
|
||||
|
||||
*/
|
||||
|
||||
#version 120
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
@@ -16,10 +26,11 @@ uniform vec2 screenDimension;
|
||||
uniform vec2 tilesInAxes; // vec2(tiles_in_horizontal, tiles_in_vertical)
|
||||
|
||||
uniform ivec2 tilemapDimension;
|
||||
uniform sampler2D tilemap; // RGB888, A is optional and will be completely ignored
|
||||
uniform sampler2D tilemap; // RGBA8888
|
||||
|
||||
uniform sampler2D tilesAtlas;
|
||||
uniform sampler2D backgroundTexture;
|
||||
uniform sampler2D tilesAtlas; // terrain, wire, fluids, etc.
|
||||
uniform sampler2D tilesBlendAtlas; // weather mix (e.g. yellowed grass)
|
||||
uniform float tilesBlend = 0.0; // percentage of blending [0f..1f]. 0: draws tilesAtlas, 1: draws tilesBlendAtlas
|
||||
|
||||
uniform ivec2 tilesInAtlas = ivec2(256, 256);
|
||||
uniform ivec2 atlasTexSize = ivec2(4096, 4096);
|
||||
@@ -34,18 +45,18 @@ ivec2 getTileXY(int tileNumber) {
|
||||
return ivec2(tileNumber % int(tilesInAtlas.x), tileNumber / int(tilesInAtlas.x));
|
||||
}
|
||||
|
||||
// return: int=0xrrggbb
|
||||
// return: int=0xaarrggbb
|
||||
int _colToInt(vec4 color) {
|
||||
return int(color.b * 255) | (int(color.g * 255) << 8) | (int(color.r * 255) << 16);
|
||||
return int(color.b * 255) | (int(color.g * 255) << 8) | (int(color.r * 255) << 16) | (int(color.a * 255) << 24);
|
||||
}
|
||||
|
||||
// 0x0rggbb where int=0xaarrggbb
|
||||
// return: [0..1048575]
|
||||
int getTileFromColor(vec4 color) {
|
||||
return _colToInt(color) & 0x0FFFFF;
|
||||
return _colToInt(color) & 0xFFFFF;
|
||||
}
|
||||
|
||||
// 0xr00000 where int=0xaarrggbb
|
||||
// 0x00r00000 where int=0xaarrggbb
|
||||
// return: [0..15]
|
||||
int getBreakageFromColor(vec4 color) {
|
||||
return (_colToInt(color) >> 20) & 0xF;
|
||||
@@ -56,6 +67,7 @@ void main() {
|
||||
// READ THE FUCKING MANUAL, YOU DONKEY !! //
|
||||
// This code purposedly uses flipped fragcoord. //
|
||||
// Make sure you don't use gl_FragCoord unknowingly! //
|
||||
// Remember, if there's a compile error, shader SILENTLY won't do anything //
|
||||
|
||||
|
||||
// default gl_FragCoord takes half-integer (represeting centre of the pixel) -- could be useful for phys solver?
|
||||
@@ -91,9 +103,15 @@ void main() {
|
||||
|
||||
// blending a breakage tex with main tex
|
||||
|
||||
vec4 finalTile = texture2D(tilesAtlas, finalUVCoordForTile);
|
||||
vec4 tileCol = texture2D(tilesAtlas, finalUVCoordForTile);
|
||||
vec4 tileAltCol = texture2D(tilesBlendAtlas, finalUVCoordForTile);
|
||||
|
||||
vec4 finalTile = mix(tileCol, tileAltCol, tilesBlend);
|
||||
|
||||
vec4 finalBreakage = texture2D(tilesAtlas, finalUVCoordForBreakage);
|
||||
|
||||
gl_FragColor = colourFilter * (mix(finalTile, finalBreakage, finalBreakage.a));
|
||||
vec4 finalColor = mix(finalTile, finalBreakage, finalBreakage.a);
|
||||
|
||||
gl_FragColor = colourFilter * finalColor;
|
||||
|
||||
}
|
||||
|
||||
32
build.gradle
32
build.gradle
@@ -42,4 +42,34 @@ compileTestKotlin {
|
||||
jar {
|
||||
baseName = 'Terrarum'
|
||||
version = '0.2'
|
||||
}
|
||||
}
|
||||
|
||||
// should be same as plain old 'gradlew run'
|
||||
task game(type: JavaExec) {
|
||||
classpath sourceSets.main.runtimeClasspath
|
||||
main = 'net.torvald.terrarum.AppLoader'
|
||||
group = "Application"
|
||||
description = "Launches the game. Should be the same as 'gradlew run'."
|
||||
}
|
||||
|
||||
task gamedebug(type: JavaExec) {
|
||||
classpath sourceSets.main.runtimeClasspath
|
||||
main = 'net.torvald.terrarum.AppLoader'
|
||||
group = "Application"
|
||||
description = "Launches the game with debuy key."
|
||||
args = ["isdev=true"]
|
||||
}
|
||||
|
||||
task spriteassembler(type: JavaExec) {
|
||||
classpath sourceSets.main.runtimeClasspath
|
||||
main = 'net.torvald.spriteassembler.SpriteAssemblerAppKt'
|
||||
group = "Application"
|
||||
description = "Launches the Sprite Assembler."
|
||||
}
|
||||
|
||||
task csveditor(type: JavaExec) {
|
||||
classpath sourceSets.main.runtimeClasspath
|
||||
main = 'net.torvald.terrarum.debuggerapp.CSVEditor'
|
||||
group = "Application"
|
||||
description = "Launches the CSV Editor. (for Blocks?)"
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
lib/gdx-nightly-20190112.zip
Normal file
BIN
lib/gdx-nightly-20190112.zip
Normal file
Binary file not shown.
BIN
lib/gdx.jar
BIN
lib/gdx.jar
Binary file not shown.
BIN
lib/kotlin-stdlib-sources.jar
Normal file
BIN
lib/kotlin-stdlib-sources.jar
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
116
src/com/badlogic/gdx/graphics/PixmapIO2.java
Normal file
116
src/com/badlogic/gdx/graphics/PixmapIO2.java
Normal file
@@ -0,0 +1,116 @@
|
||||
package com.badlogic.gdx.graphics;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.StreamUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2019-01-07.
|
||||
*/
|
||||
public class PixmapIO2 {
|
||||
|
||||
// REMEMBER: to the GL's perspective, this game's FBOs are always Y-flipped. //
|
||||
|
||||
public static void writeTGAHappy(FileHandle file, Pixmap pixmap, boolean flipY) throws IOException {
|
||||
OutputStream output = file.write(false);
|
||||
|
||||
try {
|
||||
_writeTGA(output, pixmap, false, flipY);
|
||||
} finally {
|
||||
StreamUtils.closeQuietly(output);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeTGA(FileHandle file, Pixmap pixmap, boolean flipY) throws IOException {
|
||||
OutputStream output = file.write(false);
|
||||
|
||||
try {
|
||||
_writeTGA(output, pixmap, true, flipY);
|
||||
} finally {
|
||||
StreamUtils.closeQuietly(output);
|
||||
}
|
||||
}
|
||||
|
||||
private static void _writeTGA(OutputStream out, Pixmap pixmap, boolean verbatim, boolean flipY) throws IOException {
|
||||
byte[] width = toShortLittle(pixmap.getWidth());
|
||||
byte[] height = toShortLittle(pixmap.getHeight());
|
||||
byte[] zero = toShortLittle(0);
|
||||
|
||||
out.write(0); // ID field: empty
|
||||
out.write(0); // no colour map, but should be ignored anyway as it being unmapped RGB
|
||||
out.write(2); // 2 means unmapped RGB
|
||||
out.write(new byte[]{0,0,0,0,0}); // color map spec: empty
|
||||
out.write(zero); // x origin: 0
|
||||
out.write(zero); // y origin: 0
|
||||
out.write(width); // width
|
||||
out.write(height); // height
|
||||
out.write(32); // image pixel size: we're writing 32-bit image (8bpp BGRA)
|
||||
out.write(8); // image descriptor: dunno, Photoshop writes 8 in there
|
||||
|
||||
// write actual image data
|
||||
// since we're following Photoshop's conventional header, we also follows Photoshop's
|
||||
// TGA saving scheme, that is:
|
||||
// 1. BGRA order
|
||||
// 2. Y-Flipped but not X-Flipped
|
||||
|
||||
if (!flipY) {
|
||||
for (int y = pixmap.getHeight() - 1; y >= 0; y--) {
|
||||
for (int x = 0; x < pixmap.getWidth(); x++) {
|
||||
writeTga(x, y, verbatim, pixmap, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int y = 0; y < pixmap.getHeight(); y++) {
|
||||
for (int x = 0; x < pixmap.getWidth(); x++) {
|
||||
writeTga(x, y, verbatim, pixmap, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// write footer
|
||||
// 00 00 00 00 00 00 00 00 TRUEVISION-XFILE 2E 00
|
||||
out.write(new byte[]{0,0,0,0,0,0,0,0});
|
||||
if (verbatim)
|
||||
out.write("TRUEVISION-XFILE".getBytes());
|
||||
else
|
||||
out.write("TerrarumHappyTGA".getBytes());
|
||||
out.write(new byte[]{0x2E,0});
|
||||
|
||||
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
|
||||
private static byte[] zeroalpha = new byte[]{0,0,0,0};
|
||||
private static void writeTga(int x, int y, boolean verbatim, Pixmap pixmap, OutputStream out) throws IOException {
|
||||
int color = pixmap.getPixel(x, y);
|
||||
|
||||
// if alpha == 0, write special value instead
|
||||
if (verbatim && (color & 0xFF) == 0) {
|
||||
out.write(zeroalpha);
|
||||
}
|
||||
else {
|
||||
out.write(RGBAtoBGRA(color));
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] toShortLittle(int i) {
|
||||
return new byte[]{
|
||||
(byte) (i & 0xFF),
|
||||
(byte) ((i >>> 8) & 0xFF)
|
||||
};
|
||||
}
|
||||
|
||||
private static byte[] RGBAtoBGRA(int rgba) {
|
||||
return new byte[]{
|
||||
(byte) ((rgba >>> 8) & 0xFF),
|
||||
(byte) ((rgba >>> 16) & 0xFF),
|
||||
(byte) ((rgba >>> 24) & 0xFF),
|
||||
(byte) (rgba & 0xFF)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.torvald.colourutil
|
||||
|
||||
import com.jme3.math.FastMath
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.jme3.math.FastMath
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-01-12.
|
||||
@@ -11,25 +11,27 @@ object CIEXYZUtil {
|
||||
/**
|
||||
* 0..255 -> 0.0..1.0
|
||||
*/
|
||||
private val rgbLineariseLUT = Array<Float>(257, {
|
||||
val step = minOf(it, 255) / 255f
|
||||
private val rgbLinLUT = FloatArray(256) {
|
||||
val step = it / 255f
|
||||
|
||||
if (step > 0.04045f)
|
||||
((step + 0.055f) / 1.055f).powerOf(2.4f)
|
||||
else step / 12.92f
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 0..255 -> 0.0..1.0
|
||||
*/
|
||||
private val rgbUnLineariseLUT = Array<Float>(257, {
|
||||
val step = minOf(it, 255) / 255f
|
||||
private val rgbUnLinLUT = FloatArray(256) {
|
||||
val step = it / 255f
|
||||
|
||||
if (step > 0.0031308f)
|
||||
1.055f * step.powerOf(1f / 2.4f) - 0.055f
|
||||
else
|
||||
step * 12.92f
|
||||
})
|
||||
}
|
||||
|
||||
private val rgbToXyzLut_XR = FloatArray(256) { 0.4124564f * (it / 255f) }
|
||||
|
||||
|
||||
|
||||
@@ -65,8 +67,35 @@ object CIEXYZUtil {
|
||||
|
||||
fun Color.toXYZ(): CIEXYZ = RGB(this).toXYZ()
|
||||
|
||||
/**
|
||||
* "Linearise" the sRGB triads. This use lookup table to speed up calculation.
|
||||
* Integer values (1/255, 2/255, .. , 254/255, 255/255) are accurate but any values in between are
|
||||
* linearly interpolated and thus slightly less accurate. Visually there's little-to-no difference,
|
||||
* but may not optimal for rigorous maths.
|
||||
*/
|
||||
fun RGB.linearise(): RGB {
|
||||
/*val newR = if (r > 0.04045f)
|
||||
val out = floatArrayOf(0f, 0f, 0f)
|
||||
for (i in 0..2) {
|
||||
val value = when (i) {
|
||||
0 -> this.r
|
||||
1 -> this.g
|
||||
2 -> this.b
|
||||
else -> throw InternalError("Fuck you")
|
||||
}
|
||||
val step = value.clampOne() * 255f // 0.0 .. 255.0
|
||||
val intStep = step.toInt() // 0 .. 255
|
||||
val NeXTSTEP = minOf(intStep + 1, 255) // 1 .. 255
|
||||
|
||||
out[i] = interpolateLinear(step - intStep, rgbLinLUT[intStep], rgbLinLUT[NeXTSTEP])
|
||||
}
|
||||
|
||||
|
||||
return RGB(out[0], out[1], out[2], alpha)
|
||||
}
|
||||
|
||||
/** Suitable for rigorous maths but slower */
|
||||
fun RGB.lineariseSuper(): RGB {
|
||||
val newR = if (r > 0.04045f)
|
||||
((r + 0.055f) / 1.055f).powerOf(2.4f)
|
||||
else r / 12.92f
|
||||
val newG = if (g > 0.04045f)
|
||||
@@ -77,28 +106,38 @@ object CIEXYZUtil {
|
||||
else b / 12.92f
|
||||
|
||||
|
||||
return RGB(newR, newG, newB, alpha)*/
|
||||
return RGB(newR, newG, newB, alpha)
|
||||
}
|
||||
|
||||
/**
|
||||
* "Un-linearise" the RGB triads. That is, codes the linear RGB into sRGB. This use lookup table to speed up calculation.
|
||||
* Integer values (1/255, 2/255, .. , 254/255, 255/255) are accurate but any values in between are
|
||||
* linearly interpolated and thus slightly less accurate. Visually there's little-to-no difference,
|
||||
* but may not optimal for rigorous maths.
|
||||
*/
|
||||
fun RGB.unLinearise(): RGB {
|
||||
val out = floatArrayOf(0f, 0f, 0f)
|
||||
for (i in 0..2) {
|
||||
val value = when (i) {
|
||||
0 -> this.r
|
||||
1 -> this.g
|
||||
2 -> this.b
|
||||
else -> throw Exception("Fuck you")
|
||||
else -> throw InternalError("Fuck you")
|
||||
}
|
||||
val step = value.clampOne() * 255f
|
||||
val intStep = step.toInt()
|
||||
val step = value.clampOne() * 255f // 0.0 .. 255.0
|
||||
val intStep = step.toInt() // 0 .. 255
|
||||
val NeXTSTEP = minOf(intStep + 1, 255) // 1 .. 255
|
||||
|
||||
out[i] = interpolateLinear(step - intStep, rgbLineariseLUT[intStep], rgbLineariseLUT[intStep + 1])
|
||||
out[i] = interpolateLinear(step - intStep, rgbUnLinLUT[intStep], rgbUnLinLUT[NeXTSTEP])
|
||||
}
|
||||
|
||||
|
||||
return RGB(out[0], out[1], out[2], alpha)
|
||||
}
|
||||
|
||||
fun RGB.unLinearise(): RGB {
|
||||
/*val newR = if (r > 0.0031308f)
|
||||
/** Suitable for rigorous maths but slower */
|
||||
fun RGB.unLineariseSuper(): RGB {
|
||||
val newR = if (r > 0.0031308f)
|
||||
1.055f * r.powerOf(1f / 2.4f) - 0.055f
|
||||
else
|
||||
r * 12.92f
|
||||
@@ -112,24 +151,7 @@ object CIEXYZUtil {
|
||||
b * 12.92f
|
||||
|
||||
|
||||
return RGB(newR, newG, newB, alpha)*/
|
||||
|
||||
val out = floatArrayOf(0f, 0f, 0f)
|
||||
for (i in 0..2) {
|
||||
val value = when (i) {
|
||||
0 -> this.r
|
||||
1 -> this.g
|
||||
2 -> this.b
|
||||
else -> throw Exception("Fuck you")
|
||||
}
|
||||
val step = value.clampOne() * 255f
|
||||
val intStep = step.toInt()
|
||||
|
||||
out[i] = interpolateLinear(step - intStep, rgbUnLineariseLUT[intStep], rgbUnLineariseLUT[intStep + 1])
|
||||
}
|
||||
|
||||
|
||||
return RGB(out[0], out[1], out[2], alpha)
|
||||
return RGB(newR, newG, newB, alpha)
|
||||
}
|
||||
|
||||
fun RGB.toXYZ(): CIEXYZ {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package net.torvald.colourutil
|
||||
|
||||
import com.jme3.math.FastMath
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.colourutil.CIEXYZUtil.linearise
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-07-26.
|
||||
@@ -20,4 +21,17 @@ object ColourUtil {
|
||||
|
||||
return Color(r, g, b, a)
|
||||
}
|
||||
|
||||
/** Get luminosity level using CIEXYZ colour space. Slow but accurate. */
|
||||
fun RGB.getLuminosity(): Float {
|
||||
val new = this.linearise()
|
||||
return 0.2126729f * new.r + 0.7151522f * new.g + 0.0721750f * new.b // from RGB.toXYZ
|
||||
}
|
||||
/** Get luminosity level using CIEXYZ colour space. Slow but accurate. */
|
||||
fun Color.getLuminosity() = RGB(this).getLuminosity()
|
||||
|
||||
/** Get luminosity level using NTSC standard. Fast, less accurate but should be good enough. */
|
||||
fun RGB.getLuminosityQuick() = 0.3f * this.r + 0.59f * this.g + 0.11f * this.b // NTSC standard
|
||||
/** Get luminosity level using NTSC standard. Fast, less accurate but should be good enough. */
|
||||
fun Color.getLuminosityQuick() = 0.3f * this.r + 0.59f * this.g + 0.11f * this.b // NTSC standard
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package net.torvald.dataclass
|
||||
|
||||
|
||||
/**
|
||||
* buffer[head] contains the most recent item, whereas buffer[tail] contains the oldest one.
|
||||
*
|
||||
* Notes for particle storage:
|
||||
* Particles does not need to be removed, just let it overwrite as their operation is rather
|
||||
* lightweight. So, just flagDespawn = true if it need to be "deleted" so that it won't update
|
||||
@@ -12,57 +14,67 @@ package net.torvald.dataclass
|
||||
class CircularArray<T>(val size: Int) {
|
||||
|
||||
val buffer: Array<T> = arrayOfNulls<Any>(size) as Array<T>
|
||||
var tail: Int = 0
|
||||
var head: Int = 0
|
||||
var tail: Int = 0; private set
|
||||
var head: Int = -1; private set
|
||||
|
||||
private var unreliableAddCount = 0
|
||||
|
||||
val lastIndex = size - 1
|
||||
|
||||
/**
|
||||
* Number of elements that forEach() or fold() would iterate.
|
||||
*/
|
||||
val elemCount: Int
|
||||
get() = if (tail >= head) tail - head else size
|
||||
get() = minOf(unreliableAddCount, size)
|
||||
|
||||
fun add(item: T) {
|
||||
buffer[tail] = item // overwrites oldest item when eligible
|
||||
tail = (tail + 1) % size
|
||||
if (tail == head) {
|
||||
head = (head + 1) % size
|
||||
if (unreliableAddCount <= size) unreliableAddCount += 1
|
||||
|
||||
head = (head + 1) % size
|
||||
if (unreliableAddCount > size) {
|
||||
tail = (tail + 1) % size
|
||||
}
|
||||
|
||||
buffer[head] = item // overwrites oldest item when eligible
|
||||
|
||||
|
||||
//println("$this $unreliableAddCount")
|
||||
}
|
||||
|
||||
inline fun forEach(action: (T) -> Unit) {
|
||||
fun getHeadElem(): T = buffer[head]
|
||||
fun getTailElem(): T = buffer[tail]
|
||||
|
||||
/**
|
||||
* Iterates the array with oldest element first.
|
||||
*/
|
||||
fun forEach(action: (T) -> Unit) {
|
||||
// has slightly better iteration performance than lambda
|
||||
if (tail >= head) {
|
||||
for (i in head..tail - 1)
|
||||
if (unreliableAddCount <= size) {
|
||||
for (i in 0..head)
|
||||
action(buffer[i])
|
||||
}
|
||||
else {
|
||||
for (i in 0..size - 1)
|
||||
action(buffer[(i + head) % size])
|
||||
action(buffer[(i + tail) % size])
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME not working as intended
|
||||
inline fun <R> fold(initial: R, operation: (R, T) -> R): R {
|
||||
fun <R> fold(initial: R, operation: (R, T) -> R): R {
|
||||
var accumulator = initial
|
||||
//for (element in buffer) accumulator = operation(accumulator, element)
|
||||
if (tail >= head) {
|
||||
for (i in head..tail - 1)
|
||||
operation(accumulator, buffer[i])
|
||||
if (unreliableAddCount <= size) {
|
||||
for (i in 0..head)
|
||||
accumulator = operation(accumulator, buffer[i])
|
||||
}
|
||||
else {
|
||||
for (i in 0..size - 1)
|
||||
operation(accumulator, buffer[(i + head) % size])
|
||||
accumulator = operation(accumulator, buffer[(i + tail) % size])
|
||||
}
|
||||
|
||||
return accumulator
|
||||
}
|
||||
|
||||
inline fun forEachConcurrent(action: (T) -> Unit) {
|
||||
TODO()
|
||||
}
|
||||
|
||||
inline fun forEachConcurrentWaitFor(action: (T) -> Unit) {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "CircularArray(size=" + buffer.size + ", head=" + head + ", tail=" + tail + ")"
|
||||
|
||||
59
src/net/torvald/spriteanimation/Animatable.kt
Normal file
59
src/net/torvald/spriteanimation/Animatable.kt
Normal file
@@ -0,0 +1,59 @@
|
||||
package net.torvald.spriteanimation
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import net.torvald.spriteassembler.ADProperties
|
||||
import net.torvald.spriteassembler.AssembleSheetPixmap
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2019-01-18.
|
||||
*/
|
||||
interface HasAssembledSprite {
|
||||
|
||||
var animDesc: FileHandle
|
||||
|
||||
// FIXME sometimes the animmation is invisible (row and nFrames mismatch -- row is changed to 1 but it's drawing 3rd frame?)
|
||||
|
||||
fun reassembleSprite(sprite: SpriteAnimation) {
|
||||
_rebuild(ADProperties(animDesc.read()), sprite)
|
||||
}
|
||||
|
||||
/*fun rebuild(animDesc: String, spriteAnimation: SpriteAnimation) {
|
||||
_rebuild(ADProperties(StringReader(animDesc)), spriteAnimation)
|
||||
}
|
||||
|
||||
fun rebuild(animDesc: FileHandle, spriteAnimation: SpriteAnimation) {
|
||||
_rebuild(ADProperties(animDesc.read()), spriteAnimation)
|
||||
}
|
||||
|
||||
fun rebuild(javaProp: Properties, spriteAnimation: SpriteAnimation) {
|
||||
_rebuild(ADProperties(javaProp), spriteAnimation)
|
||||
}*/
|
||||
|
||||
|
||||
private fun _rebuild(ad: ADProperties, sprite: SpriteAnimation) {
|
||||
// TODO injecting held item/armour pictures? Would it be AssembleSheetPixmap's job?
|
||||
|
||||
val pixmap = AssembleSheetPixmap(ad)
|
||||
val texture = Texture(pixmap)
|
||||
texture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
|
||||
pixmap.dispose()
|
||||
val regionPack = TextureRegionPack(texture, ad.frameWidth, ad.frameHeight)
|
||||
|
||||
val newAnimDelays = FloatArray(ad.animations.size)
|
||||
val newAnimFrames = IntArray(ad.animations.size)
|
||||
|
||||
ad.animations.forEach { t, u ->
|
||||
val index = u.row - 1
|
||||
newAnimDelays[index] = u.delay
|
||||
newAnimFrames[index] = u.frames
|
||||
}
|
||||
|
||||
sprite.setSpriteImage(regionPack)
|
||||
sprite.delays = newAnimDelays
|
||||
sprite.nFrames = newAnimFrames
|
||||
sprite.nRows = newAnimDelays.size
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@ package net.torvald.spriteanimation
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.gameactors.ActorWBMovable
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
@@ -16,12 +17,29 @@ class SpriteAnimation(val parentActor: ActorWBMovable) {
|
||||
|
||||
var currentFrame = 0
|
||||
var currentRow = 0
|
||||
var nFrames: Int = 1
|
||||
private set
|
||||
|
||||
var nFrames: IntArray = intArrayOf(1)
|
||||
internal set
|
||||
var nRows: Int = 1
|
||||
private set
|
||||
var delay = 200f
|
||||
internal set
|
||||
|
||||
private val currentDelay: Second
|
||||
get() = delays[currentRow]
|
||||
|
||||
/**
|
||||
* Sets delays for each rows. Array size must be the same as the rows of the sheet
|
||||
*/
|
||||
var delays: FloatArray = floatArrayOf(0.2f)
|
||||
set(value) {
|
||||
if (value.filter { it <= 0f }.isNotEmpty()) {
|
||||
throw IllegalArgumentException("Delay array contains zero or negative value: $delays")
|
||||
}
|
||||
|
||||
field = value
|
||||
}
|
||||
|
||||
private var delta = 0f
|
||||
|
||||
val looping = true
|
||||
private var animationRunning = true
|
||||
var flipHorizontal = false
|
||||
@@ -53,7 +71,15 @@ class SpriteAnimation(val parentActor: ActorWBMovable) {
|
||||
*/
|
||||
fun setRowsAndFrames(nRows: Int, nFrames: Int) {
|
||||
this.nRows = nRows
|
||||
this.nFrames = nFrames
|
||||
this.nFrames = IntArray(nRows) { nFrames }
|
||||
}
|
||||
|
||||
fun setFramesOf(row: Int, frameCount: Int) {
|
||||
nFrames[row] = frameCount
|
||||
}
|
||||
|
||||
fun setFramesCount(framesCount: IntArray) {
|
||||
nFrames = framesCount
|
||||
}
|
||||
|
||||
fun update(delta: Float) {
|
||||
@@ -61,17 +87,23 @@ class SpriteAnimation(val parentActor: ActorWBMovable) {
|
||||
//skip this if animation is stopped
|
||||
this.delta += delta
|
||||
|
||||
//println("delta accumulation: $delta, currentDelay: $currentDelay")
|
||||
|
||||
//check if it's time to advance the frame
|
||||
if (this.delta >= this.delay) {
|
||||
//if set to not loop, keep the frame at the last frame
|
||||
if (this.currentFrame == this.nFrames && !this.looping) {
|
||||
this.currentFrame = this.nFrames - 1
|
||||
while (this.delta >= currentDelay) {
|
||||
// advance frame
|
||||
if (looping) { // looping, wrap around
|
||||
currentFrame = (currentFrame + 1) % nFrames[currentRow]
|
||||
}
|
||||
else if (currentFrame < nFrames[currentRow] - 1) { // not looping and haven't reached the end
|
||||
currentFrame += 1
|
||||
}
|
||||
|
||||
//advance one frame, then reset delta counter
|
||||
this.currentFrame = this.currentFrame % this.nFrames
|
||||
this.delta = 0f
|
||||
// discount counter
|
||||
this.delta -= currentDelay
|
||||
}
|
||||
|
||||
//println("row, frame: $currentRow, $currentFrame")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,13 +118,13 @@ class SpriteAnimation(val parentActor: ActorWBMovable) {
|
||||
* *
|
||||
* @param scale
|
||||
*/
|
||||
@JvmOverloads fun render(batch: SpriteBatch, posX: Float, posY: Float, scale: Float = 1f) {
|
||||
fun render(batch: SpriteBatch, posX: Float, posY: Float, scale: Float = 1f) {
|
||||
if (cellWidth == 0 || cellHeight == 0) {
|
||||
throw Error("Sprite width or height is set to zero! ($cellWidth, $cellHeight); master: $parentActor")
|
||||
}
|
||||
|
||||
if (visible) {
|
||||
val region = textureRegion.get(currentRow, currentFrame)
|
||||
val region = textureRegion.get(currentFrame, currentRow)
|
||||
batch.color = colorFilter
|
||||
|
||||
if (flipHorizontal && flipVertical) {
|
||||
@@ -131,20 +163,9 @@ class SpriteAnimation(val parentActor: ActorWBMovable) {
|
||||
}
|
||||
|
||||
fun switchRow(newRow: Int) {
|
||||
currentRow = newRow % nRows
|
||||
|
||||
//if beyond the frame index then reset
|
||||
if (currentFrame > nFrames) {
|
||||
reset()
|
||||
}
|
||||
}
|
||||
|
||||
fun setSpriteDelay(newDelay: Float) {
|
||||
if (newDelay > 0) {
|
||||
delay = newDelay
|
||||
}
|
||||
else {
|
||||
throw IllegalArgumentException("Delay equal or less than zero")
|
||||
if (newRow != currentRow) {
|
||||
currentRow = newRow
|
||||
currentFrame = 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
314
src/net/torvald/spriteassembler/ADProperties.kt
Normal file
314
src/net/torvald/spriteassembler/ADProperties.kt
Normal file
@@ -0,0 +1,314 @@
|
||||
package net.torvald.spriteassembler
|
||||
|
||||
import net.torvald.terrarum.linearSearchBy
|
||||
import java.io.InputStream
|
||||
import java.io.Reader
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.collections.HashSet
|
||||
|
||||
internal data class Joint(val name: String, val position: ADPropertyObject.Vector2i) {
|
||||
override fun toString() = "$name $position"
|
||||
}
|
||||
|
||||
internal data class Skeleton(val name: String, val joints: List<Joint>) {
|
||||
override fun toString() = "$name=$joints"
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name You know it
|
||||
* @param delay Delay between each frame in seconds
|
||||
* @param row STARTS AT ONE! Row in the final spritesheet, also act as the animation index.
|
||||
* @param frames number of frames this animation has
|
||||
* @param skeleton list of joints to be transformed
|
||||
*/
|
||||
internal data class Animation(val name: String, val delay: Float, val row: Int, val frames: Int, val skeleton: Skeleton) {
|
||||
override fun toString() = "$name delay: $delay, row: $row, frames: $frames, skeleton: ${skeleton.name}"
|
||||
}
|
||||
|
||||
/** Later the 'translate' can be changed so that it represents affine transformation (Matrix2d) */
|
||||
internal data class Transform(val joint: Joint, val translate: ADPropertyObject.Vector2i) {
|
||||
override fun toString() = "$joint transform: $translate"
|
||||
}
|
||||
|
||||
class ADProperties {
|
||||
private val javaProp = Properties()
|
||||
|
||||
/** Every key is CAPITALISED */
|
||||
private val propTable = HashMap<String, List<ADPropertyObject>>()
|
||||
|
||||
/** list of bodyparts used by all the skeletons (HEAD, UPPER_TORSO, LOWER_TORSO) */
|
||||
lateinit var bodyparts: List<String>; private set
|
||||
lateinit var bodypartFiles: List<String>; private set
|
||||
/** properties that are being used as skeletons (SKELETON_STAND) */
|
||||
internal lateinit var skeletons: HashMap<String, Skeleton>; private set
|
||||
/** properties that are recognised as animations (ANIM_RUN, ANIM)IDLE) */
|
||||
internal lateinit var animations: HashMap<String, Animation>; private set
|
||||
/** an "animation frame" property (ANIM_RUN_1, ANIM_RUN_2) */
|
||||
internal lateinit var transforms: HashMap<String, List<Transform>>; private set
|
||||
|
||||
private val reservedProps = listOf("SPRITESHEET", "EXTENSION")
|
||||
private val animMustContain = listOf("DELAY", "ROW", "SKELETON")
|
||||
|
||||
lateinit var baseFilename: String; private set
|
||||
lateinit var extension: String; private set
|
||||
var frameWidth: Int = -1; private set
|
||||
var frameHeight: Int = -1; private set
|
||||
var originX: Int = -1; private set
|
||||
var originY: Int = -1; private set
|
||||
internal val origin: ADPropertyObject.Vector2i
|
||||
get() = ADPropertyObject.Vector2i(originX, originY)
|
||||
|
||||
private val animFrameSuffixRegex = Regex("""_[0-9]+""")
|
||||
|
||||
private val ALL_JOINT = Joint(ALL_JOINT_SELECT_KEY, ADPropertyObject.Vector2i(0, 0))
|
||||
|
||||
var rows = -1; private set
|
||||
var cols = -1; private set
|
||||
|
||||
companion object {
|
||||
const val ALL_JOINT_SELECT_KEY = "ALL"
|
||||
}
|
||||
|
||||
constructor(reader: Reader) {
|
||||
javaProp.load(reader)
|
||||
continueLoad()
|
||||
}
|
||||
|
||||
constructor(inputStream: InputStream) {
|
||||
javaProp.load(inputStream)
|
||||
continueLoad()
|
||||
}
|
||||
|
||||
constructor(javaProp: Properties) {
|
||||
this.javaProp.putAll(javaProp.toMap())
|
||||
}
|
||||
|
||||
private fun continueLoad() {
|
||||
javaProp.keys.forEach { propName ->
|
||||
val propsStr = javaProp.getProperty(propName as String)
|
||||
val propsList = propsStr.split(';').map { ADPropertyObject(it) }
|
||||
|
||||
propTable[propName.toUpperCase()] = propsList
|
||||
}
|
||||
|
||||
// set reserved values for the animation: filename, extension
|
||||
baseFilename = get("SPRITESHEET")[0].name
|
||||
extension = get("EXTENSION")[0].name
|
||||
val frameSizeVec = get("CONFIG").linearSearchBy { it.name == "SIZE" }!!.input as ADPropertyObject.Vector2i
|
||||
frameWidth = frameSizeVec.x
|
||||
frameHeight = frameSizeVec.y
|
||||
originX = (get("CONFIG").linearSearchBy { it.name == "ORIGINX" }!!.input as Float).toInt()
|
||||
originY = frameHeight - 1
|
||||
|
||||
var maxColFinder = -1
|
||||
var maxRowFinder = -1
|
||||
val bodyparts = HashSet<String>()
|
||||
val skeletons = HashMap<String, Skeleton>()
|
||||
val animations = HashMap<String, Animation>()
|
||||
val animFrames = HashMap<String, Int>()
|
||||
val transforms = HashMap<String, List<Transform>>()
|
||||
// scan every props, write down anim frames for later use
|
||||
propTable.keys.forEach {
|
||||
if (animFrameSuffixRegex.containsMatchIn(it)) {
|
||||
val animName = getAnimNameFromFrame(it)
|
||||
val frameNumber = getFrameNumberFromName(it)
|
||||
|
||||
// if animFrames does not have our entry, add it.
|
||||
// otherwise, max() against the existing value
|
||||
if (animFrames.containsKey(animName)) {
|
||||
animFrames[animName] = maxOf(animFrames[animName]!!, frameNumber)
|
||||
}
|
||||
else {
|
||||
animFrames[animName] = frameNumber
|
||||
}
|
||||
|
||||
maxColFinder = maxOf(maxColFinder, frameNumber)
|
||||
}
|
||||
}
|
||||
// populate skeletons and animations
|
||||
forEach { s, list ->
|
||||
// Map-ify. If it has variable == "SKELETON", the 's' is likely an animation
|
||||
// and thus, uses whatever the "input" used by the SKELETON is a skeleton
|
||||
val propsHashMap = HashMap<String, Any?>()
|
||||
list.forEach {
|
||||
propsHashMap[it.name.toUpperCase()] = it.input
|
||||
}
|
||||
|
||||
// if it is indeed anim, populate animations list
|
||||
if (propsHashMap.containsKey("SKELETON")) {
|
||||
val skeletonName = propsHashMap["SKELETON"] as String
|
||||
val skeletonDef = get(skeletonName)
|
||||
|
||||
skeletons[skeletonName] = Skeleton(skeletonName, skeletonDef.toJoints())
|
||||
animations[s] = Animation(
|
||||
s,
|
||||
propsHashMap["DELAY"] as Float,
|
||||
(propsHashMap["ROW"] as Float).toInt(),
|
||||
animFrames[s]!!,
|
||||
Skeleton(skeletonName, skeletonDef.toJoints())
|
||||
)
|
||||
|
||||
maxRowFinder = maxOf(maxRowFinder, animations[s]!!.row)
|
||||
}
|
||||
}
|
||||
|
||||
// populate the bodyparts using skeletons
|
||||
skeletons.forEach { (_, prop: Skeleton) ->
|
||||
prop.joints.forEach {
|
||||
bodyparts.add(it.name)
|
||||
}
|
||||
}
|
||||
|
||||
// populate transforms
|
||||
animations.forEach { t, u ->
|
||||
for (fc in 1..u.frames) {
|
||||
val frameName = "${t}_$fc"
|
||||
val prop = get(frameName)
|
||||
|
||||
var emptyList = prop.size == 1 && prop[0].name.isEmpty()
|
||||
|
||||
val transformList = if (!emptyList) {
|
||||
List(prop.size) { index ->
|
||||
val jointNameToSearch = prop[index].name.toUpperCase()
|
||||
val joint = if (jointNameToSearch == "ALL")
|
||||
ALL_JOINT
|
||||
else
|
||||
u.skeleton.joints.linearSearchBy { it.name == jointNameToSearch }
|
||||
?: throw NullPointerException("No such joint: $jointNameToSearch")
|
||||
val translate = prop[index].input as ADPropertyObject.Vector2i
|
||||
|
||||
Transform(joint, translate)
|
||||
}
|
||||
}
|
||||
else {
|
||||
// to make real empty list
|
||||
List(0) { Transform(ALL_JOINT, ADPropertyObject.Vector2i(0, 0)) }
|
||||
}
|
||||
|
||||
transforms[frameName] = transformList
|
||||
}
|
||||
}
|
||||
|
||||
this.bodyparts = bodyparts.toList().sorted()
|
||||
this.skeletons = skeletons
|
||||
this.animations = animations
|
||||
this.bodypartFiles = this.bodyparts.map { toFilename(it) }
|
||||
this.transforms = transforms
|
||||
|
||||
cols = maxColFinder
|
||||
rows = maxRowFinder
|
||||
}
|
||||
|
||||
operator fun get(identifier: String) = propTable[identifier.toUpperCase()]!!
|
||||
val keys
|
||||
get() = propTable.keys
|
||||
fun containsKey(key: String) = propTable.containsKey(key)
|
||||
fun forEach(predicate: (String, List<ADPropertyObject>) -> Unit) = propTable.forEach(predicate)
|
||||
|
||||
fun toFilename(partName: String) =
|
||||
"${this.baseFilename}${partName.toLowerCase()}${this.extension}"
|
||||
|
||||
internal fun getAnimByFrameName(frameName: String) = animations[getAnimNameFromFrame(frameName)]!!
|
||||
internal fun getFrameNumberFromName(frameName: String) = frameName.substring(frameName.lastIndexOf('_') + 1 until frameName.length).toInt()
|
||||
|
||||
internal fun getSkeleton(name: String) = skeletons[name]!!
|
||||
internal fun getTransform(name: String) = transforms[name]!!
|
||||
|
||||
private fun getAnimNameFromFrame(s: String) = s.substring(0 until s.lastIndexOf('_'))
|
||||
|
||||
private fun List<ADPropertyObject>.toJoints() = List(this.size) {
|
||||
Joint(this[it].name.toUpperCase(), this[it].input!! as ADPropertyObject.Vector2i)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param propertyRaw example inputs:
|
||||
* - ```DELAY 0.15```
|
||||
* - ```LEG_RIGHT 0,-1```
|
||||
*
|
||||
* Created by minjaesong on 2019-01-05.
|
||||
*/
|
||||
class ADPropertyObject(propertyRaw: String) {
|
||||
|
||||
/** If the input is like ```UPPER_TORSO``` (that is, not a variable-input pair), this holds the string UPPER_TORSO. */
|
||||
val name: String
|
||||
val input: Any?
|
||||
get() = when (type) {
|
||||
ADPropertyType.IVEC2 -> field!! as Vector2i
|
||||
ADPropertyType.FLOAT -> field!! as Float
|
||||
ADPropertyType.STRING_PAIR -> field!! as String
|
||||
else -> null
|
||||
}
|
||||
val type: ADPropertyType
|
||||
|
||||
|
||||
init {
|
||||
val propPair = propertyRaw.split(variableInputSepRegex)
|
||||
|
||||
if (isADvariable(propertyRaw)) {
|
||||
name = propPair[0]
|
||||
val inputStr = propPair[1]
|
||||
|
||||
if (isADivec2(inputStr)) {
|
||||
type = ADPropertyType.IVEC2
|
||||
input = toADivec2(inputStr)
|
||||
}
|
||||
else if (isADfloat(inputStr)) {
|
||||
type = ADPropertyType.FLOAT
|
||||
input = toADfloat(inputStr)
|
||||
}
|
||||
else {
|
||||
type = ADPropertyType.STRING_PAIR
|
||||
input = inputStr
|
||||
}
|
||||
}
|
||||
else {
|
||||
name = propertyRaw
|
||||
input = null
|
||||
type = ADPropertyType.NAME_ONLY
|
||||
}
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
private val floatRegex = Regex("""-?[0-9]+(\.[0-9]*)?""")
|
||||
private val ivec2Regex = Regex("""-?[0-9]+,-?[0-9]+""")
|
||||
private val variableInputSepRegex = Regex(""" +""")
|
||||
|
||||
fun isADivec2(s: String) = ivec2Regex.matches(s)
|
||||
fun isADfloat(s: String) = floatRegex.matches(s) && !ivec2Regex.containsMatchIn(s)
|
||||
|
||||
fun toADivec2(s: String) = if (isADivec2(s))
|
||||
Vector2i(s.substringBefore(',').toInt(), s.substringAfter(',').toInt())
|
||||
else throw IllegalArgumentException("Input not in ivec2 format: $s")
|
||||
fun toADfloat(s: String) = if (isADfloat(s))
|
||||
s.toFloat()
|
||||
else throw IllegalArgumentException("Input not in ivec2 format: $s")
|
||||
|
||||
/** example valid input: ```LEG_RIGHT 0,1``` */
|
||||
fun isADvariable(property: String) = variableInputSepRegex.containsMatchIn(property)
|
||||
/** example valid input: ```sprites/test``` */
|
||||
fun isADstring(property: String) = !isADvariable(property)
|
||||
}
|
||||
|
||||
internal data class Vector2i(var x: Int, var y: Int) {
|
||||
override fun toString() = "($x, $y)"
|
||||
|
||||
operator fun plus(other: Vector2i) = Vector2i(this.x + other.x, this.y + other.y)
|
||||
operator fun minus(other: Vector2i) = Vector2i(this.x - other.x, this.y - other.y)
|
||||
|
||||
fun invertY() = Vector2i(this.x, -this.y)
|
||||
}
|
||||
|
||||
enum class ADPropertyType {
|
||||
NAME_ONLY, // "sprite/test.tga" to nothing
|
||||
IVEC2, // "LEG_RIGHT" to (1,-1)
|
||||
FLOAT, // "DELAY" to 0.15
|
||||
STRING_PAIR // "SKELETON" to "SKELETON_DEFAULT"
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "$name ${input ?: ""}: ${type.toString().toLowerCase()}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
## Animation Description Language
|
||||
|
||||
This is a text version of my drawing of same name. 2018-01-04 CuriousTorvald
|
||||
|
||||
Author's node: yet another non-JSON domain-specific language because why not?
|
||||
|
||||
## Objective
|
||||
|
||||
* Java .properties-compatible
|
||||
* Case insensitive
|
||||
|
||||
## Example code
|
||||
|
||||
```
|
||||
SPRITESHEET=sprites/test
|
||||
EXTENSION=.tga.gz
|
||||
|
||||
ANIM_RUN=DELAY 0.15;ROW 2
|
||||
ANIM_RUN_BODYPARTS=HEAD;UPPER_TORSO;LOWER_TORSO;ARM_FWD_LEFT;ARM_FWD_RIGHT;LEG_LEFT;LEG_RIGHT
|
||||
ANIM_RUN_1=LEG_RIGHT 1,-1;LEG_LEFT -1,0
|
||||
ANIM_RUN_2=ALL 0,-1;LEG_RIGHT 0,1;LEG_LEFT 0,-1
|
||||
ANIM_RUN_3=LEG_RIGHT -1,0;LEG_LEFT 1,-1
|
||||
ANIM_RUN_4=ALL 0,-1;LEG_RIGHT 0,-1;LEG_LEFT 0,1
|
||||
|
||||
ANIM_IDLE=DELAY 2;ROW 1
|
||||
ANIM_IDLE_BODYPARTS=HEAD;UPPER_TORSO;LOWER_TORSO;ARM_REST_LEFT;ARM_REST_RIGHT;LEG_LEFT;LEG_RIGHT
|
||||
ANIM_IDLE_1=
|
||||
! ANIM_IDLE_1 will not make any transformation
|
||||
ANIM_IDLE_2=UPPER_TORSO 0,-1
|
||||
|
||||
ANIM_CROUCH=DELAY 1;ROW 3
|
||||
ANIM_CROUCH_BODYPARTS=HEAD;UPPER_TORSO;LOWER_TORSO;ARM_FWD_LEFT;ARM_FWD_RIGHT;LEG_CROUCH_LEFT;LEG_CROUCH_RIGHT
|
||||
ANIM_CROUCH_1=
|
||||
...
|
||||
```
|
||||
|
||||
### In-detail
|
||||
|
||||
```
|
||||
ANIM_RUN=DELAY 0.15;ROW 2
|
||||
```
|
||||
|
||||
Each line defines one property. A property is a field-value pair. In this code, field is ```ANIM_RUN```, and the value is ```DELAY 0.15;ROW 2```
|
||||
|
||||
The values are further parsed using ```;``` (semicolon with NO spaces attached) as a separator.
|
||||
|
||||
```
|
||||
In this example, ANIM_RUN contains two variables:
|
||||
|
||||
DELAY = 0.15
|
||||
ROW = 2
|
||||
```
|
||||
|
||||
A value of the field is consisted of zero or more variable-input pairs. Variable and the input are separated with one or more connected spaces.
|
||||
|
||||
#### Variables
|
||||
|
||||
Variables can have only one of the two types: ```float``` and ```ivec2```. Single integer value ('2' in the ROW) are regarded as a float.
|
||||
|
||||
Float and Ivec2 are determined by:
|
||||
|
||||
* Ivec2: inputs that are matched by the regex ```-?[0-9]+,-?[0-9]+``` (we call this "ivec2 regex")
|
||||
* Float: inputs that are matched by the regex ```-?[0-9]+(\.[0-9]*)?```, but not even partially matched by the ivec2 regex.
|
||||
|
||||
Any argument to the body parts takes ivec2, to move the parts accordingly.
|
||||
|
||||
#### Just one exception: SPRITESHEET and EXTENSION
|
||||
|
||||
SPRITESHEET and EXTENSION property is not parsed as a property, it's just a single string like the original .properties
|
||||
|
||||
### Naming convention of properties
|
||||
|
||||
If a field is recognised as an animation (in this case ANIM_RUN), the assembler will look for the fields named like ANIM_RUN_1, ANIM_RUN_2, ... , ANIM_RUN_9, ANIM_RUN_10 and beyond.
|
||||
|
||||
### Naming convention of files
|
||||
|
||||
If the animation specifies a "body part" (in this example LEG_LEFT and LEG_RIGHT), the assembler will look for a file ```sprites/test_leg_left.tga.gz``` and ```sprites/test_leg_right.tga.gz``` respectively. Filenames are advised to be kept all lowercase.
|
||||
|
||||
### Reserved keywords
|
||||
|
||||
These values must exist so that the file can be parsed successfully.
|
||||
|
||||
#### Root
|
||||
|
||||
|Name|Type|Meaning|
|
||||
|---|---|---|
|
||||
|SPRITESHEET|properties: NAME_ONLY|Base file name of the images|
|
||||
|EXTENSION|properties: NAME_ONLY|Extension of the base file|
|
||||
|CONFIG|properties: 2 variables|Frame size and origin-x position, 0 being left|
|
||||
|
||||
#### Animation
|
||||
|
||||
Remember that 'variables' are contained within 'properties'
|
||||
|
||||
|Name|Type|Meaning|
|
||||
|---|---|---|
|
||||
|DELAY|variable: float|Delay between frames, in seconds|
|
||||
|ROW|variable: float|which row the animation goes in the spritesheet|
|
||||
|SKELETON|variable: string_pair|Which skeleton this animation uses
|
||||
|
||||
#### Transforms
|
||||
|
||||
Things like ```LEG_RIGHT -1,0``` within ```ANIM_RUN_3``` are called 'Transform'
|
||||
|
||||
|Name|Type|Meaning|
|
||||
|---|---|---|
|
||||
|ALL|variable: ivec2|Shifts (translates) everything by set value|
|
||||
|
||||
### Notes
|
||||
|
||||
* All indices are one-based
|
||||
|
||||
## Operation
|
||||
|
||||
* Each line describes transformation
|
||||
* Transformation are applied sequentially from left to right. In other words, their order matters. Be wary of the clipping that may occur! (really?)
|
||||
* The Field is an identifier the game code -- sprite assembler -- recognises.
|
||||
* The Field of animation's name is the name the game code looks for. Example: ```this.setAnim("ANIM_RUN")```
|
||||
* Coord system is Y-Up, meaning Y=0 is the bottommost position.
|
||||
125
src/net/torvald/spriteassembler/AssembleFrameGdx.kt
Normal file
125
src/net/torvald/spriteassembler/AssembleFrameGdx.kt
Normal file
@@ -0,0 +1,125 @@
|
||||
package net.torvald.spriteassembler
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.linearSearch
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Assembles the single frame of the animation, outputs GDX Pixmap.
|
||||
*
|
||||
* The entire rendering is done by using pixmap. That is, no GPU access.
|
||||
*
|
||||
* Created by minjaesong on 2019-01-06.
|
||||
*/
|
||||
object AssembleSheetPixmap {
|
||||
|
||||
operator fun invoke(properties: ADProperties): Pixmap {
|
||||
val canvas = Pixmap(properties.cols * properties.frameWidth, properties.rows * properties.frameHeight, Pixmap.Format.RGBA8888)
|
||||
canvas.blending = Pixmap.Blending.SourceOver
|
||||
|
||||
|
||||
// actually draw
|
||||
properties.transforms.forEach { t, _ ->
|
||||
drawThisFrame(t, canvas, properties)
|
||||
}
|
||||
|
||||
return canvas
|
||||
}
|
||||
|
||||
private fun drawThisFrame(frameName: String,
|
||||
canvas: Pixmap,
|
||||
properties: ADProperties
|
||||
) {
|
||||
val theAnim = properties.getAnimByFrameName(frameName)
|
||||
val skeleton = theAnim.skeleton.joints.reversed()
|
||||
val transforms = properties.getTransform(frameName)
|
||||
val bodyparts = Array<Pixmap?>(skeleton.size) {
|
||||
// if file does not exist, null it
|
||||
val file = File("assets/" + properties.toFilename(skeleton[it].name))
|
||||
|
||||
//printdbg(this, "Loading file ${file.absolutePath}, exists: ${file.exists()}")
|
||||
|
||||
/*return*/if (file.exists()) {
|
||||
Pixmap(Gdx.files.internal(file.path))
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
}
|
||||
val transformList = AssembleFrameBase.makeTransformList(skeleton, transforms)
|
||||
|
||||
val animRow = theAnim.row
|
||||
val animFrame = properties.getFrameNumberFromName(frameName)
|
||||
|
||||
AppLoader.printdbg(this, "Frame to draw: $frameName (R$animRow C$animFrame)")
|
||||
|
||||
drawFrame(animRow, animFrame, canvas, properties, bodyparts, transformList)
|
||||
|
||||
bodyparts.forEach { it?.dispose() }
|
||||
}
|
||||
|
||||
private fun drawFrame(row: Int, column: Int,
|
||||
canvas: Pixmap,
|
||||
props: ADProperties,
|
||||
bodyparts: Array<Pixmap?>,
|
||||
transformList: List<Pair<String, ADPropertyObject.Vector2i>>
|
||||
) {
|
||||
val tmpFrame = Pixmap(props.frameWidth, props.frameHeight, Pixmap.Format.RGBA8888)
|
||||
|
||||
bodyparts.forEachIndexed { index, image ->
|
||||
if (image != null) {
|
||||
val imgCentre = AssembleFrameBase.getCentreOf(image)
|
||||
val drawPos = transformList[index].second.invertY() + props.origin - imgCentre
|
||||
|
||||
tmpFrame.drawPixmap(image, drawPos.x, drawPos.y)
|
||||
}
|
||||
}
|
||||
|
||||
canvas.drawPixmap(
|
||||
tmpFrame,
|
||||
(column - 1) * props.frameWidth,
|
||||
(row - 1) * props.frameHeight
|
||||
)
|
||||
|
||||
tmpFrame.dispose()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal object AssembleFrameBase {
|
||||
/**
|
||||
* Returns joints list with tranform applied.
|
||||
* @param skeleton list of joints
|
||||
* @param transform ordered list of transforms should be applied. First come first serve.
|
||||
* @return List of pairs that contains joint name on left, final transform value on right
|
||||
*/
|
||||
fun makeTransformList(joints: List<Joint>, transforms: List<Transform>): List<Pair<String, ADPropertyObject.Vector2i>> {
|
||||
// make our mutable list
|
||||
val out = ArrayList<Pair<String, ADPropertyObject.Vector2i>>()
|
||||
joints.forEach {
|
||||
out.add(it.name to it.position)
|
||||
}
|
||||
|
||||
// process transform queue
|
||||
transforms.forEach { transform ->
|
||||
if (transform.joint.name == ADProperties.ALL_JOINT_SELECT_KEY) {
|
||||
// transform applies to all joints
|
||||
for (c in 0 until out.size) {
|
||||
out[c] = out[c].first to (out[c].second + transform.translate)
|
||||
}
|
||||
}
|
||||
else {
|
||||
val i = out.linearSearch { it.first == transform.joint.name }!!
|
||||
// transform applies to one specific joint in the list (one specific joint is a search result)
|
||||
out[i] = out[i].first to (out[i].second + transform.translate)
|
||||
}
|
||||
}
|
||||
|
||||
return out.toList()
|
||||
}
|
||||
|
||||
fun getCentreOf(pixmap: Pixmap) = ADPropertyObject.Vector2i(pixmap.width / 2, pixmap.height / 2)
|
||||
}
|
||||
322
src/net/torvald/spriteassembler/SpriteAssemblerApp.kt
Normal file
322
src/net/torvald/spriteassembler/SpriteAssemblerApp.kt
Normal file
@@ -0,0 +1,322 @@
|
||||
package net.torvald.spriteassembler
|
||||
|
||||
import com.badlogic.gdx.Game
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.PixmapIO2
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.gdxClearAndSetBlend
|
||||
import net.torvald.terrarum.inUse
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Font
|
||||
import java.awt.event.MouseAdapter
|
||||
import java.awt.event.MouseEvent
|
||||
import java.io.StringReader
|
||||
import java.util.*
|
||||
import javax.swing.*
|
||||
import javax.swing.tree.DefaultMutableTreeNode
|
||||
import javax.swing.tree.DefaultTreeModel
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2019-01-05.
|
||||
*/
|
||||
class SpriteAssemblerApp(val gdxWindow: SpriteAssemblerPreview) : JFrame() {
|
||||
|
||||
private val panelProperties = JTree()
|
||||
private val panelAnimationsList = JList<String>()
|
||||
private val panelBodypartsList = JList<String>()
|
||||
private val panelImageFilesList = JList<String>()
|
||||
private val panelSkeletonsList = JList<String>()
|
||||
private val panelTransformsList = JList<String>()
|
||||
private val panelStatList = JList<String>()
|
||||
private val panelCode = JTextPane()
|
||||
private val statBar = JTextArea("Null.")
|
||||
|
||||
private lateinit var adProperties: ADProperties
|
||||
|
||||
private val props = Properties()
|
||||
private val lang = Properties()
|
||||
|
||||
private val captionProperties = "" + // dummy string to make IDE happy with the auto indent
|
||||
|
||||
"id=ID of this block\n" +
|
||||
"drop=ID of the block this very block should drop when mined\n" +
|
||||
"name=String identifier of the block\n" +
|
||||
"shdr=Shade Red (light absorption). Valid range 0.0-4.0\n" +
|
||||
"shdg=Shade Green (light absorption). Valid range 0.0-4.0\n" +
|
||||
"shdb=Shade Blue (light absorption). Valid range 0.0-4.0\n" +
|
||||
"shduv=Shade UV (light absorbtion). Valid range 0.0-4.0\n" +
|
||||
"lumr=Luminosity Red (light intensity). Valid range 0.0-4.0\n" +
|
||||
"lumg=Luminosity Green (light intensity). Valid range 0.0-4.0\n" +
|
||||
"lumb=Luminosity Blue (light intensity). Valid range 0.0-4.0\n" +
|
||||
"lumuv=Luminosity UV (light intensity). Valid range 0.0-4.0\n" +
|
||||
"str=Strength of the block\n" +
|
||||
"dsty=Density of the block. Water have 1000 in the in-game scale\n" +
|
||||
"mate=Material of the block\n" +
|
||||
"solid=Whether the file has full collision\n" +
|
||||
"plat=Whether the block should behave like a platform\n" +
|
||||
"wall=Whether the block can be used as a wall\n" +
|
||||
"fall=Whether the block should fall through the empty space\n" +
|
||||
"dlfn=Dynamic Light Function. 0=Static. Please see <strong>notes</strong>\n" +
|
||||
"fv=Vertical friction when player slide on the cliff. 0 means not slide-able\n" +
|
||||
"fr=Horizontal friction. <16:slippery 16:regular >16:sticky\n"
|
||||
|
||||
/**
|
||||
* ¤ is used as a \n marker
|
||||
*/
|
||||
private val translations = "" +
|
||||
"WARNING_CONTINUE=Continue?\n" +
|
||||
"WARNING_YOUR_DATA_WILL_GONE=Existing edits will be lost.\n" +
|
||||
"OPERATION_CANCELLED=Operation cancelled.\n" +
|
||||
"NO_SUCH_FILE=No such file exists, operation cancelled.\n" +
|
||||
"NEW_ROWS=Enter the number of rows to initialise the new CSV.¤Remember, you can always add or delete rows later.\n" +
|
||||
"ADD_ROWS=Enter the number of rows to add:\n" +
|
||||
"WRITE_FAIL=Writing to file has failed:\n" +
|
||||
"STAT_INIT=Creating a new CSV. You can still open existing file.\n" +
|
||||
"STAT_SAVE_TGA_SUCCESSFUL=Spritesheet exported successfully.\n" +
|
||||
"STAT_LOAD_SUCCESSFUL=File loaded successfully.\n" +
|
||||
"ERROR_INTERNAL=Something went wrong.\n" +
|
||||
"ERROR_PARSE_FAIL=Parsing failed\n" +
|
||||
"SPRITE_DEF_LOAD_SUCCESSFUL=Sprite definition loaded.\n" +
|
||||
"SPRITE_ASSEMBLE_SUCCESSFUL=Sprite assembled."
|
||||
|
||||
init {
|
||||
// setup application properties //
|
||||
try {
|
||||
props.load(StringReader(captionProperties))
|
||||
lang.load(StringReader(translations))
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
|
||||
}
|
||||
|
||||
panelCode.font = Font(Font.MONOSPACED, Font.PLAIN, 12)
|
||||
|
||||
panelAnimationsList.model = DefaultListModel()
|
||||
panelBodypartsList.model = DefaultListModel()
|
||||
panelImageFilesList.model = DefaultListModel()
|
||||
panelSkeletonsList.model = DefaultListModel()
|
||||
panelTransformsList.model = DefaultListModel()
|
||||
panelStatList.model = DefaultListModel()
|
||||
|
||||
val panelPartsList = JTabbedPane(JTabbedPane.TOP)
|
||||
panelPartsList.add("Animations", JScrollPane(panelAnimationsList))
|
||||
panelPartsList.add("Bodyparts", JScrollPane(panelBodypartsList))
|
||||
panelPartsList.add("Images", JScrollPane(panelImageFilesList))
|
||||
panelPartsList.add("Skeletons", JScrollPane(panelSkeletonsList))
|
||||
panelPartsList.add("Transforms", JScrollPane(panelTransformsList))
|
||||
panelPartsList.add("Stats", JScrollPane(panelStatList))
|
||||
|
||||
val panelDataView = JSplitPane(JSplitPane.VERTICAL_SPLIT, JScrollPane(panelProperties), panelPartsList)
|
||||
panelDataView.resizeWeight = 0.333
|
||||
|
||||
// to disable text wrap
|
||||
//val panelCodeNoWrap = JPanel(BorderLayout())
|
||||
//panelCodeNoWrap.add(panelCode)
|
||||
|
||||
val panelMain = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, JScrollPane(panelCode), panelDataView)
|
||||
panelMain.resizeWeight = 0.666
|
||||
|
||||
val menu = JMenuBar()
|
||||
menu.add(JMenu("Parse")).addMouseListener(object : MouseAdapter() {
|
||||
override fun mousePressed(e: MouseEvent?) {
|
||||
try {
|
||||
adProperties = ADProperties(StringReader(panelCode.text))
|
||||
statBar.text = lang.getProperty("SPRITE_DEF_LOAD_SUCCESSFUL")
|
||||
|
||||
val propRoot = DefaultMutableTreeNode("Properties")
|
||||
|
||||
adProperties.forEach { s, list ->
|
||||
// build tree node for the properties display
|
||||
val propNode = DefaultMutableTreeNode(s)
|
||||
propRoot.add(propNode)
|
||||
list.forEach {
|
||||
propNode.add(DefaultMutableTreeNode(it.toString()))
|
||||
}
|
||||
}
|
||||
|
||||
panelProperties.model = DefaultTreeModel(propRoot)
|
||||
|
||||
// clean the data views
|
||||
panelAnimationsList.model = DefaultListModel()
|
||||
panelBodypartsList.model = DefaultListModel()
|
||||
panelImageFilesList.model = DefaultListModel()
|
||||
panelSkeletonsList.model = DefaultListModel()
|
||||
panelTransformsList.model = DefaultListModel()
|
||||
panelStatList.model = DefaultListModel()
|
||||
|
||||
// populate animations view
|
||||
adProperties.animations.forEach {
|
||||
(panelAnimationsList.model as DefaultListModel).addElement("${it.value}")
|
||||
}
|
||||
// populate bodyparts view
|
||||
adProperties.bodyparts.forEach { partName ->
|
||||
(panelBodypartsList.model as DefaultListModel).addElement(partName)
|
||||
}
|
||||
// populate image file list view
|
||||
adProperties.bodypartFiles.forEach { partName ->
|
||||
(panelImageFilesList.model as DefaultListModel).addElement(partName)
|
||||
}
|
||||
// populate skeletons view
|
||||
adProperties.skeletons.forEach {
|
||||
(panelSkeletonsList.model as DefaultListModel).addElement("${it.value}")
|
||||
}
|
||||
// populate transforms view
|
||||
adProperties.transforms.forEach {
|
||||
(panelTransformsList.model as DefaultListModel).addElement("$it")
|
||||
}
|
||||
// populate stats
|
||||
(panelStatList.model as DefaultListModel).addElement("Spritesheet rows: ${adProperties.rows}")
|
||||
(panelStatList.model as DefaultListModel).addElement("Spritesheet columns: ${adProperties.cols}")
|
||||
(panelStatList.model as DefaultListModel).addElement("Frame size: ${adProperties.frameWidth}, ${adProperties.frameHeight}")
|
||||
(panelStatList.model as DefaultListModel).addElement("Origin position: ${adProperties.originX}, ${adProperties.originY}")
|
||||
}
|
||||
catch (fehler: Throwable) {
|
||||
displayError("ERROR_PARSE_FAIL", fehler)
|
||||
fehler.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
menu.add(JMenu("Run")).addMouseListener(object : MouseAdapter() {
|
||||
override fun mousePressed(e: MouseEvent?) {
|
||||
try {
|
||||
gdxWindow.requestAssemblyTest(adProperties)
|
||||
statBar.text = lang.getProperty("SPRITE_ASSEMBLE_SUCCESSFUL")
|
||||
}
|
||||
catch (fehler: Throwable) {
|
||||
displayError("ERROR_PARSE_FAIL", fehler)
|
||||
fehler.printStackTrace()
|
||||
}
|
||||
}
|
||||
})
|
||||
menu.add(JMenu("Export")).addMouseListener(object : MouseAdapter() {
|
||||
override fun mousePressed(e: MouseEvent?) {
|
||||
val fileChooser = JFileChooser()
|
||||
fileChooser.showSaveDialog(null)
|
||||
|
||||
if (fileChooser.selectedFile != null) {
|
||||
gdxWindow.requestExport(fileChooser.selectedFile.absolutePath)
|
||||
statBar.text = lang.getProperty("STAT_SAVE_TGA_SUCCESSFUL")
|
||||
} // else, do nothing
|
||||
}
|
||||
})
|
||||
|
||||
this.layout = BorderLayout()
|
||||
this.add(menu, BorderLayout.NORTH)
|
||||
this.add(panelMain, BorderLayout.CENTER)
|
||||
this.add(statBar, BorderLayout.SOUTH)
|
||||
this.title = "Terrarum Sprite Assembler and Viewer"
|
||||
this.isVisible = true
|
||||
this.setSize(1154, 768)
|
||||
this.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
|
||||
}
|
||||
|
||||
private fun displayMessage(messageKey: String) {
|
||||
JOptionPane.showOptionDialog(
|
||||
null,
|
||||
lang.getProperty(messageKey), null,
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.INFORMATION_MESSAGE, null,
|
||||
arrayOf("OK", "Cancel"),
|
||||
"Cancel"
|
||||
)
|
||||
}
|
||||
|
||||
private fun displayError(messageKey: String, cause: Throwable) {
|
||||
JOptionPane.showOptionDialog(null,
|
||||
lang.getProperty(messageKey) + "\n" + cause.toString(), null,
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.ERROR_MESSAGE, null,
|
||||
arrayOf("OK", "Cancel"),
|
||||
"Cancel"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class SpriteAssemblerPreview: Game() {
|
||||
private lateinit var batch: SpriteBatch
|
||||
|
||||
private lateinit var renderTexture: Texture
|
||||
private var image: Pixmap? = null
|
||||
set(value) {
|
||||
renderTexture.dispose()
|
||||
field?.dispose()
|
||||
|
||||
field = value
|
||||
renderTexture = Texture(field)
|
||||
}
|
||||
|
||||
override fun create() {
|
||||
Gdx.graphics.setTitle("Sprite Assembler Preview")
|
||||
batch = SpriteBatch()
|
||||
renderTexture = Texture(1, 1, Pixmap.Format.RGBA8888)
|
||||
}
|
||||
|
||||
private val bgCol = Color(.62f,.79f,1f,1f)
|
||||
|
||||
private var doAssemble = false
|
||||
private lateinit var assembleProp: ADProperties
|
||||
|
||||
private var doExport = false
|
||||
private lateinit var exportPath: String
|
||||
|
||||
override fun render() {
|
||||
if (doAssemble) {
|
||||
// assembly requires GL context
|
||||
doAssemble = false
|
||||
assembleImage(assembleProp)
|
||||
}
|
||||
|
||||
if (doExport && image != null) {
|
||||
doExport = false
|
||||
PixmapIO2.writeTGAHappy(Gdx.files.absolute(exportPath), image, false)
|
||||
}
|
||||
|
||||
|
||||
gdxClearAndSetBlend(.62f,.79f,1f,1f)
|
||||
|
||||
|
||||
batch.inUse {
|
||||
batch.color = Color.WHITE
|
||||
batch.draw(renderTexture, 0f, 0f)
|
||||
}
|
||||
}
|
||||
|
||||
private fun assembleImage(prop: ADProperties) {
|
||||
image = AssembleSheetPixmap(prop)
|
||||
}
|
||||
|
||||
// TODO rename to requestAssembly
|
||||
fun requestAssemblyTest(prop: ADProperties) {
|
||||
doAssemble = true
|
||||
assembleProp = prop
|
||||
}
|
||||
|
||||
fun requestExport(path: String) {
|
||||
doExport = true
|
||||
exportPath = path
|
||||
}
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
super.resize(width, height)
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val appConfig = LwjglApplicationConfiguration()
|
||||
appConfig.resizable = true
|
||||
appConfig.width = 512
|
||||
appConfig.height = 512
|
||||
appConfig.foregroundFPS = 5
|
||||
appConfig.backgroundFPS = 5
|
||||
|
||||
val gdxWindow = SpriteAssemblerPreview()
|
||||
|
||||
LwjglApplication(gdxWindow, appConfig)
|
||||
SpriteAssemblerApp(gdxWindow)
|
||||
}
|
||||
35
src/net/torvald/spriteassembler/test_sprite.properties
Normal file
35
src/net/torvald/spriteassembler/test_sprite.properties
Normal file
@@ -0,0 +1,35 @@
|
||||
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
|
||||
SPRITESHEET=mods/basegame/sprites/sprite_assembler_test_assets/test_
|
||||
EXTENSION=.tga
|
||||
# defines frame size and origin point. Origin point is given as: (originx, size.y - 1)
|
||||
CONFIG=SIZE 48,56;ORIGINX 29
|
||||
|
||||
# note to self: don't implement skeleton hierarchy: there's too many exceptions
|
||||
# besides, you have "ALL" key.
|
||||
|
||||
! a skeleton also defines what body parts (images) be used.
|
||||
! you can also write multiline text using reverse solidus; this is a feature of .properties
|
||||
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
|
||||
! are painted first, and any object that comes before it will paint over it. In other words, this list is
|
||||
! first reversed then being iterated.
|
||||
! Joints' original point is defined in the document sprite_joints.psd. It also has visual representations.
|
||||
# TODO right now accessory points are explicitly defined. Should they be injected in run-time?
|
||||
SKELETON_STAND=HEADGEAR 0,32;HAIR_FORE 0,32;\
|
||||
ARM_REST_RIGHT -7,23;HAND_REST_RIGHT -6,11;HELD_ITEM -6,11;\
|
||||
HAIR 0,32;HEAD 0,32;\
|
||||
UPPER_TORSO 0,23;LOWER_TORSO 0,15;\
|
||||
FOOT_RIGHT -2,2;LEG_REST_RIGHT -2,7;\
|
||||
FOOT_LEFT 2,2;LEG_REST_LEFT 2,7;\
|
||||
ARM_REST_LEFT 5,24;HAND_REST_LEFT 6,12
|
||||
|
||||
# skeleton_stand is used for testing purpose
|
||||
ANIM_RUN=DELAY 0.15;ROW 2;SKELETON SKELETON_STAND
|
||||
ANIM_RUN_1=LEG_REST_RIGHT 1,1;FOOT_RIGHT 1,1;LEG_REST_LEFT -1,0;FOOT_LEFT -1,0
|
||||
ANIM_RUN_2=ALL 0,1;LEG_REST_RIGHT 0,-1;FOOT_RIGHT 0,-1;LEG_REST_LEFT 0,1;FOOT_LEFT 0,1
|
||||
ANIM_RUN_3=LEG_REST_RIGHT -1,0;FOOT_RIGHT -1,0;LEG_REST_LEFT 1,1;FOOT_LEFT 1,1
|
||||
ANIM_RUN_4=ALL 0,1;LEG_REST_RIGHT 0,1;FOOT_RIGHT 0,1;LEG_REST_LEFT 0,-1;FOOT_LEFT 0,-1
|
||||
|
||||
ANIM_IDLE=DELAY 2;ROW 1;SKELETON SKELETON_STAND
|
||||
ANIM_IDLE_1=
|
||||
! ANIM_IDLE_1 will not make any transformation
|
||||
ANIM_IDLE_2=UPPER_TORSO 0,-1;HEAD 0,-1;HAIR 0,-1;HELD_ITEM 0,-1;ARM_REST_LEFT 0,-1;ARM_REST_RIGHT 0,-1;HAND_REST_LEFT 0,-1;HAND_REST_RIGHT 0,-1;HAIR_FORE 0,-1;HEADGEAR 0,-1
|
||||
@@ -3,6 +3,7 @@ package net.torvald.terrarum;
|
||||
import com.badlogic.gdx.ApplicationListener;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Screen;
|
||||
import com.badlogic.gdx.audio.AudioDevice;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
|
||||
import com.badlogic.gdx.graphics.*;
|
||||
@@ -10,13 +11,24 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
||||
import com.badlogic.gdx.utils.ScreenUtils;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import net.torvald.dataclass.ArrayListMap;
|
||||
import net.torvald.terrarum.modulebasegame.IngameRenderer;
|
||||
import net.torvald.terrarum.utils.JsonFetcher;
|
||||
import net.torvald.terrarum.utils.JsonWriter;
|
||||
import net.torvald.terrarumsansbitmap.gdx.GameFontBase;
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
import static net.torvald.terrarum.TerrarumKt.gdxClearAndSetBlend;
|
||||
|
||||
/**
|
||||
* The framework's Application Loader
|
||||
*
|
||||
@@ -30,19 +42,62 @@ public class AppLoader implements ApplicationListener {
|
||||
* AA: Major version
|
||||
* BB: Minor version
|
||||
* XXXX: Revision (Repository commits, or something arbitrary)
|
||||
*
|
||||
* e.g. 0x02010034 can be translated as 2.1.52
|
||||
* <p>
|
||||
* e.g. 0x02010034 will be translated as 2.1.52
|
||||
*/
|
||||
public static final int VERSION_RAW = 0x00_02_027C;
|
||||
public static final boolean IS_DEVELOPMENT_BUILD = true;
|
||||
|
||||
|
||||
public static final int VERSION_RAW = 0x00_02_04B1;
|
||||
|
||||
public static final String getVERSION_STRING() {
|
||||
return String.format("%d.%d.%d", VERSION_RAW >>> 24, (VERSION_RAW & 0xff0000) >>> 16, VERSION_RAW & 0xFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* when FALSE, some assertion and print code will not execute
|
||||
*/
|
||||
public static boolean IS_DEVELOPMENT_BUILD = false;
|
||||
|
||||
|
||||
/**
|
||||
* Singleton instance
|
||||
*/
|
||||
private static AppLoader INSTANCE = null;
|
||||
|
||||
private AppLoader() { }
|
||||
/**
|
||||
* Screen injected at init, so that you run THAT screen instead of the main game.
|
||||
*/
|
||||
private static Screen injectScreen = null;
|
||||
|
||||
/**
|
||||
* Initialise the application with the alternative Screen you choose
|
||||
*
|
||||
* @param appConfig LWJGL(2) Application Configuration
|
||||
* @param injectScreen GDX Screen you want to run
|
||||
*/
|
||||
public AppLoader(LwjglApplicationConfiguration appConfig, Screen injectScreen) {
|
||||
AppLoader.injectScreen = injectScreen;
|
||||
AppLoader.appConfig = appConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the application with default game screen
|
||||
*
|
||||
* @param appConfig LWJGL(2) Application Configuration
|
||||
*/
|
||||
public AppLoader(LwjglApplicationConfiguration appConfig) {
|
||||
AppLoader.appConfig = appConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default null constructor. Don't use it.
|
||||
*/
|
||||
private AppLoader() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton pattern implementation in Java.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static AppLoader getINSTANCE() {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new AppLoader();
|
||||
@@ -54,6 +109,9 @@ public class AppLoader implements ApplicationListener {
|
||||
public static final String COPYRIGHT_DATE_NAME = "Copyright 2013-2018 Torvald (minjaesong)";
|
||||
public static String GAME_LOCALE = System.getProperty("user.language") + System.getProperty("user.country");
|
||||
|
||||
/**
|
||||
* These languages won't distinguish regional differences (e.g. enUS and enUK, frFR and frCA)
|
||||
*/
|
||||
private static final String[] localeSimple = {"de", "en", "es", "it"}; // must be sorted!!
|
||||
|
||||
public static String getSysLang() {
|
||||
@@ -81,12 +139,11 @@ public class AppLoader implements ApplicationListener {
|
||||
}
|
||||
}
|
||||
|
||||
public static final String getVERSION_STRING() {
|
||||
return String.format("%d.%d.%d", VERSION_RAW >>> 24, (VERSION_RAW & 0xff0000) >>> 16, VERSION_RAW & 0xFFFF);
|
||||
}
|
||||
private static boolean splashDisplayed = false;
|
||||
private static boolean postInitFired = false;
|
||||
private static boolean screenshotRequested = false;
|
||||
|
||||
public static LwjglApplicationConfiguration appConfig;
|
||||
|
||||
public static GameFontBase fontGame;
|
||||
|
||||
/**
|
||||
@@ -95,21 +152,28 @@ public class AppLoader implements ApplicationListener {
|
||||
public static int GLOBAL_RENDER_TIMER = new Random().nextInt(1020) + 1;
|
||||
|
||||
|
||||
public static ArrayListMap debugTimers = new ArrayListMap<String, Long>();
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
ShaderProgram.pedantic = false;
|
||||
|
||||
appConfig = new LwjglApplicationConfiguration();
|
||||
LwjglApplicationConfiguration appConfig = new LwjglApplicationConfiguration();
|
||||
//appConfig.useGL30 = true; // used: loads GL 3.2, unused: loads GL 4.6; what the fuck?
|
||||
appConfig.vSyncEnabled = false;
|
||||
appConfig.resizable = false;//true;
|
||||
//appConfig.width = 1072; // IMAX ratio
|
||||
//appConfig.height = 742; // IMAX ratio
|
||||
appConfig.width = 1110; // photographic ratio (1.5:1)
|
||||
appConfig.height = 740; // photographic ratio (1.5:1)
|
||||
appConfig.backgroundFPS = 9999;
|
||||
appConfig.foregroundFPS = 9999;
|
||||
appConfig.title = GAME_NAME;
|
||||
appConfig.forceExit = false;
|
||||
|
||||
new LwjglApplication(new AppLoader(), appConfig);
|
||||
if (args.length == 1 && args[0].equals("isdev=true")) {
|
||||
IS_DEVELOPMENT_BUILD = true;
|
||||
}
|
||||
|
||||
new LwjglApplication(new AppLoader(appConfig), appConfig);
|
||||
}
|
||||
|
||||
|
||||
@@ -121,11 +185,16 @@ public class AppLoader implements ApplicationListener {
|
||||
private OrthographicCamera camera;
|
||||
private SpriteBatch logoBatch;
|
||||
public static TextureRegion logo;
|
||||
public static AudioDevice audioDevice;
|
||||
|
||||
private Color gradWhiteTop = new Color(0xf8f8f8ff);
|
||||
private Color gradWhiteBottom = new Color(0xd8d8d8ff);
|
||||
|
||||
public Screen screen;
|
||||
public static int screenW = 0;
|
||||
public static int screenH = 0;
|
||||
|
||||
public static Texture textureWhiteSquare;
|
||||
|
||||
private void initViewPort(int width, int height) {
|
||||
// Set Y to point downwards
|
||||
@@ -138,6 +207,8 @@ public class AppLoader implements ApplicationListener {
|
||||
Gdx.gl20.glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
public static final double UPDATE_RATE = 1.0 / 61.0; // TODO set it like 1/100, because apparent framerate is limited by update rate
|
||||
|
||||
private float loadTimer = 0f;
|
||||
private final float showupTime = 100f / 1000f;
|
||||
|
||||
@@ -148,16 +219,14 @@ public class AppLoader implements ApplicationListener {
|
||||
logoBatch = new SpriteBatch();
|
||||
camera = new OrthographicCamera(((float) appConfig.width), ((float) appConfig.height));
|
||||
|
||||
|
||||
initViewPort(appConfig.width, appConfig.height);
|
||||
|
||||
logo = new TextureRegion(new Texture(Gdx.files.internal("assets/graphics/logo_placeholder.tga")));
|
||||
logo.flip(false, true);
|
||||
|
||||
shaderBayerSkyboxFill = new ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/4096_bayer_skyboxfill.frag"));
|
||||
shaderHicolour = new ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/hicolour.frag"));
|
||||
shaderColLUT = new ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/passthru.frag"));
|
||||
|
||||
|
||||
|
||||
shaderBayerSkyboxFill = loadShader("assets/4096.vert", "assets/4096_bayer_skyboxfill.frag");
|
||||
shaderHicolour = loadShader("assets/4096.vert", "assets/hicolour.frag");
|
||||
shaderColLUT = loadShader("assets/4096.vert", "assets/passthru.frag");
|
||||
|
||||
fullscreenQuad = new Mesh(
|
||||
true, 4, 6,
|
||||
@@ -165,40 +234,107 @@ public class AppLoader implements ApplicationListener {
|
||||
VertexAttribute.ColorUnpacked(),
|
||||
VertexAttribute.TexCoords(0)
|
||||
);
|
||||
updateFullscreenQuad(appConfig.width, appConfig.height);
|
||||
}
|
||||
|
||||
fullscreenQuad.setVertices(new float[]{
|
||||
0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f, 1f,
|
||||
((float) appConfig.width), 0f, 0f, 1f, 1f, 1f, 1f, 1f, 1f,
|
||||
((float) appConfig.width), ((float) appConfig.height), 0f, 1f, 1f, 1f, 1f, 1f, 0f,
|
||||
0f, ((float) appConfig.height), 0f, 1f, 1f, 1f, 1f, 0f, 0f
|
||||
});
|
||||
fullscreenQuad.setIndices(new short[]{0, 1, 2, 2, 3, 0});
|
||||
private static double _kalman_xhat_k = UPDATE_RATE;
|
||||
private static double _kalman_return_value = _kalman_xhat_k;
|
||||
private static double _kalman_p_k = 1.0;
|
||||
private static final double _kalman_R = 0.2; // 0.2: empirical value
|
||||
private final double _KALMAN_UPDATE_THRE = 0.1;
|
||||
|
||||
/**
|
||||
* Because fuck you GDX. (No, really; take a look at LwjglGraphics.java, getDeltaTime() and rawDeltaTime() are exactly the same)
|
||||
* @return Render delta that is smoothed out.
|
||||
*/
|
||||
public static double getSmoothDelta() {
|
||||
// kalman filter is calculated but not actually being used.
|
||||
|
||||
|
||||
logo = new TextureRegion(new Texture(Gdx.files.internal("assets/graphics/logo_placeholder.tga")));
|
||||
logo.flip(false, true);
|
||||
// below is the kalman part
|
||||
return _kalman_return_value;
|
||||
}
|
||||
|
||||
public static void resetDeltaSmoothingHistory() {
|
||||
_kalman_xhat_k = UPDATE_RATE;
|
||||
_kalman_p_k = 1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @link http://bilgin.esme.org/BitsAndBytes/KalmanFilterforDummies
|
||||
*/
|
||||
private void updateKalmanRenderDelta() {
|
||||
|
||||
// TODO implement nonlinear kalman filter
|
||||
|
||||
// kalman filter is calculated but not actually being used.
|
||||
// the problem with this kalman filter is that it assumes most simplistic situation:
|
||||
// 1. the actual delta (measured delta - noise) is constant
|
||||
// 2. everything is linear
|
||||
// we may need to implement Extended Kalman Filter but wtf is Jacobian, I suck at maths.
|
||||
// Instead, the kalman filter will reset when new delta is given-value-times greater/lesser
|
||||
// it's not perfect but it works.
|
||||
|
||||
double observation = ((double) Gdx.graphics.getRawDeltaTime());
|
||||
|
||||
if (getMul(observation, _kalman_return_value) >= 2.5) {
|
||||
resetDeltaSmoothingHistory();
|
||||
}
|
||||
|
||||
// measurement value
|
||||
double _kalman_zed_k = observation;
|
||||
|
||||
if (_kalman_zed_k <= _KALMAN_UPDATE_THRE) {
|
||||
// time update
|
||||
double _kalman_xhatminus_k = _kalman_xhat_k;
|
||||
double _kalman_pminus_k = _kalman_p_k;
|
||||
|
||||
// measurement update
|
||||
double _kalman_gain = _kalman_pminus_k / (_kalman_pminus_k + _kalman_R);
|
||||
double _kalman_xhat_kNew = _kalman_xhatminus_k + _kalman_gain * (_kalman_zed_k - _kalman_xhatminus_k);
|
||||
double _kalman_p_kNew = (1.0 - _kalman_gain) * _kalman_pminus_k;
|
||||
|
||||
_kalman_xhat_k = _kalman_xhat_kNew;
|
||||
_kalman_p_k = _kalman_p_kNew;
|
||||
|
||||
_kalman_return_value = _kalman_xhat_kNew;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TextureRegionPack.Companion.setGlobalFlipY(true);
|
||||
fontGame = new GameFontBase("assets/graphics/fonts/terrarum-sans-bitmap", false, true, Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest, false, 128, false);
|
||||
private final double getMul_epsilon = 0.00001;
|
||||
// only for a > 0 && b > 0
|
||||
private double getMul(double a, double b) {
|
||||
if (a < getMul_epsilon || b < getMul_epsilon) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
if (a > b) {
|
||||
return a / b;
|
||||
}
|
||||
else {
|
||||
return b / a;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
|
||||
FrameBufferManager.begin(renderFBO);
|
||||
Gdx.gl.glClearColor(.094f, .094f, .094f, 0f);
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
Gdx.gl.glEnable(GL20.GL_TEXTURE_2D);
|
||||
Gdx.gl.glEnable(GL20.GL_BLEND);
|
||||
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
|
||||
Gdx.gl.glBlendEquation(GL20.GL_FUNC_ADD);
|
||||
FrameBufferManager.end();
|
||||
if (splashDisplayed && !postInitFired) {
|
||||
postInitFired = true;
|
||||
postInit();
|
||||
}
|
||||
|
||||
// update smooth delta AFTER postInit
|
||||
updateKalmanRenderDelta();
|
||||
|
||||
FrameBufferManager.begin(renderFBO);
|
||||
gdxClearAndSetBlend(.094f, .094f, .094f, 0f);
|
||||
setCameraPosition(0, 0);
|
||||
|
||||
// draw splash screen when predefined screen is null
|
||||
// because in normal operation, the only time screen == null is when the app is cold-launched
|
||||
// you can't have a text drawn here :v
|
||||
if (screen == null) {
|
||||
shaderBayerSkyboxFill.begin();
|
||||
shaderBayerSkyboxFill.setUniformMatrix("u_projTrans", camera.combined);
|
||||
@@ -224,13 +360,14 @@ public class AppLoader implements ApplicationListener {
|
||||
loadTimer += Gdx.graphics.getRawDeltaTime();
|
||||
|
||||
if (loadTimer >= showupTime) {
|
||||
Terrarum.INSTANCE.setScreenW(appConfig.width);
|
||||
Terrarum.INSTANCE.setScreenH(appConfig.height);
|
||||
// hand over the scene control to this single class; Terrarum must call
|
||||
// 'AppLoader.getINSTANCE().screen.render(delta)', this is not redundant at all!
|
||||
setScreen(Terrarum.INSTANCE);
|
||||
}
|
||||
}
|
||||
// draw the screen
|
||||
else {
|
||||
screen.render(Gdx.graphics.getDeltaTime());
|
||||
screen.render((float) UPDATE_RATE);
|
||||
}
|
||||
|
||||
// nested FBOs are just not a thing in GL!
|
||||
@@ -239,7 +376,21 @@ public class AppLoader implements ApplicationListener {
|
||||
PostProcessor.INSTANCE.draw(camera.combined, renderFBO);
|
||||
|
||||
|
||||
// process screenshot request
|
||||
if (screenshotRequested) {
|
||||
screenshotRequested = false;
|
||||
|
||||
try {
|
||||
Pixmap p = ScreenUtils.getFrameBufferPixmap(0, 0, appConfig.width, appConfig.height);
|
||||
PixmapIO2.writeTGA(Gdx.files.absolute(defaultDir + "/Screenshot.tga"), p, true);
|
||||
p.dispose();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
splashDisplayed = true;
|
||||
GLOBAL_RENDER_TIMER += 1;
|
||||
}
|
||||
|
||||
@@ -247,52 +398,72 @@ public class AppLoader implements ApplicationListener {
|
||||
public void resize(int width, int height) {
|
||||
//initViewPort(width, height);
|
||||
|
||||
Terrarum.INSTANCE.resize(width, height);
|
||||
if (screen != null) screen.resize(Terrarum.INSTANCE.getWIDTH(), Terrarum.INSTANCE.getHEIGHT());
|
||||
screenW = width;
|
||||
screenH = height;
|
||||
|
||||
if (screenW % 2 == 1) screenW -= 1;
|
||||
if (screenH % 2 == 1) screenH -= 1;
|
||||
|
||||
if (screen != null) screen.resize(screenW, screenH);
|
||||
|
||||
|
||||
if (renderFBO == null ||
|
||||
(renderFBO.getWidth() != Terrarum.INSTANCE.getWIDTH() ||
|
||||
renderFBO.getHeight() != Terrarum.INSTANCE.getHEIGHT())
|
||||
) {
|
||||
(renderFBO.getWidth() != screenW ||
|
||||
renderFBO.getHeight() != screenH)
|
||||
) {
|
||||
renderFBO = new FrameBuffer(
|
||||
Pixmap.Format.RGBA8888,
|
||||
Terrarum.INSTANCE.getWIDTH(),
|
||||
Terrarum.INSTANCE.getHEIGHT(),
|
||||
screenW,
|
||||
screenH,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
appConfig.width = Terrarum.INSTANCE.getWIDTH();
|
||||
appConfig.height = Terrarum.INSTANCE.getHEIGHT();
|
||||
appConfig.width = screenW;
|
||||
appConfig.height = screenH;
|
||||
|
||||
updateFullscreenQuad(screenW, screenH);
|
||||
|
||||
printdbg(this, "Resize event");
|
||||
|
||||
resetDeltaSmoothingHistory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose () {
|
||||
if (screen != null) screen.hide();
|
||||
|
||||
public void dispose() {
|
||||
System.out.println("Goodbye !");
|
||||
|
||||
|
||||
if (screen != null) {
|
||||
screen.hide();
|
||||
screen.dispose();
|
||||
}
|
||||
|
||||
IngameRenderer.INSTANCE.dispose();
|
||||
|
||||
|
||||
// delete temp files
|
||||
new File("./tmp_wenquanyi.tga").delete();
|
||||
new File("./tmp_wenquanyi.tga").delete(); // FIXME this is pretty much ad-hoc
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause () {
|
||||
public void pause() {
|
||||
if (screen != null) screen.pause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume () {
|
||||
public void resume() {
|
||||
if (screen != null) screen.resume();
|
||||
}
|
||||
|
||||
public void setScreen(Screen screen) {
|
||||
printdbg(this, "Changing screen to " + screen.getClass().getCanonicalName());
|
||||
|
||||
if (this.screen != null) this.screen.hide();
|
||||
// this whole thing is directtly copied from com.badlogic.gdx.Game
|
||||
|
||||
if (this.screen != null) {
|
||||
this.screen.hide();
|
||||
}
|
||||
this.screen = screen;
|
||||
if (this.screen != null) {
|
||||
this.screen.show();
|
||||
@@ -300,8 +471,36 @@ public class AppLoader implements ApplicationListener {
|
||||
}
|
||||
|
||||
printdbg(this, "Screen transisiton complete: " + this.screen.getClass().getCanonicalName());
|
||||
|
||||
resetDeltaSmoothingHistory();
|
||||
}
|
||||
|
||||
private void postInit() {
|
||||
// load configs
|
||||
getDefaultDirectory();
|
||||
createDirs();
|
||||
readConfigJson();
|
||||
|
||||
textureWhiteSquare = new Texture(Gdx.files.internal("assets/graphics/ortho_line_tex_2px.tga"));
|
||||
textureWhiteSquare.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
|
||||
|
||||
TextureRegionPack.Companion.setGlobalFlipY(true);
|
||||
fontGame = new GameFontBase("assets/graphics/fonts/terrarum-sans-bitmap", false, true,
|
||||
Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest, false, 256, false
|
||||
);
|
||||
|
||||
audioDevice = Gdx.audio.newAudioDevice(48000, false);
|
||||
|
||||
// if there is a predefined screen, open that screen after my init process
|
||||
if (injectScreen != null) {
|
||||
setScreen(injectScreen);
|
||||
}
|
||||
|
||||
|
||||
printdbg(this, "PostInit done");
|
||||
}
|
||||
|
||||
|
||||
private void setCameraPosition(float newX, float newY) {
|
||||
camera.position.set((-newX + appConfig.width / 2), (-newY + appConfig.height / 2), 0f);
|
||||
camera.update();
|
||||
@@ -318,15 +517,243 @@ public class AppLoader implements ApplicationListener {
|
||||
fullscreenQuad.setIndices(new short[]{0, 1, 2, 2, 3, 0});
|
||||
}
|
||||
|
||||
public static void requestScreenshot() {
|
||||
screenshotRequested = true;
|
||||
}
|
||||
|
||||
public static final void printdbg(Object obj, Object message) {
|
||||
if (IS_DEVELOPMENT_BUILD) {
|
||||
System.out.println("["+obj.getClass().getSimpleName()+"] "+message.toString());
|
||||
// DEFAULT DIRECTORIES //
|
||||
|
||||
public static String OSName = System.getProperty("os.name");
|
||||
public static String OSVersion = System.getProperty("os.version");
|
||||
public static String operationSystem;
|
||||
/** %appdata%/Terrarum, without trailing slash */
|
||||
public static String defaultDir;
|
||||
/** defaultDir + "/Saves", without trailing slash */
|
||||
public static String defaultSaveDir;
|
||||
/** defaultDir + "/config.json" */
|
||||
public static String configDir;
|
||||
public static RunningEnvironment environment;
|
||||
|
||||
private void getDefaultDirectory() {
|
||||
String OS = OSName.toUpperCase();
|
||||
if (OS.contains("WIN")) {
|
||||
operationSystem = "WINDOWS";
|
||||
defaultDir = System.getenv("APPDATA") + "/Terrarum";
|
||||
}
|
||||
else if (OS.contains("OS X")) {
|
||||
operationSystem = "OSX";
|
||||
defaultDir = System.getProperty("user.home") + "/Library/Application Support/Terrarum";
|
||||
}
|
||||
else if (OS.contains("NUX") || OS.contains("NIX") || OS.contains("BSD")) {
|
||||
operationSystem = "LINUX";
|
||||
defaultDir = System.getProperty("user.home") + "/.Terrarum";
|
||||
}
|
||||
else if (OS.contains("SUNOS")) {
|
||||
operationSystem = "SOLARIS";
|
||||
defaultDir = System.getProperty("user.home") + "/.Terrarum";
|
||||
}
|
||||
else if (System.getProperty("java.runtime.name").toUpperCase().contains("ANDROID")) {
|
||||
operationSystem = "ANDROID";
|
||||
defaultDir = System.getProperty("user.home") + "/.Terrarum";
|
||||
environment = RunningEnvironment.MOBILE;
|
||||
}
|
||||
else {
|
||||
operationSystem = "UNKNOWN";
|
||||
defaultDir = System.getProperty("user.home") + "/.Terrarum";
|
||||
}
|
||||
|
||||
defaultSaveDir = defaultDir + "/Saves";
|
||||
configDir = defaultDir + "/config.json";
|
||||
|
||||
System.out.println(String.format("os.name = %s (with identifier %s)", OSName, operationSystem));
|
||||
System.out.println(String.format("os.version = %s", OSVersion));
|
||||
System.out.println(String.format("default directory: %s", defaultDir));
|
||||
}
|
||||
|
||||
private void createDirs() {
|
||||
File[] dirs = {new File(defaultSaveDir)};
|
||||
|
||||
for (File it : dirs) {
|
||||
if (!it.exists())
|
||||
it.mkdirs();
|
||||
}
|
||||
|
||||
//dirs.forEach { if (!it.exists()) it.mkdirs() }
|
||||
}
|
||||
|
||||
|
||||
// CONFIG //
|
||||
|
||||
private static KVHashMap gameConfig = new KVHashMap();
|
||||
|
||||
private static void createConfigJson() throws IOException {
|
||||
File configFile = new File(configDir);
|
||||
|
||||
if (!configFile.exists() || configFile.length() == 0L) {
|
||||
JsonWriter.INSTANCE.writeToFile(DefaultConfig.INSTANCE.fetch(), configDir);
|
||||
}
|
||||
}
|
||||
public static final void printdbgerr(Object obj, Object message) {
|
||||
if (IS_DEVELOPMENT_BUILD) {
|
||||
System.err.println("["+obj.getClass().getSimpleName()+"] "+message.toString());
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true on successful, false on failure.
|
||||
*/
|
||||
private static Boolean readConfigJson() {
|
||||
try {
|
||||
// read from disk and build config from it
|
||||
JsonObject jsonObject = JsonFetcher.INSTANCE.invoke(configDir);
|
||||
|
||||
// make config
|
||||
jsonObject.entrySet().forEach((entry) ->
|
||||
gameConfig.set(entry.getKey(), entry.getValue())
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (java.nio.file.NoSuchFileException e) {
|
||||
// write default config to game dir. Call this method again to read config from it.
|
||||
try {
|
||||
createConfigJson();
|
||||
}
|
||||
catch (IOException e1) {
|
||||
System.out.println("[AppLoader] Unable to write config.json file");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return config from config set. If the config does not exist, default value will be returned.
|
||||
* @param key
|
||||
* *
|
||||
* @return Config from config set or default config if it does not exist.
|
||||
* *
|
||||
* @throws NullPointerException if the specified config simply does not exist.
|
||||
*/
|
||||
public static int getConfigInt(String key) {
|
||||
Object cfg = getConfigMaster(key);
|
||||
if (cfg instanceof JsonPrimitive)
|
||||
return ((JsonPrimitive) cfg).getAsInt();
|
||||
else
|
||||
return Integer.parseInt(((String) cfg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return config from config set. If the config does not exist, default value will be returned.
|
||||
* @param key
|
||||
* *
|
||||
* @return Config from config set or default config if it does not exist.
|
||||
* *
|
||||
* @throws NullPointerException if the specified config simply does not exist.
|
||||
*/
|
||||
public static String getConfigString(String key) {
|
||||
Object cfg = getConfigMaster(key);
|
||||
if (cfg instanceof JsonPrimitive)
|
||||
return ((JsonPrimitive) cfg).getAsString();
|
||||
else
|
||||
return ((String) cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return config from config set. If the config does not exist, default value will be returned.
|
||||
* @param key
|
||||
* *
|
||||
* @return Config from config set or default config if it does not exist.
|
||||
* *
|
||||
* @throws NullPointerException if the specified config simply does not exist.
|
||||
*/
|
||||
public static boolean getConfigBoolean(String key) {
|
||||
Object cfg = getConfigMaster(key);
|
||||
if (cfg instanceof JsonPrimitive)
|
||||
return ((JsonPrimitive) cfg).getAsBoolean();
|
||||
else
|
||||
return ((boolean) cfg);
|
||||
}
|
||||
|
||||
public static int[] getConfigIntArray(String key) {
|
||||
Object cfg = getConfigMaster(key);
|
||||
if (cfg instanceof JsonArray) {
|
||||
JsonArray jsonArray = ((JsonArray) cfg).getAsJsonArray();
|
||||
//return IntArray(jsonArray.size(), { i -> jsonArray[i].asInt })
|
||||
int[] intArray = new int[jsonArray.size()];
|
||||
for (int i = 0; i < jsonArray.size(); i++) {
|
||||
intArray[i] = jsonArray.get(i).getAsInt();
|
||||
}
|
||||
return intArray;
|
||||
}
|
||||
else
|
||||
return ((int[]) cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get config from config file. If the entry does not exist, get from defaults; if the entry is not in the default, NullPointerException will be thrown
|
||||
*/
|
||||
private static JsonObject getDefaultConfig() {
|
||||
return DefaultConfig.INSTANCE.fetch();
|
||||
}
|
||||
|
||||
private static Object getConfigMaster(String key1) {
|
||||
String key = key1.toLowerCase();
|
||||
|
||||
Object config;
|
||||
try {
|
||||
config = gameConfig.get(key);
|
||||
}
|
||||
catch (NullPointerException e) {
|
||||
config = null;
|
||||
}
|
||||
|
||||
Object defaults;
|
||||
try {
|
||||
defaults = getDefaultConfig().get(key);
|
||||
}
|
||||
catch (NullPointerException e) {
|
||||
defaults = null;
|
||||
}
|
||||
|
||||
if (config == null) {
|
||||
if (defaults == null) {
|
||||
throw new NullPointerException("key not found: '$key'");
|
||||
}
|
||||
else {
|
||||
return defaults;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setConfig(String key, Object value) {
|
||||
gameConfig.set(key, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// //
|
||||
|
||||
public static void printdbg(Object obj, Object message) {
|
||||
if (IS_DEVELOPMENT_BUILD || getConfigBoolean("forcedevbuild")) {
|
||||
System.out.println("[" + obj.getClass().getSimpleName() + "] " + message.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void printdbgerr(Object obj, Object message) {
|
||||
if (IS_DEVELOPMENT_BUILD || getConfigBoolean("forcedevbuild")) {
|
||||
System.err.println("[" + obj.getClass().getSimpleName() + "] " + message.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static ShaderProgram loadShader(String vert, String frag) {
|
||||
ShaderProgram s = new ShaderProgram(Gdx.files.internal(vert), Gdx.files.internal(frag));
|
||||
|
||||
if (s.getLog().contains("error C")) {
|
||||
throw new Error(String.format("Shader program loaded with %s, %s failed:\n%s", vert, frag, s.getLog()));
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ object DefaultConfig {
|
||||
|
||||
jsonObject.addProperty("displayfps", 0) // 0: no limit, non-zero: limit
|
||||
jsonObject.addProperty("usevsync", true)
|
||||
jsonObject.addProperty("forcedevbuild", false)
|
||||
|
||||
|
||||
jsonObject.addProperty("imtooyoungtodie", false) // no perma-death
|
||||
@@ -66,8 +67,8 @@ object DefaultConfig {
|
||||
|
||||
jsonObject.addProperty("keyjump", Input.Keys.SPACE)
|
||||
|
||||
val keyquickbars = JsonArray(); for (i in Input.Keys.NUMPAD_1..Input.Keys.NUMPAD_9) keyquickbars.add(i); keyquickbars.add(Input.Keys.NUMPAD_0) // NUM_1 to NUM_0
|
||||
jsonObject.add("keyquickbars", keyquickbars)
|
||||
val keyquickslots = JsonArray(); for (i in Input.Keys.NUM_1..Input.Keys.NUM_9) keyquickslots.add(i); keyquickslots.add(Input.Keys.NUM_0) // NUM_1 to NUM_0
|
||||
jsonObject.add("keyquickslots", keyquickslots)
|
||||
|
||||
jsonObject.addProperty("mouseprimary", Input.Buttons.LEFT) // left mouse
|
||||
jsonObject.addProperty("mousesecondary", Input.Buttons.RIGHT) // right mouse
|
||||
@@ -75,23 +76,17 @@ object DefaultConfig {
|
||||
|
||||
jsonObject.addProperty("pcgamepadenv", "console")
|
||||
|
||||
jsonObject.addProperty("safetywarning", true)
|
||||
//jsonObject.addProperty("safetywarning", true)
|
||||
|
||||
|
||||
jsonObject.addProperty("maxparticles", 768)
|
||||
|
||||
|
||||
jsonObject.addProperty("fullframelightupdate", false)
|
||||
|
||||
jsonObject.addProperty("temperatureunit", 1) // -1: american, 0: kelvin, 1: celcius
|
||||
|
||||
|
||||
// "fancy" graphics settings
|
||||
jsonObject.addProperty("fxdither", true)
|
||||
jsonObject.addProperty("fx3dlut", false)
|
||||
|
||||
|
||||
jsonObject.addProperty("__debug", false)
|
||||
//jsonObject.addProperty("fx3dlut", false)
|
||||
|
||||
|
||||
return jsonObject
|
||||
|
||||
@@ -3,7 +3,6 @@ package net.torvald.terrarum
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Screen
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.GL20
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
@@ -39,8 +38,7 @@ object ErrorDisp : Screen {
|
||||
}
|
||||
|
||||
override fun render(delta: Float) {
|
||||
Gdx.gl.glClearColor(.094f, .094f, .094f, 0f)
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||
gdxClearAndSetBlend(.094f, .094f, .094f, 0f)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
* list of Actors that is sorted by Actors' referenceID
|
||||
*/
|
||||
//val ACTORCONTAINER_INITIAL_SIZE = 64
|
||||
val PARTICLES_MAX = Terrarum.getConfigInt("maxparticles")
|
||||
val PARTICLES_MAX = AppLoader.getConfigInt("maxparticles")
|
||||
//val actorContainer = ArrayList<Actor>(ACTORCONTAINER_INITIAL_SIZE)
|
||||
//val actorContainerInactive = ArrayList<Actor>(ACTORCONTAINER_INITIAL_SIZE)
|
||||
val particlesContainer = CircularArray<ParticleBase>(PARTICLES_MAX)
|
||||
@@ -362,14 +362,14 @@ class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
width = 900,
|
||||
height = Terrarum.HEIGHT - 160,
|
||||
categoryWidth = 210,
|
||||
toggleKeyLiteral = Terrarum.getConfigInt("keyinventory")
|
||||
toggleKeyLiteral = AppLoader.getConfigInt("keyinventory")
|
||||
)*/
|
||||
/*uiInventoryPlayer.setPosition(
|
||||
-uiInventoryPlayer.width,
|
||||
70
|
||||
)*/
|
||||
uiInventoryPlayer = UIInventoryFull(player,
|
||||
toggleKeyLiteral = Terrarum.getConfigInt("keyinventory")
|
||||
toggleKeyLiteral = AppLoader.getConfigInt("keyinventory")
|
||||
)
|
||||
uiInventoryPlayer.setPosition(0, 0)
|
||||
|
||||
@@ -464,7 +464,7 @@ class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
override fun run() {
|
||||
var updateTries = 0
|
||||
while (ingame.updateDeltaCounter >= ingame.updateRate) {
|
||||
ingame.updateGame(Terrarum.deltaTime)
|
||||
ingame.updateGame(AppLoader.getSmoothDelta().toFloat())
|
||||
ingame.updateDeltaCounter -= ingame.updateRate
|
||||
updateTries++
|
||||
|
||||
@@ -515,7 +515,7 @@ class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
|
||||
|
||||
if (false && Terrarum.getConfigBoolean("multithread")) { // NO MULTITHREADING: camera don't like concurrent modification (jittery actor movements)
|
||||
if (false && AppLoader.getConfigBoolean("multithread")) { // NO MULTITHREADING: camera don't like concurrent modification (jittery actor movements)
|
||||
if (firstTimeRun || updateThreadWrapper.state == Thread.State.TERMINATED) {
|
||||
updateThreadWrapper = Thread(ingameUpdateThread, "Terrarum UpdateThread")
|
||||
updateThreadWrapper.start()
|
||||
@@ -529,7 +529,7 @@ class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
while (updateDeltaCounter >= updateRate) {
|
||||
|
||||
//updateGame(delta)
|
||||
Terrarum.debugTimers["Ingame.update"] = measureNanoTime { updateGame(delta) }
|
||||
AppLoader.debugTimers["Ingame.update"] = measureNanoTime { updateGame(delta) }
|
||||
|
||||
updateDeltaCounter -= updateRate
|
||||
updateTries++
|
||||
@@ -544,7 +544,7 @@ class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
/** RENDER CODE GOES HERE */
|
||||
//renderGame(batch)
|
||||
Terrarum.debugTimers["Ingame.render"] = measureNanoTime { renderGame(batch) }
|
||||
AppLoader.debugTimers["Ingame.render"] = measureNanoTime { renderGame(batch) }
|
||||
}
|
||||
|
||||
protected fun updateGame(delta: Float) {
|
||||
@@ -1090,7 +1090,7 @@ class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
playableActorDelegate = newActor
|
||||
WorldSimulator(player, Terrarum.deltaTime)
|
||||
WorldSimulator(player, AppLoader.getSmoothDelta().toFloat())
|
||||
}
|
||||
|
||||
private fun changePossession(refid: Int) {
|
||||
@@ -1107,7 +1107,7 @@ class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
// accept new delegate
|
||||
playableActorDelegate = PlayableActorDelegate(getActorByID(refid) as ActorHumanoid)
|
||||
playableActorDelegate!!.actor.collisionType = ActorWithPhysics.COLLISION_KINEMATIC
|
||||
WorldSimulator(player, Terrarum.deltaTime)
|
||||
WorldSimulator(player, AppLoader.getSmoothDelta().toFloat())
|
||||
}
|
||||
|
||||
/** Send message to notifier UI and toggle the UI as opened. */
|
||||
|
||||
@@ -55,4 +55,40 @@ class GdxColorMap {
|
||||
fun getRaw(x: Int, y: Int): RGBA8888 = data[y * width + x]
|
||||
fun getRaw(x: Int): RGBA8888 = if (is2D) throw OperationNotSupportedException("This is 2D color map") else data[x]
|
||||
|
||||
override fun toString(): String {
|
||||
val sb = StringBuilder()
|
||||
|
||||
sb.append("ColorMap ${width}x$height:\n")
|
||||
|
||||
var yi = 0
|
||||
var xi = 0
|
||||
for (y in ((0 until height).take(2) + (0 until height).toList().takeLast(2)).distinct()) {
|
||||
|
||||
if (y - yi > 1) {
|
||||
sb.append(when (width) {
|
||||
in 1..4 -> ".......... ".repeat(width) + '\n'
|
||||
else -> ".......... .......... ... .......... .......... \n"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
for (x in ((0 until width).take(2) + (0 until width).toList().takeLast(2)).distinct()) {
|
||||
if (x - xi > 1) {
|
||||
sb.append("... ")
|
||||
}
|
||||
|
||||
sb.append("0x")
|
||||
sb.append(getRaw(x, y).toLong().and(0xFFFFFFFF).toString(16).toUpperCase().padStart(8, '0'))
|
||||
sb.append(' ')
|
||||
|
||||
xi = x
|
||||
}
|
||||
|
||||
sb.append('\n')
|
||||
|
||||
yi = y
|
||||
}
|
||||
|
||||
return sb.toString()
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||
import net.torvald.terrarum.ui.ConsoleWindow
|
||||
import java.util.ArrayList
|
||||
import java.util.*
|
||||
import java.util.concurrent.locks.Lock
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import javax.swing.JOptionPane
|
||||
@@ -23,7 +23,7 @@ open class IngameInstance(val batch: SpriteBatch) : Screen {
|
||||
|
||||
open lateinit var consoleHandler: ConsoleWindow
|
||||
|
||||
open lateinit var world: GameWorld
|
||||
open var world: GameWorld = GameWorld.makeNullWorld()
|
||||
/** how many different planets/stages/etc. are thenre. Whole stages must be manually managed by YOU. */
|
||||
var gameworldCount = 0
|
||||
/** The actor the game is currently allowing you to control.
|
||||
@@ -36,6 +36,11 @@ open class IngameInstance(val batch: SpriteBatch) : Screen {
|
||||
*/
|
||||
open var actorNowPlaying: ActorHumanoid? = null
|
||||
|
||||
open var gameInitialised = false
|
||||
internal set
|
||||
open var gameFullyLoaded = false
|
||||
internal set
|
||||
|
||||
val ACTORCONTAINER_INITIAL_SIZE = 64
|
||||
val actorContainer = ArrayList<Actor>(ACTORCONTAINER_INITIAL_SIZE)
|
||||
val actorContainerInactive = ArrayList<Actor>(ACTORCONTAINER_INITIAL_SIZE)
|
||||
@@ -44,6 +49,8 @@ open class IngameInstance(val batch: SpriteBatch) : Screen {
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
// the very basic show() implementation
|
||||
gameInitialised = true
|
||||
}
|
||||
|
||||
override fun render(delta: Float) {
|
||||
@@ -197,7 +204,7 @@ open class IngameInstance(val batch: SpriteBatch) : Screen {
|
||||
|
||||
|
||||
fun insertionSortLastElem(arr: ArrayList<Actor>) {
|
||||
lock(ReentrantLock()) {
|
||||
ReentrantLock().lock {
|
||||
var j = arr.lastIndex - 1
|
||||
val x = arr.last()
|
||||
while (j >= 0 && arr[j] > x) {
|
||||
@@ -208,13 +215,14 @@ open class IngameInstance(val batch: SpriteBatch) : Screen {
|
||||
}
|
||||
}
|
||||
|
||||
inline fun lock(lock: Lock, body: () -> Unit) {
|
||||
lock.lock()
|
||||
try {
|
||||
body()
|
||||
}
|
||||
finally {
|
||||
lock.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun Lock.lock(body: () -> Unit) {
|
||||
this.lock()
|
||||
try {
|
||||
body()
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import com.google.gson.JsonPrimitive
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
typealias ItemValue = KVHashMap
|
||||
typealias GameConfig = KVHashMap
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2015-12-30.
|
||||
|
||||
@@ -2,19 +2,21 @@ package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.ScreenAdapter
|
||||
import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.dataclass.HistoryArray
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-07-13.
|
||||
*/
|
||||
object LoadScreen : ScreenAdapter() {
|
||||
|
||||
var screenToLoad: Ingame? = null
|
||||
var screenToLoad: IngameInstance? = null
|
||||
private lateinit var screenLoadingThread: Thread
|
||||
|
||||
|
||||
@@ -123,12 +125,10 @@ object LoadScreen : ScreenAdapter() {
|
||||
|
||||
|
||||
|
||||
Gdx.gl.glClearColor(.094f, .094f, .094f, 0f)
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||
gdxClearAndSetBlend(.094f, .094f, .094f, 0f)
|
||||
|
||||
textFbo.inAction(null, null) {
|
||||
Gdx.gl.glClearColor(0f, 0f, 0f, 0f)
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||
gdxClearAndSetBlend(0f, 0f, 0f, 0f)
|
||||
}
|
||||
|
||||
// update arrow object
|
||||
@@ -161,7 +161,7 @@ object LoadScreen : ScreenAdapter() {
|
||||
Terrarum.batch.inUse {
|
||||
|
||||
|
||||
blendNormal()
|
||||
blendNormal(Terrarum.batch)
|
||||
Terrarum.fontGame
|
||||
it.color = Color.WHITE
|
||||
|
||||
@@ -169,7 +169,7 @@ object LoadScreen : ScreenAdapter() {
|
||||
Terrarum.fontGame.draw(it, textToPrint, ((textFbo.width - textWidth) / 2).toInt().toFloat(), 0f)
|
||||
|
||||
|
||||
blendMul()
|
||||
blendMul(Terrarum.batch)
|
||||
// draw colour overlay, flipped
|
||||
it.draw(textOverlayTex,
|
||||
(textFbo.width - textWidth) / 2f,
|
||||
@@ -184,7 +184,7 @@ object LoadScreen : ScreenAdapter() {
|
||||
Terrarum.batch.inUse {
|
||||
initViewPort(Terrarum.WIDTH, Terrarum.HEIGHT) // dunno, no render without this
|
||||
it.projectionMatrix = camera.combined
|
||||
blendNormal()
|
||||
blendNormal(Terrarum.batch)
|
||||
|
||||
|
||||
// almost black background
|
||||
@@ -251,7 +251,7 @@ object LoadScreen : ScreenAdapter() {
|
||||
|
||||
initViewPort(Terrarum.WIDTH, Terrarum.HEIGHT) // dunno, no render without this
|
||||
it.projectionMatrix = camera.combined
|
||||
blendNormal()
|
||||
blendNormal(Terrarum.batch)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -229,6 +229,8 @@ object ModMgr {
|
||||
val className = it["classname"].toString()
|
||||
val itemID = it["id"].toInt()
|
||||
|
||||
printdbg(this, "Reading item #$itemID with className $className")
|
||||
|
||||
val loadedClass = Class.forName(className)
|
||||
val loadedClassConstructor = loadedClass.getConstructor(ItemID::class.java)
|
||||
val loadedClassInstance = loadedClassConstructor.newInstance(itemID)
|
||||
|
||||
@@ -53,3 +53,5 @@ data class Point2d(var x: Double, var y: Double) : Cloneable {
|
||||
fun distSqr(other: Point2d) = ((this.x - other.x).sqr() + (this.y - other.y).sqr())
|
||||
|
||||
}
|
||||
|
||||
data class Point2i(val x: Int, val y: Int)
|
||||
|
||||
@@ -37,16 +37,12 @@ object PostProcessor {
|
||||
|
||||
|
||||
|
||||
Terrarum.debugTimers["Renderer.PostProcessor"] = measureNanoTime {
|
||||
AppLoader.debugTimers["Renderer.PostProcessor"] = measureNanoTime {
|
||||
|
||||
Gdx.gl.glClearColor(.094f, .094f, .094f, 0f)
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||
Gdx.gl.glEnable(GL20.GL_TEXTURE_2D)
|
||||
Gdx.gl.glEnable(GL20.GL_BLEND)
|
||||
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA)
|
||||
gdxClearAndSetBlend(.094f, .094f, .094f, 0f)
|
||||
|
||||
val shader: ShaderProgram? =
|
||||
if (Terrarum.getConfigBoolean("fxdither"))
|
||||
if (AppLoader.getConfigBoolean("fxdither"))
|
||||
AppLoader.shaderHicolour
|
||||
else
|
||||
null
|
||||
@@ -54,7 +50,6 @@ object PostProcessor {
|
||||
fbo.colorBufferTexture.bind(0)
|
||||
|
||||
shader?.begin()
|
||||
shader?.setUniformf("resolution", AppLoader.appConfig.width.toFloat(), AppLoader.appConfig.height.toFloat())
|
||||
shader?.setUniformMatrix("u_projTrans", projMat)
|
||||
shader?.setUniformi("u_texture", 0)
|
||||
AppLoader.fullscreenQuad.render(shader, GL20.GL_TRIANGLES)
|
||||
|
||||
72
src/net/torvald/terrarum/QNDTreeNode.kt
Normal file
72
src/net/torvald/terrarum/QNDTreeNode.kt
Normal file
@@ -0,0 +1,72 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class QNDTreeNode<T>(var data: T? = null, var parent: QNDTreeNode<T>? = null) {
|
||||
var children = ArrayList<QNDTreeNode<T>>()
|
||||
|
||||
|
||||
private fun traverse1(node: QNDTreeNode<T>, action: (QNDTreeNode<T>, Int) -> Unit, depth: Int = 0) {
|
||||
//if (node == null) return
|
||||
action(node, depth)
|
||||
node.children.forEach { traverse1(it, action, depth + 1) }
|
||||
}
|
||||
|
||||
private fun traverse2(node: QNDTreeNode<T>, action: (QNDTreeNode<T>, Int) -> Unit, depth: Int = 0) {
|
||||
//if (node == null) return
|
||||
node.children.forEach { traverse2(it, action, depth + 1) }
|
||||
action(node, depth)
|
||||
}
|
||||
|
||||
/**
|
||||
* (QNDTreeNode, Int) is Node-depth pair, starting from zero.
|
||||
*/
|
||||
fun traversePreorder(action: (QNDTreeNode<T>, Int) -> Unit) {
|
||||
this.traverse1(this, action)
|
||||
}
|
||||
|
||||
/**
|
||||
* (QNDTreeNode, Int) is Node-depth pair, starting from zero.
|
||||
*/
|
||||
fun traversePostorder(action: (QNDTreeNode<T>, Int) -> Unit) {
|
||||
this.traverse2(this, action)
|
||||
}
|
||||
|
||||
/**
|
||||
* (QNDTreeNode, Int) is Node-depth pair, starting from zero.
|
||||
*/
|
||||
fun traverseLevelorder(action: (QNDTreeNode<T>, Int) -> Unit) {
|
||||
val q = ArrayList<Pair<QNDTreeNode<T>, Int>>() // node, depth
|
||||
q.add(this to 0)
|
||||
while (q.isNotEmpty()) {
|
||||
val node = q.removeAt(0)
|
||||
action(node.first, node.second)
|
||||
node.first.children.forEach {
|
||||
q.add(it to node.second + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves data in the node in a specific depth (level).
|
||||
* Probably only useful for level = 1
|
||||
*/
|
||||
fun getLevelData(level: Int): List<T?> {
|
||||
val list = ArrayList<T?>()
|
||||
|
||||
traversePreorder { node, i ->
|
||||
if (i == level) {
|
||||
list.add(node.data)
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
override fun toString() = data.toString()
|
||||
|
||||
fun print() {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
@@ -3,26 +3,24 @@ package net.torvald.terrarum
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Screen
|
||||
import com.badlogic.gdx.assets.AssetManager
|
||||
import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.GL20
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonPrimitive
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.dataclass.ArrayListMap
|
||||
import net.torvald.dataclass.CircularArray
|
||||
import net.torvald.getcpuname.GetCpuName
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.AppLoader.printdbg
|
||||
import net.torvald.terrarum.AppLoader.printdbgerr
|
||||
import net.torvald.terrarum.AppLoader.*
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameactors.ActorID
|
||||
import net.torvald.terrarum.imagefont.TinyAlphNum
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||
import net.torvald.terrarum.utils.JsonFetcher
|
||||
import net.torvald.terrarum.utils.JsonWriter
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import net.torvald.terrarumsansbitmap.gdx.GameFontBase
|
||||
@@ -30,8 +28,7 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import org.lwjgl.BufferUtils
|
||||
import org.lwjgl.input.Controllers
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import net.torvald.getcpuname.GetCpuName
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
|
||||
|
||||
@@ -50,11 +47,6 @@ object Terrarum : Screen {
|
||||
*/
|
||||
const val PLAYER_REF_ID: Int = 0x91A7E2
|
||||
|
||||
val debugTimers = ArrayListMap<String, Long>()
|
||||
|
||||
var screenW = 0
|
||||
var screenH = 0
|
||||
|
||||
lateinit var batch: SpriteBatch
|
||||
lateinit var shapeRender: ShapeRenderer // DO NOT USE!! for very limited applications e.g. WeatherMixer
|
||||
inline fun inShapeRenderer(shapeRendererType: ShapeRenderer.ShapeType = ShapeRenderer.ShapeType.Filled, action: (ShapeRenderer) -> Unit) {
|
||||
@@ -69,9 +61,9 @@ object Terrarum : Screen {
|
||||
//////////////////////////////
|
||||
|
||||
val WIDTH: Int
|
||||
get() = if (screenW % 2 == 0) screenW else screenW - 1
|
||||
get() = AppLoader.screenW
|
||||
val HEIGHT: Int
|
||||
get() = if (screenH % 2 == 0) screenH else screenH - 1
|
||||
get() = AppLoader.screenH
|
||||
|
||||
//val WIDTH_MIN = 800
|
||||
//val HEIGHT_MIN = 600
|
||||
@@ -82,44 +74,22 @@ object Terrarum : Screen {
|
||||
get() = HEIGHT.ushr(1)
|
||||
|
||||
/**
|
||||
* To be used with physics simulator
|
||||
* To be used with physics simulator. This is a magic number.
|
||||
*/
|
||||
val TARGET_FPS: Double = 26.0 + (2.0 / 3.0)
|
||||
val PHYS_TIME_FRAME: Double = 26.0 + (2.0 / 3.0)
|
||||
// 26.0 + (2.0 / 3.0) // lower value == faster gravity response (IT WON'T HOTSWAP!!)
|
||||
// protip: using METER, game unit and SI unit will have same number
|
||||
|
||||
/**
|
||||
* To be used with render, to achieve smooth frame drawing
|
||||
* TARGET_INTERNAL_FPS > TARGET_FPS for smooth frame drawing
|
||||
*/
|
||||
val TARGET_INTERNAL_FPS: Double = 60.0
|
||||
|
||||
internal val UPDATE_CATCHUP_MAX_TRIES = 10
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var previousScreen: Screen? = null // to be used with temporary states like StateMonitorCheck
|
||||
|
||||
|
||||
var ingame: IngameInstance? = null
|
||||
private val gameConfig = GameConfig()
|
||||
|
||||
val OSName = System.getProperty("os.name")
|
||||
val OSVersion = System.getProperty("os.version")
|
||||
lateinit var OperationSystem: String // all caps "WINDOWS, "OSX", "LINUX", "SOLARIS", "UNKNOWN"
|
||||
private set
|
||||
lateinit var defaultDir: String
|
||||
private set
|
||||
lateinit var defaultSaveDir: String
|
||||
private set
|
||||
|
||||
|
||||
|
||||
private val javaHeapCircularArray = CircularArray<Int>(128)
|
||||
private val nativeHeapCircularArray = CircularArray<Int>(128)
|
||||
private val javaHeapCircularArray = CircularArray<Int>(64)
|
||||
private val nativeHeapCircularArray = CircularArray<Int>(64)
|
||||
private val updateRateCircularArray = CircularArray<Double>(16)
|
||||
|
||||
val memJavaHeap: Int
|
||||
get() {
|
||||
@@ -139,9 +109,14 @@ object Terrarum : Screen {
|
||||
}
|
||||
val memXmx: Int
|
||||
get() = (Runtime.getRuntime().maxMemory() shr 20).toInt()
|
||||
val updateRateStr: String
|
||||
get() {
|
||||
updateRateCircularArray.add(updateRate)
|
||||
|
||||
var environment: RunningEnvironment
|
||||
private set
|
||||
var acc = 0.0
|
||||
updateRateCircularArray.forEach { acc = maxOf(acc, it) }
|
||||
return String.format("%.2f", acc)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -190,7 +165,7 @@ object Terrarum : Screen {
|
||||
val CONTROLLER_DEADZONE = 0.1f
|
||||
|
||||
/** Available CPU threads */
|
||||
val THREADS = Runtime.getRuntime().availableProcessors()
|
||||
val THREADS = Runtime.getRuntime().availableProcessors() + 1
|
||||
|
||||
/**
|
||||
* If the game is multithreading.
|
||||
@@ -199,9 +174,7 @@ object Terrarum : Screen {
|
||||
* THREADS >= 2 and config "multithread" is true
|
||||
*/
|
||||
val MULTITHREAD: Boolean
|
||||
get() = THREADS >= 2 && getConfigBoolean("multithread")
|
||||
|
||||
private lateinit var configDir: String
|
||||
get() = THREADS >= 3 && getConfigBoolean("multithread")
|
||||
|
||||
const val NAME = AppLoader.GAME_NAME
|
||||
|
||||
@@ -209,6 +182,8 @@ object Terrarum : Screen {
|
||||
val systemArch = System.getProperty("os.arch")
|
||||
val processor = GetCpuName.getModelName()
|
||||
val processorVendor = GetCpuName.getCPUID()
|
||||
lateinit var renderer: String
|
||||
lateinit var rendererVendor: String
|
||||
|
||||
val is32BitJVM = !System.getProperty("sun.arch.data.model").contains("64")
|
||||
|
||||
@@ -220,10 +195,6 @@ object Terrarum : Screen {
|
||||
lateinit var shaderRGBOnly: ShaderProgram
|
||||
lateinit var shaderAtoGrey: ShaderProgram
|
||||
|
||||
|
||||
lateinit var textureWhiteSquare: Texture
|
||||
|
||||
|
||||
lateinit var testTexture: Texture
|
||||
|
||||
|
||||
@@ -231,8 +202,6 @@ object Terrarum : Screen {
|
||||
val fullscreenQuad = AppLoader.fullscreenQuad
|
||||
|
||||
|
||||
val deltaTime: Float; get() = Gdx.graphics.rawDeltaTime
|
||||
|
||||
|
||||
lateinit var assetManager: AssetManager // TODO
|
||||
|
||||
@@ -243,16 +212,6 @@ object Terrarum : Screen {
|
||||
println("LibGDX version ${com.badlogic.gdx.Version.VERSION}")
|
||||
|
||||
|
||||
getDefaultDirectory()
|
||||
createDirs()
|
||||
|
||||
|
||||
// read config i guess...?
|
||||
val readFromDisk = readConfigJson()
|
||||
if (!readFromDisk) readConfigJson() // what's this for?
|
||||
|
||||
|
||||
|
||||
println("os.arch = $systemArch") // debug info
|
||||
|
||||
if (is32BitJVM) {
|
||||
@@ -278,18 +237,19 @@ object Terrarum : Screen {
|
||||
}
|
||||
|
||||
|
||||
|
||||
environment = try {
|
||||
Controllers.getController(0) // test if controller exists
|
||||
if (getConfigString("pcgamepadenv") == "console")
|
||||
RunningEnvironment.CONSOLE
|
||||
else
|
||||
// setting environment as MOBILE precedes this code
|
||||
if (environment != RunningEnvironment.MOBILE) {
|
||||
environment = try {
|
||||
Controllers.getController(0) // test if controller exists
|
||||
if (getConfigString("pcgamepadenv") == "console")
|
||||
RunningEnvironment.CONSOLE
|
||||
else
|
||||
RunningEnvironment.PC
|
||||
}
|
||||
catch (e: IndexOutOfBoundsException) {
|
||||
RunningEnvironment.PC
|
||||
}
|
||||
}
|
||||
catch (e: IndexOutOfBoundsException) {
|
||||
RunningEnvironment.PC
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -325,9 +285,15 @@ object Terrarum : Screen {
|
||||
testTexture = Texture(Gdx.files.internal("./assets/test_texture.tga"))
|
||||
|
||||
|
||||
val glInfo = Gdx.graphics.glVersion.debugVersionString
|
||||
|
||||
println("GL_VERSION = $GL_VERSION")
|
||||
println("GL_MAX_TEXTURE_SIZE = $GL_MAX_TEXTURE_SIZE")
|
||||
println("GL info:\n${Gdx.graphics.glVersion.debugVersionString}") // debug info
|
||||
println("GL info:\n$glInfo") // debug info
|
||||
|
||||
// set up renderer info variables
|
||||
renderer = Gdx.graphics.glVersion.rendererString
|
||||
rendererVendor = Gdx.graphics.glVersion.vendorString
|
||||
|
||||
|
||||
if (GL_VERSION < MINIMAL_GL_VERSION || GL_MAX_TEXTURE_SIZE < MINIMAL_GL_MAX_TEXTURE_SIZE) {
|
||||
@@ -345,27 +311,22 @@ object Terrarum : Screen {
|
||||
shapeRender = ShapeRenderer()
|
||||
|
||||
|
||||
//fontGame = GameFontBase("assets/graphics/fonts/terrarum-sans-bitmap", flipY = true)
|
||||
fontSmallNumbers = TinyAlphNum
|
||||
|
||||
|
||||
textureWhiteSquare = Texture(Gdx.files.internal("assets/graphics/ortho_line_tex_2px.tga"))
|
||||
textureWhiteSquare.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
|
||||
|
||||
|
||||
ShaderProgram.pedantic = false
|
||||
shaderBlur = ShaderProgram(Gdx.files.internal("assets/blur.vert"), Gdx.files.internal("assets/blur.frag"))
|
||||
shaderBlur = AppLoader.loadShader("assets/blur.vert", "assets/blur.frag")
|
||||
|
||||
|
||||
if (getConfigBoolean("fxdither")) {
|
||||
shaderBayer = ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/4096_bayer.frag"))
|
||||
shaderBayer = AppLoader.loadShader("assets/4096.vert", "assets/4096_bayer.frag")
|
||||
shaderBayer.begin()
|
||||
shaderBayer.setUniformf("rcount", 64f)
|
||||
shaderBayer.setUniformf("gcount", 64f)
|
||||
shaderBayer.setUniformf("bcount", 64f)
|
||||
shaderBayer.end()
|
||||
|
||||
shaderSkyboxFill = ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/4096_bayer_skyboxfill.frag"))
|
||||
shaderSkyboxFill = AppLoader.loadShader("assets/4096.vert", "assets/4096_bayer_skyboxfill.frag")
|
||||
shaderSkyboxFill.begin()
|
||||
shaderSkyboxFill.setUniformf("rcount", 64f)
|
||||
shaderSkyboxFill.setUniformf("gcount", 64f)
|
||||
@@ -373,15 +334,15 @@ object Terrarum : Screen {
|
||||
shaderSkyboxFill.end()
|
||||
}
|
||||
else {
|
||||
shaderBayer = ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/passthru.frag"))
|
||||
shaderSkyboxFill = ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/skyboxfill.frag"))
|
||||
shaderBayer = AppLoader.loadShader("assets/4096.vert", "assets/passthru.frag")
|
||||
shaderSkyboxFill = AppLoader.loadShader("assets/4096.vert", "assets/skyboxfill.frag")
|
||||
}
|
||||
|
||||
|
||||
shaderBlendGlow = ShaderProgram(Gdx.files.internal("assets/blendGlow.vert"), Gdx.files.internal("assets/blendGlow.frag"))
|
||||
shaderBlendGlow = AppLoader.loadShader("assets/blendGlow.vert", "assets/blendGlow.frag")
|
||||
|
||||
shaderRGBOnly = ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/rgbonly.frag"))
|
||||
shaderAtoGrey = ShaderProgram(Gdx.files.internal("assets/4096.vert"), Gdx.files.internal("assets/aonly.frag"))
|
||||
shaderRGBOnly = AppLoader.loadShader("assets/4096.vert", "assets/rgbonly.frag")
|
||||
shaderAtoGrey = AppLoader.loadShader("assets/4096.vert", "assets/aonly.frag")
|
||||
|
||||
|
||||
if (!shaderBlendGlow.isCompiled) {
|
||||
@@ -419,18 +380,18 @@ object Terrarum : Screen {
|
||||
|
||||
|
||||
|
||||
// jump right into the ingame
|
||||
/*ingame = Ingame(batch)
|
||||
ingame!!.gameLoadInfoPayload = Ingame.NewWorldParameters(2400, 800, HQRNG().nextLong())
|
||||
ingame!!.gameLoadMode = Ingame.GameLoadMode.CREATE_NEW
|
||||
LoadScreen.screenToLoad = ingame!!
|
||||
super.setScreen(LoadScreen)*/
|
||||
// jump straight into the ingame
|
||||
/*val ingame = Ingame(batch)
|
||||
ingame.gameLoadInfoPayload = Ingame.NewWorldParameters(2400, 800, HQRNG().nextLong())
|
||||
ingame.gameLoadMode = Ingame.GameLoadMode.CREATE_NEW
|
||||
LoadScreen.screenToLoad = ingame
|
||||
this.ingame = ingame
|
||||
setScreen(LoadScreen)*/
|
||||
|
||||
|
||||
|
||||
// title screen
|
||||
AppLoader.getINSTANCE().setScreen(TitleScreen(batch))
|
||||
//appLoader.setScreen(FuckingWorldRenderer(batch))
|
||||
}
|
||||
|
||||
fun setScreen(screen: Screen) {
|
||||
@@ -438,10 +399,9 @@ object Terrarum : Screen {
|
||||
}
|
||||
|
||||
override fun render(delta: Float) {
|
||||
Terrarum.debugTimers["GDX.delta"] = delta.times(1000_000_000f).toLong()
|
||||
AppLoader.getINSTANCE().screen.render(deltaTime)
|
||||
//GLOBAL_RENDER_TIMER += 1
|
||||
// moved to AppLoader; global event must be place at the apploader to prevent ACCIDENTAL forgot-to-update type of bug.
|
||||
AppLoader.debugTimers["GDX.rawDelta"] = Gdx.graphics.rawDeltaTime.times(1000_000_000f).toLong()
|
||||
AppLoader.debugTimers["GDX.smtDelta"] = AppLoader.getSmoothDelta().times(1000_000_000f).toLong()
|
||||
AppLoader.getINSTANCE().screen.render(delta)
|
||||
}
|
||||
|
||||
override fun pause() {
|
||||
@@ -477,206 +437,16 @@ object Terrarum : Screen {
|
||||
}
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
//var width = maxOf(width, WIDTH_MIN)
|
||||
//var height = maxOf(height, HEIGHT_MIN)
|
||||
|
||||
var width = width
|
||||
var height = height
|
||||
|
||||
if (width % 2 == 1) width -= 1
|
||||
if (height % 2 == 1) height -= 1
|
||||
|
||||
screenW = width
|
||||
screenH = height
|
||||
|
||||
|
||||
try {
|
||||
AppLoader.getINSTANCE().screen.resize(screenW, screenH)
|
||||
/*try {
|
||||
AppLoader.getINSTANCE().screen.resize(width, height)
|
||||
}
|
||||
catch (e: NullPointerException) { }
|
||||
|
||||
// re-calculate fullscreen quad
|
||||
//updateFullscreenQuad(screenW, screenH)
|
||||
|
||||
//appLoader.resize(width, height)
|
||||
//Gdx.graphics.setWindowedMode(width, height)
|
||||
catch (e: NullPointerException) { }*/ // I sense circular recursion...
|
||||
|
||||
printdbg(this, "newsize: ${Gdx.graphics.width}x${Gdx.graphics.height} | internal: ${width}x$height")
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private fun getDefaultDirectory() {
|
||||
val OS = System.getProperty("os.name").toUpperCase()
|
||||
if (OS.contains("WIN")) {
|
||||
OperationSystem = "WINDOWS"
|
||||
defaultDir = System.getenv("APPDATA") + "/Terrarum"
|
||||
}
|
||||
else if (OS.contains("OS X")) {
|
||||
OperationSystem = "OSX"
|
||||
defaultDir = System.getProperty("user.home") + "/Library/Application Support/Terrarum"
|
||||
}
|
||||
else if (OS.contains("NUX") || OS.contains("NIX") || OS.contains("BSD")) {
|
||||
OperationSystem = "LINUX"
|
||||
defaultDir = System.getProperty("user.home") + "/.Terrarum"
|
||||
}
|
||||
else if (OS.contains("SUNOS")) {
|
||||
OperationSystem = "SOLARIS"
|
||||
defaultDir = System.getProperty("user.home") + "/.Terrarum"
|
||||
}
|
||||
else if (System.getProperty("java.runtime.name").toUpperCase().contains("ANDROID")) {
|
||||
OperationSystem = "ANDROID"
|
||||
defaultDir = System.getProperty("user.home") + "/.Terrarum"
|
||||
environment = RunningEnvironment.MOBILE
|
||||
}
|
||||
else {
|
||||
OperationSystem = "UNKNOWN"
|
||||
defaultDir = System.getProperty("user.home") + "/.Terrarum"
|
||||
}
|
||||
|
||||
defaultSaveDir = defaultDir + "/Saves"
|
||||
configDir = defaultDir + "/config.json"
|
||||
|
||||
println("os.name = $OSName (with identifier $OperationSystem)")
|
||||
println("os.version = $OSVersion")
|
||||
println("default directory: $defaultDir")
|
||||
}
|
||||
|
||||
private fun createDirs() {
|
||||
val dirs = arrayOf(File(defaultSaveDir))
|
||||
dirs.forEach { if (!it.exists()) it.mkdirs() }
|
||||
}
|
||||
|
||||
private fun createConfigJson() {
|
||||
val configFile = File(configDir)
|
||||
|
||||
if (!configFile.exists() || configFile.length() == 0L) {
|
||||
JsonWriter.writeToFile(DefaultConfig.fetch(), configDir)
|
||||
}
|
||||
}
|
||||
|
||||
private fun readConfigJson(): Boolean {
|
||||
try {
|
||||
// read from disk and build config from it
|
||||
val jsonObject = JsonFetcher(configDir)
|
||||
|
||||
// make config
|
||||
jsonObject.entrySet().forEach { entry -> gameConfig[entry.key] = entry.value }
|
||||
|
||||
return true
|
||||
}
|
||||
catch (e: IOException) {
|
||||
// write default config to game dir. Call this method again to read config from it.
|
||||
try {
|
||||
createConfigJson()
|
||||
}
|
||||
catch (e1: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return config from config set. If the config does not exist, default value will be returned.
|
||||
* @param key
|
||||
* *
|
||||
* @return Config from config set or default config if it does not exist.
|
||||
* *
|
||||
* @throws NullPointerException if the specified config simply does not exist.
|
||||
*/
|
||||
fun getConfigInt(key: String): Int {
|
||||
val cfg = getConfigMaster(key)
|
||||
if (cfg is JsonPrimitive)
|
||||
return cfg.asInt
|
||||
else
|
||||
return cfg as Int
|
||||
}
|
||||
|
||||
/**
|
||||
* Return config from config set. If the config does not exist, default value will be returned.
|
||||
* @param key
|
||||
* *
|
||||
* @return Config from config set or default config if it does not exist.
|
||||
* *
|
||||
* @throws NullPointerException if the specified config simply does not exist.
|
||||
*/
|
||||
fun getConfigString(key: String): String {
|
||||
val cfg = getConfigMaster(key)
|
||||
if (cfg is JsonPrimitive)
|
||||
return cfg.asString
|
||||
else
|
||||
return cfg as String
|
||||
}
|
||||
|
||||
/**
|
||||
* Return config from config set. If the config does not exist, default value will be returned.
|
||||
* @param key
|
||||
* *
|
||||
* @return Config from config set or default config if it does not exist.
|
||||
* *
|
||||
* @throws NullPointerException if the specified config simply does not exist.
|
||||
*/
|
||||
fun getConfigBoolean(key: String): Boolean {
|
||||
val cfg = getConfigMaster(key)
|
||||
if (cfg is JsonPrimitive)
|
||||
return cfg.asBoolean
|
||||
else
|
||||
return cfg as Boolean
|
||||
}
|
||||
|
||||
fun getConfigIntArray(key: String): IntArray {
|
||||
val cfg = getConfigMaster(key)
|
||||
if (cfg is JsonArray) {
|
||||
val jsonArray = cfg.asJsonArray
|
||||
return IntArray(jsonArray.size(), { i -> jsonArray[i].asInt })
|
||||
}
|
||||
else
|
||||
return cfg as IntArray
|
||||
}
|
||||
|
||||
/**
|
||||
* Get config from config file. If the entry does not exist, get from defaults; if the entry is not in the default, NullPointerException will be thrown
|
||||
*/
|
||||
private val defaultConfig = DefaultConfig.fetch()
|
||||
|
||||
private fun getConfigMaster(key: String): Any {
|
||||
val key = key.toLowerCase()
|
||||
|
||||
val config = try {
|
||||
gameConfig[key]
|
||||
}
|
||||
catch (e: NullPointerException) {
|
||||
null
|
||||
}
|
||||
|
||||
val defaults = try {
|
||||
defaultConfig.get(key)
|
||||
}
|
||||
catch (e: NullPointerException) {
|
||||
null
|
||||
}
|
||||
|
||||
if (config == null) {
|
||||
if (defaults == null) {
|
||||
throw NullPointerException("key not found: '$key'")
|
||||
}
|
||||
else {
|
||||
return defaults
|
||||
}
|
||||
}
|
||||
else {
|
||||
return config
|
||||
}
|
||||
}
|
||||
|
||||
fun setConfig(key: String, value: Any) {
|
||||
gameConfig[key] = value
|
||||
}
|
||||
|
||||
val currentSaveDir: File
|
||||
get() {
|
||||
val file = File(defaultSaveDir + "/test")
|
||||
@@ -703,15 +473,9 @@ object Terrarum : Screen {
|
||||
get() = Gdx.input.x
|
||||
inline val mouseScreenY: Int
|
||||
get() = Gdx.input.y
|
||||
/** Bigger than 1.0 */
|
||||
/** Delta converted as it it was a FPS */
|
||||
inline val updateRate: Double
|
||||
get() = 1.0 / Gdx.graphics.deltaTime
|
||||
val updateRateStr: String
|
||||
get() = String.format("%.2f", updateRate)
|
||||
/** Smaller than 1.0 */
|
||||
val renderRate = 1.0 / TARGET_INTERNAL_FPS
|
||||
val renderRateStr = TARGET_INTERNAL_FPS.toString()
|
||||
|
||||
get() = 1.0 / AppLoader.getSmoothDelta()
|
||||
/**
|
||||
* Usage:
|
||||
*
|
||||
@@ -727,6 +491,7 @@ object Terrarum : Screen {
|
||||
Actor.RenderOrder.MIDDLE -> Actor.RANGE_MIDDLE
|
||||
Actor.RenderOrder.MIDTOP -> Actor.RANGE_MIDTOP
|
||||
Actor.RenderOrder.FRONT -> Actor.RANGE_FRONT
|
||||
Actor.RenderOrder.OVERLAY-> Actor.RANDE_OVERLAY
|
||||
}
|
||||
}
|
||||
catch (gameNotInitialisedException: KotlinNullPointerException) {
|
||||
@@ -780,9 +545,9 @@ fun Float.round(): Float {
|
||||
|
||||
// ShapeRenderer alternative for rects
|
||||
fun SpriteBatch.fillRect(x: Float, y: Float, w: Float, h: Float) {
|
||||
this.draw(Terrarum.textureWhiteSquare, x, y, w, h)
|
||||
this.draw(AppLoader.textureWhiteSquare, x, y, w, h)
|
||||
}
|
||||
inline fun SpriteBatch.drawStraightLine(x: Float, y: Float, otherEnd: Float, thickness: Float, isVertical: Boolean) {
|
||||
fun SpriteBatch.drawStraightLine(x: Float, y: Float, otherEnd: Float, thickness: Float, isVertical: Boolean) {
|
||||
if (!isVertical)
|
||||
this.fillRect(x, y, otherEnd - x, thickness)
|
||||
else
|
||||
@@ -794,36 +559,70 @@ inline fun SpriteBatch.drawStraightLine(x: Float, y: Float, otherEnd: Float, thi
|
||||
infix fun Color.mul(other: Color): Color = this.cpy().mul(other)
|
||||
|
||||
|
||||
|
||||
/*inline fun Color.toRGB10(): RGB10 {
|
||||
val bits = this.toIntBits() // ABGR
|
||||
// 0bxxRRRRRRRRRRGGGGGGGGGGBBBBBBBBBB
|
||||
// 0bAAAAAAAABBBBBBBBGGGGGGGGRRRRRRRR
|
||||
return bits.and(0x0000FF).shl(20) or bits.and(0x00FF00).shl(2) or bits.and(0xFF0000).ushr(16)
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
fun blendMul(batch: SpriteBatch? = null) {
|
||||
(batch ?: Terrarum.batch).enableBlending()
|
||||
(batch ?: Terrarum.batch).setBlendFunction(GL20.GL_DST_COLOR, GL20.GL_ONE_MINUS_SRC_ALPHA)
|
||||
Gdx.gl.glBlendEquation(GL20.GL_FUNC_ADD) // batch.flush does not touch blend equation
|
||||
fun blendMul(batch: SpriteBatch) {
|
||||
// will break if the colour image contains semitransparency
|
||||
batch.enableBlending()
|
||||
batch.setBlendFunction(GL20.GL_DST_COLOR, GL20.GL_ONE_MINUS_SRC_ALPHA)
|
||||
}
|
||||
|
||||
fun blendNormal(batch: SpriteBatch? = null) {
|
||||
(batch ?: Terrarum.batch).enableBlending()
|
||||
(batch ?: Terrarum.batch).setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA)
|
||||
Gdx.gl.glBlendEquation(GL20.GL_FUNC_ADD) // batch.flush does not touch blend equation
|
||||
fun blendScreen(batch: SpriteBatch) {
|
||||
// will break if the colour image contains semitransparency
|
||||
batch.enableBlending()
|
||||
batch.setBlendFunction(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_COLOR)
|
||||
}
|
||||
|
||||
fun blendScreen(batch: SpriteBatch? = null) {
|
||||
(batch ?: Terrarum.batch).enableBlending()
|
||||
(batch ?: Terrarum.batch).setBlendFunction(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_COLOR)
|
||||
Gdx.gl.glBlendEquation(GL20.GL_FUNC_ADD) // batch.flush does not touch blend equation
|
||||
fun blendDisable(batch: SpriteBatch) {
|
||||
batch.disableBlending()
|
||||
}
|
||||
|
||||
fun blendDisable(batch: SpriteBatch? = null) {
|
||||
(batch ?: Terrarum.batch).disableBlending()
|
||||
fun blendNormal(batch: SpriteBatch) {
|
||||
batch.enableBlending()
|
||||
batch.setBlendFunctionSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_SRC_ALPHA, GL20.GL_ONE)
|
||||
|
||||
// ALPHA *MUST BE* PREMULTIPLIED //
|
||||
|
||||
// One way to tell:
|
||||
// 1. Check (RGB) and (A) values.
|
||||
// 2. If there exist a pixel such that max(R,G,B) > (A), then the image is NOT premultiplied.
|
||||
// Easy way:
|
||||
// Base game (mods/basegame/blocks/terrain.tga.gz) has impure window glass. When looking at the RGB channel only:
|
||||
// premultipied if the glass looks very dark.
|
||||
// not premultipied if the glass looks VERY GREEN.
|
||||
|
||||
// helpful links:
|
||||
// - https://gamedev.stackexchange.com/questions/82741/normal-blend-mode-with-opengl-trouble
|
||||
// - https://www.andersriggelsen.dk/glblendfunc.php
|
||||
}
|
||||
|
||||
fun gdxClearAndSetBlend(r: Float, g: Float, b: Float, a: Float) {
|
||||
Gdx.gl.glClearColor(r,g,b,a)
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||
gdxSetBlend()
|
||||
}
|
||||
|
||||
fun gdxSetBlend() {
|
||||
Gdx.gl.glEnable(GL20.GL_TEXTURE_2D)
|
||||
Gdx.gl.glEnable(GL20.GL_BLEND)
|
||||
}
|
||||
|
||||
fun gdxSetBlendNormal() {
|
||||
gdxSetBlend()
|
||||
Gdx.gl.glBlendFuncSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_SRC_ALPHA, GL20.GL_ONE)
|
||||
//Gdx.gl.glBlendEquationSeparate(GL20.GL_FUNC_ADD, GL30.GL_MAX) // batch.flush does not touch blend equation
|
||||
|
||||
// ALPHA *MUST BE* PREMULTIPLIED //
|
||||
|
||||
// One way to tell:
|
||||
// 1. Check (RGB) and (A) values.
|
||||
// 2. If there exist a pixel such that max(R,G,B) > (A), then the image is NOT premultiplied.
|
||||
// Easy way:
|
||||
// Base game (mods/basegame/blocks/terrain.tga.gz) has impure window glass. When looking at the RGB channel only:
|
||||
// premultipied if the glass looks very dark.
|
||||
// not premultipied if the glass looks VERY GREEN.
|
||||
|
||||
// helpful links:
|
||||
// - https://gamedev.stackexchange.com/questions/82741/normal-blend-mode-with-opengl-trouble
|
||||
// - https://www.andersriggelsen.dk/glblendfunc.php
|
||||
}
|
||||
|
||||
object BlendMode {
|
||||
@@ -832,11 +631,11 @@ object BlendMode {
|
||||
const val NORMAL = "normal"
|
||||
//const val MAX = "GL_MAX" // not supported by GLES -- use shader
|
||||
|
||||
fun resolve(mode: String) {
|
||||
fun resolve(mode: String, batch: SpriteBatch) {
|
||||
when (mode) {
|
||||
SCREEN -> blendScreen()
|
||||
MULTIPLY -> blendMul()
|
||||
NORMAL -> blendNormal()
|
||||
SCREEN -> blendScreen(batch)
|
||||
MULTIPLY -> blendMul(batch)
|
||||
NORMAL -> blendNormal(batch)
|
||||
//MAX -> blendLightenOnly() // not supported by GLES -- use shader
|
||||
else -> throw Error("Unknown blend mode: $mode")
|
||||
}
|
||||
@@ -890,23 +689,23 @@ val ccK = GameFontBase.toColorCode(0x888F)
|
||||
|
||||
typealias Second = Float
|
||||
|
||||
inline fun Int.sqr(): Int = this * this
|
||||
inline fun Double.floorInt() = Math.floor(this).toInt()
|
||||
inline fun Float.floorInt() = FastMath.floor(this)
|
||||
inline fun Float.floor() = FastMath.floor(this).toFloat()
|
||||
inline fun Double.ceilInt() = Math.ceil(this).toInt()
|
||||
inline fun Float.ceil(): Float = FastMath.ceil(this).toFloat()
|
||||
inline fun Float.ceilInt() = FastMath.ceil(this)
|
||||
inline fun Double.round() = Math.round(this).toDouble()
|
||||
inline fun Double.floor() = Math.floor(this)
|
||||
inline fun Double.ceil() = this.floor() + 1.0
|
||||
inline fun Double.roundInt(): Int = Math.round(this).toInt()
|
||||
inline fun Float.roundInt(): Int = Math.round(this)
|
||||
inline fun Double.abs() = Math.abs(this)
|
||||
inline fun Double.sqr() = this * this
|
||||
inline fun Double.sqrt() = Math.sqrt(this)
|
||||
inline fun Float.sqrt() = FastMath.sqrt(this)
|
||||
inline fun Int.abs() = if (this < 0) -this else this
|
||||
fun Int.sqr(): Int = this * this
|
||||
fun Double.floorInt() = Math.floor(this).toInt()
|
||||
fun Float.floorInt() = FastMath.floor(this)
|
||||
fun Float.floor() = FastMath.floor(this).toFloat()
|
||||
fun Double.ceilInt() = Math.ceil(this).toInt()
|
||||
fun Float.ceil(): Float = FastMath.ceil(this).toFloat()
|
||||
fun Float.ceilInt() = FastMath.ceil(this)
|
||||
fun Double.round() = Math.round(this).toDouble()
|
||||
fun Double.floor() = Math.floor(this)
|
||||
fun Double.ceil() = this.floor() + 1.0
|
||||
fun Double.roundInt(): Int = Math.round(this).toInt()
|
||||
fun Float.roundInt(): Int = Math.round(this)
|
||||
fun Double.abs() = Math.abs(this)
|
||||
fun Double.sqr() = this * this
|
||||
fun Double.sqrt() = Math.sqrt(this)
|
||||
fun Float.sqrt() = FastMath.sqrt(this)
|
||||
fun Int.abs() = this.absoluteValue
|
||||
fun Double.bipolarClamp(limit: Double) =
|
||||
this.coerceIn(-limit, limit)
|
||||
|
||||
@@ -938,4 +737,19 @@ fun interpolateLinear(scale: Double, startValue: Double, endValue: Double): Doub
|
||||
return endValue
|
||||
}
|
||||
return (1.0 - scale) * startValue + scale * endValue
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> List<T>.linearSearch(selector: (T) -> Boolean): Int? {
|
||||
this.forEachIndexed { index, it ->
|
||||
if (selector.invoke(it)) return index
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
fun <T> List<T>.linearSearchBy(selector: (T) -> Boolean): T? {
|
||||
this.forEach {
|
||||
if (selector.invoke(it)) return it
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@ package net.torvald.terrarum
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.InputAdapter
|
||||
import com.badlogic.gdx.Screen
|
||||
import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
@@ -18,14 +21,16 @@ import net.torvald.terrarum.gameworld.fmod
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.*
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.HumanoidNPC
|
||||
import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIRemoCon
|
||||
import net.torvald.terrarum.serialise.ReadLayerData
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarum.modulebasegame.ui.UITitleRemoConYaml
|
||||
import net.torvald.terrarum.modulebasegame.weather.WeatherMixer
|
||||
import net.torvald.terrarum.worlddrawer.*
|
||||
import net.torvald.terrarum.serialise.ReadLayerData
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import java.io.FileInputStream
|
||||
|
||||
/**
|
||||
@@ -49,7 +54,7 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
|
||||
}
|
||||
|
||||
|
||||
private var loadDone = false
|
||||
//private var loadDone = false // not required; draw-while-loading is implemented in the AppLoader
|
||||
|
||||
private lateinit var demoWorld: GameWorldExtension
|
||||
private lateinit var cameraNodes: FloatArray // camera Y-pos
|
||||
@@ -128,14 +133,14 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
|
||||
|
||||
// construct camera nodes
|
||||
val nodeCount = 100
|
||||
cameraNodes = kotlin.FloatArray(nodeCount, { it ->
|
||||
cameraNodes = kotlin.FloatArray(nodeCount) { it ->
|
||||
val tileXPos = (demoWorld.width.toFloat() * it / nodeCount).floorInt()
|
||||
var travelDownCounter = 0
|
||||
while (!BlockCodex[demoWorld.getTileFromTerrain(tileXPos, travelDownCounter)].isSolid) {
|
||||
travelDownCounter += 4
|
||||
}
|
||||
travelDownCounter * FeaturesDrawer.TILE_SIZE.toFloat()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
cameraPlayer = object : HumanoidNPC(cameraAI, born = 0, usePhysics = false, forceAssignRefID = Terrarum.PLAYER_REF_ID) {
|
||||
@@ -164,7 +169,7 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
|
||||
|
||||
uiContainer.add(uiMenu)
|
||||
|
||||
loadDone = true
|
||||
//loadDone = true
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +177,7 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
printdbg(this, "atrniartsientsarinoetsar")
|
||||
printdbg(this, "show() called")
|
||||
|
||||
initViewPort(Terrarum.WIDTH, Terrarum.HEIGHT)
|
||||
|
||||
@@ -184,40 +189,26 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
|
||||
|
||||
|
||||
worldFBO = FrameBuffer(Pixmap.Format.RGBA8888, Terrarum.WIDTH, Terrarum.HEIGHT, false)
|
||||
|
||||
loadThingsWhileIntroIsVisible()
|
||||
|
||||
printdbg(this, "show() exit")
|
||||
}
|
||||
|
||||
|
||||
private val introUncoverTime: Second = 0.3f
|
||||
private var introUncoverDeltaCounter = 0f
|
||||
private var updateDeltaCounter = 0.0
|
||||
protected val renderRate = Terrarum.renderRate
|
||||
|
||||
override fun render(delta: Float) {
|
||||
if (!loadDone) {
|
||||
loadThingsWhileIntroIsVisible()
|
||||
}
|
||||
else {
|
||||
// async update
|
||||
updateDeltaCounter += delta
|
||||
var updateTries = 0
|
||||
while (updateDeltaCounter >= renderRate) {
|
||||
updateScreen(delta)
|
||||
updateDeltaCounter -= renderRate
|
||||
updateTries++
|
||||
// TODO async update
|
||||
|
||||
if (updateTries >= Terrarum.UPDATE_CATCHUP_MAX_TRIES) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// render? just do it anyway
|
||||
renderScreen()
|
||||
}
|
||||
updateScreen(delta)
|
||||
// render? just do it anyway
|
||||
renderScreen()
|
||||
}
|
||||
|
||||
fun updateScreen(delta: Float) {
|
||||
//Gdx.graphics.setTitle(Ingame.getCanonicalTitle())
|
||||
|
||||
demoWorld.globalLight = WeatherMixer.globalLightNow
|
||||
demoWorld.updateWorldTime(delta)
|
||||
WeatherMixer.update(delta, cameraPlayer, demoWorld)
|
||||
@@ -236,12 +227,13 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
|
||||
}
|
||||
|
||||
fun renderScreen() {
|
||||
Gdx.graphics.setTitle(Ingame.getCanonicalTitle())
|
||||
|
||||
|
||||
//camera.setToOrtho(true, Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT.toFloat())
|
||||
|
||||
// render world
|
||||
Gdx.gl.glClearColor(.64f, .754f, .84f, 1f)
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||
gdxClearAndSetBlend(.64f, .754f, .84f, 1f)
|
||||
|
||||
|
||||
IngameRenderer.invoke(world = demoWorld, uisToDraw = uiContainer)
|
||||
@@ -257,7 +249,7 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
|
||||
|
||||
private fun renderOverlayTexts() {
|
||||
setCameraPosition(0f, 0f)
|
||||
blendNormal()
|
||||
blendNormal(batch)
|
||||
batch.shader = null
|
||||
|
||||
batch.color = Color.LIGHT_GRAY
|
||||
@@ -289,22 +281,24 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
|
||||
}
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
printdbg(this, "resize() called")
|
||||
|
||||
// Set up viewport when window is resized
|
||||
initViewPort(Terrarum.WIDTH, Terrarum.HEIGHT)
|
||||
|
||||
BlocksDrawer.resize(Terrarum.WIDTH, Terrarum.HEIGHT)
|
||||
LightmapRenderer.resize(Terrarum.WIDTH, Terrarum.HEIGHT)
|
||||
|
||||
if (loadDone) {
|
||||
// resize UI by re-creating it (!!)
|
||||
uiMenu.resize(Terrarum.WIDTH, Terrarum.HEIGHT)
|
||||
//uiMenu.setPosition(0, UITitleRemoConRoot.menubarOffY)
|
||||
uiMenu.setPosition(0, 0) // shitty hack. Could be:
|
||||
// 1: Init code and resize code are different
|
||||
// 2: The UI is coded shit
|
||||
}
|
||||
// resize UI by re-creating it (!!)
|
||||
uiMenu.resize(Terrarum.WIDTH, Terrarum.HEIGHT)
|
||||
// TODO I forgot what the fuck kind of hack I was talking about
|
||||
//uiMenu.setPosition(0, UITitleRemoConRoot.menubarOffY)
|
||||
uiMenu.setPosition(0, 0) // shitty hack. Could be:
|
||||
// 1: Init code and resize code are different
|
||||
// 2: The UI is coded shit
|
||||
|
||||
|
||||
IngameRenderer.resize(Terrarum.WIDTH, Terrarum.HEIGHT)
|
||||
|
||||
printdbg(this, "resize() exit")
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
|
||||
@@ -10,7 +10,7 @@ import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryCellBase
|
||||
import net.torvald.terrarum.ui.*
|
||||
import net.torvald.terrarum.ui.UIItemTextButton
|
||||
|
||||
/***
|
||||
* Note that the UI will not render if either item or itemImage is null.
|
||||
@@ -74,12 +74,12 @@ class UIItemInventoryElem(
|
||||
if (item != null || drawBackOnNull) {
|
||||
// do not highlight even if drawBackOnNull is true
|
||||
if (mouseUp && item != null) {
|
||||
BlendMode.resolve(mouseoverBackBlendMode)
|
||||
BlendMode.resolve(mouseoverBackBlendMode, batch)
|
||||
batch.color = mouseoverBackCol
|
||||
}
|
||||
// if drawBackOnNull, just draw background
|
||||
else {
|
||||
BlendMode.resolve(backBlendMode)
|
||||
BlendMode.resolve(backBlendMode, batch)
|
||||
batch.color = backCol
|
||||
}
|
||||
batch.fillRect(posX.toFloat(), posY.toFloat(), width.toFloat(), height.toFloat())
|
||||
@@ -87,7 +87,7 @@ class UIItemInventoryElem(
|
||||
|
||||
|
||||
if (item != null && itemImage != null) {
|
||||
blendNormal()
|
||||
blendNormal(batch)
|
||||
|
||||
// item image
|
||||
batch.color = Color.WHITE
|
||||
@@ -136,14 +136,14 @@ class UIItemInventoryElem(
|
||||
}
|
||||
|
||||
override fun keyDown(keycode: Int): Boolean {
|
||||
if (item != null && Terrarum.ingame != null && keycode in Input.Keys.NUM_1..Input.Keys.NUM_0) {
|
||||
if (item != null && Terrarum.ingame != null && keycode in Input.Keys.NUM_0..Input.Keys.NUM_9) {
|
||||
val player = (Terrarum.ingame!! as Ingame).actorNowPlaying
|
||||
|
||||
if (player == null) return false
|
||||
|
||||
val inventory = player.inventory
|
||||
val slot = if (keycode == Input.Keys.NUM_0) 9 else keycode - Input.Keys.NUM_1
|
||||
val currentSlotItem = inventory?.getQuickBar(slot)
|
||||
val currentSlotItem = inventory?.getQuickslot(slot)
|
||||
|
||||
|
||||
inventory.setQuickBar(
|
||||
@@ -157,13 +157,13 @@ class UIItemInventoryElem(
|
||||
// search for duplicates in the quickbar, except mine
|
||||
// if there is, unregister the other
|
||||
(0..9).minus(slot).forEach {
|
||||
if (inventory.getQuickBar(it)?.item == item) {
|
||||
if (inventory.getQuickslot(it)?.item == item) {
|
||||
inventory.setQuickBar(it, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
return super.keyDown(keycode)
|
||||
}
|
||||
|
||||
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
@@ -171,6 +171,10 @@ class UIItemInventoryElem(
|
||||
|
||||
// equip da shit
|
||||
val itemEquipSlot = item!!.equipPosition
|
||||
if (itemEquipSlot == GameItem.EquipPosition.NULL) {
|
||||
TODO("Equip position is NULL, does this mean it's single-consume items like a potion?")
|
||||
}
|
||||
|
||||
val player = (Terrarum.ingame!! as Ingame).actorNowPlaying
|
||||
|
||||
if (player == null) return false
|
||||
@@ -185,7 +189,7 @@ class UIItemInventoryElem(
|
||||
|
||||
inventoryUI.rebuildList()
|
||||
|
||||
return true
|
||||
return super.touchDown(screenX, screenY, pointer, button)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryCellBase
|
||||
import net.torvald.terrarum.ui.*
|
||||
import net.torvald.terrarum.ui.UIItemTextButton
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-10-20.
|
||||
@@ -56,12 +56,12 @@ class UIItemInventoryElemSimple(
|
||||
if (item != null || drawBackOnNull) {
|
||||
// do not highlight even if drawBackOnNull is true
|
||||
if (mouseUp && item != null || equippedSlot != null) { // "equippedSlot != null": also highlight back if equipped
|
||||
BlendMode.resolve(mouseoverBackBlendMode)
|
||||
BlendMode.resolve(mouseoverBackBlendMode, batch)
|
||||
batch.color = mouseoverBackCol
|
||||
}
|
||||
// if drawBackOnNull, just draw background
|
||||
else {
|
||||
BlendMode.resolve(backBlendMode)
|
||||
BlendMode.resolve(backBlendMode, batch)
|
||||
batch.color = backCol
|
||||
}
|
||||
batch.fillRect(posX.toFloat(), posY.toFloat(), width.toFloat(), height.toFloat())
|
||||
@@ -72,7 +72,7 @@ class UIItemInventoryElemSimple(
|
||||
// and you can clearly see the quickslot UI anyway
|
||||
|
||||
if (item != null && itemImage != null) {
|
||||
blendNormal()
|
||||
blendNormal(batch)
|
||||
|
||||
// item image
|
||||
batch.color = Color.WHITE
|
||||
@@ -121,15 +121,14 @@ class UIItemInventoryElemSimple(
|
||||
}
|
||||
|
||||
override fun keyDown(keycode: Int): Boolean {
|
||||
if (item != null && Terrarum.ingame != null && keycode in Input.Keys.NUM_1..Input.Keys.NUM_0) {
|
||||
println("keydown elemgrid")
|
||||
if (item != null && Terrarum.ingame != null && keycode in Input.Keys.NUM_0..Input.Keys.NUM_9) {
|
||||
|
||||
val player = (Terrarum.ingame!! as Ingame).actorNowPlaying
|
||||
if (player == null) return false
|
||||
|
||||
val inventory = player.inventory
|
||||
val slot = if (keycode == Input.Keys.NUM_0) 9 else keycode - Input.Keys.NUM_1
|
||||
val currentSlotItem = inventory.getQuickBar(slot)
|
||||
val currentSlotItem = inventory.getQuickslot(slot)
|
||||
|
||||
|
||||
inventory.setQuickBar(
|
||||
@@ -143,13 +142,13 @@ class UIItemInventoryElemSimple(
|
||||
// search for duplicates in the quickbar, except mine
|
||||
// if there is, unregister the other
|
||||
(0..9).minus(slot).forEach {
|
||||
if (inventory.getQuickBar(it)?.item == item) {
|
||||
if (inventory.getQuickslot(it)?.item == item) {
|
||||
inventory.setQuickBar(it, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
return super.keyDown(keycode)
|
||||
}
|
||||
|
||||
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
@@ -172,7 +171,7 @@ class UIItemInventoryElemSimple(
|
||||
|
||||
inventoryUI.rebuildList()
|
||||
|
||||
return true
|
||||
return super.touchDown(screenX, screenY, pointer, button)
|
||||
}
|
||||
|
||||
|
||||
|
||||
197
src/net/torvald/terrarum/Yaml.kt
Normal file
197
src/net/torvald/terrarum/Yaml.kt
Normal file
@@ -0,0 +1,197 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Simplified version of YAML, only for the representation of a text tree.
|
||||
*
|
||||
* Example code:
|
||||
* ```
|
||||
* - File
|
||||
* - New : Ctrl-N
|
||||
* - Open : Ctrl-O
|
||||
* - Open Recent
|
||||
* - yaml_example.yaml
|
||||
* - Yaml.kt
|
||||
* - Close : Ctrl-W
|
||||
* - Settings
|
||||
* - Line Separators
|
||||
* - CRLF
|
||||
* - CR
|
||||
* - LF
|
||||
* - Edit
|
||||
* - Undo : Ctrl-Z
|
||||
* - Redo : Shift-Ctrl-Z
|
||||
* - Cut : Ctrl-X
|
||||
* - Copy : Ctrl-C
|
||||
* - Paste : Ctrl-V
|
||||
* - Find
|
||||
* - Find : Ctrl-F
|
||||
* - Replace : Shift-Ctrl-F
|
||||
* - Convert Indents
|
||||
* - To Spaces
|
||||
* - Set Project Indentation
|
||||
* - To Tabs
|
||||
* - Refactor
|
||||
* - Refactor This
|
||||
* - Rename : Shift-Ctrl-R
|
||||
* - Extract
|
||||
* - Variable
|
||||
* - Property
|
||||
* - Function
|
||||
* ```
|
||||
*
|
||||
* - All lines are indented with one space
|
||||
* - All entries are preceded by '- ' (dash and a space)
|
||||
* - All propery are separated by ' : ' (space colon space)
|
||||
* - A line that does not start with '- ' are simply ignored, so you can freely make empty lines and/or comments.
|
||||
*
|
||||
* Any deviation to the above rule will cause a parse failure, because it's simple and dumb as that.
|
||||
*
|
||||
* Created by minjaesong on 2018-12-08.
|
||||
*/
|
||||
inline class Yaml(val text: String) {
|
||||
|
||||
companion object {
|
||||
val SEPARATOR = Regex(" : ")
|
||||
}
|
||||
|
||||
fun parse(): QNDTreeNode<String> {
|
||||
var currentIndentLevel = -1
|
||||
val root = QNDTreeNode<String>()
|
||||
var currentNode = root
|
||||
val nodesStack = Stack<QNDTreeNode<String>>()
|
||||
val validLineStartRe = Regex(""" *\- """)
|
||||
|
||||
nodesStack.push(currentNode)
|
||||
|
||||
text.split('\n') .forEach {
|
||||
if (validLineStartRe.containsMatchIn(it)) { // take partial match; do the task if the text's line is valid
|
||||
val indentLevel = it.countSpaces()
|
||||
val it = it.trimIndent()
|
||||
if (it.startsWith("- ")) { // just double check if indent-trimmed line looks valid
|
||||
val nodeName = it.drop(2)
|
||||
|
||||
if (indentLevel == currentIndentLevel) {
|
||||
val sibling = QNDTreeNode(nodeName, currentNode.parent)
|
||||
currentNode.parent!!.children.add(sibling)
|
||||
currentNode = sibling
|
||||
}
|
||||
else if (indentLevel > currentIndentLevel) {
|
||||
val childNode = QNDTreeNode(nodeName, currentNode)
|
||||
currentNode.children.add(childNode)
|
||||
nodesStack.push(currentNode)
|
||||
currentNode = childNode
|
||||
currentIndentLevel = indentLevel
|
||||
}
|
||||
else {
|
||||
repeat(currentIndentLevel - indentLevel) { currentNode = nodesStack.pop() }
|
||||
currentIndentLevel = indentLevel
|
||||
val sibling = QNDTreeNode(nodeName, currentNode.parent)
|
||||
currentNode.parent!!.children.add(sibling)
|
||||
currentNode = sibling
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// test traverse resulting tree
|
||||
/*root.traversePreorder { node, depth ->
|
||||
repeat(depth + 1) { print("-") }
|
||||
println("${node.data} -> ${node.parent}")
|
||||
}*/
|
||||
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
fun parseAsYamlInvokable(): QNDTreeNode<Pair<String, YamlInvokable?>> {
|
||||
var currentIndentLevel = -1
|
||||
val root = QNDTreeNode<Pair<String, YamlInvokable?>>()
|
||||
var currentNode = root
|
||||
val nodesStack = Stack<QNDTreeNode<Pair<String, YamlInvokable?>>>()
|
||||
val validLineStartRe = Regex(""" *\- """)
|
||||
|
||||
nodesStack.push(currentNode)
|
||||
|
||||
text.split('\n') .forEach {
|
||||
if (validLineStartRe.containsMatchIn(it)) { // take partial match; do the task if the text's line is valid
|
||||
val indentLevel = it.countSpaces()
|
||||
val it = it.trimIndent()
|
||||
if (it.startsWith("- ")) { // just double check if indent-trimmed line looks valid
|
||||
val nodeString = it.drop(2)
|
||||
val nodeNameAndInvocation = nodeString.split(SEPARATOR)
|
||||
val nodeName = nodeNameAndInvocation[0]
|
||||
val nodeInvocation = loadClass(nodeNameAndInvocation[1])
|
||||
|
||||
val nameInvokePair = nodeName to nodeInvocation
|
||||
|
||||
if (indentLevel == currentIndentLevel) {
|
||||
val sibling = QNDTreeNode(nameInvokePair, currentNode.parent)
|
||||
currentNode.parent!!.children.add(sibling)
|
||||
currentNode = sibling
|
||||
}
|
||||
else if (indentLevel > currentIndentLevel) {
|
||||
val childNode = QNDTreeNode(nameInvokePair, currentNode)
|
||||
currentNode.children.add(childNode)
|
||||
nodesStack.push(currentNode)
|
||||
currentNode = childNode
|
||||
currentIndentLevel = indentLevel
|
||||
}
|
||||
else {
|
||||
repeat(currentIndentLevel - indentLevel) { currentNode = nodesStack.pop() }
|
||||
currentIndentLevel = indentLevel
|
||||
val sibling = QNDTreeNode(nameInvokePair, currentNode.parent)
|
||||
currentNode.parent!!.children.add(sibling)
|
||||
currentNode = sibling
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// test traverse resulting tree
|
||||
/*root.traversePreorder { node, depth ->
|
||||
repeat(depth + 1) { print("-") }
|
||||
println("${node.data} -> ${node.parent}")
|
||||
}*/
|
||||
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
private fun String.countSpaces(): Int {
|
||||
var c = 0
|
||||
while (c <= this.length) {
|
||||
if (this[c] == ' ')
|
||||
c++
|
||||
else
|
||||
break
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
private fun loadClass(name: String): YamlInvokable {
|
||||
val newClass = Class.forName(name)
|
||||
val newClassConstructor = newClass.getConstructor(/* no args defined */)
|
||||
val newClassInstance = newClassConstructor.newInstance(/* no args defined */)
|
||||
return newClassInstance as YamlInvokable
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple interface that meant to be attached with Yaml tree, so that the entry can be ```invoke()```d.
|
||||
*
|
||||
* Example usage in Yaml:
|
||||
* ```
|
||||
* - File
|
||||
* - Import : net.torvald.terrarum.whatever.package.ImportFile
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
interface YamlInvokable {
|
||||
operator fun invoke()
|
||||
}
|
||||
@@ -5,149 +5,126 @@ package net.torvald.terrarum.blockproperties
|
||||
*/
|
||||
object Block {
|
||||
|
||||
val AIR = 0 // hard coded; this is the standard
|
||||
const val AIR = 0 // hard coded; this is the standard
|
||||
|
||||
val STONE = 16
|
||||
val STONE_QUARRIED = 17
|
||||
val STONE_TILE_WHITE = 18
|
||||
val STONE_BRICKS = 19
|
||||
const val STONE = 16
|
||||
const val STONE_QUARRIED = 17
|
||||
const val STONE_TILE_WHITE = 18
|
||||
const val STONE_BRICKS = 19
|
||||
|
||||
val DIRT = 32
|
||||
val GRASS = 33
|
||||
val GRASSWALL = 34
|
||||
const val DIRT = 32
|
||||
const val GRASS = 33
|
||||
const val GRASSWALL = 34
|
||||
|
||||
val PLANK_NORMAL = 48
|
||||
val PLANK_EBONY = 49
|
||||
val PLANK_BIRCH = 50
|
||||
val PLANK_BLOODROSE = 51
|
||||
const val PLANK_NORMAL = 48
|
||||
const val PLANK_EBONY = 49
|
||||
const val PLANK_BIRCH = 50
|
||||
const val PLANK_BLOODROSE = 51
|
||||
|
||||
val TRUNK_NORMAL = 64
|
||||
val TRUNK_EBONY = 65
|
||||
val TRUNK_BIRCH = 66
|
||||
val TRUNK_BLOODROSE = 67
|
||||
const val TRUNK_NORMAL = 64
|
||||
const val TRUNK_EBONY = 65
|
||||
const val TRUNK_BIRCH = 66
|
||||
const val TRUNK_BLOODROSE = 67
|
||||
|
||||
val SAND = 80
|
||||
val SAND_WHITE = 81
|
||||
val SAND_RED = 82
|
||||
val SAND_DESERT = 83
|
||||
val SAND_BLACK = 84
|
||||
val SAND_GREEN = 85
|
||||
const val SAND = 80
|
||||
const val SAND_WHITE = 81
|
||||
const val SAND_RED = 82
|
||||
const val SAND_DESERT = 83
|
||||
const val SAND_BLACK = 84
|
||||
const val SAND_GREEN = 85
|
||||
|
||||
val GRAVEL = 96
|
||||
val GRAVEL_GREY = 97
|
||||
const val GRAVEL = 96
|
||||
const val GRAVEL_GREY = 97
|
||||
|
||||
val ORE_COPPER = 112
|
||||
val ORE_IRON = 113
|
||||
val ORE_GOLD = 114
|
||||
val ORE_SILVER = 115
|
||||
val ORE_ILMENITE = 116
|
||||
val ORE_AURICHALCUM = 117
|
||||
const val ORE_COPPER = 112
|
||||
const val ORE_IRON = 113
|
||||
const val ORE_GOLD = 114
|
||||
const val ORE_SILVER = 115
|
||||
const val ORE_ILMENITE = 116
|
||||
const val ORE_AURICHALCUM = 117
|
||||
|
||||
val RAW_RUBY = 128
|
||||
val RAW_EMERALD = 129
|
||||
val RAW_SAPPHIRE = 130
|
||||
val RAW_TOPAZ = 131
|
||||
val RAW_DIAMOND = 132
|
||||
val RAW_AMETHYST = 133
|
||||
const val RAW_RUBY = 128
|
||||
const val RAW_EMERALD = 129
|
||||
const val RAW_SAPPHIRE = 130
|
||||
const val RAW_TOPAZ = 131
|
||||
const val RAW_DIAMOND = 132
|
||||
const val RAW_AMETHYST = 133
|
||||
|
||||
val SNOW = 144
|
||||
val ICE_FRAGILE = 145
|
||||
val ICE_NATURAL = 146
|
||||
val ICE_MAGICAL = 147
|
||||
const val SNOW = 144
|
||||
const val ICE_FRAGILE = 145
|
||||
const val ICE_NATURAL = 146
|
||||
const val ICE_MAGICAL = 147
|
||||
|
||||
val GLASS_CRUDE = 148
|
||||
val GLASS_CLEAN = 149
|
||||
const val GLASS_CRUDE = 148
|
||||
const val GLASS_CLEAN = 149
|
||||
|
||||
val PLATFORM_STONE = 160
|
||||
val PLATFORM_WOODEN = 161
|
||||
val PLATFORM_EBONY = 162
|
||||
val PLATFORM_BIRCH = 163
|
||||
val PLATFORM_BLOODROSE = 164
|
||||
const val PLATFORM_STONE = 160
|
||||
const val PLATFORM_WOODEN = 161
|
||||
const val PLATFORM_EBONY = 162
|
||||
const val PLATFORM_BIRCH = 163
|
||||
const val PLATFORM_BLOODROSE = 164
|
||||
|
||||
val TORCH = 176
|
||||
val TORCH_FROST = 177
|
||||
const val TORCH = 176
|
||||
const val TORCH_FROST = 177
|
||||
|
||||
val TORCH_OFF = 192
|
||||
val TORCH_FROST_OFF = 193
|
||||
const val TORCH_OFF = 192
|
||||
const val TORCH_FROST_OFF = 193
|
||||
|
||||
val ILLUMINATOR_WHITE = 208
|
||||
val ILLUMINATOR_YELLOW = 209
|
||||
val ILLUMINATOR_ORANGE = 210
|
||||
val ILLUMINATOR_RED = 211
|
||||
val ILLUMINATOR_FUCHSIA = 212
|
||||
val ILLUMINATOR_PURPLE = 213
|
||||
val ILLUMINATOR_BLUE = 214
|
||||
val ILLUMINATOR_CYAN = 215
|
||||
val ILLUMINATOR_GREEN = 216
|
||||
val ILLUMINATOR_GREEN_DARK = 217
|
||||
val ILLUMINATOR_BROWN = 218
|
||||
val ILLUMINATOR_TAN = 219
|
||||
val ILLUMINATOR_GREY_LIGHT = 220
|
||||
val ILLUMINATOR_GREY_MED = 221
|
||||
val ILLUMINATOR_GREY_DARK = 222
|
||||
val ILLUMINATOR_BLACK = 223
|
||||
const val ILLUMINATOR_WHITE = 208
|
||||
const val ILLUMINATOR_YELLOW = 209
|
||||
const val ILLUMINATOR_ORANGE = 210
|
||||
const val ILLUMINATOR_RED = 211
|
||||
const val ILLUMINATOR_FUCHSIA = 212
|
||||
const val ILLUMINATOR_PURPLE = 213
|
||||
const val ILLUMINATOR_BLUE = 214
|
||||
const val ILLUMINATOR_CYAN = 215
|
||||
const val ILLUMINATOR_GREEN = 216
|
||||
const val ILLUMINATOR_GREEN_DARK = 217
|
||||
const val ILLUMINATOR_BROWN = 218
|
||||
const val ILLUMINATOR_TAN = 219
|
||||
const val ILLUMINATOR_GREY_LIGHT = 220
|
||||
const val ILLUMINATOR_GREY_MED = 221
|
||||
const val ILLUMINATOR_GREY_DARK = 222
|
||||
const val ILLUMINATOR_BLACK = 223
|
||||
|
||||
val ILLUMINATOR_WHITE_OFF = 224
|
||||
val ILLUMINATOR_YELLOW_OFF = 225
|
||||
val ILLUMINATOR_ORANGE_OFF = 226
|
||||
val ILLUMINATOR_RED_OFF = 227
|
||||
val ILLUMINATOR_FUCHSIA_OFF = 228
|
||||
val ILLUMINATOR_PURPLE_OFF = 229
|
||||
val ILLUMINATOR_BLUE_OFF = 230
|
||||
val ILLUMINATOR_CYAN_OFF = 231
|
||||
val ILLUMINATOR_GREEN_OFF = 232
|
||||
val ILLUMINATOR_GREEN_DARK_OFF = 233
|
||||
val ILLUMINATOR_BROWN_OFF = 234
|
||||
val ILLUMINATOR_TAN_OFF = 235
|
||||
val ILLUMINATOR_GREY_LIGHT_OFF = 236
|
||||
val ILLUMINATOR_GREY_MED_OFF = 237
|
||||
val ILLUMINATOR_GREY_DARK_OFF = 238
|
||||
val ILLUMINATOR_BLACK_OFF = 239
|
||||
const val ILLUMINATOR_WHITE_OFF = 224
|
||||
const val ILLUMINATOR_YELLOW_OFF = 225
|
||||
const val ILLUMINATOR_ORANGE_OFF = 226
|
||||
const val ILLUMINATOR_RED_OFF = 227
|
||||
const val ILLUMINATOR_FUCHSIA_OFF = 228
|
||||
const val ILLUMINATOR_PURPLE_OFF = 229
|
||||
const val ILLUMINATOR_BLUE_OFF = 230
|
||||
const val ILLUMINATOR_CYAN_OFF = 231
|
||||
const val ILLUMINATOR_GREEN_OFF = 232
|
||||
const val ILLUMINATOR_GREEN_DARK_OFF = 233
|
||||
const val ILLUMINATOR_BROWN_OFF = 234
|
||||
const val ILLUMINATOR_TAN_OFF = 235
|
||||
const val ILLUMINATOR_GREY_LIGHT_OFF = 236
|
||||
const val ILLUMINATOR_GREY_MED_OFF = 237
|
||||
const val ILLUMINATOR_GREY_DARK_OFF = 238
|
||||
const val ILLUMINATOR_BLACK_OFF = 239
|
||||
|
||||
val SANDSTONE = 240
|
||||
val SANDSTONE_WHITE = 241
|
||||
val SANDSTONE_RED = 242
|
||||
val SANDSTONE_DESERT = 243
|
||||
val SANDSTONE_BLACK = 244
|
||||
val SANDSTONE_GREEN = 245
|
||||
const val SANDSTONE = 240
|
||||
const val SANDSTONE_WHITE = 241
|
||||
const val SANDSTONE_RED = 242
|
||||
const val SANDSTONE_DESERT = 243
|
||||
const val SANDSTONE_BLACK = 244
|
||||
const val SANDSTONE_GREEN = 245
|
||||
|
||||
val LANTERN = 256
|
||||
val SUNSTONE = 257
|
||||
val DAYLIGHT_CAPACITOR = 258
|
||||
const val LANTERN = 256
|
||||
const val SUNSTONE = 257
|
||||
const val DAYLIGHT_CAPACITOR = 258
|
||||
|
||||
val WATER_1 = 4080
|
||||
val WATER_2 = 4081
|
||||
val WATER_3 = 4082
|
||||
val WATER_4 = 4083
|
||||
val WATER_5 = 4084
|
||||
val WATER_6 = 4085
|
||||
val WATER_7 = 4086
|
||||
val WATER_8 = 4087
|
||||
val WATER_9 = 4088
|
||||
val WATER_10 = 4089
|
||||
val WATER_11 = 4090
|
||||
val WATER_12 = 4091
|
||||
val WATER_13 = 4092
|
||||
val WATER_14 = 4093
|
||||
val WATER_15 = 4094
|
||||
val WATER = 4095
|
||||
|
||||
val LAVA_1 = 4064
|
||||
val LAVA_2 = 4065
|
||||
val LAVA_3 = 4066
|
||||
val LAVA_4 = 4067
|
||||
val LAVA_5 = 4068
|
||||
val LAVA_6 = 4069
|
||||
val LAVA_7 = 4070
|
||||
val LAVA_8 = 4071
|
||||
val LAVA_9 = 4072
|
||||
val LAVA_10 = 4073
|
||||
val LAVA_11 = 4074
|
||||
val LAVA_12 = 4075
|
||||
val LAVA_13 = 4076
|
||||
val LAVA_14 = 4077
|
||||
val LAVA_15 = 4078
|
||||
val LAVA = 4079
|
||||
const val ACTORBLOCK_NO_COLLISION = 4191
|
||||
const val ACTORBLOCK_FULL_COLLISION = 4092
|
||||
const val ACTORBLOCK_ALLOW_MOVE_DOWN = 4093
|
||||
const val ACTORBLOCK_NO_PASS_RIGHT = 4094
|
||||
const val ACTORBLOCK_NO_PASS_LEFT = 4095
|
||||
|
||||
val NULL = -1
|
||||
|
||||
const val LAVA = 4094
|
||||
const val WATER = 4095
|
||||
|
||||
const val NULL = -1
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package net.torvald.terrarum.blockproperties
|
||||
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.utils.CSVFetcher
|
||||
import net.torvald.terrarum.gameworld.MapLayer
|
||||
import net.torvald.terrarum.gameworld.PairedMapLayer
|
||||
import net.torvald.terrarum.utils.CSVFetcher
|
||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||
import org.apache.commons.csv.CSVRecord
|
||||
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
@@ -97,7 +96,7 @@ object BlockCodex {
|
||||
prop.shadeColB = floatVal(record, "shdb") / LightmapRenderer.MUL_FLOAT
|
||||
prop.shadeColA = floatVal(record, "shduv") / LightmapRenderer.MUL_FLOAT
|
||||
|
||||
prop.strength = intVal(record, "strength")
|
||||
prop.strength = intVal(record, "str")
|
||||
prop.density = intVal(record, "dsty")
|
||||
|
||||
prop.lumColR = floatVal(record, "lumr") / LightmapRenderer.MUL_FLOAT
|
||||
@@ -105,12 +104,13 @@ object BlockCodex {
|
||||
prop.lumColB = floatVal(record, "lumb") / LightmapRenderer.MUL_FLOAT
|
||||
prop.lumColA = floatVal(record, "lumuv") / LightmapRenderer.MUL_FLOAT
|
||||
|
||||
prop.friction = intVal(record, "friction")
|
||||
prop.friction = intVal(record, "fr")
|
||||
prop.viscosity = intVal(record, "vscs")
|
||||
|
||||
prop.isFluid = boolVal(record, "fluid")
|
||||
//prop.isFluid = boolVal(record, "fluid")
|
||||
prop.isSolid = boolVal(record, "solid")
|
||||
prop.isClear = boolVal(record, "clear")
|
||||
//prop.isClear = boolVal(record, "clear")
|
||||
prop.isPlatform = boolVal(record, "plat")
|
||||
prop.isWallable = boolVal(record, "wall")
|
||||
prop.isFallable = boolVal(record, "fall")
|
||||
prop.isVertFriction = boolVal(record, "fv")
|
||||
|
||||
@@ -27,9 +27,9 @@ class BlockProp {
|
||||
var density: Int = 0
|
||||
var viscosity: Int = 0
|
||||
|
||||
var isFluid: Boolean = false
|
||||
var isSolid: Boolean = false
|
||||
var isClear: Boolean = false
|
||||
//var isClear: Boolean = false
|
||||
var isPlatform: Boolean = false
|
||||
var isWallable: Boolean = false
|
||||
var isVertFriction: Boolean = false
|
||||
|
||||
|
||||
@@ -4,11 +4,12 @@ import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.modulebasegame.gameworld.WorldTime
|
||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||
import net.torvald.terrarum.modulebasegame.weather.WeatherMixer
|
||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-06-16.
|
||||
@@ -63,9 +64,9 @@ object BlockPropUtil {
|
||||
internal fun dynamicLumFuncTickClock() {
|
||||
// FPS-time compensation
|
||||
if (Gdx.graphics.framesPerSecond > 0) {
|
||||
flickerFuncX += Terrarum.deltaTime * 1000f
|
||||
breathFuncX += Terrarum.deltaTime * 1000f
|
||||
pulsateFuncX += Terrarum.deltaTime * 1000f
|
||||
flickerFuncX += AppLoader.getSmoothDelta().toFloat() * 1000f
|
||||
breathFuncX += AppLoader.getSmoothDelta().toFloat() * 1000f
|
||||
pulsateFuncX += AppLoader.getSmoothDelta().toFloat() * 1000f
|
||||
}
|
||||
|
||||
// flicker-related vars
|
||||
|
||||
20
src/net/torvald/terrarum/blockproperties/Fluid.kt
Normal file
20
src/net/torvald/terrarum/blockproperties/Fluid.kt
Normal file
@@ -0,0 +1,20 @@
|
||||
package net.torvald.terrarum.blockproperties
|
||||
|
||||
import net.torvald.terrarum.gameworld.FluidType
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-08-06.
|
||||
*/
|
||||
object Fluid {
|
||||
|
||||
val NULL = FluidType(0)
|
||||
|
||||
val WATER = FluidType(1)
|
||||
val STATIC_WATER = FluidType(-1)
|
||||
|
||||
val LAVA = FluidType(2)
|
||||
val STATIC_LAVA = FluidType(-2)
|
||||
|
||||
|
||||
val fluidRange = 1..2 // TODO MANUAL UPDATE
|
||||
}
|
||||
@@ -2,13 +2,17 @@ package net.torvald.terrarum.concurrent
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
|
||||
typealias RunnableFun = () -> Unit
|
||||
/** Int: index of the processing core */
|
||||
typealias ThreadableFun = (Int) -> Unit
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-05-25.
|
||||
*/
|
||||
object ThreadParallel {
|
||||
val threads = Terrarum.THREADS // modify this to your taste
|
||||
val threadCount = Terrarum.THREADS // modify this to your taste
|
||||
|
||||
private val pool: Array<Thread?> = Array(threads, { null })
|
||||
private val pool: Array<Thread?> = Array(threadCount, { null })
|
||||
|
||||
/**
|
||||
* Map Runnable object to certain index of the thread pool.
|
||||
@@ -23,7 +27,7 @@ object ThreadParallel {
|
||||
/**
|
||||
* @param runFunc A function that takes an int input (the index), and returns nothing
|
||||
*/
|
||||
fun map(index: Int, prefix: String, runFunc: (Int) -> Unit) {
|
||||
fun map(index: Int, prefix: String, runFunc: ThreadableFun) {
|
||||
val runnable = object : Runnable {
|
||||
override fun run() {
|
||||
runFunc(index)
|
||||
@@ -52,15 +56,80 @@ object ThreadParallel {
|
||||
* Primitive locking
|
||||
*/
|
||||
fun allFinished(): Boolean {
|
||||
pool.forEach { if (it?.state != Thread.State.TERMINATED) return false }
|
||||
pool.forEach { if (it != null && it.state != Thread.State.TERMINATED) return false }
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A thread pool that will hold the execution until all the tasks are completed.
|
||||
*
|
||||
* Tasks are not guaranteed to be done orderly; but the first task in the list will be executed first.
|
||||
*/
|
||||
@Deprecated("Experimental.", ReplaceWith("ThreadParallel", "net.torvald.terrarum.concurrent.ThreadParallel"))
|
||||
object BlockingThreadPool {
|
||||
val threadCount = Terrarum.THREADS // modify this to your taste
|
||||
private val pool: Array<Thread?> = Array(threadCount, { null })
|
||||
private var tasks: List<RunnableFun> = ArrayList<RunnableFun>()
|
||||
@Volatile private var dispatchedTasks = 0
|
||||
private var threadPrefix = ""
|
||||
|
||||
/** @return false on failure (likely the previous jobs not finished), true on success */
|
||||
fun map(prefix: String, tasks: List<RunnableFun>) = setTasks(tasks, prefix)
|
||||
/** @return false on failure (likely the previous jobs not finished), true on success */
|
||||
fun setTasks(tasks: List<RunnableFun>, prefix: String): Boolean {
|
||||
if (!allFinished())
|
||||
return false
|
||||
|
||||
this.tasks = tasks
|
||||
dispatchedTasks = 0
|
||||
threadPrefix = prefix
|
||||
return true
|
||||
}
|
||||
|
||||
private fun dequeueTask(): RunnableFun {
|
||||
dispatchedTasks += 1
|
||||
return tasks[dispatchedTasks - 1]
|
||||
}
|
||||
|
||||
|
||||
fun startAllWaitForDie() {
|
||||
while (dispatchedTasks <= tasks.lastIndex) {
|
||||
// marble rolling down the slanted channel-track of threads, if a channel is empty (a task assigned
|
||||
// to the thread is dead) the marble will roll into the channel, and the marble is a task #MarbleMachineX
|
||||
for (i in 0 until threadCount) {
|
||||
// but unlike the marble machine, marble don't actually roll down, we can just pick up any number
|
||||
// of marbles and put it into an empty channel whenever we encounter one
|
||||
|
||||
// SO WHAT WE DO is first fill any empty channels:
|
||||
if (dispatchedTasks <= tasks.lastIndex && // because cache invalidation damnit
|
||||
(pool[i] == null || pool[i]!!.state == Thread.State.TERMINATED)) {
|
||||
pool[i] = Thread(dequeueTask().makeRunnable(), "$threadPrefix-$dispatchedTasks") // thread name index is one-based
|
||||
pool[i]!!.start()
|
||||
}
|
||||
|
||||
// then, sleep this very thread, wake if any of the thread in the pool is terminated,
|
||||
// and GOTO loop_start; if we don't sleep, this function will be busy-waiting
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun allFinished(): Boolean {
|
||||
pool.forEach { if (it != null && it.state != Thread.State.TERMINATED) return false }
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
private fun RunnableFun.makeRunnable() = Runnable {
|
||||
this.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
object ParallelUtils {
|
||||
fun <T, R> Iterable<T>.parallelMap(transform: (T) -> R): List<R> {
|
||||
val tasks = this.sliceEvenly(ThreadParallel.threads)
|
||||
val destination = Array(ThreadParallel.threads) { ArrayList<R>() }
|
||||
val tasks = this.sliceEvenly(ThreadParallel.threadCount)
|
||||
val destination = Array(ThreadParallel.threadCount) { ArrayList<R>() }
|
||||
tasks.forEachIndexed { index, list ->
|
||||
ThreadParallel.map(index, "ParallelUtils.parallelMap@${this.javaClass.canonicalName}") {
|
||||
for (item in list)
|
||||
@@ -100,9 +169,9 @@ object ParallelUtils {
|
||||
return al
|
||||
}
|
||||
|
||||
fun Iterable<*>.sliceEvenly(slices: Int): List<List<*>> = this.toList().sliceEvenly(slices)
|
||||
fun <T> Iterable<T>.sliceEvenly(slices: Int): List<List<T>> = this.toList().sliceEvenly(slices)
|
||||
|
||||
fun List<*>.sliceEvenly(slices: Int): List<List<*>> {
|
||||
fun <T> List<T>.sliceEvenly(slices: Int): List<List<T>> {
|
||||
return (0 until slices).map {
|
||||
this.subList(
|
||||
this.size.toFloat().div(slices).times(it).roundInt(),
|
||||
@@ -111,7 +180,7 @@ object ParallelUtils {
|
||||
}
|
||||
}
|
||||
|
||||
fun Array<*>.sliceEvenly(slices: Int): List<Array<*>> {
|
||||
fun <T> Array<T>.sliceEvenly(slices: Int): List<Array<T>> {
|
||||
return (0 until slices).map {
|
||||
this.sliceArray(
|
||||
this.size.toFloat().div(slices).times(it).roundInt() until
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.torvald.terrarum.console
|
||||
|
||||
import net.torvald.terrarum.modulebasegame.console.*
|
||||
import java.util.HashMap
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-15.
|
||||
@@ -43,6 +43,7 @@ object CommandDict {
|
||||
"setscale" to SetScale,
|
||||
"kill" to KillActor,
|
||||
"money" to MoneyDisp,
|
||||
"screenshot" to TakeScreenshot,
|
||||
|
||||
// Test codes
|
||||
"bulletintest" to SetBulletin,
|
||||
@@ -59,7 +60,8 @@ object CommandDict {
|
||||
|
||||
|
||||
/* !! */"exportlayer" to ExportLayerData,
|
||||
/* !! */"importlayer" to ImportLayerData
|
||||
/* !! */"importlayer" to ImportLayerData,
|
||||
/* !! */"exportfborgb" to ExportRendererFboRGB
|
||||
)
|
||||
|
||||
operator fun get(commandName: String): ConsoleCommand {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package net.torvald.terrarum.console
|
||||
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.ccG
|
||||
import net.torvald.terrarum.ccW
|
||||
import net.torvald.terrarum.ccY
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import java.time.ZonedDateTime
|
||||
import java.util.ArrayList
|
||||
import java.util.Formatter
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
@@ -20,7 +21,8 @@ internal object CommandInterpreter {
|
||||
"getlocale",
|
||||
"help",
|
||||
"version",
|
||||
"tips"
|
||||
"tips",
|
||||
"screenshot"
|
||||
)
|
||||
|
||||
internal fun execute(command: String) {
|
||||
|
||||
14
src/net/torvald/terrarum/console/ExportRendererFboRGB.kt
Normal file
14
src/net/torvald/terrarum/console/ExportRendererFboRGB.kt
Normal file
@@ -0,0 +1,14 @@
|
||||
package net.torvald.terrarum.console
|
||||
|
||||
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
||||
|
||||
object ExportRendererFboRGB: ConsoleCommand {
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
IngameRenderer.fboRGBexportRequested = true
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
|
||||
}
|
||||
}
|
||||
13
src/net/torvald/terrarum/console/TakeScreenshot.kt
Normal file
13
src/net/torvald/terrarum/console/TakeScreenshot.kt
Normal file
@@ -0,0 +1,13 @@
|
||||
package net.torvald.terrarum.console
|
||||
|
||||
import net.torvald.terrarum.AppLoader
|
||||
|
||||
object TakeScreenshot: ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
AppLoader.requestScreenshot()
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Takes screenshot and save it to the default directory as 'screenshot.tga'")
|
||||
}
|
||||
}
|
||||
539
src/net/torvald/terrarum/debuggerapp/CSVEditor.java
Normal file
539
src/net/torvald/terrarum/debuggerapp/CSVEditor.java
Normal file
@@ -0,0 +1,539 @@
|
||||
package net.torvald.terrarum.debuggerapp;
|
||||
|
||||
import net.torvald.terrarum.utils.CSVFetcher;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Should be made into its own artifact to build.
|
||||
*
|
||||
* Only recognisable columns are read and saved, thus this app should be update when new properties are added.
|
||||
*
|
||||
* Created by minjaesong on 2019-01-01.
|
||||
*/
|
||||
public class CSVEditor extends JFrame {
|
||||
|
||||
/** Default columns. When you open existing csv, it should overwrite this. */
|
||||
private String[] columns = new String[]{"id", "drop", "name", "shdr", "shdg", "shdb", "shduv", "str", "dsty", "mate", "solid", "plat", "wall", "fall", "dlfn", "fv", "fr", "lumr", "lumg", "lumb", "lumuv"};
|
||||
private final int FOUR_DIGIT = 42;
|
||||
private final int SIX_DIGIT = 50;
|
||||
private final int TWO_DIGIT = 30;
|
||||
private final int ARBITRARY = 240;
|
||||
private int[] colWidth = new int[]{FOUR_DIGIT, FOUR_DIGIT, ARBITRARY, SIX_DIGIT, SIX_DIGIT, SIX_DIGIT, SIX_DIGIT, TWO_DIGIT, FOUR_DIGIT, FOUR_DIGIT, TWO_DIGIT, TWO_DIGIT, TWO_DIGIT, TWO_DIGIT, TWO_DIGIT, TWO_DIGIT, TWO_DIGIT, SIX_DIGIT, SIX_DIGIT, SIX_DIGIT, SIX_DIGIT};
|
||||
|
||||
private final int UNDO_BUFFER_SIZE = 10;
|
||||
|
||||
private CSVFormat csvFormat = CSVFetcher.INSTANCE.getTerrarumCSVFormat();
|
||||
|
||||
private final int INITIAL_ROWS = 2;
|
||||
|
||||
private JPanel panelSpreadSheet = new JPanel();
|
||||
private JPanel panelComment = new JPanel();
|
||||
private JSplitPane panelWorking = new JSplitPane(JSplitPane.VERTICAL_SPLIT, panelSpreadSheet, panelComment);
|
||||
|
||||
private JMenuBar menuBar = new JMenuBar();
|
||||
private JTable spreadsheet = new JTable(new DefaultTableModel(columns, INITIAL_ROWS)); // it MUST be DefaultTableModel because that's what I'm using
|
||||
private JTextPane caption = new JTextPane();
|
||||
private JTextPane comment = new JTextPane();
|
||||
private JLabel statBar = new JLabel("null.");
|
||||
|
||||
private JMenu undoMenu = new JMenu("Undo");
|
||||
private JMenu redoMenu = new JMenu("Redo");
|
||||
|
||||
private Properties props = new Properties();
|
||||
private Properties lang = new Properties();
|
||||
|
||||
private TraversingCircularArray<Object[][]> undoBuffer = new TraversingCircularArray(UNDO_BUFFER_SIZE);
|
||||
|
||||
public CSVEditor() {
|
||||
// setup application properties //
|
||||
try {
|
||||
props.load(new StringReader(captionProperties));
|
||||
lang.load(new StringReader(translations));
|
||||
}
|
||||
catch (Throwable e) {
|
||||
|
||||
}
|
||||
|
||||
// setup layout //
|
||||
|
||||
this.setLayout(new BorderLayout());
|
||||
panelSpreadSheet.setLayout(new BorderLayout());
|
||||
panelComment.setLayout(new BorderLayout());
|
||||
|
||||
spreadsheet.setVisible(true);
|
||||
|
||||
caption.setVisible(true);
|
||||
caption.setEditable(false);
|
||||
caption.setContentType("text/html");
|
||||
caption.setText("<span style=\"font:sans-serif; color:#888888; font-style:italic;\">Description of the selected column will be displayed here.</span>");
|
||||
|
||||
comment.setVisible(true);
|
||||
comment.setPreferredSize(new Dimension(100, 220));
|
||||
comment.setText("# This is a comment section.\n# All the comment must begin with this '#' mark.\n# null value on the CSV is represented as 'N/A'.");
|
||||
|
||||
panelSpreadSheet.add(menuBar, BorderLayout.NORTH);
|
||||
panelSpreadSheet.add(new JScrollPane(spreadsheet, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS
|
||||
), BorderLayout.CENTER);
|
||||
panelComment.add(caption, BorderLayout.NORTH);
|
||||
panelComment.add(new JScrollPane(comment, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS
|
||||
), BorderLayout.CENTER);
|
||||
this.add(statBar, BorderLayout.SOUTH);
|
||||
this.add(panelWorking, BorderLayout.CENTER);
|
||||
this.add(menuBar, BorderLayout.NORTH);
|
||||
|
||||
this.setTitle("Terrarum CSV Editor");
|
||||
this.setVisible(true);
|
||||
this.setSize(1154, 768);
|
||||
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
|
||||
// setup menubar //
|
||||
|
||||
menuBar.add(new JMenu("File") {
|
||||
{
|
||||
add("Open...").addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
// let's show generic warning first
|
||||
if (discardAgreed()) {
|
||||
|
||||
// actually read file
|
||||
JFileChooser fileChooser = new JFileChooser() {
|
||||
{
|
||||
setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
setMultiSelectionEnabled(false);
|
||||
}
|
||||
};
|
||||
|
||||
fileChooser.showOpenDialog(null);
|
||||
|
||||
if (fileChooser.getSelectedFile() != null) {
|
||||
if (fileChooser.getSelectedFile().exists()) {
|
||||
List<CSVRecord> records = CSVFetcher.INSTANCE.readFromFile(
|
||||
fileChooser.getSelectedFile().getAbsolutePath());
|
||||
|
||||
// turn list of records into a spreadsheet
|
||||
|
||||
// first dispose of any existing data
|
||||
((DefaultTableModel) spreadsheet.getModel()).setRowCount(0);
|
||||
|
||||
// then work on the file
|
||||
for (CSVRecord record : records) {
|
||||
String[] newRow = new String[columns.length];
|
||||
|
||||
// construct newRow
|
||||
for (String column : columns) {
|
||||
String value = record.get(column);
|
||||
if (value == null) {
|
||||
value = csvFormat.getNullString();
|
||||
}
|
||||
|
||||
newRow[spreadsheet.getColumnModel().getColumnIndex(column)] = value;
|
||||
}
|
||||
|
||||
((DefaultTableModel) spreadsheet.getModel()).addRow(newRow);
|
||||
}
|
||||
|
||||
// then add the comments
|
||||
// since the Commons CSV simply ignores the comments, we have to read them on our own.
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
List<String> allTheLines = Files.readAllLines(
|
||||
fileChooser.getSelectedFile().toPath());
|
||||
|
||||
allTheLines.forEach(line -> {
|
||||
if (line.startsWith("" + csvFormat.getCommentMarker().toString())) {
|
||||
sb.append(line);
|
||||
sb.append('\n');
|
||||
}
|
||||
});
|
||||
|
||||
comment.setText(sb.toString());
|
||||
|
||||
statBar.setText(lang.getProperty("STAT_LOAD_SUCCESSFUL"));
|
||||
}
|
||||
catch (Throwable fuck) {
|
||||
displayError("ERROR_INTERNAL", fuck);
|
||||
}
|
||||
}
|
||||
// if file not found
|
||||
else {
|
||||
displayMessage("NO_SUCH_FILE");
|
||||
}
|
||||
} // if opening cancelled, do nothing
|
||||
} // if discard cancelled, do nothing
|
||||
}
|
||||
});
|
||||
|
||||
add("Save...").addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
JFileChooser fileChooser = new JFileChooser() {
|
||||
{
|
||||
setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
setMultiSelectionEnabled(false);
|
||||
}
|
||||
};
|
||||
|
||||
fileChooser.showSaveDialog(null);
|
||||
|
||||
if (fileChooser.getSelectedFile() != null) {
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream(fileChooser.getSelectedFile());
|
||||
|
||||
fos.write(toCSV().getBytes());
|
||||
|
||||
fos.flush();
|
||||
fos.close();
|
||||
|
||||
|
||||
statBar.setText(lang.getProperty("STAT_SAVE_SUCCESSFUL"));
|
||||
}
|
||||
catch (IOException iofuck) {
|
||||
displayError("WRITE_FAIL", iofuck);
|
||||
}
|
||||
} // if saving cancelled, do nothing
|
||||
}
|
||||
});
|
||||
|
||||
add("New").addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (discardAgreed()) {
|
||||
// ask new rows
|
||||
Integer rows = askInteger("NEW_ROWS");
|
||||
|
||||
if (rows != null) {
|
||||
// first, delete everything
|
||||
((DefaultTableModel) spreadsheet.getModel()).setRowCount(0);
|
||||
|
||||
// then add some columns
|
||||
((DefaultTableModel) spreadsheet.getModel()).setRowCount(rows);
|
||||
|
||||
// notify the user as well
|
||||
statBar.setText(lang.getProperty("STAT_NEW_FILE"));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
undoMenu.setEnabled(false);
|
||||
redoMenu.setEnabled(false);
|
||||
|
||||
menuBar.add(new JMenu("Edit") {
|
||||
{
|
||||
add("New rows...").addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
Integer rows = askInteger("ADD_ROWS");
|
||||
|
||||
if (rows != null) {
|
||||
DefaultTableModel tableModel = (DefaultTableModel) spreadsheet.getModel();
|
||||
tableModel.setRowCount(tableModel.getRowCount() + rows);
|
||||
}
|
||||
}
|
||||
});
|
||||
add("New column...");
|
||||
add("Delete current row");
|
||||
add("Delete current column");
|
||||
addSeparator();
|
||||
add(undoMenu);
|
||||
add(redoMenu);
|
||||
addSeparator();
|
||||
add("Sort by ID").addMouseListener(new MouseAdapter() {
|
||||
private String[] getRow(int row, DefaultTableModel table) {
|
||||
String[] v = new String[table.getColumnCount()];
|
||||
for (int k = 0; k < v.length; k++) {
|
||||
v[k] = (String) table.getValueAt(row, k);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
private void setRow(int row, String[] data, DefaultTableModel table) {
|
||||
for (int k = 0; k < data.length; k++) {
|
||||
table.setValueAt(data[k], row, k);
|
||||
}
|
||||
}
|
||||
|
||||
private int toInt(String s) {
|
||||
int i;
|
||||
try {
|
||||
i = Integer.parseInt(s);
|
||||
|
||||
if (i == -1) i = 2147483646;
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
i = 2147483647;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
DefaultTableModel table = (DefaultTableModel) spreadsheet.getModel();
|
||||
int tableLen = table.getRowCount();
|
||||
|
||||
// perkele, had to get dirty
|
||||
// using insertion sort (should work good enough)
|
||||
int i = 1;
|
||||
while (i < tableLen) {
|
||||
String[] xData = getRow(i, table);
|
||||
int xComparator = toInt(xData[0]); // x <- A[i]
|
||||
|
||||
int j = i - 1;
|
||||
String[] jData = getRow(j, table);
|
||||
|
||||
while (j >= 0 && toInt(jData[0]) > xComparator) {
|
||||
// manually set a row
|
||||
setRow(j + 1, jData, table);
|
||||
j -= 1;
|
||||
|
||||
if (j < 0) break;
|
||||
jData = getRow(j, table);
|
||||
}
|
||||
|
||||
setRow(j + 1, xData, table);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
menuBar.revalidate();
|
||||
|
||||
// setup spreadsheet //
|
||||
|
||||
// no resize
|
||||
spreadsheet.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
|
||||
// set column width
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
spreadsheet.getColumnModel().getColumn(i).setPreferredWidth(colWidth[i]);
|
||||
}
|
||||
// make tables do things
|
||||
spreadsheet.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
|
||||
}
|
||||
});
|
||||
// make tables do things
|
||||
spreadsheet.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
// make caption line working
|
||||
JTable table = ((JTable) e.getSource());
|
||||
int col = table.getSelectedColumn();
|
||||
String colName = table.getColumnName(col);
|
||||
String captionText = props.getProperty(colName);
|
||||
|
||||
caption.setText("<span style=\"font:sans-serif;\"><b>" + colName + "</b><span style=\"color:#404040;\">" +
|
||||
((captionText == null) ? "" : ": " + captionText) +
|
||||
"</span></span>"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
statBar.setText(lang.getProperty("STAT_INIT"));
|
||||
|
||||
this.revalidate();
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new CSVEditor();
|
||||
}
|
||||
|
||||
private String toCSV() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int cols = spreadsheet.getColumnModel().getColumnCount();
|
||||
int rows = spreadsheet.getRowCount(); // actual rows, not counting the titles row
|
||||
|
||||
// add all the column titles
|
||||
for (int i = 0; i < cols; i++) {
|
||||
sb.append('"');
|
||||
sb.append(spreadsheet.getColumnName(i));
|
||||
sb.append('"');
|
||||
if (i + 1 < cols) sb.append(';');
|
||||
} sb.append('\n');
|
||||
|
||||
// loop for all the rows
|
||||
forEachRow:
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
Object rawValue = spreadsheet.getModel().getValueAt(row, col);
|
||||
|
||||
String cell;
|
||||
if (rawValue == null)
|
||||
cell = "";
|
||||
else
|
||||
cell = ((String) rawValue).toUpperCase();
|
||||
|
||||
// skip if ID cell is empty
|
||||
if (col == 0 && cell.isEmpty()) {
|
||||
continue forEachRow;
|
||||
}
|
||||
|
||||
sb.append('"');
|
||||
sb.append(cell);
|
||||
sb.append('"');
|
||||
if (col + 1 < cols) sb.append(';');
|
||||
}
|
||||
sb.append("\n");
|
||||
} sb.append("\n\n");
|
||||
|
||||
// add comments
|
||||
sb.append(comment.getText());
|
||||
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private boolean discardAgreed() {
|
||||
return 0 == JOptionPane.showOptionDialog(null,
|
||||
lang.getProperty("WARNING_YOUR_DATA_WILL_GONE") + " " + lang.getProperty("WARNING_CONTINUE"),
|
||||
null,
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.WARNING_MESSAGE,
|
||||
null,
|
||||
new String[]{"OK", "Cancel"},
|
||||
"Cancel"
|
||||
);
|
||||
}
|
||||
private boolean confirmedContinue(String messageKey) {
|
||||
return 0 == JOptionPane.showOptionDialog(null,
|
||||
lang.getProperty(messageKey) + " " + lang.getProperty("WARNING_CONTINUE"),
|
||||
null,
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.WARNING_MESSAGE,
|
||||
null,
|
||||
new String[]{"OK", "Cancel"},
|
||||
"Cancel"
|
||||
);
|
||||
}
|
||||
private void displayMessage(String messageKey) {
|
||||
JOptionPane.showOptionDialog(null,
|
||||
lang.getProperty(messageKey),
|
||||
null,
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.INFORMATION_MESSAGE,
|
||||
null,
|
||||
new String[]{"OK", "Cancel"},
|
||||
"Cancel"
|
||||
);
|
||||
}
|
||||
private void displayError(String messageKey, Throwable cause) {
|
||||
JOptionPane.showOptionDialog(null,
|
||||
lang.getProperty(messageKey) + "\n" + cause.toString(),
|
||||
null,
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.ERROR_MESSAGE,
|
||||
null,
|
||||
new String[]{"OK", "Cancel"},
|
||||
"Cancel"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param messageKey
|
||||
* @return null if the operation cancelled, nonzero int if the choice was made
|
||||
*/
|
||||
private Integer askInteger(String messageKey) {
|
||||
OptionSize optionWindow = new OptionSize(lang.getProperty(messageKey));
|
||||
int confirmedStatus = optionWindow.showDialog();
|
||||
|
||||
if (confirmedStatus == JOptionPane.CANCEL_OPTION) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return ((Integer) optionWindow.capacity.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private String captionProperties =
|
||||
"" + // dummy string to make IDE happy with the auto indent
|
||||
"id=ID of this block\n" +
|
||||
"drop=ID of the block this very block should drop when mined\n" +
|
||||
"name=String identifier of the block\n" +
|
||||
"shdr=Shade Red (light absorption). Valid range 0.0-4.0\n" +
|
||||
"shdg=Shade Green (light absorption). Valid range 0.0-4.0\n" +
|
||||
"shdb=Shade Blue (light absorption). Valid range 0.0-4.0\n" +
|
||||
"shduv=Shade UV (light absorbtion). Valid range 0.0-4.0\n" +
|
||||
"lumr=Luminosity Red (light intensity). Valid range 0.0-4.0\n" +
|
||||
"lumg=Luminosity Green (light intensity). Valid range 0.0-4.0\n" +
|
||||
"lumb=Luminosity Blue (light intensity). Valid range 0.0-4.0\n" +
|
||||
"lumuv=Luminosity UV (light intensity). Valid range 0.0-4.0\n" +
|
||||
"str=Strength of the block\n" +
|
||||
"dsty=Density of the block. Water have 1000 in the in-game scale\n" +
|
||||
"mate=Material of the block\n" +
|
||||
"solid=Whether the file has full collision\n" +
|
||||
"plat=Whether the block should behave like a platform\n" +
|
||||
"wall=Whether the block can be used as a wall\n" +
|
||||
"fall=Whether the block should fall through the empty space\n" +
|
||||
"dlfn=Dynamic Light Function. 0=Static. Please see <strong>notes</strong>\n" +
|
||||
"fv=Vertical friction when player slide on the cliff. 0 means not slide-able\n" +
|
||||
"fr=Horizontal friction. <16:slippery 16:regular >16:sticky\n";
|
||||
|
||||
/**
|
||||
* ¤ is used as a \n marker
|
||||
*/
|
||||
private String translations =
|
||||
"" +
|
||||
"WARNING_CONTINUE=Continue?\n" +
|
||||
"WARNING_YOUR_DATA_WILL_GONE=Existing edits will be lost.\n" +
|
||||
"OPERATION_CANCELLED=Operation cancelled.\n" +
|
||||
"NO_SUCH_FILE=No such file exists, operation cancelled.\n" +
|
||||
"NEW_ROWS=Enter the number of rows to initialise the new CSV.¤Remember, you can always add or delete rows later.\n" +
|
||||
"ADD_ROWS=Enter the number of rows to add:\n" +
|
||||
"WRITE_FAIL=Writing to file has failed:\n" +
|
||||
"STAT_INIT=Creating a new CSV. You can still open existing file.\n" +
|
||||
"STAT_SAVE_SUCCESSFUL=File saved successfully.\n" +
|
||||
"STAT_NEW_FILE=New CSV created.\n" +
|
||||
"STAT_LOAD_SUCCESSFUL=File loaded successfully.\n" +
|
||||
"ERROR_INTERNAL=Something went wrong.\n";
|
||||
}
|
||||
|
||||
class OptionSize {
|
||||
JSpinner capacity = new JSpinner(new SpinnerNumberModel(
|
||||
10,
|
||||
1,
|
||||
4096,
|
||||
1
|
||||
));
|
||||
private JPanel settingPanel = new JPanel();
|
||||
|
||||
OptionSize(String message) {
|
||||
settingPanel.add(new JLabel("<html>" + message.replace("¤", "<br />") + "</html>"));
|
||||
settingPanel.add(capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns either JOptionPane.OK_OPTION or JOptionPane.CANCEL_OPTION
|
||||
*/
|
||||
int showDialog() {
|
||||
return JOptionPane.showConfirmDialog(null, settingPanel,
|
||||
null, JOptionPane.OK_CANCEL_OPTION);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package net.torvald.terrarum.debuggerapp;
|
||||
|
||||
/**
|
||||
* To be used as undo/redo buffer. Which means, current position can go backward and rewrite objects ahead.
|
||||
*
|
||||
* The most recent item will be same as the current edit.
|
||||
*
|
||||
* Created by minjaesong on 2019-01-09.
|
||||
*/
|
||||
public class TraversingCircularArray<T> {
|
||||
|
||||
private T[] buf;
|
||||
private int size;
|
||||
|
||||
public TraversingCircularArray(int size) {
|
||||
buf = (T[]) new Object[size]; // create array of nulls
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
private int tail = 0;
|
||||
private int head = -1;
|
||||
|
||||
private int unreliableAddCount = 0;
|
||||
|
||||
/**
|
||||
* Adds new item.
|
||||
* @param item
|
||||
*/
|
||||
public void undoNew(T item) {
|
||||
if (unreliableAddCount <= size) unreliableAddCount += 1;
|
||||
|
||||
head = (head + 1) % size;
|
||||
if (unreliableAddCount > size) {
|
||||
tail = (tail + 1) % size;
|
||||
}
|
||||
|
||||
buf[head] = item; // overwrites oldest item when eligible
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops existing item. This function is analogous to rewinding the tape. Existing data will be untouched.
|
||||
* @return
|
||||
*/
|
||||
public T redo() {
|
||||
tail -= 1;
|
||||
return buf[tail];
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo the redo. This function is analogous to fast-forwarding the tape, without touching already recorded data.
|
||||
* If head of the tape reached, will do nothing.
|
||||
*/
|
||||
public T undoAgain() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex.ACTORID_MIN
|
||||
|
||||
|
||||
@@ -19,14 +16,16 @@ abstract class Actor(val renderOrder: RenderOrder) : Comparable<Actor>, Runnable
|
||||
BEHIND, // tapestries, some particles (obstructed by terrain)
|
||||
MIDDLE, // actors
|
||||
MIDTOP, // bullets, thrown items
|
||||
FRONT // fake tiles
|
||||
FRONT, // fake tiles
|
||||
OVERLAY // screen overlay, not affected by lightmap
|
||||
}
|
||||
|
||||
companion object {
|
||||
val RANGE_BEHIND = ACTORID_MIN..0x1FFF_FFFF
|
||||
val RANGE_MIDDLE = 0x2000_0000..0x5FFF_FFFF
|
||||
val RANGE_MIDTOP = 0x6000_0000..0x6FFF_FFFF
|
||||
val RANGE_FRONT = 0x7000_0000..0x7FFF_FFFF
|
||||
val RANGE_BEHIND = ACTORID_MIN..0x1FFF_FFFF // 1
|
||||
val RANGE_MIDDLE = 0x2000_0000..0x4FFF_FFFF // 3
|
||||
val RANGE_MIDTOP = 0x5000_0000..0x5FFF_FFFF // 1
|
||||
val RANGE_FRONT = 0x6000_0000..0x6FFF_FFFF // 1
|
||||
val RANDE_OVERLAY= 0x7000_0000..0x7FFF_FFFF // 1
|
||||
}
|
||||
|
||||
abstract fun update(delta: Float)
|
||||
@@ -62,6 +61,8 @@ abstract class Actor(val renderOrder: RenderOrder) : Comparable<Actor>, Runnable
|
||||
*/
|
||||
abstract @Event fun onActorValueChange(key: String, value: Any?)
|
||||
|
||||
abstract fun dispose()
|
||||
|
||||
}
|
||||
|
||||
annotation class Event
|
||||
|
||||
@@ -12,6 +12,10 @@ class ActorValue(val actor: Actor) : KVHashMap() {
|
||||
}
|
||||
|
||||
override fun set(key: String, value: Any) {
|
||||
/*if (key == AVKey.__PLAYER_QUICKSLOTSEL) {
|
||||
Thread.currentThread().stackTrace.forEach { println(it) }
|
||||
}*/
|
||||
|
||||
super.set(key, value)
|
||||
actor.onActorValueChange(key, value) // fire the event handler
|
||||
}
|
||||
|
||||
@@ -3,19 +3,19 @@ package net.torvald.terrarum.gameactors
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.Point2d
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.spriteanimation.SpriteAnimation
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.AppLoader.printdbg
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.blockproperties.BlockProp
|
||||
import net.torvald.terrarum.gamecontroller.KeyToggler
|
||||
import net.torvald.terrarum.gameworld.BlockAddress
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import org.dyn4j.geometry.Vector2
|
||||
import java.util.*
|
||||
@@ -45,16 +45,16 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
private val world: GameWorld?
|
||||
get() = Terrarum.ingame?.world
|
||||
|
||||
|
||||
|
||||
@Transient internal var sprite: SpriteAnimation? = null
|
||||
@Transient internal var spriteGlow: SpriteAnimation? = null
|
||||
|
||||
var drawMode = BlendMode.NORMAL
|
||||
|
||||
var hitboxTranslateX: Int = 0// relative to spritePosX
|
||||
protected set
|
||||
protected set
|
||||
var hitboxTranslateY: Int = 0// relative to spritePosY
|
||||
protected set
|
||||
protected set
|
||||
var baseHitboxW: Int = 0
|
||||
protected set
|
||||
var baseHitboxH: Int = 0
|
||||
@@ -66,39 +66,64 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
*/
|
||||
override val hitbox = Hitbox(0.0, 0.0, 0.0, 0.0) // Hitbox is implemented using Double;
|
||||
|
||||
/** half integer tilewise hitbox */ // got the idea from gl_FragCoord
|
||||
/** half integer tilewise hitbox.
|
||||
* May hold width/height of zero; the end point should be inclusive!
|
||||
*
|
||||
* e.g. USE `for (x in hitbox.startX..hitbox.endX)`, NOT `for (x in hitbox.startX until hitbox.endX)`
|
||||
*/ // got the idea from gl_FragCoord
|
||||
val hIntTilewiseHitbox: Hitbox
|
||||
get() = Hitbox.fromTwoPoints(
|
||||
hitbox.startX.plus(0.0001f).div(TILE_SIZE).floor() + 0.5f,
|
||||
hitbox.startY.plus(0.0001f).div(TILE_SIZE).floor() + 0.5f,
|
||||
hitbox.endX.plus(0.0001f).div(TILE_SIZE).floor() + 0.5f,
|
||||
hitbox.endY.plus(0.0001f).div(TILE_SIZE).floor() + 0.5f
|
||||
hitbox.startX.plus(0.00001f).div(TILE_SIZE).floor() + 0.5f,
|
||||
hitbox.startY.plus(0.00001f).div(TILE_SIZE).floor() + 0.5f,
|
||||
hitbox.endX.plus(0.00001f).div(TILE_SIZE).floor() + 0.5f,
|
||||
hitbox.endY.plus(0.00001f).div(TILE_SIZE).floor() + 0.5f,
|
||||
true
|
||||
)
|
||||
|
||||
|
||||
/** May hold width/height of zero; the end point should be inclusive!
|
||||
*
|
||||
* e.g. USE `for (x in hitbox.startX..hitbox.endX)`, NOT `for (x in hitbox.startX until hitbox.endX)`
|
||||
*/
|
||||
val intTilewiseHitbox: Hitbox
|
||||
get() = Hitbox.fromTwoPoints(
|
||||
hitbox.startX.plus(0.0001f).div(TILE_SIZE).floor(),
|
||||
hitbox.startY.plus(0.0001f).div(TILE_SIZE).floor(),
|
||||
hitbox.endX.plus(0.0001f).div(TILE_SIZE).floor(),
|
||||
hitbox.endY.plus(0.0001f).div(TILE_SIZE).floor()
|
||||
hitbox.startX.plus(0.00001f).div(TILE_SIZE).floor(),
|
||||
hitbox.startY.plus(0.00001f).div(TILE_SIZE).floor(),
|
||||
hitbox.endX.plus(0.00001f).div(TILE_SIZE).floor(),
|
||||
hitbox.endY.plus(0.00001f).div(TILE_SIZE).floor(),
|
||||
true
|
||||
)
|
||||
|
||||
/**
|
||||
* Unit: Pixels per 1/60 (or AppLoader.UPDATE_RATE) seconds.
|
||||
*
|
||||
* When the engine resolves this value, the framerate must be accounted for. E.g.:
|
||||
* 3.0 is resolved as 3.0 if FPS is 60, but the same value should be resolved as 6.0 if FPS is 30.
|
||||
* v_resolved = v * (60/FPS) or, v * (60 * delta_t)
|
||||
* (Use this code verbatim: '(Terrarum.PHYS_REF_FPS * delta)')
|
||||
*
|
||||
*
|
||||
* Elevators/Movingwalks/etc.: edit hitbox manually!
|
||||
*
|
||||
* Velocity vector for newtonian sim.
|
||||
* Acceleration: used in code like:
|
||||
* veloY += 3.0
|
||||
* +3.0 is acceleration. You __accumulate__ acceleration to the velocity.
|
||||
*
|
||||
* V for Velocity!
|
||||
*/
|
||||
internal val externalForce = Vector2(0.0, 0.0)
|
||||
internal val externalV = Vector2(0.0, 0.0)
|
||||
|
||||
@Transient private val VELO_HARD_LIMIT = 100.0
|
||||
|
||||
/**
|
||||
* Unit: Pixels per 1/60 (or AppLoader.UPDATE_RATE) seconds.
|
||||
*
|
||||
* for "Controllable" actors
|
||||
*
|
||||
* V for Velocity!
|
||||
*/
|
||||
var controllerMoveDelta: Vector2? = if (this is Controllable) Vector2() else null
|
||||
var controllerV: Vector2? = if (this is Controllable) Vector2() else null
|
||||
|
||||
// not sure we need this...
|
||||
//var jumpable = true // this is kind of like "semaphore"
|
||||
@@ -120,16 +145,16 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
/** Apparent mass. Use "avBaseMass" for base mass */
|
||||
val mass: Double
|
||||
get() = actorValue.getAsDouble(AVKey.BASEMASS) ?: MASS_DEFAULT * Math.pow(scale, 3.0)
|
||||
/*set(value) { // use "var avBaseMass: Double"
|
||||
if (value <= 0)
|
||||
throw IllegalArgumentException("mass cannot be less than or equal to zero.")
|
||||
else if (value < MASS_LOWEST) {
|
||||
printdbg(this, "input too small; using $MASS_LOWEST instead.")
|
||||
actorValue[AVKey.BASEMASS] = MASS_LOWEST
|
||||
}
|
||||
/*set(value) { // use "var avBaseMass: Double"
|
||||
if (value <= 0)
|
||||
throw IllegalArgumentException("mass cannot be less than or equal to zero.")
|
||||
else if (value < MASS_LOWEST) {
|
||||
printdbg(this, "input too small; using $MASS_LOWEST instead.")
|
||||
actorValue[AVKey.BASEMASS] = MASS_LOWEST
|
||||
}
|
||||
|
||||
actorValue[AVKey.BASEMASS] = value / Math.pow(scale, 3.0)
|
||||
}*/
|
||||
actorValue[AVKey.BASEMASS] = value / Math.pow(scale, 3.0)
|
||||
}*/
|
||||
@Transient val MASS_DEFAULT: Double = 60.0
|
||||
/** Valid range: [0, 1] */
|
||||
var elasticity: Double = 0.0
|
||||
@@ -172,8 +197,8 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
|
||||
private inline val grounded: Boolean
|
||||
get() = if (world == null) true else {
|
||||
isNoClip ||
|
||||
(world!!.gravitation.y > 0 && isWalled(hitbox, COLLIDING_BOTTOM) ||
|
||||
isNoClip ||
|
||||
(world!!.gravitation.y > 0 && isWalled(hitbox, COLLIDING_BOTTOM) ||
|
||||
world!!.gravitation.y < 0 && isWalled(hitbox, COLLIDING_TOP))
|
||||
}
|
||||
/** Default to 'true' */
|
||||
@@ -199,7 +224,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
* meter to pixel : 24/FPS
|
||||
*/
|
||||
private val gravitation: Vector2
|
||||
get() = world?.gravitation ?: Vector2(0.0, 9.8)
|
||||
get() = world?.gravitation ?: Vector2(0.0, 9.8)
|
||||
@Transient val DRAG_COEFF_DEFAULT = 1.2
|
||||
/** Drag coefficient. Parachutes have much higher value than bare body (1.2) */
|
||||
var dragCoefficient: Double
|
||||
@@ -253,10 +278,6 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
internal var walledTop = false // UNUSED; only for BasicDebugInfoWindow
|
||||
internal var walledBottom = false // UNUSED; only for BasicDebugInfoWindow
|
||||
internal var colliding = false
|
||||
|
||||
protected inline val updateDelta: Float
|
||||
get() = Terrarum.deltaTime
|
||||
|
||||
|
||||
var isWalkingH = false
|
||||
var isWalkingV = false
|
||||
@@ -323,7 +344,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
inline val feetPosTile: IntArray
|
||||
get() = intArrayOf(hIntTilewiseHitbox.centeredX.floorInt(), hIntTilewiseHitbox.endY.floorInt())
|
||||
|
||||
override fun run() = update(updateDelta)
|
||||
override fun run() = update(AppLoader.getSmoothDelta().toFloat())
|
||||
|
||||
/**
|
||||
* Add vector value to the velocity, in the time unit of single frame.
|
||||
@@ -333,14 +354,13 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
* @param acc : Acceleration in Vector2
|
||||
*/
|
||||
fun applyForce(acc: Vector2) {
|
||||
externalForce += acc * speedMultByTile
|
||||
externalV += acc * speedMultByTile
|
||||
}
|
||||
|
||||
private val bounceDampenVelThreshold = 0.5
|
||||
|
||||
override fun update(delta: Float) {
|
||||
if (isUpdate && !flagDespawn) {
|
||||
|
||||
if (!assertPrinted) assertInit()
|
||||
|
||||
if (sprite != null) sprite!!.update(delta)
|
||||
@@ -361,7 +381,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Codes that modifies velocity (moveDelta and externalForce) //
|
||||
// Codes that modifies velocity (moveDelta and externalV) //
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// --> Apply more forces <-- //
|
||||
@@ -369,15 +389,15 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
// Actors are subject to the gravity and the buoyancy if they are not levitating
|
||||
|
||||
if (!isNoSubjectToGrav) {
|
||||
applyGravitation()
|
||||
applyGravitation(delta)
|
||||
}
|
||||
|
||||
//applyBuoyancy()
|
||||
}
|
||||
|
||||
// hard limit velocity
|
||||
externalForce.x = externalForce.x.bipolarClamp(VELO_HARD_LIMIT) // displaceHitbox SHOULD use moveDelta
|
||||
externalForce.y = externalForce.y.bipolarClamp(VELO_HARD_LIMIT)
|
||||
externalV.x = externalV.x.bipolarClamp(VELO_HARD_LIMIT) // displaceHitbox SHOULD use moveDelta
|
||||
externalV.y = externalV.y.bipolarClamp(VELO_HARD_LIMIT)
|
||||
|
||||
if (!isChronostasis) {
|
||||
///////////////////////////////////////////////////
|
||||
@@ -390,36 +410,11 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
* This body is NON-STATIC and the other body is STATIC
|
||||
*/
|
||||
if (!isNoCollideWorld) {
|
||||
// // HOW IT SHOULD WORK // //
|
||||
// ////////////////////////
|
||||
// combineVeloToMoveDelta now
|
||||
// displace hitbox (!! force--moveDelta--still exist, do not touch the force !!)
|
||||
// make sure "touching" is perfectly useable
|
||||
// 16-step ccd applies here
|
||||
// ((nextHitbox <- hitbox))
|
||||
// resolve forces (use up the force && deform the vector):
|
||||
// // "touching" should work at this point if displaceHitbox is successful
|
||||
// [Collision]:
|
||||
// if touching (test for both axes):
|
||||
// re-direct force vector by mul w/ elasticity
|
||||
// if not touching:
|
||||
// do nothing
|
||||
// [Friction]:
|
||||
// deform vector "externalForce"
|
||||
// if isControllable:
|
||||
// also alter walkX/Y
|
||||
// translate ((nextHitbox)) hitbox by moveDelta (forces), this consumes force
|
||||
// DO NOT set whatever delta to zero
|
||||
// ((hitbox <- nextHitbox))
|
||||
//
|
||||
// ((comments)) [Label]
|
||||
|
||||
|
||||
displaceHitbox()
|
||||
displaceHitbox(delta.toDouble())
|
||||
}
|
||||
else {
|
||||
hitbox.translate(externalForce)
|
||||
hitbox.translate(controllerMoveDelta)
|
||||
val vecSum = externalV + (controllerV ?: Vector2(0.0, 0.0))
|
||||
hitbox.translate(vecSum)
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
@@ -433,9 +428,9 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
// TODO less friction for non-animating objects (make items glide far more on ice)
|
||||
|
||||
// FIXME asymmetry on friction
|
||||
setHorizontalFriction() // friction SHOULD use and alter externalForce
|
||||
setHorizontalFriction(delta) // friction SHOULD use and alter externalV
|
||||
//if (isNoClip) { // TODO also hanging on the rope, etc.
|
||||
setVerticalFriction()
|
||||
setVerticalFriction(delta)
|
||||
//}
|
||||
|
||||
|
||||
@@ -475,38 +470,38 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
if (!(isWalled(hitbox, COLLIDING_LEFT) && walkX < 0)
|
||||
|| !(isWalled(hitbox, COLLIDING_RIGHT) && walkX > 0)
|
||||
) {
|
||||
moveDelta.x = externalForce.x + walkX
|
||||
moveDelta.x = externalV.x + walkX
|
||||
}
|
||||
|
||||
// decide whether to ignore walkY
|
||||
if (!(isWalled(hitbox, COLLIDING_TOP) && walkY < 0)
|
||||
|| !(isWalled(hitbox, COLLIDING_BOTTOM) && walkY > 0)
|
||||
) {
|
||||
moveDelta.y = externalForce.y + walkY
|
||||
moveDelta.y = externalV.y + walkY
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!isWalled(hitbox, COLLIDING_LEFT)
|
||||
|| !isWalled(hitbox, COLLIDING_RIGHT)
|
||||
) {
|
||||
moveDelta.x = externalForce.x
|
||||
moveDelta.x = externalV.x
|
||||
}
|
||||
|
||||
// decide whether to ignore walkY
|
||||
if (!isWalled(hitbox, COLLIDING_TOP)
|
||||
|| !isWalled(hitbox, COLLIDING_BOTTOM)
|
||||
) {
|
||||
moveDelta.y = externalForce.y
|
||||
moveDelta.y = externalV.y
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
fun getDrag(externalForce: Vector2): Vector2 {
|
||||
fun getDrag(delta: Float, externalForce: Vector2): Vector2 {
|
||||
/**
|
||||
* weight; gravitational force in action
|
||||
* W = mass * G (9.8 [m/s^2])
|
||||
*/
|
||||
val W: Vector2 = gravitation * Terrarum.TARGET_FPS.toDouble()
|
||||
val W: Vector2 = gravitation * Terrarum.PHYS_TIME_FRAME.toDouble()
|
||||
/**
|
||||
* Area
|
||||
*/
|
||||
@@ -517,9 +512,12 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
*/
|
||||
val D: Vector2 = Vector2(externalForce.x.magnSqr(), externalForce.y.magnSqr()) * dragCoefficient * 0.5 * A// * tileDensityFluid.toDouble()
|
||||
|
||||
val V: Vector2 = (W - D) / Terrarum.TARGET_FPS * SI_TO_GAME_ACC
|
||||
val V: Vector2 = (W - D) / Terrarum.PHYS_TIME_FRAME * SI_TO_GAME_ACC
|
||||
|
||||
return V
|
||||
|
||||
// FIXME v * const, where const = 1.0 for FPS=60, sqrt(2.0) for FPS=30, etc.
|
||||
// this is "close enough" solution and not perfect.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -537,11 +535,11 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
*
|
||||
* Apply only if not grounded; normal force is precessed separately.
|
||||
*/
|
||||
private fun applyGravitation() {
|
||||
private fun applyGravitation(delta: Float) {
|
||||
|
||||
if (!isNoSubjectToGrav && !(gravitation.y > 0 && walledBottom || gravitation.y < 0 && walledTop)) {
|
||||
//if (!isWalled(hitbox, COLLIDING_BOTTOM)) {
|
||||
applyForce(getDrag(externalForce))
|
||||
applyForce(getDrag(delta, externalV))
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -573,35 +571,73 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
}
|
||||
}*/
|
||||
|
||||
private fun displaceHitbox() {
|
||||
private fun displaceHitbox(delta: Double) {
|
||||
// // HOW IT SHOULD WORK // //
|
||||
// ////////////////////////
|
||||
// combineVeloToMoveDelta now
|
||||
// displace hitbox (!! force--moveDelta--still exist, do not touch the force !!)
|
||||
// make sure "touching" is perfectly useable
|
||||
// 16-step ccd applies here
|
||||
// ((nextHitbox <- hitbox))
|
||||
// resolve forces (use up the force && deform the vector):
|
||||
// // "touching" should work at this point if displaceHitbox is successful
|
||||
// [Collision]:
|
||||
// if touching (test for both axes):
|
||||
// re-direct force vector by mul w/ elasticity
|
||||
// if not touching:
|
||||
// do nothing
|
||||
// [Friction]:
|
||||
// deform vector "externalV"
|
||||
// if isControllable:
|
||||
// also alter walkX/Y
|
||||
// translate ((nextHitbox)) hitbox by moveDelta (forces), this consumes force
|
||||
// DO NOT set whatever delta to zero
|
||||
// ((hitbox <- nextHitbox))
|
||||
//
|
||||
// ((comments)) [Label]
|
||||
|
||||
if (world != null) {
|
||||
|
||||
fun debug1(wut: Any?) {
|
||||
// vvvvv set it true to make debug print work
|
||||
if (true) println(wut)
|
||||
if (true) printdbg(this, wut)
|
||||
}
|
||||
|
||||
fun debug2(wut: Any?) {
|
||||
// vvvvv set it true to make debug print work
|
||||
if (false) println(wut)
|
||||
if (false) printdbg(this, wut)
|
||||
}
|
||||
|
||||
fun debug3(wut: Any?) {
|
||||
// vvvvv set it true to make debug print work
|
||||
if (false) println(wut)
|
||||
if (false) printdbg(this, wut)
|
||||
}
|
||||
|
||||
fun debug4(wut: Any?) {
|
||||
// vvvvv set it true to make debug print work
|
||||
if (false) println(wut)
|
||||
if (false) printdbg(this, wut)
|
||||
}
|
||||
|
||||
fun BlockAddress.isFeetTile(hitbox: Hitbox): Boolean {
|
||||
val (x, y) = LandUtil.resolveBlockAddr(world!!, this)
|
||||
val newTilewiseHitbox = Hitbox.fromTwoPoints(
|
||||
hitbox.startX.div(TILE_SIZE).floor(),
|
||||
hitbox.startY.div(TILE_SIZE).floor(),
|
||||
hitbox.endX.minus(0.00001).div(TILE_SIZE).floor(),
|
||||
hitbox.endY.minus(0.00001).div(TILE_SIZE).floor(),
|
||||
true
|
||||
)
|
||||
|
||||
// offset 1 pixel to the down so that friction would work
|
||||
return (y == hitbox.endY.plus(1.0).div(TILE_SIZE).floorInt()) && // copied from forEachFeetTileNum
|
||||
(x in newTilewiseHitbox.startX.toInt()..newTilewiseHitbox.endX.toInt()) // copied from forEachOccupyingTilePos
|
||||
}
|
||||
|
||||
fun Double.modTile() = this.toInt().div(TILE_SIZE).times(TILE_SIZE)
|
||||
fun Double.modTileDelta() = this - this.modTile()
|
||||
|
||||
|
||||
val vectorSum = externalForce + controllerMoveDelta
|
||||
val vectorSum = (externalV + controllerV)
|
||||
val ccdSteps = minOf(16, (vectorSum.magnitudeSquared / TILE_SIZE.sqr()).floorInt() + 1) // adaptive
|
||||
|
||||
|
||||
@@ -616,10 +652,10 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
// 20 sixteenStep may be optional, I think, but it'd be good to have
|
||||
|
||||
// ignore MOST of the codes below (it might be possible to recycle the structure??)
|
||||
// and the idea above has not yet implemented, and may never will. --Torvald, 2018-12-30
|
||||
|
||||
val sixteenStep = (0..ccdSteps).map { hitbox.clone().translate(vectorSum * (it / ccdSteps.toDouble())) } // zeroth step is for special condition
|
||||
|
||||
val affectingTiles = ArrayList<BlockAddress>()
|
||||
var collidingStep: Int? = null
|
||||
|
||||
for (step in 1..ccdSteps) {
|
||||
@@ -628,17 +664,14 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
|
||||
forEachOccupyingTilePos(stepBox) {
|
||||
val tileCoord = LandUtil.resolveBlockAddr(world!!, it)
|
||||
val tileProp = BlockCodex.getOrNull(world!!.getTileFromTerrain(tileCoord.first, tileCoord.second))
|
||||
val tile = world!!.getTileFromTerrain(tileCoord.first, tileCoord.second) ?: Block.STONE
|
||||
|
||||
if (tileProp == null || tileProp.isSolid) {
|
||||
affectingTiles.add(it)
|
||||
if (shouldICollideWithThis(tile) || (it.isFeetTile(stepBox) && shouldICollideWithThisFeet(tile))) {
|
||||
collidingStep = step
|
||||
}
|
||||
}
|
||||
|
||||
if (affectingTiles.isNotEmpty()) {
|
||||
collidingStep = step
|
||||
break // collision found on this step, break and proceed to next step
|
||||
}
|
||||
if (collidingStep != null) break
|
||||
}
|
||||
|
||||
|
||||
@@ -661,7 +694,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
debug1("== Collision step: $collidingStep / $ccdSteps")
|
||||
|
||||
|
||||
val newHitbox = hitbox.reassign(sixteenStep[collidingStep])
|
||||
val newHitbox = hitbox.reassign(sixteenStep[collidingStep!!])
|
||||
|
||||
var selfCollisionStatus = 0
|
||||
if (isWalled(newHitbox, COLLIDING_LEFT)) selfCollisionStatus += COLL_LEFTSIDE // 1
|
||||
@@ -671,12 +704,6 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
|
||||
// fixme UP and RIGHT && LEFT and DOWN bug
|
||||
|
||||
debug1("Collision type: $selfCollisionStatus")
|
||||
affectingTiles.forEach {
|
||||
val tileCoord = LandUtil.resolveBlockAddr(world!!, it)
|
||||
debug2("affectign tile: ${tileCoord.first}, ${tileCoord.second}")
|
||||
}
|
||||
|
||||
when (selfCollisionStatus) {
|
||||
0 -> {
|
||||
debug1("[ActorWBMovable] Contradiction -- collision detected by CCD, but isWalled() says otherwise")
|
||||
@@ -690,7 +717,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
15 -> {
|
||||
newHitbox.reassign(sixteenStep[0]); zeroX = true; zeroY = true
|
||||
}
|
||||
// one-side collision
|
||||
// one-side collision
|
||||
1, 11 -> {
|
||||
newHitbox.translatePosX(TILE_SIZE - newHitbox.startX.modTileDelta()); bounceX = true
|
||||
}
|
||||
@@ -709,7 +736,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
// fire Collision Event with one/two/three-side collision
|
||||
// for the ease of writing, this jumptable is separated from above.
|
||||
when (selfCollisionStatus) {
|
||||
// TODO compose CollisionInfo and fire collided()
|
||||
// TODO compose CollisionInfo and fire collided()
|
||||
}
|
||||
|
||||
|
||||
@@ -811,20 +838,20 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
|
||||
// bounce X/Y
|
||||
if (bounceX) {
|
||||
externalForce.x *= elasticity
|
||||
controllerMoveDelta?.let { controllerMoveDelta!!.x *= elasticity }
|
||||
externalV.x *= elasticity
|
||||
controllerV?.let { controllerV!!.x *= elasticity }
|
||||
}
|
||||
if (bounceY) {
|
||||
externalForce.y *= elasticity
|
||||
controllerMoveDelta?.let { controllerMoveDelta!!.y *= elasticity }
|
||||
externalV.y *= elasticity
|
||||
controllerV?.let { controllerV!!.y *= elasticity }
|
||||
}
|
||||
if (zeroX) {
|
||||
externalForce.x = 0.0
|
||||
controllerMoveDelta?.let { controllerMoveDelta!!.x = 0.0 }
|
||||
externalV.x = 0.0
|
||||
controllerV?.let { controllerV!!.x = 0.0 }
|
||||
}
|
||||
if (zeroY) {
|
||||
externalForce.y = 0.0
|
||||
controllerMoveDelta?.let { controllerMoveDelta!!.y = 0.0 }
|
||||
externalV.y = 0.0
|
||||
controllerV?.let { controllerV!!.y = 0.0 }
|
||||
}
|
||||
|
||||
|
||||
@@ -833,7 +860,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
|
||||
// slam-into-whatever damage (such dirty; much hack; wow)
|
||||
// vvvv hack (supposed to be 1.0) vvv 50% hack
|
||||
val collisionDamage = mass * (vectorSum.magnitude / (10.0 / Terrarum.TARGET_FPS).sqr()) / fallDamageDampening.sqr() * GAME_TO_SI_ACC
|
||||
val collisionDamage = mass * (vectorSum.magnitude / (10.0 / Terrarum.PHYS_TIME_FRAME).sqr()) / fallDamageDampening.sqr() * GAME_TO_SI_ACC
|
||||
// kg * m / s^2 (mass * acceleration), acceleration -> (vectorMagn / (0.01)^2).gameToSI()
|
||||
if (collisionDamage != 0.0) debug1("Collision damage: $collisionDamage N")
|
||||
// FIXME instead of 0.5mv^2, we can model after "change of velocity (aka accel)", just as in real-life; big change of accel on given unit time is what kills
|
||||
@@ -939,23 +966,61 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
val tyStart = y1.plus(0.5f).div(TILE_SIZE).floorInt()
|
||||
val tyEnd = y2.plus(0.5f).div(TILE_SIZE).floorInt()
|
||||
|
||||
return isCollidingInternal(txStart, tyStart, txEnd, tyEnd)
|
||||
return isCollidingInternal(txStart, tyStart, txEnd, tyEnd, option == COLLIDING_BOTTOM)
|
||||
}
|
||||
|
||||
private fun isCollidingInternal(txStart: Int, tyStart: Int, txEnd: Int, tyEnd: Int): Boolean {
|
||||
private fun isCollidingInternal(txStart: Int, tyStart: Int, txEnd: Int, tyEnd: Int, feet: Boolean = false): Boolean {
|
||||
if (world == null) return false
|
||||
|
||||
|
||||
for (y in tyStart..tyEnd) {
|
||||
for (x in txStart..txEnd) {
|
||||
val tile = world!!.getTileFromTerrain(x, y)
|
||||
if (BlockCodex[tile].isSolid)
|
||||
return true
|
||||
val tile = world!!.getTileFromTerrain(x, y) ?: Block.STONE
|
||||
|
||||
if (feet) {
|
||||
if (shouldICollideWithThisFeet(tile))
|
||||
return true
|
||||
}
|
||||
else {
|
||||
if (shouldICollideWithThis(tile))
|
||||
return true
|
||||
}
|
||||
|
||||
// this weird statement means that if's the condition is TRUE, return TRUE;
|
||||
// if the condition is FALSE, do nothing and let succeeding code handle it.
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* If this tile should be treated as "collidable"
|
||||
*
|
||||
* Very straightforward for the actual solid tiles, not so much for the platforms
|
||||
*/
|
||||
private fun shouldICollideWithThis(tile: Int) =
|
||||
// regular solid block
|
||||
(BlockCodex[tile].isSolid)
|
||||
|
||||
/**
|
||||
* If this tile should be treated as "collidable"
|
||||
*
|
||||
* Just like "shouldICollideWithThis" but it's intended to work with feet tiles
|
||||
*/
|
||||
private fun shouldICollideWithThisFeet(tile: Int) =
|
||||
// regular solid block
|
||||
(BlockCodex[tile].isSolid) ||
|
||||
// platforms, moving downward AND not "going down"
|
||||
(this is ActorHumanoid && BlockCodex[tile].isPlatform &&
|
||||
externalV.y + (controllerV?.y ?: 0.0) >= 0.0 &&
|
||||
!this.isDownDown && this.axisY <= 0f) ||
|
||||
// platforms, moving downward
|
||||
(this !is ActorHumanoid && BlockCodex[tile].isPlatform &&
|
||||
externalV.y + (controllerV?.y ?: 0.0) >= 0.0)
|
||||
// TODO: as for the platform, only apply it when it's a feet tile
|
||||
|
||||
|
||||
|
||||
private fun getContactingAreaFluid(side: Int, translateX: Int = 0, translateY: Int = 0): Int {
|
||||
if (world == null) return 0
|
||||
|
||||
@@ -966,30 +1031,30 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
val tileY: Int
|
||||
if (side == COLLIDING_LEFT) {
|
||||
tileX = div16TruncateToMapWidth(hitbox.hitboxStart.x.roundInt()
|
||||
+ i + translateX)
|
||||
+ i + translateX)
|
||||
tileY = div16TruncateToMapHeight(hitbox.hitboxEnd.y.roundInt() + translateY)
|
||||
}
|
||||
else if (side == COLLIDING_TOP) {
|
||||
tileX = div16TruncateToMapWidth(hitbox.hitboxStart.x.roundInt()
|
||||
+ i + translateX)
|
||||
+ i + translateX)
|
||||
tileY = div16TruncateToMapHeight(hitbox.hitboxStart.y.roundInt() + translateY)
|
||||
}
|
||||
else if (side == COLLIDING_RIGHT) {
|
||||
tileX = div16TruncateToMapWidth(hitbox.hitboxEnd.x.roundInt() + translateX)
|
||||
tileY = div16TruncateToMapHeight(hitbox.hitboxStart.y.roundInt()
|
||||
+ i + translateY)
|
||||
+ i + translateY)
|
||||
}
|
||||
else if (side == COLLIDING_LEFT) {
|
||||
tileX = div16TruncateToMapWidth(hitbox.hitboxStart.x.roundInt() + translateX)
|
||||
tileY = div16TruncateToMapHeight(hitbox.hitboxStart.y.roundInt()
|
||||
+ i + translateY)
|
||||
+ i + translateY)
|
||||
}
|
||||
else {
|
||||
throw IllegalArgumentException(side.toString() + ": Wrong side input")
|
||||
}
|
||||
|
||||
// evaluate
|
||||
if (BlockCodex[world!!.getTileFromTerrain(tileX, tileY)].isFluid) {
|
||||
if (world!!.getFluid(tileX, tileY).isFluid()) {
|
||||
contactAreaCounter += 1
|
||||
}
|
||||
}
|
||||
@@ -1006,7 +1071,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
|
||||
/** about stopping
|
||||
* for about get moving, see updateMovementControl */
|
||||
private fun setHorizontalFriction() {
|
||||
private fun setHorizontalFriction(delta: Float) {
|
||||
val friction = if (isNoClip)
|
||||
BASE_FRICTION * BlockCodex[Block.STONE].friction.frictionToMult()
|
||||
else {
|
||||
@@ -1014,50 +1079,50 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
BASE_FRICTION * if (grounded) feetFriction else bodyFriction
|
||||
}
|
||||
|
||||
if (externalForce.x < 0) {
|
||||
externalForce.x += friction
|
||||
if (externalForce.x > 0) externalForce.x = 0.0 // compensate overshoot
|
||||
if (externalV.x < 0) {
|
||||
externalV.x += friction
|
||||
if (externalV.x > 0) externalV.x = 0.0 // compensate overshoot
|
||||
}
|
||||
else if (externalForce.x > 0) {
|
||||
externalForce.x -= friction
|
||||
if (externalForce.x < 0) externalForce.x = 0.0 // compensate overshoot
|
||||
else if (externalV.x > 0) {
|
||||
externalV.x -= friction
|
||||
if (externalV.x < 0) externalV.x = 0.0 // compensate overshoot
|
||||
}
|
||||
|
||||
if (this is Controllable) {
|
||||
if (controllerMoveDelta!!.x < 0) {
|
||||
controllerMoveDelta!!.x += friction
|
||||
if (controllerMoveDelta!!.x > 0) controllerMoveDelta!!.x = 0.0
|
||||
if (controllerV!!.x < 0) {
|
||||
controllerV!!.x += friction
|
||||
if (controllerV!!.x > 0) controllerV!!.x = 0.0
|
||||
}
|
||||
else if (controllerMoveDelta!!.x > 0) {
|
||||
controllerMoveDelta!!.x -= friction
|
||||
if (controllerMoveDelta!!.x < 0) controllerMoveDelta!!.x = 0.0
|
||||
else if (controllerV!!.x > 0) {
|
||||
controllerV!!.x -= friction
|
||||
if (controllerV!!.x < 0) controllerV!!.x = 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setVerticalFriction() {
|
||||
private fun setVerticalFriction(delta: Float) {
|
||||
val friction = if (isNoClip)
|
||||
BASE_FRICTION * BlockCodex[Block.STONE].friction.frictionToMult()
|
||||
else
|
||||
BASE_FRICTION * bodyFriction
|
||||
|
||||
if (externalForce.y < 0) {
|
||||
externalForce.y += friction
|
||||
if (externalForce.y > 0) externalForce.y = 0.0 // compensate overshoot
|
||||
if (externalV.y < 0) {
|
||||
externalV.y += friction
|
||||
if (externalV.y > 0) externalV.y = 0.0 // compensate overshoot
|
||||
}
|
||||
else if (externalForce.y > 0) {
|
||||
externalForce.y -= friction
|
||||
if (externalForce.y < 0) externalForce.y = 0.0 // compensate overshoot
|
||||
else if (externalV.y > 0) {
|
||||
externalV.y -= friction
|
||||
if (externalV.y < 0) externalV.y = 0.0 // compensate overshoot
|
||||
}
|
||||
|
||||
if (this is Controllable) {
|
||||
if (controllerMoveDelta!!.y < 0) {
|
||||
controllerMoveDelta!!.y += friction
|
||||
if (controllerMoveDelta!!.y > 0) controllerMoveDelta!!.y = 0.0
|
||||
if (controllerV!!.y < 0) {
|
||||
controllerV!!.y += friction
|
||||
if (controllerV!!.y > 0) controllerV!!.y = 0.0
|
||||
}
|
||||
else if (controllerMoveDelta!!.y > 0) {
|
||||
controllerMoveDelta!!.y -= friction
|
||||
if (controllerMoveDelta!!.y < 0) controllerMoveDelta!!.y = 0.0
|
||||
else if (controllerV!!.y > 0) {
|
||||
controllerV!!.y -= friction
|
||||
if (controllerV!!.y < 0) controllerV!!.y = 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1094,17 +1159,23 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
).toDouble()
|
||||
|
||||
|
||||
// body friction is always as same as the air. Fluid doesn't matter, they use viscosity
|
||||
// (or viscosity was the wrong way and the friction DO matter? hmm... -- Torvald, 2018-12-31)
|
||||
// (or perhaps... they work in tandem, viscocity slows things down, friction makes go and stop fast -- Torvald, 2019-01-01; not the proudest thing to do in the ney year)
|
||||
// going down the platform won't show abnormal slowing (it's because of the friction prop!)
|
||||
internal inline val bodyFriction: Double
|
||||
get() {
|
||||
var friction = 0.0
|
||||
/*var friction = 0.0
|
||||
forEachOccupyingTileNum {
|
||||
// get max friction
|
||||
if (getTileFriction(it ?: Block.AIR) > friction)
|
||||
friction = getTileFriction(it ?: Block.AIR)
|
||||
}
|
||||
|
||||
return friction
|
||||
return friction*/
|
||||
return getTileFriction(Block.AIR)
|
||||
}
|
||||
// after all, feet friction is what it matters
|
||||
internal inline val feetFriction: Double
|
||||
get() {
|
||||
var friction = 0.0
|
||||
@@ -1178,10 +1249,10 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
private inline val tileDensityFluid: Int
|
||||
get() {
|
||||
var density = 0
|
||||
forEachOccupyingTile {
|
||||
forEachOccupyingFluid {
|
||||
// get max density for each tile
|
||||
if (it?.isFluid ?: false && it?.density ?: 0 > density) {
|
||||
density = it?.density ?: 0
|
||||
if (it?.isFluid() ?: false && it?.getProp()?.density ?: 0 > density) {
|
||||
density = it?.getProp()?.density ?: 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1265,7 +1336,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
|
||||
override fun drawGlow(batch: SpriteBatch) {
|
||||
if (isVisible && spriteGlow != null) {
|
||||
blendNormal()
|
||||
blendNormal(batch)
|
||||
drawSpriteInGoodPosition(spriteGlow!!, batch)
|
||||
}
|
||||
}
|
||||
@@ -1273,7 +1344,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
override fun drawBody(batch: SpriteBatch) {
|
||||
if (isVisible && sprite != null) {
|
||||
if (!KeyToggler.isOn(Input.Keys.F12)) {
|
||||
BlendMode.resolve(drawMode)
|
||||
BlendMode.resolve(drawMode, batch)
|
||||
drawSpriteInGoodPosition(sprite!!, batch)
|
||||
}
|
||||
else {
|
||||
@@ -1372,8 +1443,8 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
field = value
|
||||
|
||||
if (value) {
|
||||
externalForce.zero()
|
||||
controllerMoveDelta?.zero()
|
||||
externalV.zero()
|
||||
controllerV?.zero()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1401,8 +1472,8 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
|
||||
private fun forEachOccupyingTileNum(consumer: (Int?) -> Unit) {
|
||||
if (world == null) return
|
||||
|
||||
|
||||
|
||||
|
||||
val tiles = ArrayList<Int?>()
|
||||
for (y in hIntTilewiseHitbox.startY.toInt()..hIntTilewiseHitbox.endY.toInt()) {
|
||||
for (x in hIntTilewiseHitbox.startX.toInt()..hIntTilewiseHitbox.endX.toInt()) {
|
||||
@@ -1416,7 +1487,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
private fun forEachOccupyingTile(consumer: (BlockProp?) -> Unit) {
|
||||
if (world == null) return
|
||||
|
||||
|
||||
|
||||
val tileProps = ArrayList<BlockProp?>()
|
||||
for (y in hIntTilewiseHitbox.startY.toInt()..hIntTilewiseHitbox.endY.toInt()) {
|
||||
for (x in hIntTilewiseHitbox.startX.toInt()..hIntTilewiseHitbox.endX.toInt()) {
|
||||
@@ -1427,16 +1498,32 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
return tileProps.forEach(consumer)
|
||||
}
|
||||
|
||||
private fun forEachOccupyingFluid(consumer: (GameWorld.FluidInfo?) -> Unit) {
|
||||
if (world == null) return
|
||||
|
||||
|
||||
val fluids = ArrayList<GameWorld.FluidInfo?>()
|
||||
|
||||
for (y in hIntTilewiseHitbox.startY.toInt()..hIntTilewiseHitbox.endY.toInt()) {
|
||||
for (x in hIntTilewiseHitbox.startX.toInt()..hIntTilewiseHitbox.endX.toInt()) {
|
||||
fluids.add(world!!.getFluid(x, y))
|
||||
}
|
||||
}
|
||||
|
||||
return fluids.forEach(consumer)
|
||||
}
|
||||
|
||||
private fun forEachOccupyingTilePos(hitbox: Hitbox, consumer: (BlockAddress) -> Unit) {
|
||||
if (world == null) return
|
||||
|
||||
|
||||
|
||||
val newTilewiseHitbox = Hitbox.fromTwoPoints(
|
||||
hitbox.startX.div(TILE_SIZE).floor(),
|
||||
hitbox.startY.div(TILE_SIZE).floor(),
|
||||
hitbox.endX.minus(0.00001).div(TILE_SIZE).floor(),
|
||||
hitbox.endY.minus(0.00001).div(TILE_SIZE).floor()
|
||||
)
|
||||
hitbox.endY.minus(0.00001).div(TILE_SIZE).floor(),
|
||||
true
|
||||
) // NOT the same as intTilewiseHitbox !!
|
||||
|
||||
val tilePosList = ArrayList<BlockAddress>()
|
||||
for (y in newTilewiseHitbox.startY.toInt()..newTilewiseHitbox.endY.toInt()) {
|
||||
@@ -1451,7 +1538,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
private fun forEachFeetTileNum(consumer: (Int?) -> Unit) {
|
||||
if (world == null) return
|
||||
|
||||
|
||||
|
||||
val tiles = ArrayList<Int?>()
|
||||
|
||||
// offset 1 pixel to the down so that friction would work
|
||||
@@ -1467,7 +1554,7 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
private fun forEachFeetTile(consumer: (BlockProp?) -> Unit) {
|
||||
if (world == null) return
|
||||
|
||||
|
||||
|
||||
val tileProps = ArrayList<BlockProp?>()
|
||||
|
||||
// offset 1 pixel to the down so that friction would work
|
||||
@@ -1492,16 +1579,16 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
/**
|
||||
* [m / s^2] * SI_TO_GAME_ACC -> [px / InternalFrame^2]
|
||||
*/
|
||||
@Transient val SI_TO_GAME_ACC = METER / (Terrarum.TARGET_FPS * Terrarum.TARGET_FPS)
|
||||
@Transient val SI_TO_GAME_ACC = METER / (Terrarum.PHYS_TIME_FRAME * Terrarum.PHYS_TIME_FRAME)
|
||||
/**
|
||||
* [m / s] * SI_TO_GAME_VEL -> [px / InternalFrame]
|
||||
*/
|
||||
@Transient val SI_TO_GAME_VEL = METER / Terrarum.TARGET_FPS
|
||||
@Transient val SI_TO_GAME_VEL = METER / Terrarum.PHYS_TIME_FRAME
|
||||
|
||||
/**
|
||||
* [px / InternalFrame^2] * GAME_TO_SI_ACC -> [m / s^2]
|
||||
*/
|
||||
@Transient val GAME_TO_SI_ACC = (Terrarum.TARGET_FPS * Terrarum.TARGET_FPS) / METER
|
||||
@Transient val GAME_TO_SI_ACC = (Terrarum.PHYS_TIME_FRAME * Terrarum.PHYS_TIME_FRAME) / METER
|
||||
|
||||
|
||||
/**
|
||||
@@ -1571,9 +1658,9 @@ open class ActorWBMovable(renderOrder: RenderOrder, val immobileBody: Boolean =
|
||||
internal val avAcceleration: Double
|
||||
get() { if (accelMultMovement.isNaN()) println("accelMultMovement: $accelMultMovement")
|
||||
return actorValue.getAsDouble(AVKey.ACCEL)!! *
|
||||
(actorValue.getAsDouble(AVKey.ACCELBUFF) ?: 1.0) *
|
||||
accelMultMovement *
|
||||
scale.sqrt()
|
||||
(actorValue.getAsDouble(AVKey.ACCELBUFF) ?: 1.0) *
|
||||
accelMultMovement *
|
||||
scale.sqrt()
|
||||
}
|
||||
internal val avSpeedCap: Double
|
||||
get() = actorValue.getAsDouble(AVKey.SPEED)!! *
|
||||
|
||||
@@ -12,6 +12,4 @@ abstract class ActorWithBody(renderOrder: RenderOrder) : Actor(renderOrder) {
|
||||
abstract fun drawBody(batch: SpriteBatch)
|
||||
abstract fun drawGlow(batch: SpriteBatch)
|
||||
open var tooltipText: String? = null // null: display nothing
|
||||
|
||||
abstract fun dispose()
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import org.dyn4j.geometry.Vector2
|
||||
*
|
||||
* Created by minjaesong on 2016-01-15.
|
||||
*/
|
||||
class Hitbox(x1: Double, y1: Double, width: Double, height: Double) {
|
||||
class Hitbox(x1: Double, y1: Double, width: Double, height: Double, var suppressWarning: Boolean = false) {
|
||||
|
||||
@Volatile var hitboxStart: Point2d
|
||||
private set
|
||||
@@ -25,6 +25,11 @@ class Hitbox(x1: Double, y1: Double, width: Double, height: Double) {
|
||||
hitboxStart = Point2d(x1, y1)
|
||||
this.width = width
|
||||
this.height = height
|
||||
|
||||
if (!suppressWarning && (width == 0.0 || height == 0.0)) {
|
||||
println("[Hitbox] width or height is zero ($this), perhaps you want to check it out?")
|
||||
Thread.currentThread().stackTrace.forEach { println(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
@@ -59,6 +64,12 @@ class Hitbox(x1: Double, y1: Double, width: Double, height: Double) {
|
||||
hitboxStart = Point2d(x1, y1)
|
||||
this.width = width
|
||||
this.height = height
|
||||
|
||||
if (!suppressWarning && (width == 0.0 || height == 0.0)) {
|
||||
println("[Hitbox] width or height is zero ($this), perhaps you want to check it out?")
|
||||
Thread.currentThread().stackTrace.forEach { println(it) }
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
fun setFromTwoPoints(x1: Double, y1: Double, x2: Double, y2: Double): Hitbox {
|
||||
@@ -72,8 +83,8 @@ class Hitbox(x1: Double, y1: Double, width: Double, height: Double) {
|
||||
fun setPosition(x1: Double, y1: Double): Hitbox {
|
||||
hitboxStart = Point2d(x1, y1)
|
||||
|
||||
if (width == 0.0 || height == 0.0) {
|
||||
println("[Hitbox] width or height is zero, perhaps you want to check it out?")
|
||||
if (!suppressWarning && (width == 0.0 || height == 0.0)) {
|
||||
println("[Hitbox] width or height is zero ($this), perhaps you want to check it out?")
|
||||
Thread.currentThread().stackTrace.forEach { println(it) }
|
||||
}
|
||||
|
||||
@@ -125,7 +136,7 @@ class Hitbox(x1: Double, y1: Double, width: Double, height: Double) {
|
||||
val centeredY: Double
|
||||
get() = (hitboxStart.y + hitboxEnd.y) * 0.5
|
||||
|
||||
fun intersects(position: Point2d) =
|
||||
infix fun intersects(position: Point2d) =
|
||||
(position.x >= startX && position.x <= startX + width) &&
|
||||
(position.y >= startY && position.y <= startY + height)
|
||||
|
||||
@@ -134,8 +145,8 @@ class Hitbox(x1: Double, y1: Double, width: Double, height: Double) {
|
||||
fun clone(): Hitbox = Hitbox(startX, startY, width, height)
|
||||
|
||||
companion object {
|
||||
fun fromTwoPoints(x1: Double, y1: Double, x2: Double, y2: Double) =
|
||||
Hitbox(x1, y1, x2 - x1, y2 - y1)
|
||||
fun fromTwoPoints(x1: Double, y1: Double, x2: Double, y2: Double, nowarn: Boolean = false) =
|
||||
Hitbox(x1, y1, x2 - x1, y2 - y1, nowarn)
|
||||
}
|
||||
|
||||
operator fun minus(other: Hitbox): Vector2 {
|
||||
|
||||
@@ -46,7 +46,7 @@ import org.luaj.vm2.*
|
||||
*/
|
||||
fun composeActorObject(actor: ActorWBMovable): LuaTable {
|
||||
val t: LuaTable = LuaTable()
|
||||
val moveDelta = actor.externalForce + actor.controllerMoveDelta
|
||||
val moveDelta = actor.externalV + actor.controllerV
|
||||
|
||||
t["name"] = actor.actorValue.getAsString(AVKey.NAME).toLua()
|
||||
t["startX"] = actor.hitbox.centeredX.toLua()
|
||||
|
||||
@@ -3,11 +3,14 @@ package net.torvald.terrarum.gamecontroller
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.InputAdapter
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.floorInt
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
import net.torvald.terrarum.gameworld.fmod
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.floorInt
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
|
||||
/**
|
||||
@@ -40,17 +43,19 @@ class IngameController(val ingame: Ingame) : InputAdapter() {
|
||||
|
||||
// Use item: assuming the player has only one effective grip (EquipPosition.HAND_GRIP)
|
||||
if (ingame.canPlayerControl) {
|
||||
if (Gdx.input.isButtonPressed(Terrarum.getConfigInt("mouseprimary")) || Gdx.input.isButtonPressed(Terrarum.getConfigInt("mousesecondary"))) {
|
||||
if (Gdx.input.isButtonPressed(AppLoader.getConfigInt("mouseprimary")) ||
|
||||
Gdx.input.isButtonPressed(AppLoader.getConfigInt("mousesecondary"))) {
|
||||
|
||||
val player = (Terrarum.ingame!! as Ingame).actorNowPlaying
|
||||
if (player == null) return
|
||||
|
||||
val itemOnGrip = player.inventory.itemEquipped[GameItem.EquipPosition.HAND_GRIP]
|
||||
|
||||
itemOnGrip?.let {
|
||||
if (Gdx.input.isButtonPressed(Terrarum.getConfigInt("mouseprimary"))) {
|
||||
if (Gdx.input.isButtonPressed(AppLoader.getConfigInt("mouseprimary"))) {
|
||||
player.consumePrimary(it)
|
||||
}
|
||||
if (Gdx.input.isButtonPressed(Terrarum.getConfigInt("mousesecondary"))) {
|
||||
if (Gdx.input.isButtonPressed(AppLoader.getConfigInt("mousesecondary"))) {
|
||||
player.consumeSecondary(it)
|
||||
}
|
||||
}
|
||||
@@ -67,12 +72,19 @@ class IngameController(val ingame: Ingame) : InputAdapter() {
|
||||
|
||||
if (ingame.canPlayerControl) {
|
||||
ingame.actorNowPlaying?.keyDown(keycode)
|
||||
}
|
||||
|
||||
if (Terrarum.getConfigIntArray("keyquickselalt").contains(keycode)
|
||||
|| keycode == Terrarum.getConfigInt("keyquicksel")) {
|
||||
ingame.uiPieMenu.setAsOpen()
|
||||
ingame.uiQuickBar.setAsClose()
|
||||
// quickslot by number keys
|
||||
val quickslotKeys = AppLoader.getConfigIntArray("keyquickslots")
|
||||
if (keycode in quickslotKeys) {
|
||||
ingame.actorNowPlaying?.actorValue?.set(AVKey.__PLAYER_QUICKSLOTSEL, quickslotKeys.indexOf(keycode))
|
||||
}
|
||||
|
||||
// pie menu
|
||||
if (AppLoader.getConfigIntArray("keyquickselalt").contains(keycode)
|
||||
|| keycode == AppLoader.getConfigInt("keyquicksel")) {
|
||||
ingame.uiPieMenu.setAsOpen()
|
||||
ingame.uiQuickBar.setAsClose()
|
||||
}
|
||||
}
|
||||
|
||||
ingame.uiContainer.forEach { it.keyDown(keycode) } // for KeyboardControlled UIcanvases
|
||||
@@ -90,8 +102,8 @@ class IngameController(val ingame: Ingame) : InputAdapter() {
|
||||
}
|
||||
|
||||
override fun keyUp(keycode: Int): Boolean {
|
||||
if (Terrarum.getConfigIntArray("keyquickselalt").contains(keycode)
|
||||
|| keycode == Terrarum.getConfigInt("keyquicksel")) {
|
||||
if (AppLoader.getConfigIntArray("keyquickselalt").contains(keycode)
|
||||
|| keycode == AppLoader.getConfigInt("keyquicksel")) {
|
||||
ingame.uiPieMenu.setAsClose()
|
||||
ingame.uiQuickBar.setAsOpen()
|
||||
}
|
||||
@@ -118,11 +130,11 @@ class IngameController(val ingame: Ingame) : InputAdapter() {
|
||||
// fire world click events; the event is defined as Ingame's (or any others') WorldClick event
|
||||
if (ingame.uiContainer.map { if ((it.isOpening || it.isOpened) && it.mouseUp) 1 else 0 }.sum() == 0) { // no UI on the mouse, right?
|
||||
|
||||
if (button == Terrarum.getConfigInt("mouseprimary")) {
|
||||
ingame.worldPrimaryClickEnd(Terrarum.deltaTime)
|
||||
if (button == AppLoader.getConfigInt("mouseprimary")) {
|
||||
ingame.worldPrimaryClickEnd(AppLoader.getSmoothDelta().toFloat())
|
||||
}
|
||||
if (button == Terrarum.getConfigInt("mousesecondary")) {
|
||||
ingame.worldSecondaryClickEnd(Terrarum.deltaTime)
|
||||
if (button == AppLoader.getConfigInt("mousesecondary")) {
|
||||
ingame.worldSecondaryClickEnd(AppLoader.getSmoothDelta().toFloat())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,6 +146,16 @@ class IngameController(val ingame: Ingame) : InputAdapter() {
|
||||
}
|
||||
|
||||
override fun scrolled(amount: Int): Boolean {
|
||||
if (ingame.canPlayerControl) {
|
||||
// quickslot by wheel
|
||||
if (ingame.actorNowPlaying != null) {
|
||||
ingame.actorNowPlaying!!.actorValue.set(
|
||||
AVKey.__PLAYER_QUICKSLOTSEL,
|
||||
(ingame.actorNowPlaying!!.actorValue.getAsInt(AVKey.__PLAYER_QUICKSLOTSEL)!! - amount) fmod ingame.actorNowPlaying!!.inventory.quickSlot.size
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ingame.uiContainer.forEach { it.scrolled(amount) }
|
||||
return true
|
||||
}
|
||||
@@ -149,11 +171,11 @@ class IngameController(val ingame: Ingame) : InputAdapter() {
|
||||
// fire world click events; the event is defined as Ingame's (or any others') WorldClick event
|
||||
if (ingame.uiContainer.map { if ((it.isOpening || it.isOpened) && it.mouseUp) 1 else 0 }.sum() == 0) { // no UI on the mouse, right?
|
||||
|
||||
if (button == Terrarum.getConfigInt("mouseprimary")) {
|
||||
ingame.worldPrimaryClickStart(Terrarum.deltaTime)
|
||||
if (button == AppLoader.getConfigInt("mouseprimary")) {
|
||||
ingame.worldPrimaryClickStart(AppLoader.getSmoothDelta().toFloat())
|
||||
}
|
||||
if (button == Terrarum.getConfigInt("mousesecondary")) {
|
||||
ingame.worldSecondaryClickStart(Terrarum.deltaTime)
|
||||
if (button == AppLoader.getConfigInt("mousesecondary")) {
|
||||
ingame.worldSecondaryClickStart(AppLoader.getSmoothDelta().toFloat())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ object KeyToggler {
|
||||
return currentState[key]
|
||||
}
|
||||
|
||||
/**
|
||||
* Put this into the each scene's update/render method.
|
||||
*/
|
||||
fun update(gameMode: Boolean = true) {
|
||||
for (it in 0..255) {
|
||||
if (gameMode && it in gameKeys &&
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
package net.torvald.terrarum.gameworld
|
||||
|
||||
import net.torvald.terrarum.blockproperties.Fluid
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-08-06.
|
||||
*/
|
||||
object FluidCodex {
|
||||
const val FLUID_LAVA = 0xFE.toByte()
|
||||
const val FLUID_WATER = 0xFF.toByte()
|
||||
}
|
||||
|
||||
operator fun get(type: FluidType): FluidProp {
|
||||
return if (type sameAs Fluid.NULL)
|
||||
nullProp
|
||||
else
|
||||
waterProp
|
||||
}
|
||||
|
||||
// TODO temporary, should read from CSV
|
||||
val nullProp = FluidProp.getNullProp()
|
||||
val waterProp = FluidProp()
|
||||
|
||||
init {
|
||||
waterProp.shadeColR = 0.1016f
|
||||
waterProp.shadeColG = 0.0744f
|
||||
waterProp.shadeColB = 0.0508f
|
||||
waterProp.shadeColA = 0.0508f
|
||||
|
||||
waterProp.density = 1000
|
||||
}
|
||||
}
|
||||
|
||||
48
src/net/torvald/terrarum/gameworld/FluidProp.kt
Normal file
48
src/net/torvald/terrarum/gameworld/FluidProp.kt
Normal file
@@ -0,0 +1,48 @@
|
||||
package net.torvald.terrarum.gameworld
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.blockproperties.BlockPropUtil
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2018-12-29.
|
||||
*/
|
||||
class FluidProp {
|
||||
|
||||
var density: Int = 0
|
||||
|
||||
var dynamicLuminosityFunction: Int = 0
|
||||
|
||||
/** 1.0f for 1023, 0.25f for 255 */
|
||||
var shadeColR = 0f
|
||||
var shadeColG = 0f
|
||||
var shadeColB = 0f
|
||||
var shadeColA = 0f
|
||||
|
||||
/** 1.0f for 1023, 0.25f for 255 */
|
||||
var lumColR = 0f
|
||||
var lumColG = 0f
|
||||
var lumColB = 0f
|
||||
var lumColA = 0f
|
||||
|
||||
inline val opacity: Color
|
||||
get() = Color(shadeColR, shadeColG, shadeColB, shadeColA)
|
||||
|
||||
inline val luminosity: Color
|
||||
get() = BlockPropUtil.getDynamicLumFunc(Color(lumColR, lumColG, lumColB, lumColA), dynamicLuminosityFunction)
|
||||
|
||||
|
||||
companion object {
|
||||
fun getNullProp(): FluidProp {
|
||||
val p = FluidProp()
|
||||
|
||||
p.shadeColR = BlockCodex[Block.AIR].shadeColR
|
||||
p.shadeColG = BlockCodex[Block.AIR].shadeColG
|
||||
p.shadeColB = BlockCodex[Block.AIR].shadeColB
|
||||
p.shadeColA = BlockCodex[Block.AIR].shadeColA
|
||||
|
||||
return p
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,16 @@
|
||||
package net.torvald.terrarum.gameworld
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.blockproperties.Fluid
|
||||
import net.torvald.terrarum.modulebasegame.gameworld.WorldSimulator
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import net.torvald.terrarum.serialise.ReadLayerDataLzma
|
||||
import org.dyn4j.geometry.Vector2
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
typealias BlockAddress = Long
|
||||
typealias BlockDamage = Float
|
||||
|
||||
open class GameWorld {
|
||||
|
||||
@@ -35,15 +38,17 @@ open class GameWorld {
|
||||
val layerTerrainLowBits: PairedMapLayer
|
||||
|
||||
//val layerThermal: MapLayerHalfFloat // in Kelvins
|
||||
//val layerAirPressure: MapLayerHalfFloat // (milibar - 1000)
|
||||
//val layerFluidPressure: MapLayerHalfFloat // (milibar - 1000)
|
||||
|
||||
/** Tilewise spawn point */
|
||||
var spawnX: Int
|
||||
/** Tilewise spawn point */
|
||||
var spawnY: Int
|
||||
|
||||
val wallDamages: HashMap<BlockAddress, BlockDamage>
|
||||
val terrainDamages: HashMap<BlockAddress, BlockDamage>
|
||||
val wallDamages: HashMap<BlockAddress, Float>
|
||||
val terrainDamages: HashMap<BlockAddress, Float>
|
||||
val fluidTypes: HashMap<BlockAddress, FluidType>
|
||||
val fluidFills: HashMap<BlockAddress, Float>
|
||||
|
||||
//public World physWorld = new World( new Vec2(0, -Terrarum.game.gravitationalAccel) );
|
||||
//physics
|
||||
@@ -59,6 +64,8 @@ open class GameWorld {
|
||||
|
||||
|
||||
constructor(worldIndex: Int, width: Int, height: Int, creationTIME_T: Long, lastPlayTIME_T: Long, totalPlayTime: Int) {
|
||||
if (width <= 0 || height <= 0) throw IllegalArgumentException("Non-positive width/height: ($width, $height)")
|
||||
|
||||
this.worldIndex = worldIndex
|
||||
this.width = width
|
||||
this.height = height
|
||||
@@ -72,14 +79,16 @@ open class GameWorld {
|
||||
layerTerrainLowBits = PairedMapLayer(width, height)
|
||||
layerWallLowBits = PairedMapLayer(width, height)
|
||||
|
||||
wallDamages = HashMap<BlockAddress, BlockDamage>()
|
||||
terrainDamages = HashMap<BlockAddress, BlockDamage>()
|
||||
wallDamages = HashMap<BlockAddress, Float>()
|
||||
terrainDamages = HashMap<BlockAddress, Float>()
|
||||
fluidTypes = HashMap<BlockAddress, FluidType>()
|
||||
fluidFills = HashMap<BlockAddress, Float>()
|
||||
|
||||
// temperature layer: 2x2 is one cell
|
||||
//layerThermal = MapLayerHalfFloat(width / 2, height / 2, averageTemperature)
|
||||
//layerThermal = MapLayerHalfFloat(width, height, averageTemperature)
|
||||
|
||||
// air pressure layer: 4 * 8 is one cell
|
||||
//layerAirPressure = MapLayerHalfFloat(width / 4, height / 8, 13f) // 1013 mBar
|
||||
// fluid pressure layer: 4 * 8 is one cell
|
||||
//layerFluidPressure = MapLayerHalfFloat(width, height, 13f) // 1013 mBar
|
||||
|
||||
|
||||
creationTime = creationTIME_T
|
||||
@@ -98,6 +107,8 @@ open class GameWorld {
|
||||
|
||||
wallDamages = layerData.wallDamages
|
||||
terrainDamages = layerData.terrainDamages
|
||||
fluidTypes = layerData.fluidTypes
|
||||
fluidFills = layerData.fluidFills
|
||||
|
||||
spawnX = layerData.spawnX
|
||||
spawnY = layerData.spawnY
|
||||
@@ -144,9 +155,12 @@ open class GameWorld {
|
||||
val damageDataArray: ByteArray
|
||||
get() = layerTerrainLowBits.data
|
||||
|
||||
private fun coerceXY(x: Int, y: Int) = (x fmod width) to (y.coerceWorld())
|
||||
|
||||
fun getTileFromWall(x: Int, y: Int): Int? {
|
||||
val wall: Int? = layerWall.getTile(x fmod width, y)
|
||||
val wallDamage: Int? = getWallLowBits(x fmod width, y)
|
||||
val (x, y) = coerceXY(x, y)
|
||||
val wall: Int? = layerWall.getTile(x, y)
|
||||
val wallDamage: Int? = getWallLowBits(x, y)
|
||||
return if (wall == null || wallDamage == null)
|
||||
null
|
||||
else
|
||||
@@ -154,8 +168,9 @@ open class GameWorld {
|
||||
}
|
||||
|
||||
fun getTileFromTerrain(x: Int, y: Int): Int? {
|
||||
val terrain: Int? = layerTerrain.getTile(x fmod width, y)
|
||||
val terrainDamage: Int? = getTerrainLowBits(x fmod width, y)
|
||||
val (x, y) = coerceXY(x, y)
|
||||
val terrain: Int? = layerTerrain.getTile(x, y)
|
||||
val terrainDamage: Int? = getTerrainLowBits(x, y)
|
||||
return if (terrain == null || terrainDamage == null)
|
||||
null
|
||||
else
|
||||
@@ -163,15 +178,18 @@ open class GameWorld {
|
||||
}
|
||||
|
||||
fun getTileFromWire(x: Int, y: Int): Int? {
|
||||
return layerWire.getTile(x fmod width, y)
|
||||
val (x, y) = coerceXY(x, y)
|
||||
return layerWire.getTile(x, y)
|
||||
}
|
||||
|
||||
fun getWallLowBits(x: Int, y: Int): Int? {
|
||||
return layerWallLowBits.getData(x fmod width, y)
|
||||
val (x, y) = coerceXY(x, y)
|
||||
return layerWallLowBits.getData(x, y)
|
||||
}
|
||||
|
||||
fun getTerrainLowBits(x: Int, y: Int): Int? {
|
||||
return layerTerrainLowBits.getData(x fmod width, y)
|
||||
val (x, y) = coerceXY(x, y)
|
||||
return layerTerrainLowBits.getData(x, y)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,7 +201,8 @@ open class GameWorld {
|
||||
* @param combinedTilenum (tilenum * 16) + damage
|
||||
*/
|
||||
fun setTileWall(x: Int, y: Int, combinedTilenum: Int) {
|
||||
setTileWall(x fmod width, y, (combinedTilenum / PairedMapLayer.RANGE).toByte(), combinedTilenum % PairedMapLayer.RANGE)
|
||||
val (x, y) = coerceXY(x, y)
|
||||
setTileWall(x, y, (combinedTilenum / PairedMapLayer.RANGE).toByte(), combinedTilenum % PairedMapLayer.RANGE)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,23 +214,37 @@ open class GameWorld {
|
||||
* @param combinedTilenum (tilenum * 16) + damage
|
||||
*/
|
||||
fun setTileTerrain(x: Int, y: Int, combinedTilenum: Int) {
|
||||
setTileTerrain(x fmod width, y, (combinedTilenum / PairedMapLayer.RANGE).toByte(), combinedTilenum % PairedMapLayer.RANGE)
|
||||
val (x, y) = coerceXY(x, y)
|
||||
setTileTerrain(x, y, (combinedTilenum / PairedMapLayer.RANGE).toByte(), combinedTilenum % PairedMapLayer.RANGE)
|
||||
}
|
||||
|
||||
fun setTileWall(x: Int, y: Int, tile: Byte, damage: Int) {
|
||||
layerWall.setTile(x fmod width, y, tile)
|
||||
layerWallLowBits.setData(x fmod width, y, damage)
|
||||
val (x, y) = coerceXY(x, y)
|
||||
layerWall.setTile(x, y, tile)
|
||||
layerWallLowBits.setData(x, y, damage)
|
||||
wallDamages.remove(LandUtil.getBlockAddr(this, x, y))
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning: this function alters fluid lists: be wary of call order!
|
||||
*/
|
||||
fun setTileTerrain(x: Int, y: Int, tile: Byte, damage: Int) {
|
||||
layerTerrain.setTile(x fmod width, y, tile)
|
||||
layerTerrainLowBits.setData(x fmod width, y, damage)
|
||||
terrainDamages.remove(LandUtil.getBlockAddr(this, x, y))
|
||||
val (x, y) = coerceXY(x, y)
|
||||
layerTerrain.setTile(x, y, tile)
|
||||
layerTerrainLowBits.setData(x, y, damage)
|
||||
val blockAddr = LandUtil.getBlockAddr(this, x, y)
|
||||
terrainDamages.remove(blockAddr)
|
||||
|
||||
if (BlockCodex[tile * PairedMapLayer.RANGE + damage].isSolid) {
|
||||
fluidFills.remove(blockAddr)
|
||||
fluidTypes.remove(blockAddr)
|
||||
}
|
||||
// fluid tiles-item should be modified so that they will also place fluid onto their respective map
|
||||
}
|
||||
|
||||
fun setTileWire(x: Int, y: Int, tile: Byte) {
|
||||
layerWire.setTile(x fmod width, y, tile)
|
||||
val (x, y) = coerceXY(x, y)
|
||||
layerWire.setTile(x, y, tile)
|
||||
}
|
||||
|
||||
fun getTileFrom(mode: Int, x: Int, y: Int): Int? {
|
||||
@@ -293,6 +326,7 @@ open class GameWorld {
|
||||
// remove tile from the world
|
||||
if (terrainDamages[addr] ?: 0f >= BlockCodex[getTileFromTerrain(x, y)].strength) {
|
||||
setTileTerrain(x, y, 0)
|
||||
terrainDamages.remove(addr)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -321,6 +355,7 @@ open class GameWorld {
|
||||
// remove tile from the world
|
||||
if (wallDamages[addr]!! >= BlockCodex[getTileFromWall(x, y)].strength) {
|
||||
setTileWall(x, y, 0)
|
||||
wallDamages.remove(addr)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -329,30 +364,88 @@ open class GameWorld {
|
||||
fun getWallDamage(x: Int, y: Int): Float =
|
||||
wallDamages[LandUtil.getBlockAddr(this, x, y)] ?: 0f
|
||||
|
||||
fun setFluid(x: Int, y: Int, fluidType: FluidType, fill: Float) {
|
||||
/*if (x == 60 && y == 256) {
|
||||
printdbg(this, "Setting fluid $fill at ($x,$y)")
|
||||
}*/
|
||||
|
||||
|
||||
if (fluidType == Fluid.NULL && fill != 0f) {
|
||||
throw Error("Illegal fluid at ($x,$y): ${FluidInfo(fluidType, fill)}")
|
||||
}
|
||||
|
||||
|
||||
val addr = LandUtil.getBlockAddr(this, x, y)
|
||||
|
||||
if (fill > WorldSimulator.FLUID_MIN_MASS) {
|
||||
//setTileTerrain(x, y, fluidTypeToBlock(fluidType))
|
||||
fluidFills[addr] = fill
|
||||
fluidTypes[addr] = fluidType
|
||||
}
|
||||
else {
|
||||
fluidFills.remove(addr)
|
||||
fluidTypes.remove(addr)
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*if (x == 60 && y == 256) {
|
||||
printdbg(this, "TileTerrain: ${getTileFromTerrain(x, y)}")
|
||||
printdbg(this, "fluidTypes[$addr] = ${fluidTypes[addr]} (should be ${fluidType.value})")
|
||||
printdbg(this, "fluidFills[$addr] = ${fluidFills[addr]} (should be $fill)")
|
||||
}*/
|
||||
}
|
||||
|
||||
fun getFluid(x: Int, y: Int): FluidInfo {
|
||||
val addr = LandUtil.getBlockAddr(this, x, y)
|
||||
val fill = fluidFills[addr]
|
||||
val type = fluidTypes[addr]
|
||||
return if (type == null) FluidInfo(Fluid.NULL, 0f) else FluidInfo(type, fill!!)
|
||||
}
|
||||
|
||||
private fun fluidTypeToBlock(type: FluidType) = when (type.abs()) {
|
||||
Fluid.NULL.value -> Block.AIR
|
||||
in Fluid.fluidRange -> GameWorld.TILES_SUPPORTED - type.abs()
|
||||
else -> throw IllegalArgumentException("Unsupported fluid type: $type")
|
||||
}
|
||||
|
||||
data class FluidInfo(val type: FluidType, val amount: Float) {
|
||||
/** test if this fluid should be considered as one */
|
||||
fun isFluid() = type != Fluid.NULL && amount >= WorldSimulator.FLUID_MIN_MASS
|
||||
fun getProp() = FluidCodex[type]
|
||||
override fun toString() = "Fluid type: ${type.value}, amount: $amount"
|
||||
}
|
||||
|
||||
|
||||
fun getTemperature(worldTileX: Int, worldTileY: Int): Float? {
|
||||
return null
|
||||
//return layerThermal.getValue((worldTileX fmod width) / 2, worldTileY / 2)
|
||||
}
|
||||
|
||||
fun getAirPressure(worldTileX: Int, worldTileY: Int): Float? {
|
||||
return null
|
||||
//return layerAirPressure.getValue((worldTileX fmod width) / 4, worldTileY / 8)
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun Int.coerceWorld() = this.coerceIn(0, height - 1)
|
||||
|
||||
companion object {
|
||||
|
||||
@Transient val WALL = 0
|
||||
@Transient val TERRAIN = 1
|
||||
@Transient val WIRE = 2
|
||||
|
||||
/** 4096 */
|
||||
@Transient val TILES_SUPPORTED = MapLayer.RANGE * PairedMapLayer.RANGE
|
||||
@Transient val SIZEOF: Byte = MapLayer.SIZEOF
|
||||
@Transient val LAYERS: Byte = 4 // terrain, wall (layerTerrainLowBits + layerWallLowBits), wire
|
||||
|
||||
fun makeNullWorld() = GameWorld(-1, 1, 1, 0, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
infix fun Int.fmod(other: Int) = Math.floorMod(this, other)
|
||||
infix fun Float.fmod(other: Float) = if (this >= 0f) this % other else (this % other) + other
|
||||
|
||||
inline class FluidType(val value: Int) {
|
||||
infix fun sameAs(other: FluidType) = this.value.absoluteValue == other.value.absoluteValue
|
||||
fun abs() = this.value.absoluteValue
|
||||
}
|
||||
@@ -11,13 +11,13 @@ import net.torvald.dataclass.Float16Bits
|
||||
open class MapLayerHalfFloat(val width: Int, val height: Int) : Iterable<Float16Bits> {
|
||||
|
||||
constructor(width: Int, height: Int, init: Float) : this(width, height) {
|
||||
data = Array(height) { Array(width, { Float16.fromFloat(init) }) }
|
||||
data = Array(height) { Array(width) { Float16.fromFloat(init) } }
|
||||
}
|
||||
|
||||
internal @Volatile var data: Array<Array<Float16Bits>> // in parallel programming: do not trust your register; always read freshly from RAM!
|
||||
|
||||
init {
|
||||
data = Array(height) { Array(width, { 0.toShort() }) }
|
||||
data = Array(height) { Array(width) { 0.toShort() } }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,11 +27,13 @@ object TinyAlphNum : BitmapFont() {
|
||||
return W * str.length
|
||||
}
|
||||
|
||||
lateinit var colourHolder: Color
|
||||
lateinit var colMain: Color
|
||||
lateinit var colShadow: Color
|
||||
|
||||
override fun draw(batch: Batch, text: CharSequence, x: Float, y: Float): GlyphLayout? {
|
||||
val originalColour = batch.color
|
||||
colourHolder = batch.color
|
||||
val originalColour = batch.color.cpy()
|
||||
colMain = batch.color.cpy()
|
||||
colShadow = colMain.cpy().mul(0.5f, 0.5f, 0.5f, 1f)
|
||||
|
||||
val x = x.round()
|
||||
val y = y.round()
|
||||
@@ -43,16 +45,17 @@ object TinyAlphNum : BitmapFont() {
|
||||
val cclow = text[index + 1]
|
||||
val colour = getColour(cchigh, cclow)
|
||||
|
||||
colourHolder = colour
|
||||
colMain = colour
|
||||
colShadow = colMain.cpy().mul(0.5f, 0.5f, 0.5f, 1f)
|
||||
}
|
||||
else if (c in 0.toChar()..255.toChar()) {
|
||||
batch.color = colourHolder.cpy().mul(0.5f, 0.5f, 0.5f, 1f)
|
||||
batch.color = colShadow
|
||||
batch.draw(fontSheet.get(c.toInt() % 16, c.toInt() / 16), x + charsPrinted * W + 1, y)
|
||||
batch.draw(fontSheet.get(c.toInt() % 16, c.toInt() / 16), x + charsPrinted * W, y + 1)
|
||||
batch.draw(fontSheet.get(c.toInt() % 16, c.toInt() / 16), x + charsPrinted * W + 1, y + 1)
|
||||
|
||||
|
||||
batch.color = colourHolder.cpy()
|
||||
batch.color = colMain
|
||||
batch.draw(fontSheet.get(c.toInt() % 16, c.toInt() / 16), x + charsPrinted * W, y)
|
||||
|
||||
charsPrinted += 1
|
||||
|
||||
@@ -47,9 +47,10 @@ abstract class GameItem : Comparable<GameItem>, Cloneable {
|
||||
|
||||
var nameColour = Color.WHITE
|
||||
|
||||
|
||||
/** In kg */
|
||||
abstract var baseMass: Double
|
||||
|
||||
/** In kg */
|
||||
abstract var baseToolSize: Double?
|
||||
|
||||
abstract var inventoryCategory: String // "weapon", "tool", "armor", etc. (all smallcaps)
|
||||
|
||||
@@ -3,12 +3,12 @@ package net.torvald.terrarum.itemproperties
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.terrarum.KVHashMap
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.CanBeAnItem
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.blockproperties.Fluid
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.worlddrawer.BlocksDrawer
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer.TILE_SIZE
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.CanBeAnItem
|
||||
import net.torvald.terrarum.worlddrawer.BlocksDrawer
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
@@ -26,18 +26,20 @@ object ItemCodex {
|
||||
val ITEM_TILES = 0..GameWorld.TILES_SUPPORTED - 1
|
||||
val ITEM_WALLS = GameWorld.TILES_SUPPORTED..GameWorld.TILES_SUPPORTED * 2 - 1
|
||||
val ITEM_WIRES = GameWorld.TILES_SUPPORTED * 2..GameWorld.TILES_SUPPORTED * 2 + 255
|
||||
val ITEM_STATIC = ITEM_WIRES.endInclusive + 1..32767
|
||||
val ITEM_DYNAMIC = 32768..0x0FFF_FFFF
|
||||
val ITEM_STATIC = ITEM_WIRES.endInclusive + 1..0x0F_FFFF
|
||||
val ITEM_DYNAMIC = 0x10_0000..0x0FFF_FFFF
|
||||
val ACTORID_MIN = ITEM_DYNAMIC.endInclusive + 1
|
||||
|
||||
private val itemImagePlaceholder = TextureRegion(Texture("./assets/item_kari_24.tga"))
|
||||
|
||||
//private val ingame = Terrarum.ingame!! as Ingame
|
||||
//private val ingame = Terrarum.ingame!! as Ingame // WARNING you can't put this here, ExceptionInInitializerError
|
||||
|
||||
|
||||
// TODO: when generalised, there's no guarantee that blocks will be used as an item. Write customised item prop loader and init it on the Ingame
|
||||
|
||||
init {
|
||||
//val ingame = Terrarum.ingame!! as Ingame // WARNING you can't put this here, ExceptionInInitializerError
|
||||
|
||||
|
||||
/*println("[ItemCodex] recording item ID ")
|
||||
|
||||
@@ -169,6 +171,34 @@ object ItemCodex {
|
||||
}*/
|
||||
|
||||
|
||||
// test water bucket
|
||||
itemCodex[9000] = object : GameItem() {
|
||||
override var dynamicID: ItemID = 9000
|
||||
override val originalID: ItemID = 9000
|
||||
|
||||
override val isUnique: Boolean = true
|
||||
override val originalName: String = "Infinite Water Bucket"
|
||||
|
||||
override var baseMass: Double = 1000.0
|
||||
override var baseToolSize: Double? = null
|
||||
|
||||
override var inventoryCategory: String = "tool"
|
||||
override var stackable: Boolean = false
|
||||
|
||||
override val isDynamic: Boolean = false
|
||||
override val material: Material = Material(1,1,1,1,1,1,1,1,1,1.0)
|
||||
|
||||
override val equipPosition: Int = EquipPosition.HAND_GRIP
|
||||
|
||||
override fun startSecondaryUse(delta: Float): Boolean {
|
||||
val ingame = Terrarum.ingame!! as Ingame // must be in here
|
||||
ingame.world.setFluid(Terrarum.mouseTileX, Terrarum.mouseTileY, Fluid.WATER, 1f)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// read from save (if applicable) and fill dynamicItemDescription
|
||||
|
||||
|
||||
@@ -200,7 +230,9 @@ object ItemCodex {
|
||||
itemCodex[code] = item
|
||||
}
|
||||
|
||||
fun getItemImage(item: GameItem): TextureRegion {
|
||||
fun getItemImage(item: GameItem?): TextureRegion? {
|
||||
if (item == null) return null
|
||||
|
||||
// terrain
|
||||
if (item.originalID in ITEM_TILES) {
|
||||
return BlocksDrawer.tilesTerrain.get(
|
||||
@@ -211,8 +243,8 @@ object ItemCodex {
|
||||
// wall
|
||||
else if (item.originalID in ITEM_WALLS) {
|
||||
return BlocksDrawer.tileItemWall.get(
|
||||
(item.originalID.minus(ITEM_WALLS.first) % 16) * TILE_SIZE,
|
||||
(item.originalID.minus(ITEM_WALLS.first) / 16) * TILE_SIZE
|
||||
(item.originalID.minus(ITEM_WALLS.first) % 16) * 16,
|
||||
(item.originalID.minus(ITEM_WALLS.first) / 16)
|
||||
)
|
||||
}
|
||||
// wire
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
package net.torvald.terrarum.modulebasegame
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.InputAdapter
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.IngameInstance
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.Yaml
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.gameactors.*
|
||||
import net.torvald.terrarum.gamecontroller.KeyToggler
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||
import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension
|
||||
import net.torvald.terrarum.modulebasegame.gameworld.WorldTime
|
||||
import net.torvald.terrarum.modulebasegame.ui.Notification
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIBuildingMakerToolbox
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarum.ui.UINSMenu
|
||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
@@ -23,6 +27,32 @@ import kotlin.system.measureNanoTime
|
||||
*/
|
||||
class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
private val menuYaml = Yaml("""
|
||||
- File
|
||||
- New
|
||||
- Export…
|
||||
- Export sel…
|
||||
- Import…
|
||||
- Save world…
|
||||
- Load world…
|
||||
- Tool
|
||||
- Pencil
|
||||
- Eyedropper
|
||||
- Select mrq.
|
||||
- Move
|
||||
- Undo
|
||||
- Redo
|
||||
- Time
|
||||
- Morning
|
||||
- Noon
|
||||
- Dusk
|
||||
- Night
|
||||
- Set…
|
||||
- Weather
|
||||
- Sunny
|
||||
- Raining
|
||||
""".trimIndent())
|
||||
|
||||
private val timeNow = System.currentTimeMillis() / 1000
|
||||
|
||||
val gameWorld = GameWorldExtension(1, 1024, 256, timeNow, timeNow, 0)
|
||||
@@ -49,23 +79,29 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
override var actorNowPlaying: ActorHumanoid? = MovableWorldCamera()
|
||||
|
||||
val uiToolbox = UIBuildingMakerToolbox()
|
||||
val uiToolbox = UINSMenu("Menu", 100, menuYaml)
|
||||
val notifier = Notification()
|
||||
|
||||
val uiContainer = ArrayList<UICanvas>()
|
||||
|
||||
val blockPointingCursor = object : ActorWithBody(Actor.RenderOrder.FRONT) {
|
||||
val blockPointingCursor = object : ActorWithBody(Actor.RenderOrder.OVERLAY) {
|
||||
|
||||
override var referenceID: ActorID? = Terrarum.generateUniqueReferenceID(renderOrder)
|
||||
val body = TextureRegionPack(Gdx.files.internal("assets/graphics/blocks/block_markings_common.tga"), 16, 16)
|
||||
override val hitbox = Hitbox(0.0, 0.0, 16.0, 16.0)
|
||||
|
||||
init {
|
||||
this.actorValue[AVKey.LUMR] = 1.0
|
||||
this.actorValue[AVKey.LUMG] = 1.0
|
||||
}
|
||||
|
||||
override fun drawBody(batch: SpriteBatch) {
|
||||
batch.color = Color.YELLOW
|
||||
batch.draw(body.get(0, 0), hitbox.startX.toFloat(), hitbox.startY.toFloat())
|
||||
}
|
||||
|
||||
override fun drawGlow(batch: SpriteBatch) { }
|
||||
|
||||
override fun dispose() {
|
||||
body.dispose()
|
||||
}
|
||||
@@ -84,20 +120,21 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
}
|
||||
|
||||
protected var updateDeltaCounter = 0.0
|
||||
protected val updateRate = 1.0 / Terrarum.TARGET_INTERNAL_FPS
|
||||
|
||||
private val actorsRenderTop = ArrayList<ActorWithBody>()
|
||||
private val actorsRenderOverlay = ArrayList<ActorWithBody>()
|
||||
|
||||
init {
|
||||
actorsRenderTop.add(blockPointingCursor)
|
||||
gameWorld.time.setTimeOfToday(WorldTime.HOUR_SEC * 10)
|
||||
gameWorld.globalLight = Color(.8f,.8f,.8f,.8f)
|
||||
|
||||
actorsRenderOverlay.add(blockPointingCursor)
|
||||
|
||||
uiContainer.add(uiToolbox)
|
||||
uiContainer.add(notifier)
|
||||
|
||||
|
||||
|
||||
uiToolbox.setPosition(Terrarum.WIDTH - 20, 4)
|
||||
uiToolbox.setPosition(0, 0)
|
||||
uiToolbox.isVisible = true
|
||||
notifier.setPosition(
|
||||
(Terrarum.WIDTH - notifier.width) / 2, Terrarum.HEIGHT - notifier.height)
|
||||
|
||||
@@ -109,6 +146,11 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
LightmapRenderer.fireRecalculateEvent()
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
Gdx.input.inputProcessor = BuildingMakerController(this)
|
||||
super.show()
|
||||
}
|
||||
|
||||
override fun render(delta: Float) {
|
||||
Gdx.graphics.setTitle(Ingame.getCanonicalTitle())
|
||||
|
||||
@@ -116,38 +158,16 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
// ASYNCHRONOUS UPDATE AND RENDER //
|
||||
|
||||
|
||||
/** UPDATE CODE GOES HERE */
|
||||
updateDeltaCounter += delta
|
||||
// TODO async update
|
||||
updateGame(delta)
|
||||
|
||||
|
||||
|
||||
if (false && Terrarum.getConfigBoolean("multithread")) { // NO MULTITHREADING: camera don't like concurrent modification (jittery actor movements)
|
||||
// else, NOP;
|
||||
}
|
||||
else {
|
||||
var updateTries = 0
|
||||
while (updateDeltaCounter >= updateRate) {
|
||||
|
||||
//updateGame(delta)
|
||||
Terrarum.debugTimers["Ingame.update"] = measureNanoTime { updateGame(delta) }
|
||||
|
||||
updateDeltaCounter -= updateRate
|
||||
updateTries++
|
||||
|
||||
if (updateTries >= Terrarum.UPDATE_CATCHUP_MAX_TRIES) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** RENDER CODE GOES HERE */
|
||||
//renderGame(batch)
|
||||
Terrarum.debugTimers["Ingame.render"] = measureNanoTime { renderGame() }
|
||||
// render? just do it anyway
|
||||
renderGame()
|
||||
}
|
||||
|
||||
private fun updateGame(delta: Float) {
|
||||
KeyToggler.update(false)
|
||||
|
||||
blockPointingCursor.update(delta)
|
||||
actorNowPlaying?.update(delta)
|
||||
uiContainer.forEach { it.update(delta) }
|
||||
@@ -156,18 +176,63 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
private fun renderGame() {
|
||||
IngameRenderer(world as GameWorldExtension, actorsRenderFront = actorsRenderTop, uisToDraw = uiContainer)
|
||||
IngameRenderer(world as GameWorldExtension, actorsRenderOverlay = actorsRenderOverlay, uisToDraw = uiContainer)
|
||||
}
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
IngameRenderer.resize(Terrarum.WIDTH, Terrarum.HEIGHT)
|
||||
uiToolbox.setPosition(Terrarum.WIDTH - 20, 4)
|
||||
uiToolbox.setPosition(0, 0)
|
||||
notifier.setPosition(
|
||||
(Terrarum.WIDTH - notifier.width) / 2, Terrarum.HEIGHT - notifier.height)
|
||||
println("[BuildingMaker] Resize event")
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
IngameRenderer.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
class BuildingMakerController(val screen: BuildingMaker) : InputAdapter() {
|
||||
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
screen.uiContainer.forEach { it.touchUp(screenX, screenY, pointer, button) }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun mouseMoved(screenX: Int, screenY: Int): Boolean {
|
||||
screen.uiContainer.forEach { it.mouseMoved(screenX, screenY) }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun keyTyped(character: Char): Boolean {
|
||||
screen.uiContainer.forEach { it.keyTyped(character) }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun scrolled(amount: Int): Boolean {
|
||||
screen.uiContainer.forEach { it.scrolled(amount) }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun keyUp(keycode: Int): Boolean {
|
||||
screen.uiContainer.forEach { it.keyUp(keycode) }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
|
||||
screen.uiContainer.forEach { it.touchDragged(screenX, screenY, pointer) }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun keyDown(keycode: Int): Boolean {
|
||||
screen.uiContainer.forEach { it.keyDown(keycode) }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
screen.uiContainer.forEach { it.touchDown(screenX, screenY, pointer, button) }
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class MovableWorldCamera : ActorHumanoid(0, usePhysics = false) {
|
||||
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
package net.torvald.terrarum.modulebasegame
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
|
||||
import net.torvald.dataclass.CircularArray
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.AppLoader.printdbg
|
||||
import net.torvald.terrarum.blockproperties.BlockPropUtil
|
||||
import net.torvald.terrarum.blockstats.BlockStats
|
||||
import net.torvald.terrarum.concurrent.ThreadParallel
|
||||
import net.torvald.terrarum.gameactors.*
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.physicssolver.CollisionSolver
|
||||
import net.torvald.terrarum.console.Authenticator
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.gamecontroller.IngameController
|
||||
import net.torvald.terrarum.gamecontroller.KeyToggler
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.gameworld.WorldSimulator
|
||||
import net.torvald.terrarum.modulebasegame.weather.WeatherMixer
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.AppLoader.printdbg
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.modulebasegame.console.AVTracker
|
||||
import net.torvald.terrarum.modulebasegame.console.ActorsList
|
||||
import net.torvald.terrarum.console.Authenticator
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.*
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.physicssolver.CollisionSolver
|
||||
import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension
|
||||
import net.torvald.terrarum.modulebasegame.gameworld.WorldSimulator
|
||||
import net.torvald.terrarum.modulebasegame.imagefont.Watch7SegMain
|
||||
import net.torvald.terrarum.modulebasegame.imagefont.WatchDotAlph
|
||||
import net.torvald.terrarum.modulebasegame.ui.*
|
||||
import net.torvald.terrarum.ui.*
|
||||
import net.torvald.terrarum.modulebasegame.weather.WeatherMixer
|
||||
import net.torvald.terrarum.modulebasegame.worldgenerator.RoguelikeRandomiser
|
||||
import net.torvald.terrarum.modulebasegame.worldgenerator.WorldGenerator
|
||||
import net.torvald.terrarum.ui.BasicDebugInfoWindow
|
||||
import net.torvald.terrarum.ui.ConsoleWindow
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import java.util.*
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.system.measureNanoTime
|
||||
|
||||
|
||||
@@ -47,14 +47,14 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
private val ACTOR_UPDATE_RANGE = 4096
|
||||
|
||||
lateinit var historicalFigureIDBucket: ArrayList<Int>
|
||||
var historicalFigureIDBucket: ArrayList<Int> = ArrayList<Int>()
|
||||
|
||||
|
||||
/**
|
||||
* list of Actors that is sorted by Actors' referenceID
|
||||
*/
|
||||
//val ACTORCONTAINER_INITIAL_SIZE = 64
|
||||
val PARTICLES_MAX = Terrarum.getConfigInt("maxparticles")
|
||||
val PARTICLES_MAX = AppLoader.getConfigInt("maxparticles")
|
||||
//val actorContainer = ArrayList<Actor>(ACTORCONTAINER_INITIAL_SIZE)
|
||||
//val actorContainerInactive = ArrayList<Actor>(ACTORCONTAINER_INITIAL_SIZE)
|
||||
val particlesContainer = CircularArray<ParticleBase>(PARTICLES_MAX)
|
||||
@@ -64,7 +64,13 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
private val actorsRenderMiddle = ArrayList<ActorWithBody>(ACTORCONTAINER_INITIAL_SIZE)
|
||||
private val actorsRenderMidTop = ArrayList<ActorWithBody>(ACTORCONTAINER_INITIAL_SIZE)
|
||||
private val actorsRenderFront = ArrayList<ActorWithBody>(ACTORCONTAINER_INITIAL_SIZE)
|
||||
private val actorsRenderOverlay= ArrayList<ActorWithBody>(ACTORCONTAINER_INITIAL_SIZE)
|
||||
|
||||
private var visibleActorsRenderBehind: List<ActorWithBody> = ArrayList(1)
|
||||
private var visibleActorsRenderMiddle: List<ActorWithBody> = ArrayList(1)
|
||||
private var visibleActorsRenderMidTop: List<ActorWithBody> = ArrayList(1)
|
||||
private var visibleActorsRenderFront: List<ActorWithBody> = ArrayList(1)
|
||||
private var visibleActorsRenderOverlay: List<ActorWithBody> = ArrayList(1)
|
||||
|
||||
//var screenZoom = 1.0f // definition moved to IngameInstance
|
||||
//val ZOOM_MAXIMUM = 4.0f // definition moved to IngameInstance
|
||||
@@ -79,8 +85,12 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
fun getCanonicalTitle() = AppLoader.GAME_NAME +
|
||||
" — F: ${Gdx.graphics.framesPerSecond} (Δt${Terrarum.updateRateStr} / RT${Terrarum.renderRateStr})" +
|
||||
" — M: J${Terrarum.memJavaHeap}M / N${Terrarum.memNativeHeap}M / X${Terrarum.memXmx}M"
|
||||
" — F: ${Gdx.graphics.framesPerSecond}" +
|
||||
if (AppLoader.IS_DEVELOPMENT_BUILD)
|
||||
" (ΔF${Terrarum.updateRateStr})" +
|
||||
" — M: J${Terrarum.memJavaHeap}M / N${Terrarum.memNativeHeap}M / X${Terrarum.memXmx}M"
|
||||
else
|
||||
""
|
||||
}
|
||||
|
||||
|
||||
@@ -111,11 +121,11 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
// UI aliases
|
||||
lateinit var uiAliases: ArrayList<UICanvas>
|
||||
private set
|
||||
lateinit var uiAlasesPausing: ArrayList<UICanvas>
|
||||
lateinit var uiAliasesPausing: ArrayList<UICanvas>
|
||||
private set
|
||||
|
||||
inline val paused: Boolean
|
||||
get() = uiAlasesPausing.map { if (it.isOpened) return true else 0 }.isEmpty() // isEmply is always false, which we want
|
||||
get() = uiAliasesPausing.map { if (it.isOpened) return true else 0 }.isEmpty() // isEmpty is always false, which we want
|
||||
/**
|
||||
* Set to false if UI is opened; set to true if UI is closed.
|
||||
*/
|
||||
@@ -132,10 +142,10 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
//private val ingameDrawThread: ThreadIngameDraw // draw must be on the main thread
|
||||
|
||||
|
||||
var gameInitialised = false
|
||||
private set
|
||||
var gameFullyLoaded = false
|
||||
private set
|
||||
override var gameInitialised = false
|
||||
internal set
|
||||
override var gameFullyLoaded = false
|
||||
internal set
|
||||
|
||||
|
||||
private val TILE_SIZEF = FeaturesDrawer.TILE_SIZE.toFloat()
|
||||
@@ -168,7 +178,8 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
//BlocksDrawer.world = this.world
|
||||
FeaturesDrawer.world = this.world
|
||||
|
||||
gameInitialised = true
|
||||
|
||||
super.show() // gameInitialised = true
|
||||
}
|
||||
|
||||
data class GameSaveData(
|
||||
@@ -245,22 +256,6 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
|
||||
historicalFigureIDBucket = ArrayList<Int>()
|
||||
|
||||
|
||||
|
||||
// add new player and put it to actorContainer
|
||||
//playableActorDelegate = PlayableActorDelegate(PlayerBuilderSigrid())
|
||||
//playableActorDelegate = PlayableActorDelegate(PlayerBuilderTestSubject1())
|
||||
//addNewActor(player)
|
||||
|
||||
|
||||
// test actor
|
||||
//addNewActor(PlayerBuilderCynthia())
|
||||
|
||||
|
||||
// it won't work:
|
||||
//setTheRealGamerFirstTime(PlayerBuilderSigrid())
|
||||
// because NO GL CONTEXT IN THIS THREAD, might want 'postInit()'?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +263,8 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
/** Load rest of the game with GL context */
|
||||
fun postInit() {
|
||||
setTheRealGamerFirstTime(PlayerBuilderSigrid())
|
||||
//setTheRealGamerFirstTime(PlayerBuilderSigrid())
|
||||
setTheRealGamerFirstTime(PlayerBuilderTestSubject1())
|
||||
|
||||
|
||||
|
||||
@@ -303,25 +299,25 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
width = 900,
|
||||
height = Terrarum.HEIGHT - 160,
|
||||
categoryWidth = 210,
|
||||
toggleKeyLiteral = Terrarum.getConfigInt("keyinventory")
|
||||
toggleKeyLiteral = AppLoader.getConfigInt("keyinventory")
|
||||
)*/
|
||||
/*uiInventoryPlayer.setPosition(
|
||||
-uiInventoryPlayer.width,
|
||||
70
|
||||
)*/
|
||||
uiInventoryPlayer = UIInventoryFull(actorNowPlaying,
|
||||
toggleKeyLiteral = Terrarum.getConfigInt("keyinventory")
|
||||
toggleKeyLiteral = AppLoader.getConfigInt("keyinventory")
|
||||
)
|
||||
uiInventoryPlayer.setPosition(0, 0)
|
||||
|
||||
// >- lesser UIs -<
|
||||
// quick bar
|
||||
uiQuickBar = UIQuickBar()
|
||||
uiQuickBar = UIQuickslotBar()
|
||||
uiQuickBar.isVisible = true
|
||||
uiQuickBar.setPosition((Terrarum.WIDTH - uiQuickBar.width) / 2 + 12, -10)
|
||||
uiQuickBar.setPosition((Terrarum.WIDTH - uiQuickBar.width) / 2, 8)
|
||||
|
||||
// pie menu
|
||||
uiPieMenu = UIPieMenu()
|
||||
uiPieMenu = uiQuickslotPie()
|
||||
uiPieMenu.setPosition(Terrarum.HALFW, Terrarum.HALFH)
|
||||
|
||||
// vital metre
|
||||
@@ -364,13 +360,13 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
uiTooltip
|
||||
// drawn last
|
||||
)
|
||||
uiAlasesPausing = arrayListOf(
|
||||
uiAliasesPausing = arrayListOf(
|
||||
uiInventoryPlayer,
|
||||
//uiInventoryContainer,
|
||||
consoleHandler,
|
||||
uiCheatMotherfuckerNootNoot
|
||||
)
|
||||
uiAlasesPausing.forEach { addUI(it) } // put them all to the UIContainer
|
||||
uiAliasesPausing.forEach { addUI(it) } // put them all to the UIContainer
|
||||
uiAliases.forEach { addUI(it) } // put them all to the UIContainer
|
||||
|
||||
|
||||
@@ -388,6 +384,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
LightmapRenderer.fireRecalculateEvent()
|
||||
|
||||
|
||||
AppLoader.debugTimers["Ingame.updateCounter"] = 0
|
||||
|
||||
|
||||
|
||||
@@ -417,9 +414,6 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
itemOnGrip?.endSecondaryUse(delta)
|
||||
}
|
||||
|
||||
protected var updateDeltaCounter = 0.0
|
||||
protected val renderRate = Terrarum.renderRate
|
||||
|
||||
private var firstTimeRun = true
|
||||
|
||||
///////////////
|
||||
@@ -427,19 +421,13 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
///////////////
|
||||
private class ThreadIngameUpdate(val ingame: Ingame): Runnable {
|
||||
override fun run() {
|
||||
var updateTries = 0
|
||||
while (ingame.updateDeltaCounter >= ingame.renderRate) {
|
||||
ingame.updateGame(Terrarum.deltaTime)
|
||||
ingame.updateDeltaCounter -= ingame.renderRate
|
||||
updateTries++
|
||||
|
||||
if (updateTries >= Terrarum.UPDATE_CATCHUP_MAX_TRIES) {
|
||||
break
|
||||
}
|
||||
}
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
|
||||
private var countdownToDeltaReset = 15 // number of frames
|
||||
private var updateAkku = 0.0
|
||||
|
||||
override fun render(delta: Float) {
|
||||
// Q&D solution for LoadScreen and Ingame, where while LoadScreen is working, Ingame now no longer has GL Context
|
||||
// there's still things to load which needs GL context to be present
|
||||
@@ -460,49 +448,34 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
|
||||
if (countdownToDeltaReset >= 0) {
|
||||
if (countdownToDeltaReset == 0) {
|
||||
AppLoader.resetDeltaSmoothingHistory()
|
||||
}
|
||||
countdownToDeltaReset -= 1
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Gdx.graphics.setTitle(getCanonicalTitle())
|
||||
|
||||
// ASYNCHRONOUS UPDATE AND RENDER //
|
||||
|
||||
|
||||
/** UPDATE CODE GOES HERE */
|
||||
updateDeltaCounter += delta
|
||||
val dt = AppLoader.getSmoothDelta()
|
||||
updateAkku += dt
|
||||
|
||||
|
||||
|
||||
if (false && Terrarum.getConfigBoolean("multithread")) { // NO MULTITHREADING: camera don't like concurrent modification (jittery actor movements)
|
||||
if (firstTimeRun || updateThreadWrapper.state == Thread.State.TERMINATED) {
|
||||
updateThreadWrapper = Thread(ingameUpdateThread, "Terrarum UpdateThread")
|
||||
updateThreadWrapper.start()
|
||||
|
||||
if (firstTimeRun) firstTimeRun = false
|
||||
}
|
||||
// else, NOP;
|
||||
}
|
||||
else {
|
||||
var updateTries = 0
|
||||
while (updateDeltaCounter >= renderRate) {
|
||||
|
||||
//updateGame(delta)
|
||||
Terrarum.debugTimers["Ingame.update"] = measureNanoTime { updateGame(delta) }
|
||||
|
||||
updateDeltaCounter -= renderRate
|
||||
updateTries++
|
||||
|
||||
if (updateTries >= Terrarum.UPDATE_CATCHUP_MAX_TRIES) {
|
||||
break
|
||||
}
|
||||
}
|
||||
var i = 0L
|
||||
while (updateAkku >= delta) {
|
||||
AppLoader.debugTimers["Ingame.update"] = measureNanoTime { updateGame(delta) }
|
||||
updateAkku -= delta
|
||||
i += 1
|
||||
}
|
||||
AppLoader.debugTimers["Ingame.updateCounter"] = i
|
||||
|
||||
|
||||
|
||||
/** RENDER CODE GOES HERE */
|
||||
//renderGame(batch)
|
||||
Terrarum.debugTimers["Ingame.render"] = measureNanoTime { renderGame() }
|
||||
AppLoader.debugTimers["Ingame.render"] = measureNanoTime { renderGame() }
|
||||
AppLoader.debugTimers["Ingame.render-Light"] =
|
||||
(AppLoader.debugTimers["Ingame.render"] as Long) - ((AppLoader.debugTimers["Renderer.LightTotal"] as? Long) ?: 0)
|
||||
}
|
||||
|
||||
protected fun updateGame(delta: Float) {
|
||||
@@ -522,7 +495,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
///////////////////////////
|
||||
BlockPropUtil.dynamicLumFuncTickClock()
|
||||
world.updateWorldTime(delta)
|
||||
//WorldSimulator(player, delta)
|
||||
WorldSimulator.invoke(actorNowPlaying, delta)
|
||||
WeatherMixer.update(delta, actorNowPlaying, world)
|
||||
BlockStats.update()
|
||||
|
||||
@@ -549,6 +522,13 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
particlesContainer.forEach { if (!it.flagDespawn) particlesActive++; it.update(delta) }
|
||||
// TODO thread pool(?)
|
||||
CollisionSolver.process()
|
||||
|
||||
|
||||
visibleActorsRenderBehind = actorsRenderBehind.filter { it.inScreen() }
|
||||
visibleActorsRenderMiddle = actorsRenderMiddle.filter { it.inScreen() }
|
||||
visibleActorsRenderMidTop = actorsRenderMidTop.filter { it.inScreen() }
|
||||
visibleActorsRenderFront = actorsRenderFront.filter { it.inScreen() }
|
||||
visibleActorsRenderOverlay=actorsRenderOverlay.filter { it.inScreen() }
|
||||
}
|
||||
|
||||
|
||||
@@ -568,12 +548,15 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
|
||||
private fun renderGame() {
|
||||
Gdx.graphics.setTitle(getCanonicalTitle())
|
||||
|
||||
IngameRenderer.invoke(
|
||||
world as GameWorldExtension,
|
||||
actorsRenderBehind,
|
||||
actorsRenderMiddle,
|
||||
actorsRenderMidTop,
|
||||
actorsRenderFront,
|
||||
visibleActorsRenderBehind,
|
||||
visibleActorsRenderMiddle,
|
||||
visibleActorsRenderMidTop,
|
||||
visibleActorsRenderFront,
|
||||
visibleActorsRenderOverlay,
|
||||
particlesContainer,
|
||||
actorNowPlaying,
|
||||
uiContainer
|
||||
@@ -598,7 +581,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
actorNowPlaying = newActor
|
||||
WorldSimulator(actorNowPlaying, Terrarum.deltaTime)
|
||||
//WorldSimulator(actorNowPlaying, AppLoader.getSmoothDelta().toFloat())
|
||||
}
|
||||
|
||||
private fun changePossession(refid: Int) {
|
||||
@@ -782,6 +765,10 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
val i = actorsRenderFront.binarySearch(actor.referenceID!!)
|
||||
actorsRenderFront.removeAt(i)
|
||||
}
|
||||
Actor.RenderOrder.OVERLAY-> {
|
||||
val i = actorsRenderOverlay.binarySearch(actor.referenceID!!)
|
||||
actorsRenderFront.removeAt(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -817,6 +804,9 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
Actor.RenderOrder.FRONT -> {
|
||||
actorsRenderFront.add(actor); insertionSortLastElemAV(actorsRenderFront)
|
||||
}
|
||||
Actor.RenderOrder.OVERLAY-> {
|
||||
actorsRenderOverlay.add(actor); insertionSortLastElemAV(actorsRenderOverlay)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -848,6 +838,9 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
Actor.RenderOrder.FRONT -> {
|
||||
actorsRenderFront.add(actor); insertionSortLastElemAV(actorsRenderFront)
|
||||
}
|
||||
Actor.RenderOrder.OVERLAY-> {
|
||||
actorsRenderOverlay.add(actor); insertionSortLastElemAV(actorsRenderOverlay)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -869,7 +862,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
private fun insertionSortLastElemAV(arr: ArrayList<ActorWithBody>) { // out-projection doesn't work, duh
|
||||
lock(ReentrantLock()) {
|
||||
ReentrantLock().lock {
|
||||
var j = arr.lastIndex - 1
|
||||
val x = arr.last()
|
||||
while (j >= 0 && arr[j] > x) {
|
||||
@@ -954,16 +947,17 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
actorsRenderMiddle.forEach { it.dispose() }
|
||||
actorsRenderMidTop.forEach { it.dispose() }
|
||||
actorsRenderFront.forEach { it.dispose() }
|
||||
actorsRenderOverlay.forEach { it.dispose() }
|
||||
|
||||
uiAliases.forEach { it.dispose() }
|
||||
uiAlasesPausing.forEach { it.dispose() }
|
||||
uiAliasesPausing.forEach { it.dispose() }
|
||||
|
||||
|
||||
WatchDotAlph.dispose()
|
||||
Watch7SegMain.dispose()
|
||||
WatchDotAlph.dispose()
|
||||
|
||||
ItemSlotImageBuilder.dispose()
|
||||
ItemSlotImageFactory.dispose()
|
||||
|
||||
MessageWindow.SEGMENT_BLACK.dispose()
|
||||
MessageWindow.SEGMENT_WHITE.dispose()
|
||||
@@ -975,4 +969,5 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
printdbg(this, "-> $it")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user