Compare commits
611 Commits
v1.0.1
...
customize-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
071563beb9 | ||
|
|
d631bfcdd0 | ||
|
|
4382d67c19 | ||
|
|
e38e7060d4 | ||
|
|
d6fc3bb2d8 | ||
|
|
82793d14f4 | ||
|
|
a5d252f19b | ||
|
|
e5d4d310c0 | ||
|
|
fa1621ff56 | ||
|
|
52e5611e1b | ||
|
|
d540a9ff04 | ||
|
|
1b6fe7e15b | ||
|
|
900140f8f7 | ||
|
|
14430c4f0a | ||
|
|
a1fc68f13a | ||
|
|
2e15d01be3 | ||
|
|
96335aebc9 | ||
|
|
6ab3c508e6 | ||
|
|
f790a10e88 | ||
|
|
6b879e71b8 | ||
|
|
9878e205e6 | ||
|
|
0a5afd1e18 | ||
|
|
625bf69b33 | ||
|
|
48c01eb8a1 | ||
|
|
b105517ab3 | ||
|
|
7d6371fd1c | ||
|
|
dc9824e2be | ||
|
|
60a0d3ab8c | ||
|
|
58c82f9268 | ||
|
|
8fcdbe0bee | ||
|
|
afff399fca | ||
|
|
080f999626 | ||
|
|
593f80144c | ||
|
|
4df9ee557d | ||
|
|
f6ba9d38fd | ||
|
|
c4cc713272 | ||
|
|
f9af163495 | ||
|
|
9d6f4d9686 | ||
|
|
2e14e4620e | ||
|
|
95d92d8bd0 | ||
|
|
d586e81827 | ||
|
|
67375a5857 | ||
|
|
3dbea2e400 | ||
|
|
bd7321b128 | ||
|
|
ad7b0e56ab | ||
|
|
e770e64a48 | ||
|
|
5956227dcb | ||
|
|
f443e365cc | ||
|
|
b443e21c6e | ||
|
|
19ed168d42 | ||
|
|
939211d640 | ||
|
|
0a9aaab4d1 | ||
|
|
9fb917c357 | ||
|
|
aa31185b35 | ||
|
|
ec0685ea19 | ||
|
|
2c7ab7f5c8 | ||
|
|
8de73ad774 | ||
|
|
3ceacf1001 | ||
|
|
31afb4d568 | ||
|
|
95cbba3920 | ||
|
|
16b044ae31 | ||
|
|
caea9cb4fb | ||
|
|
8325823493 | ||
|
|
8e1e8d483c | ||
|
|
1b18c2baa3 | ||
|
|
70d5830f00 | ||
|
|
401df384ef | ||
|
|
59af02cca9 | ||
|
|
c6565ac96a | ||
|
|
16f4ab7787 | ||
|
|
e23c4eddda | ||
|
|
601f0c7b44 | ||
|
|
f411d75643 | ||
|
|
81fce5f4a2 | ||
|
|
0e447c55a8 | ||
|
|
91806d8ccb | ||
|
|
a30fb4cfdd | ||
|
|
def8effa9f | ||
|
|
d46ee07583 | ||
|
|
ee19238667 | ||
|
|
0d83cff24e | ||
|
|
30a3bf9b71 | ||
|
|
8c61b0bd8c | ||
|
|
6e9f1ae517 | ||
|
|
ad3e0eb752 | ||
|
|
b40bfcc64a | ||
|
|
b706756ec9 | ||
|
|
427672741a | ||
|
|
bb3513956c | ||
|
|
84aecfa823 | ||
|
|
7f920fe13b | ||
|
|
9178abc53d | ||
|
|
84288612ef | ||
|
|
4a94b19f60 | ||
|
|
b0b161ceb5 | ||
|
|
1c2fd05bcd | ||
|
|
e0b18a8785 | ||
|
|
8929941d13 | ||
|
|
8d2d5df65f | ||
|
|
fe47d88035 | ||
|
|
29e81f3bf4 | ||
|
|
05b4c125e6 | ||
|
|
96573a7209 | ||
|
|
caf28a7286 | ||
|
|
25a3de62e7 | ||
|
|
fd3cd887b6 | ||
|
|
c3a6d07dc4 | ||
|
|
ed7ffac816 | ||
|
|
59c43590cc | ||
|
|
f14f37f970 | ||
|
|
cba1fc8f61 | ||
|
|
8329d2fcf6 | ||
|
|
1de7ef0151 | ||
|
|
f1f4cac316 | ||
|
|
6ce6639f10 | ||
|
|
c5ad0c294f | ||
|
|
f780969178 | ||
|
|
f3f61abc18 | ||
|
|
369a54f836 | ||
|
|
e9f3b34888 | ||
|
|
c1258cbb4c | ||
|
|
49804a52e6 | ||
|
|
e0e0db219c | ||
|
|
f93aa710a4 | ||
|
|
ca206da4af | ||
|
|
f6461a44dc | ||
|
|
3a271a399f | ||
|
|
ac1f4477ef | ||
|
|
708862ca24 | ||
|
|
57711cae5f | ||
|
|
f6e9a9d975 | ||
|
|
4cd40b33af | ||
|
|
053e70dde4 | ||
|
|
4b51b2f29b | ||
|
|
cdfd308193 | ||
|
|
7327588fc3 | ||
|
|
d16f0010ac | ||
|
|
a27b2496d4 | ||
|
|
a2d61dc7c4 | ||
|
|
093d4f23d8 | ||
|
|
3331ad02b0 | ||
|
|
661c689029 | ||
|
|
b1049fceb1 | ||
|
|
f933bff8ae | ||
|
|
9f08c73b3c | ||
|
|
4eaea0e3c0 | ||
|
|
c652312157 | ||
|
|
8cc48cf52a | ||
|
|
9faa427a28 | ||
|
|
480094a3eb | ||
|
|
1366b050b0 | ||
|
|
e68c2a4784 | ||
|
|
78ae0fb3bf | ||
|
|
127de14318 | ||
|
|
28d1d410d5 | ||
|
|
4b65bdf021 | ||
|
|
cbb9cbc6fd | ||
|
|
c72d8778ba | ||
|
|
d6c3d74b3f | ||
|
|
3c7248af5f | ||
|
|
fd9fa80204 | ||
|
|
3d5cb4c3f4 | ||
|
|
01a68af4a4 | ||
|
|
6a75ec07e9 | ||
|
|
1d310eb626 | ||
|
|
ffc440c809 | ||
|
|
a4daffa30e | ||
|
|
ccabbd7688 | ||
|
|
d27eafe03a | ||
|
|
7a45ac72f0 | ||
|
|
f6cfc1fa3a | ||
|
|
6dcbcb97ad | ||
|
|
769599c463 | ||
|
|
50d7c71db1 | ||
|
|
b07a7bcefd | ||
|
|
867d28ac62 | ||
|
|
d9a173678a | ||
|
|
dde3255b07 | ||
|
|
1506ae7048 | ||
|
|
ce5d07e09c | ||
|
|
2d8a637f7d | ||
|
|
8414effc04 | ||
|
|
3a17818ceb | ||
|
|
90d1545bb2 | ||
|
|
a7628ccaea | ||
|
|
3af2a49250 | ||
|
|
ffe90eef49 | ||
|
|
c4c2806071 | ||
|
|
fe035d8514 | ||
|
|
cf98070cd0 | ||
|
|
0ffcb107af | ||
|
|
cf5f865a23 | ||
|
|
37e4822ed5 | ||
|
|
bf639a2c4a | ||
|
|
89839be3af | ||
|
|
ec722475b6 | ||
|
|
32ed3c3271 | ||
|
|
03bf507893 | ||
|
|
681b7c388b | ||
|
|
fe0d767521 | ||
|
|
62c5c4757c | ||
|
|
70b0b61664 | ||
|
|
53a4437be9 | ||
|
|
42c541012c | ||
|
|
61293bd39c | ||
|
|
d641fefc13 | ||
|
|
666e5cf62d | ||
|
|
2565900f90 | ||
|
|
6b6fa3f111 | ||
|
|
a06097aef5 | ||
|
|
efdc2e0199 | ||
|
|
d6a74468da | ||
|
|
fcf8a87603 | ||
|
|
a8815229a0 | ||
|
|
aa99b2e1d3 | ||
|
|
63d8300c61 | ||
|
|
81c3ff9b1a | ||
|
|
a0652e2646 | ||
|
|
df3ac30de6 | ||
|
|
6ca1329720 | ||
|
|
129361836f | ||
|
|
cf4921de1e | ||
|
|
ecc6a8679b | ||
|
|
a39f149817 | ||
|
|
540cc1e08b | ||
|
|
ef34fdb519 | ||
|
|
9b02f600de | ||
|
|
0bb07dbd50 | ||
|
|
0a85ce520b | ||
|
|
99bc14cf3a | ||
|
|
527e152297 | ||
|
|
c8d45854ba | ||
|
|
11472e8be9 | ||
|
|
69e4adf5b3 | ||
|
|
a2eabd668b | ||
|
|
6d1273d325 | ||
|
|
e23b39abaa | ||
|
|
117b1d7b44 | ||
|
|
6398f8a79e | ||
|
|
81b9345303 | ||
|
|
249892716e | ||
|
|
3e8227a62b | ||
|
|
1570f860e8 | ||
|
|
d7c4589a55 | ||
|
|
0a9a1dc7ca | ||
|
|
42346f66b2 | ||
|
|
7ac651b736 | ||
|
|
0bb822ba60 | ||
|
|
075de8f837 | ||
|
|
36b5ceba8a | ||
|
|
f5d3cfb5e3 | ||
|
|
81210f46af | ||
|
|
c14f671a0d | ||
|
|
33141672ed | ||
|
|
28083cfea9 | ||
|
|
c9864741f3 | ||
|
|
5a230efd2b | ||
|
|
3aea6a98ef | ||
|
|
ba49abcea6 | ||
|
|
47f5be8340 | ||
|
|
d435185e9e | ||
|
|
dcd450a9b7 | ||
|
|
bfbf692cc0 | ||
|
|
2714dc1ea1 | ||
|
|
8604d9c401 | ||
|
|
b9261c3da2 | ||
|
|
ed7176b796 | ||
|
|
6cac53d20b | ||
|
|
ad3860790c | ||
|
|
bffe81d0b3 | ||
|
|
6ab08bd22b | ||
|
|
060c79fc20 | ||
|
|
ac64fde502 | ||
|
|
7496afa4f8 | ||
|
|
66955f893a | ||
|
|
9ee4cb4a26 | ||
|
|
a5cefd6c8b | ||
|
|
d040ea814a | ||
|
|
03145e4fcd | ||
|
|
812079004c | ||
|
|
6224af6178 | ||
|
|
a8d3cdd148 | ||
|
|
95cc863fde | ||
|
|
cc1562b056 | ||
|
|
07f3c82444 | ||
|
|
9976728e04 | ||
|
|
5922d15b1c | ||
|
|
248d6dfb92 | ||
|
|
73cc93a3e4 | ||
|
|
34259269a4 | ||
|
|
11217974c6 | ||
|
|
0e13989f9c | ||
|
|
57dcf42b5c | ||
|
|
c2c26db5d9 | ||
|
|
b6ee5fcbe9 | ||
|
|
0e11569397 | ||
|
|
4b137dac5f | ||
|
|
1f6d5ebbc9 | ||
|
|
462baa0a04 | ||
|
|
b74f3c368b | ||
|
|
a05ab09e1b | ||
|
|
1b0cd6d757 | ||
|
|
b8dea116ee | ||
|
|
e11f1af9ae | ||
|
|
9c34b26fec | ||
|
|
9a6d45541f | ||
|
|
f4775775b8 | ||
|
|
a48d744cde | ||
|
|
16dbe1122e | ||
|
|
b0cb70ffa6 | ||
|
|
512530c653 | ||
|
|
982d4cc0f9 | ||
|
|
3b951b8578 | ||
|
|
17a4ee8a68 | ||
|
|
c85cda4b48 | ||
|
|
c7ca358295 | ||
|
|
96296417c6 | ||
|
|
737076a126 | ||
|
|
c0908cf14f | ||
|
|
343911f736 | ||
|
|
281c1aa82a | ||
|
|
18afce71b0 | ||
|
|
9599d63f45 | ||
|
|
ce351988b5 | ||
|
|
feb3821565 | ||
|
|
54eaff26ea | ||
|
|
5a7ffde45e | ||
|
|
1c0385ad11 | ||
|
|
0fe6d88a3a | ||
|
|
7596d4d721 | ||
|
|
8333e553e2 | ||
|
|
6f62cfd466 | ||
|
|
280b55ab05 | ||
|
|
e02dcdf69d | ||
|
|
b5701fb9b9 | ||
|
|
c569b879f6 | ||
|
|
b36ac50425 | ||
|
|
029a84a113 | ||
|
|
e6fddd6905 | ||
|
|
b0b69bd780 | ||
|
|
6de4ac87df | ||
|
|
502c920656 | ||
|
|
c383fc6b95 | ||
|
|
4b03c714b4 | ||
|
|
0d93279a10 | ||
|
|
510d7bfe95 | ||
|
|
19d0d2919f | ||
|
|
42f01c8d45 | ||
|
|
0474199b5c | ||
|
|
8a4ce6c658 | ||
|
|
884034f0bf | ||
|
|
602ef7c1e1 | ||
|
|
897ff2bbd2 | ||
|
|
9ade107e95 | ||
|
|
1698cfa04b | ||
|
|
59639c60a3 | ||
|
|
f056f0e131 | ||
|
|
dc90beb696 | ||
|
|
90da2164f2 | ||
|
|
9d9e09e80f | ||
|
|
cd51e0cdd7 | ||
|
|
d49869f45c | ||
|
|
3a541d4b67 | ||
|
|
7471f9cdbe | ||
|
|
fe9ba9171e | ||
|
|
6c03e4e293 | ||
|
|
3f25c9265b | ||
|
|
fa475c754e | ||
|
|
5e9cf96106 | ||
|
|
a70912d311 | ||
|
|
67351b8b09 | ||
|
|
e0e0a1ee7d | ||
|
|
fa11122f87 | ||
|
|
ef54463fcc | ||
|
|
2255481d50 | ||
|
|
03a7e2e1b1 | ||
|
|
19bcfebe0d | ||
|
|
393d89f8c4 | ||
|
|
9c6286f94a | ||
|
|
fa058f24b4 | ||
|
|
b2420bdc80 | ||
|
|
23bee9fd62 | ||
|
|
3ec827d5c1 | ||
|
|
c692fc91af | ||
|
|
a38151bf2c | ||
|
|
b689b3a757 | ||
|
|
e7d68c4f72 | ||
|
|
bc43bdc99c | ||
|
|
e5aa4a3518 | ||
|
|
4e98093d6c | ||
|
|
1342fd3ecf | ||
|
|
3015f39368 | ||
|
|
37f7ecc1c3 | ||
|
|
bdf2c219ab | ||
|
|
3488833c2e | ||
|
|
4821cab724 | ||
|
|
0851354c8a | ||
|
|
2f42818a33 | ||
|
|
12367acb33 | ||
|
|
caa8b06d4f | ||
|
|
2b63360b95 | ||
|
|
8dd8d1c312 | ||
|
|
8ee0f478ad | ||
|
|
9c6daa4abe | ||
|
|
01f264e0c2 | ||
|
|
1bbd586cbb | ||
|
|
223930c464 | ||
|
|
40510539ee | ||
|
|
c47113ca29 | ||
|
|
ad9b8586e9 | ||
|
|
5b151634a5 | ||
|
|
7627092478 | ||
|
|
b60fe43b06 | ||
|
|
21aec548af | ||
|
|
beb010cd0f | ||
|
|
b23d05f850 | ||
|
|
e16659d96d | ||
|
|
4c1020af5f | ||
|
|
a4105d5826 | ||
|
|
ddae4df4ab | ||
|
|
74a9a9e530 | ||
|
|
223d214f57 | ||
|
|
a52fd4e70a | ||
|
|
266c727870 | ||
|
|
54d230432b | ||
|
|
9663532e44 | ||
|
|
a4e9123bcc | ||
|
|
08691ce319 | ||
|
|
d03fd5e43f | ||
|
|
7ddd8f2894 | ||
|
|
93a341bbaa | ||
|
|
d2c4538656 | ||
|
|
8a5c3bc97b | ||
|
|
db57fe6a5e | ||
|
|
56d798dd12 | ||
|
|
90942c46b2 | ||
|
|
1cda2beef7 | ||
|
|
8754a5d6c9 | ||
|
|
65f43804b3 | ||
|
|
9b150257fb | ||
|
|
32c7883f82 | ||
|
|
1c73fb7240 | ||
|
|
cce1bb223e | ||
|
|
624076ae9b | ||
|
|
8d61a19dbe | ||
|
|
0264c00ab8 | ||
|
|
e1f22b8218 | ||
|
|
fe4c125474 | ||
|
|
56d27400ac | ||
|
|
b5681984cd | ||
|
|
a541d0f24a | ||
|
|
20a41088c6 | ||
|
|
16ab9cb958 | ||
|
|
5f9ceb7f5d | ||
|
|
a1c1e03da0 | ||
|
|
ac0a044a32 | ||
|
|
4aae167bd8 | ||
|
|
2e5be31ed4 | ||
|
|
45278f66a5 | ||
|
|
2205077d36 | ||
|
|
67f966f7a9 | ||
|
|
463968d798 | ||
|
|
109dc6680c | ||
|
|
23c5f070fa | ||
|
|
fd9843f8dc | ||
|
|
443070226f | ||
|
|
db63d8a085 | ||
|
|
f203cfcc83 | ||
|
|
9ceb490f72 | ||
|
|
5b7a676b35 | ||
|
|
e50e26cf87 | ||
|
|
f59c072d68 | ||
|
|
79c396c1a0 | ||
|
|
9bb053b3ba | ||
|
|
3168c2ec09 | ||
|
|
cb9c72d1db | ||
|
|
7a455dcad5 | ||
|
|
cacbecb324 | ||
|
|
c521dcaf57 | ||
|
|
b89c06008b | ||
|
|
c20e40652d | ||
|
|
2fe74627bd | ||
|
|
9864a2551d | ||
|
|
dea8c98399 | ||
|
|
108a20ef27 | ||
|
|
0adc65054c | ||
|
|
d72a74f6c3 | ||
|
|
1d05bac7a1 | ||
|
|
980b40dcdd | ||
|
|
b1a8707fb2 | ||
|
|
382de999cc | ||
|
|
06618d9e21 | ||
|
|
1b6e29acc0 | ||
|
|
e5992779f3 | ||
|
|
d7bc8e4176 | ||
|
|
629978d7a6 | ||
|
|
039ad65557 | ||
|
|
26e5104a96 | ||
|
|
d39276fe3a | ||
|
|
2a17a07784 | ||
|
|
56d35bef0d | ||
|
|
676098dc5f | ||
|
|
857d3902bb | ||
|
|
7803378d82 | ||
|
|
893a116fb4 | ||
|
|
916bf40602 | ||
|
|
40d6348b09 | ||
|
|
1e5047cd48 | ||
|
|
7750006127 | ||
|
|
1b69c97ce4 | ||
|
|
b3431fadf7 | ||
|
|
2a0d0633f1 | ||
|
|
4ed86be78e | ||
|
|
db13317613 | ||
|
|
8deb855b12 | ||
|
|
24277424d2 | ||
|
|
c593eceaaf | ||
|
|
e3a811c83d | ||
|
|
89fd83012a | ||
|
|
e71447a3d3 | ||
|
|
b89d6dfd72 | ||
|
|
3878be0d09 | ||
|
|
21d550ad1e | ||
|
|
134ab451e3 | ||
|
|
25fc67fec1 | ||
|
|
a41780caa2 | ||
|
|
4eb5e39946 | ||
|
|
354b0812c9 | ||
|
|
bee34bfdf4 | ||
|
|
d31e367870 | ||
|
|
16f0be1a45 | ||
|
|
ebba548206 | ||
|
|
c9fa9a4765 | ||
|
|
cfca07f7f2 | ||
|
|
0f60556b73 | ||
|
|
a1521049b5 | ||
|
|
1128813bf0 | ||
|
|
1f6339b3b3 | ||
|
|
79f5e00f6e | ||
|
|
957c5af66b | ||
|
|
c5c5ecd499 | ||
|
|
df4382f2e0 | ||
|
|
8700d0c601 | ||
|
|
27c5beea01 | ||
|
|
52af5cfc1f | ||
|
|
5a47f74023 | ||
|
|
c35ea77c59 | ||
|
|
b10c580d6f | ||
|
|
7096116296 | ||
|
|
330edde003 | ||
|
|
cac96bfc13 | ||
|
|
31edb19379 | ||
|
|
d482f0e610 | ||
|
|
c3bffa6777 | ||
|
|
140234f40e | ||
|
|
13b76287f8 | ||
|
|
a55feb9301 | ||
|
|
d86a887cf9 | ||
|
|
5b2a1d13a1 | ||
|
|
1ca08cb97a | ||
|
|
ca78b94a7d | ||
|
|
dcb53393c1 | ||
|
|
4ece7d1188 | ||
|
|
87289a34c0 | ||
|
|
2859410d4b | ||
|
|
9d53496521 | ||
|
|
4a8d5b13a8 | ||
|
|
8ba4fa309d | ||
|
|
0cab26227a | ||
|
|
1694c68ebc | ||
|
|
6c74c461c2 | ||
|
|
0ec5306de5 | ||
|
|
ba2ae3c303 | ||
|
|
019dbbb56e | ||
|
|
a47918a83c | ||
|
|
25e07fb597 | ||
|
|
43ad927817 | ||
|
|
d7966cdab2 | ||
|
|
33bda1612c | ||
|
|
f3eef3fe6c | ||
|
|
d8ae5fbd32 | ||
|
|
02e83a1989 | ||
|
|
5c8f7c4b00 | ||
|
|
3592a7232c | ||
|
|
ef067cd954 | ||
|
|
17382d7c7e | ||
|
|
5170948588 | ||
|
|
3ccb087d20 | ||
|
|
3f9145b745 | ||
|
|
5b79d8ca79 | ||
|
|
25c1eeee5c | ||
|
|
f5060c301b | ||
|
|
8a2ca4b733 | ||
|
|
9610de0a66 | ||
|
|
64627ddde9 | ||
|
|
63bcb2d009 | ||
|
|
df5bceaf2a | ||
|
|
66d46bd8a5 | ||
|
|
28a433ea76 | ||
|
|
2c69834a12 | ||
|
|
00ee53efca | ||
|
|
4989cf6d5a | ||
|
|
0d5aa705f0 | ||
|
|
307b032118 | ||
|
|
ab8279078e | ||
|
|
b7ac80e684 | ||
|
|
6064a4bc79 | ||
|
|
e41a4b8e16 | ||
|
|
39057fd1fb | ||
|
|
cbdb0eeba4 | ||
|
|
73b6a16551 |
@@ -1,2 +1,3 @@
|
||||
BasedOnStyle: WebKit
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
FixNamespaceComments: true
|
||||
|
||||
12
.gitattributes
vendored
@@ -2,14 +2,24 @@
|
||||
*.c text eol=lf
|
||||
*.cc text eol=lf
|
||||
*.cmake text eol=lf
|
||||
*.gradle text eol=lf
|
||||
*.h text eol=lf
|
||||
*.md text eol=lf
|
||||
*.java text eol=lf
|
||||
*.json text eol=lf
|
||||
*.md text eol=lf
|
||||
*.mm text eol=lf
|
||||
*.plist text eol=lf
|
||||
*.pro text eol=lf
|
||||
*.properties text eol=lf
|
||||
*.xml text eol=lf
|
||||
*.yml text eol=lf
|
||||
.clang-format text eol=lf
|
||||
.editorconfig text eol=lf
|
||||
.gitattributes text eol=lf
|
||||
.gitignore text eol=lf
|
||||
gradlew text eol=lf
|
||||
CMakeLists.txt text eol=lf
|
||||
LICENSE text eol=lf
|
||||
|
||||
# Force CRLF
|
||||
*.bat text eol=crlf
|
||||
|
||||
261
.github/workflows/ci-build.yml
vendored
@@ -2,19 +2,12 @@ name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/ci-build.yml'
|
||||
- 'src/**.cc'
|
||||
- 'src/**.h'
|
||||
- '**/CMakeLists.txt'
|
||||
- '**/*.cmake'
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/ci-build.yml'
|
||||
- 'src/**.cc'
|
||||
- 'src/**.h'
|
||||
- '**/CMakeLists.txt'
|
||||
- '**/*.cmake'
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -33,15 +26,106 @@ jobs:
|
||||
sudo apt install cppcheck
|
||||
|
||||
- name: Clone
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: cppcheck
|
||||
run: cppcheck --std=c++17 src/
|
||||
|
||||
code-format:
|
||||
name: Code format check
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: clang-format
|
||||
run: find src -type f -name \*.cc -o -name \*.h | xargs clang-format --dry-run --Werror
|
||||
|
||||
android:
|
||||
name: Android
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 11
|
||||
cache: gradle
|
||||
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: os/android/app/.cxx
|
||||
key: android-cmake-v2
|
||||
|
||||
- name: Setup signing config
|
||||
if: env.KEYSTORE_FILE_BASE64 != '' && env.KEYSTORE_PROPERTIES_FILE_BASE64 != ''
|
||||
run: |
|
||||
cd os/android
|
||||
echo "$KEYSTORE_FILE_BASE64" | base64 --decode > debug.keystore
|
||||
echo "$KEYSTORE_PROPERTIES_FILE_BASE64" | base64 --decode > debug-keystore.properties
|
||||
env:
|
||||
KEYSTORE_FILE_BASE64: ${{ secrets.ANDROID_DEBUG_KEYSTORE_FILE_BASE64 }}
|
||||
KEYSTORE_PROPERTIES_FILE_BASE64: ${{ secrets.ANDROID_DEBUG_KEYSTORE_PROPERTIES_FILE_BASE64 }}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd os/android
|
||||
./gradlew assembleDebug
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fallout2-ce-debug.apk
|
||||
path: os/android/app/build/outputs/apk/debug/app-debug.apk
|
||||
retention-days: 7
|
||||
|
||||
ios:
|
||||
name: iOS
|
||||
|
||||
runs-on: macos-13
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: out
|
||||
key: ios-cmake-v5
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake --preset ios
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake --build --preset ios-debug
|
||||
|
||||
- name: Pack
|
||||
run: |
|
||||
cd out/build/ios
|
||||
cpack -C Debug
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fallout2-ce.ipa
|
||||
path: out/build/ios/fallout2-ce.ipa
|
||||
retention-days: 7
|
||||
|
||||
linux:
|
||||
name: Linux (${{ matrix.arch }})
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -52,14 +136,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Dependencies (x86)
|
||||
if: matrix.arch == 'x86'
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt update
|
||||
sudo apt install --allow-downgrades libpcre2-8-0=10.34-7
|
||||
sudo apt install g++-multilib libsdl2-dev:i386 zlib1g-dev:i386
|
||||
|
||||
- name: Dependencies (x64)
|
||||
@@ -69,77 +152,122 @@ jobs:
|
||||
sudo apt install libsdl2-dev zlib1g-dev
|
||||
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build
|
||||
key: linux-${{ matrix.arch }}-cmake-v1
|
||||
path: out
|
||||
key: linux-${{ matrix.arch }}-cmake-v3
|
||||
|
||||
- name: Configure (x86)
|
||||
if: matrix.arch == 'x86'
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake \
|
||||
-B build \
|
||||
-D CMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-D CMAKE_TOOLCHAIN_FILE=cmake/toolchain/Linux32.cmake \
|
||||
# EOL
|
||||
|
||||
- name: Configure (x64)
|
||||
if: matrix.arch == 'x64'
|
||||
run: |
|
||||
cmake \
|
||||
-B build \
|
||||
-D CMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
# EOL
|
||||
cmake --preset linux-${{ matrix.arch }}-debug
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake \
|
||||
--build build \
|
||||
-j $(nproc) \
|
||||
# EOL
|
||||
cmake --build --preset linux-${{ matrix.arch }}-debug
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fallout2-ce-linux-${{ matrix.arch }}
|
||||
path: out/build/linux-${{ matrix.arch }}-debug/fallout2-ce
|
||||
retention-days: 7
|
||||
|
||||
linux-armhf:
|
||||
name: Linux (armhf)
|
||||
|
||||
runs-on: ubuntu-22.04-arm
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Dependencies
|
||||
run: |
|
||||
sudo dpkg --add-architecture armhf
|
||||
sudo apt update
|
||||
sudo apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf libsdl2-dev:armhf zlib1g-dev:armhf
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake \
|
||||
-B build \
|
||||
-D CMAKE_BUILD_TYPE=Debug \
|
||||
-D FALLOUT_VENDORED=OFF \
|
||||
-D CMAKE_SYSTEM_PROCESSOR=arm \
|
||||
-D CMAKE_C_COMPILER=arm-linux-gnueabihf-gcc \
|
||||
-D CMAKE_CXX_COMPILER=arm-linux-gnueabihf-g++ \
|
||||
# EOL
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fallout2-ce-linux-armhf
|
||||
path: build/fallout2-ce
|
||||
retention-days: 7
|
||||
|
||||
linux-arm64:
|
||||
name: Linux (arm64)
|
||||
|
||||
runs-on: ubuntu-22.04-arm
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install libsdl2-dev zlib1g-dev
|
||||
|
||||
- name: Configure
|
||||
run: cmake -B build -D CMAKE_BUILD_TYPE=Debug -D FALLOUT_VENDORED=OFF
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fallout2-ce-linux-arm64
|
||||
path: build/fallout2-ce
|
||||
retention-days: 7
|
||||
|
||||
macos:
|
||||
name: macOS
|
||||
|
||||
runs-on: macos-11
|
||||
runs-on: macos-13
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build
|
||||
key: macos-cmake-v3
|
||||
path: out
|
||||
key: macos-cmake-v6
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake \
|
||||
-B build \
|
||||
-D CMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
# EOL
|
||||
cmake --preset macos
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake \
|
||||
--build build \
|
||||
-j $(sysctl -n hw.physicalcpu) \
|
||||
--target package \
|
||||
# EOL
|
||||
cmake --build --preset macos-debug
|
||||
|
||||
- name: Pack
|
||||
run: |
|
||||
cd out/build/macos
|
||||
cpack -C Debug
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fallout2-ce-macos.dmg
|
||||
path: build/fallout2-ce.dmg
|
||||
path: out/build/macos/Fallout II Community Edition.dmg
|
||||
retention-days: 7
|
||||
|
||||
windows:
|
||||
@@ -158,32 +286,25 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build
|
||||
key: windows-${{ matrix.arch }}-cmake-v1
|
||||
path: out
|
||||
key: windows-${{ matrix.arch }}-cmake-v2
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake \
|
||||
-B build \
|
||||
-G "Visual Studio 16 2019" \
|
||||
-A ${{ matrix.generator-platform }} \
|
||||
# EOL
|
||||
cmake --preset windows-${{ matrix.arch }}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake \
|
||||
--build build \
|
||||
--config RelWithDebInfo \
|
||||
# EOL
|
||||
cmake --build --preset windows-${{ matrix.arch }}-debug
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fallout2-ce-windows-${{ matrix.arch }}
|
||||
path: build/RelWithDebInfo/fallout2-ce.exe
|
||||
path: out/build/windows-${{ matrix.arch }}/Debug/fallout2-ce.exe
|
||||
retention-days: 7
|
||||
|
||||
155
.github/workflows/release.yml
vendored
@@ -10,6 +10,100 @@ defaults:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
android:
|
||||
name: Android
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 11
|
||||
cache: gradle
|
||||
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: os/android/app/.cxx
|
||||
key: android-cmake-v1
|
||||
|
||||
- name: Setup signing config
|
||||
if: env.KEYSTORE_FILE_BASE64 != '' && env.KEYSTORE_PROPERTIES_FILE_BASE64 != ''
|
||||
run: |
|
||||
cd os/android
|
||||
echo "$KEYSTORE_FILE_BASE64" | base64 --decode > release.keystore
|
||||
echo "$KEYSTORE_PROPERTIES_FILE_BASE64" | base64 --decode > release-keystore.properties
|
||||
env:
|
||||
KEYSTORE_FILE_BASE64: ${{ secrets.ANDROID_RELEASE_KEYSTORE_FILE_BASE64 }}
|
||||
KEYSTORE_PROPERTIES_FILE_BASE64: ${{ secrets.ANDROID_RELEASE_KEYSTORE_PROPERTIES_FILE_BASE64 }}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd os/android
|
||||
./gradlew assembleRelease
|
||||
|
||||
- name: Upload
|
||||
run: |
|
||||
cd os/android/app/build/outputs/apk/release
|
||||
cp app-release.apk fallout2-ce-android.apk
|
||||
gh release upload ${{ github.event.release.tag_name }} fallout2-ce-android.apk
|
||||
rm fallout2-ce-android.apk
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
ios:
|
||||
name: iOS
|
||||
|
||||
runs-on: macos-12
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build
|
||||
key: ios-cmake-v1
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake \
|
||||
-B build \
|
||||
-D CMAKE_TOOLCHAIN_FILE=cmake/toolchain/ios.toolchain.cmake \
|
||||
-D ENABLE_BITCODE=0 \
|
||||
-D PLATFORM=OS64 \
|
||||
-G Xcode \
|
||||
-D CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY='' \
|
||||
# EOL
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake \
|
||||
--build build \
|
||||
--config RelWithDebInfo \
|
||||
-j $(sysctl -n hw.physicalcpu) \
|
||||
# EOL
|
||||
|
||||
- name: Pack
|
||||
run: |
|
||||
cd build
|
||||
cpack -C RelWithDebInfo
|
||||
|
||||
- name: Upload
|
||||
run: |
|
||||
cd build
|
||||
cp fallout2-ce.ipa fallout2-ce-ios.ipa
|
||||
gh release upload ${{ github.event.release.tag_name }} fallout2-ce-ios.ipa
|
||||
rm fallout2-ce-ios.ipa
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
linux:
|
||||
name: Linux (${{ matrix.arch }})
|
||||
|
||||
@@ -24,7 +118,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Dependencies (x86)
|
||||
if: matrix.arch == 'x86'
|
||||
@@ -41,7 +135,7 @@ jobs:
|
||||
sudo apt install libsdl2-dev zlib1g-dev
|
||||
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build
|
||||
key: linux-${{ matrix.arch }}-cmake-v1
|
||||
@@ -74,7 +168,7 @@ jobs:
|
||||
run: |
|
||||
cd build
|
||||
tar -czvf fallout2-ce-linux-${{ matrix.arch }}.tar.gz fallout2-ce
|
||||
gh release upload ${{ github.ref_name }} fallout2-ce-linux-${{ matrix.arch }}.tar.gz
|
||||
gh release upload ${{ github.event.release.tag_name }} fallout2-ce-linux-${{ matrix.arch }}.tar.gz
|
||||
rm fallout2-ce-linux-${{ matrix.arch }}.tar.gz
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -86,16 +180,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Import code signing certificates
|
||||
uses: apple-actions/import-codesign-certs@v1
|
||||
uses: apple-actions/import-codesign-certs@v2
|
||||
with:
|
||||
p12-file-base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_FILE_BASE64 }}
|
||||
p12-password: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_PASSWORD }}
|
||||
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build
|
||||
key: macos-cmake-v3
|
||||
@@ -104,41 +198,44 @@ jobs:
|
||||
run: |
|
||||
cmake \
|
||||
-B build \
|
||||
-D CMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-D CPACK_BUNDLE_APPLE_CERT_APP="${{ secrets.APPLE_DEVELOPER_CERTIFICATE_IDENTITY }}" \
|
||||
-G Xcode \
|
||||
-D CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY="${{ secrets.APPLE_DEVELOPER_CERTIFICATE_IDENTITY }}" \
|
||||
-D CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_INJECT_BASE_ENTITLEMENTS="NO" \
|
||||
-D CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS="--options=runtime --timestamp" \
|
||||
# EOL
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake \
|
||||
--build build \
|
||||
--config RelWithDebInfo \
|
||||
-j $(sysctl -n hw.physicalcpu) \
|
||||
--target package \
|
||||
# EOL
|
||||
|
||||
- name: Pack
|
||||
run: |
|
||||
cd build
|
||||
cpack -C RelWithDebInfo
|
||||
|
||||
- name: Notarize
|
||||
run: |
|
||||
brew install mitchellh/gon/gon
|
||||
cat << EOF > config.json
|
||||
{
|
||||
"notarize": {
|
||||
"path": "build/fallout2-ce.dmg",
|
||||
"bundle_id": "$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" build/fallout2-ce.app/Contents/Info.plist)",
|
||||
"staple": true
|
||||
}
|
||||
}
|
||||
EOF
|
||||
gon config.json
|
||||
rm config.json
|
||||
env:
|
||||
AC_USERNAME: ${{ secrets.APPLE_DEVELOPER_AC_USERNAME }}
|
||||
AC_PASSWORD: ${{ secrets.APPLE_DEVELOPER_AC_PASSWORD }}
|
||||
xcrun notarytool submit \
|
||||
"build/Fallout II Community Edition.dmg" \
|
||||
--apple-id "${{ secrets.APPLE_DEVELOPER_AC_USERNAME }}" \
|
||||
--team-id "${{ secrets.APPLE_DEVELOPER_AC_TEAM }}" \
|
||||
--password "${{ secrets.APPLE_DEVELOPER_AC_PASSWORD }}" \
|
||||
--wait
|
||||
|
||||
- name: Staple
|
||||
run: |
|
||||
xcrun stapler staple \
|
||||
"build/Fallout II Community Edition.dmg"
|
||||
|
||||
- name: Upload
|
||||
run: |
|
||||
cd build
|
||||
cp fallout2-ce.dmg fallout2-ce-macos.dmg
|
||||
gh release upload ${{ github.ref_name }} fallout2-ce-macos.dmg
|
||||
cp "Fallout II Community Edition.dmg" fallout2-ce-macos.dmg
|
||||
gh release upload ${{ github.event.release.tag_name }} fallout2-ce-macos.dmg
|
||||
rm fallout2-ce-macos.dmg
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -159,10 +256,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build
|
||||
key: windows-${{ matrix.arch }}-cmake-v1
|
||||
@@ -186,7 +283,7 @@ jobs:
|
||||
run: |
|
||||
cd build/RelWithDebInfo
|
||||
7z a fallout2-ce-windows-${{ matrix.arch }}.zip fallout2-ce.exe
|
||||
gh release upload ${{ github.ref_name }} fallout2-ce-windows-${{ matrix.arch }}.zip
|
||||
gh release upload ${{ github.event.release.tag_name }} fallout2-ce-windows-${{ matrix.arch }}.zip
|
||||
rm fallout2-ce-windows-${{ matrix.arch }}.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
1
.gitignore
vendored
@@ -391,3 +391,4 @@ FodyWeavers.xsd
|
||||
# CMake
|
||||
/out
|
||||
/build
|
||||
CMakeUserPresets.json
|
||||
|
||||
166
CMakeLists.txt
@@ -4,9 +4,14 @@ set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
||||
|
||||
set(EXECUTABLE_NAME fallout2-ce)
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.11" CACHE STRING "")
|
||||
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "")
|
||||
if(APPLE)
|
||||
if(IOS)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "12" CACHE STRING "")
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "")
|
||||
else()
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "")
|
||||
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
project(${EXECUTABLE_NAME})
|
||||
@@ -15,7 +20,9 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
||||
set(CMAKE_CXX_EXTENSIONS NO)
|
||||
|
||||
if (ANDROID)
|
||||
option(FALLOUT_VENDORED "Use vendored third-party libraries" ON)
|
||||
|
||||
if(ANDROID)
|
||||
add_library(${EXECUTABLE_NAME} SHARED)
|
||||
else()
|
||||
add_executable(${EXECUTABLE_NAME} WIN32 MACOSX_BUNDLE)
|
||||
@@ -52,8 +59,6 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/combat.h"
|
||||
"src/config.cc"
|
||||
"src/config.h"
|
||||
"src/core.cc"
|
||||
"src/core.h"
|
||||
"src/credits.cc"
|
||||
"src/credits.h"
|
||||
"src/critter.cc"
|
||||
@@ -80,8 +85,6 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/display_monitor.h"
|
||||
"src/draw.cc"
|
||||
"src/draw.h"
|
||||
"src/electronic_registration.cc"
|
||||
"src/electronic_registration.h"
|
||||
"src/elevator.cc"
|
||||
"src/elevator.h"
|
||||
"src/endgame.cc"
|
||||
@@ -104,8 +107,6 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/game_mouse.h"
|
||||
"src/game_movie.cc"
|
||||
"src/game_movie.h"
|
||||
"src/game_palette.cc"
|
||||
"src/game_palette.h"
|
||||
"src/game_sound.cc"
|
||||
"src/game_sound.h"
|
||||
"src/game_vars.h"
|
||||
@@ -115,10 +116,10 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/geometry.h"
|
||||
"src/graph_lib.cc"
|
||||
"src/graph_lib.h"
|
||||
"src/grayscale.cc"
|
||||
"src/grayscale.h"
|
||||
"src/heap.cc"
|
||||
"src/heap.h"
|
||||
"src/input.cc"
|
||||
"src/input.h"
|
||||
"src/interface.cc"
|
||||
"src/interface.h"
|
||||
"src/interpreter_extra.cc"
|
||||
@@ -131,6 +132,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/inventory.h"
|
||||
"src/item.cc"
|
||||
"src/item.h"
|
||||
"src/kb.cc"
|
||||
"src/kb.h"
|
||||
"src/light.cc"
|
||||
"src/light.h"
|
||||
"src/lips.cc"
|
||||
@@ -139,6 +142,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/loadsave.h"
|
||||
"src/main.cc"
|
||||
"src/main.h"
|
||||
"src/mainmenu.cc"
|
||||
"src/mainmenu.h"
|
||||
"src/map_defs.h"
|
||||
"src/map.cc"
|
||||
"src/map.h"
|
||||
@@ -149,10 +154,10 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/memory.h"
|
||||
"src/message.cc"
|
||||
"src/message.h"
|
||||
"src/mmx.cc"
|
||||
"src/mmx.h"
|
||||
"src/mouse_manager.cc"
|
||||
"src/mouse_manager.h"
|
||||
"src/mouse.cc"
|
||||
"src/mouse.h"
|
||||
"src/movie_effect.cc"
|
||||
"src/movie_effect.h"
|
||||
"src/movie_lib.cc"
|
||||
@@ -170,6 +175,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/palette.h"
|
||||
"src/party_member.cc"
|
||||
"src/party_member.h"
|
||||
"src/pcx.cc"
|
||||
"src/pcx.h"
|
||||
"src/perk_defs.h"
|
||||
"src/perk.cc"
|
||||
"src/perk.h"
|
||||
@@ -212,6 +219,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/stat.h"
|
||||
"src/string_parsers.cc"
|
||||
"src/string_parsers.h"
|
||||
"src/svga.cc"
|
||||
"src/svga.h"
|
||||
"src/text_font.cc"
|
||||
"src/text_font.h"
|
||||
"src/text_object.cc"
|
||||
@@ -221,8 +230,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/trait_defs.h"
|
||||
"src/trait.cc"
|
||||
"src/trait.h"
|
||||
"src/trap.cc"
|
||||
"src/trap.h"
|
||||
"src/vcr.cc"
|
||||
"src/vcr.h"
|
||||
"src/version.cc"
|
||||
"src/version.h"
|
||||
"src/widget.cc"
|
||||
@@ -237,8 +246,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/window.h"
|
||||
"src/word_wrap.cc"
|
||||
"src/word_wrap.h"
|
||||
"src/world_map.cc"
|
||||
"src/world_map.h"
|
||||
"src/worldmap.cc"
|
||||
"src/worldmap.h"
|
||||
"src/xfile.cc"
|
||||
"src/xfile.h"
|
||||
)
|
||||
@@ -246,25 +255,53 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/audio_engine.cc"
|
||||
"src/audio_engine.h"
|
||||
"src/delay.cc"
|
||||
"src/delay.h"
|
||||
"src/fps_limiter.cc"
|
||||
"src/fps_limiter.h"
|
||||
"src/platform_compat.cc"
|
||||
"src/platform_compat.h"
|
||||
"src/pointer_registry.cc"
|
||||
"src/pointer_registry.h"
|
||||
"src/preferences.cc"
|
||||
"src/preferences.h"
|
||||
"src/settings.cc"
|
||||
"src/settings.h"
|
||||
"src/sfall_config.cc"
|
||||
"src/sfall_config.h"
|
||||
"src/sfall_global_vars.cc"
|
||||
"src/sfall_global_vars.h"
|
||||
"src/sfall_global_scripts.cc"
|
||||
"src/sfall_global_scripts.h"
|
||||
"src/sfall_ini.cc"
|
||||
"src/sfall_ini.h"
|
||||
"src/sfall_kb_helpers.cc"
|
||||
"src/sfall_kb_helpers.h"
|
||||
"src/sfall_lists.cc"
|
||||
"src/sfall_lists.h"
|
||||
"src/sfall_metarules.cc"
|
||||
"src/sfall_metarules.h"
|
||||
"src/sfall_opcodes.cc"
|
||||
"src/sfall_opcodes.h"
|
||||
"src/sfall_arrays.cc"
|
||||
"src/sfall_arrays.h"
|
||||
"src/touch.cc"
|
||||
"src/touch.h"
|
||||
)
|
||||
|
||||
if(IOS)
|
||||
target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/platform/ios/paths.h"
|
||||
"src/platform/ios/paths.mm"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_compile_definitions(${EXECUTABLE_NAME} PUBLIC
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
_CRT_NONSTDC_NO_WARNINGS
|
||||
)
|
||||
else()
|
||||
target_compile_definitions(${EXECUTABLE_NAME} PRIVATE
|
||||
$<$<CONFIG:Debug>:_DEBUG>
|
||||
$<$<CONFIG:RelWithDebInfo>:_DEBUG>
|
||||
NOMINMAX
|
||||
WIN32_LEAN_AND_MEAN
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -274,18 +311,61 @@ if(WIN32)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"os/windows/fallout2-ce.ico"
|
||||
"os/windows/fallout2-ce.rc"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set_target_properties(${EXECUTABLE_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/os/macos/Info.plist")
|
||||
if(IOS)
|
||||
set(RESOURCES
|
||||
"os/ios/AppIcon.xcassets"
|
||||
"os/ios/LaunchScreen.storyboard"
|
||||
)
|
||||
|
||||
target_sources(${EXECUTABLE_NAME} PUBLIC ${RESOURCES})
|
||||
set_source_files_properties(${RESOURCES} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||
|
||||
set_target_properties(${EXECUTABLE_NAME} PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/os/ios/Info.plist"
|
||||
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon"
|
||||
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.alexbatalov.fallout2-ce"
|
||||
XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2"
|
||||
)
|
||||
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME "${EXECUTABLE_NAME}")
|
||||
set(MACOSX_BUNDLE_DISPLAY_NAME "Fallout 2")
|
||||
else()
|
||||
set(RESOURCES
|
||||
"os/macos/fallout2-ce.icns"
|
||||
)
|
||||
|
||||
target_sources(${EXECUTABLE_NAME} PUBLIC ${RESOURCES})
|
||||
set_source_files_properties(${RESOURCES} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||
|
||||
set_target_properties(${EXECUTABLE_NAME} PROPERTIES
|
||||
OUTPUT_NAME "Fallout II Community Edition"
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/os/macos/Info.plist"
|
||||
XCODE_ATTRIBUTE_EXECUTABLE_NAME "${EXECUTABLE_NAME}"
|
||||
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.alexbatalov.fallout2-ce"
|
||||
)
|
||||
|
||||
set(MACOSX_BUNDLE_ICON_FILE "fallout2-ce.icns")
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME "Fallout II: Community Edition")
|
||||
set(MACOSX_BUNDLE_DISPLAY_NAME "Fallout II")
|
||||
endif()
|
||||
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.alexbatalov.fallout2-ce")
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME "${EXECUTABLE_NAME}")
|
||||
set(MACOSX_BUNDLE_DISPLAY_NAME "Fallout 2")
|
||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "1.3.0")
|
||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "1.3.0")
|
||||
endif()
|
||||
|
||||
add_subdirectory("third_party/fpattern")
|
||||
target_link_libraries(${EXECUTABLE_NAME} ${FPATTERN_LIBRARY})
|
||||
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${FPATTERN_INCLUDE_DIR})
|
||||
target_link_libraries(${EXECUTABLE_NAME} fpattern::fpattern)
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
if(FALLOUT_VENDORED)
|
||||
add_subdirectory("third_party/zlib")
|
||||
add_subdirectory("third_party/sdl2")
|
||||
else()
|
||||
@@ -300,23 +380,21 @@ target_link_libraries(${EXECUTABLE_NAME} ${SDL2_LIBRARIES})
|
||||
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${SDL2_INCLUDE_DIRS})
|
||||
|
||||
if(APPLE)
|
||||
install(TARGETS ${EXECUTABLE_NAME} DESTINATION .)
|
||||
install(CODE "
|
||||
include(BundleUtilities)
|
||||
fixup_bundle(${CMAKE_BINARY_DIR}/${MACOSX_BUNDLE_BUNDLE_NAME}.app \"\" \"\")
|
||||
"
|
||||
COMPONENT Runtime)
|
||||
if(IOS)
|
||||
install(TARGETS ${EXECUTABLE_NAME} DESTINATION "Payload")
|
||||
|
||||
if (CPACK_BUNDLE_APPLE_CERT_APP)
|
||||
install(CODE "
|
||||
execute_process(COMMAND codesign --deep --force --options runtime --sign \"${CPACK_BUNDLE_APPLE_CERT_APP}\" ${CMAKE_BINARY_DIR}/${MACOSX_BUNDLE_BUNDLE_NAME}.app)
|
||||
"
|
||||
COMPONENT Runtime)
|
||||
set(CPACK_GENERATOR "ZIP")
|
||||
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
|
||||
set(CPACK_PACKAGE_FILE_NAME "fallout2-ce")
|
||||
set(CPACK_ARCHIVE_FILE_EXTENSION "ipa")
|
||||
else()
|
||||
install(TARGETS ${EXECUTABLE_NAME} DESTINATION .)
|
||||
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
set(CPACK_DMG_DS_STORE_SETUP_SCRIPT "${CMAKE_SOURCE_DIR}/os/macos/dmg/setup.scpt")
|
||||
set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/os/macos/dmg/background.png")
|
||||
set(CPACK_PACKAGE_FILE_NAME "Fallout II Community Edition")
|
||||
endif()
|
||||
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
set(CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK ON)
|
||||
set(CPACK_PACKAGE_FILE_NAME "fallout2-ce")
|
||||
|
||||
include(CPack)
|
||||
endif()
|
||||
|
||||
196
CMakePresets.json
Normal file
@@ -0,0 +1,196 @@
|
||||
{
|
||||
"version": 6,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 19,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "base",
|
||||
"hidden": true,
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}"
|
||||
},
|
||||
{
|
||||
"name": "windows-base",
|
||||
"hidden": true,
|
||||
"inherits": [
|
||||
"base"
|
||||
],
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-x86",
|
||||
"inherits": [
|
||||
"windows-base"
|
||||
],
|
||||
"generator": "Visual Studio 16 2019",
|
||||
"architecture": "Win32"
|
||||
},
|
||||
{
|
||||
"name": "windows-x64",
|
||||
"inherits": [
|
||||
"windows-base"
|
||||
],
|
||||
"generator": "Visual Studio 16 2019",
|
||||
"architecture": "x64"
|
||||
},
|
||||
{
|
||||
"name": "linux-base",
|
||||
"hidden": true,
|
||||
"inherits": [
|
||||
"base"
|
||||
],
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Linux"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"FALLOUT_VENDORED": "OFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-x86-base",
|
||||
"hidden": true,
|
||||
"inherits": [
|
||||
"linux-base"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_FLAGS": "-m32",
|
||||
"CMAKE_CXX_FLAGS": "-m32",
|
||||
"CMAKE_SYSTEM_NAME": "Linux",
|
||||
"CMAKE_SYSTEM_PROCESSOR": "i386"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-x86-debug",
|
||||
"inherits": [
|
||||
"linux-x86-base"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-x86-release",
|
||||
"inherits": [
|
||||
"linux-x86-base"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-x64-debug",
|
||||
"inherits": [
|
||||
"linux-base"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-x64-release",
|
||||
"inherits": [
|
||||
"linux-base"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "darwin-base",
|
||||
"hidden": true,
|
||||
"inherits": [
|
||||
"base"
|
||||
],
|
||||
"generator": "Xcode",
|
||||
"cacheVariables": {
|
||||
"CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY": ""
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Darwin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "macos",
|
||||
"inherits": [
|
||||
"darwin-base"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ios",
|
||||
"inherits": [
|
||||
"darwin-base"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_SYSTEM_NAME": "iOS"
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "windows-x86-debug",
|
||||
"configurePreset": "windows-x86",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "windows-x86-release",
|
||||
"configurePreset": "windows-x86",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "windows-x64-debug",
|
||||
"configurePreset": "windows-x64",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "windows-x64-release",
|
||||
"configurePreset": "windows-x64",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "linux-x86-debug",
|
||||
"configurePreset": "linux-x86-debug"
|
||||
},
|
||||
{
|
||||
"name": "linux-x86-release",
|
||||
"configurePreset": "linux-x86-release"
|
||||
},
|
||||
{
|
||||
"name": "linux-x64-debug",
|
||||
"configurePreset": "linux-x64-debug"
|
||||
},
|
||||
{
|
||||
"name": "linux-x64-release",
|
||||
"configurePreset": "linux-x64-release"
|
||||
},
|
||||
{
|
||||
"name": "macos-debug",
|
||||
"configurePreset": "macos",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "macos-release",
|
||||
"configurePreset": "macos",
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "ios-debug",
|
||||
"configurePreset": "ios",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "ios-release",
|
||||
"configurePreset": "ios",
|
||||
"configuration": "RelWithDebInfo"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x86-Debug",
|
||||
"generator": "Visual Studio 16 2019",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [ "msvc_x86" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "x86-Release",
|
||||
"generator": "Visual Studio 16 2019",
|
||||
"configurationType": "Release",
|
||||
"inheritEnvironments": [ "msvc_x86" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "x64-Debug",
|
||||
"generator": "Visual Studio 16 2019 Win64",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"variables": []
|
||||
},
|
||||
{
|
||||
"name": "x64-Release",
|
||||
"generator": "Visual Studio 16 2019 Win64",
|
||||
"configurationType": "Release",
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"variables": []
|
||||
}
|
||||
]
|
||||
}
|
||||
51
LICENSE.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Sustainable Use License
|
||||
|
||||
Version 1.0
|
||||
|
||||
## Acceptance
|
||||
|
||||
By using the software, you agree to all of the terms and conditions below.
|
||||
|
||||
## Copyright License
|
||||
|
||||
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations below.
|
||||
|
||||
## Limitations
|
||||
|
||||
You may use or modify the software only for your own internal business purposes or for non-commercial or personal use. You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes. You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor’s trademarks is subject to applicable law.
|
||||
|
||||
## Patents
|
||||
|
||||
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
||||
|
||||
## Notices
|
||||
|
||||
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms. If you modify the software, you must include in any modified copies of the software a prominent notice stating that you have modified the software.
|
||||
|
||||
## No Other Rights
|
||||
|
||||
These terms do not imply any licenses other than those expressly granted in these terms.
|
||||
|
||||
## Termination
|
||||
|
||||
If you use the software in violation of these terms, such use is not licensed, and your license will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your license will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your license to terminate automatically and permanently.
|
||||
|
||||
## No Liability
|
||||
|
||||
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
|
||||
|
||||
## Definitions
|
||||
|
||||
The "licensor" is the entity offering these terms.
|
||||
|
||||
The "software" is the software the licensor makes available under these terms, including any portion of it.
|
||||
|
||||
"You" refers to the individual or entity agreeing to these terms.
|
||||
|
||||
"Your company" is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. Control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
||||
|
||||
"Your license" is the license granted to you for the software under these terms.
|
||||
|
||||
"Use" means anything you do with the software requiring your license.
|
||||
|
||||
"Trademark" means trademarks, service marks, and similar rights.
|
||||
62
README.md
@@ -1,8 +1,14 @@
|
||||
# Fallout 2 Community Edition
|
||||
|
||||
Fallout 2 Community Edition is a fully working re-implementation of Fallout 2, with the same original gameplay, engine bugfixes, and some quality of life improvements, that works (mostly) hassle-free on multiple platforms.
|
||||
|
||||
Popular Fallout 2 total conversion mods are partially supported. Original versions of Nevada and Sonora (that do not rely on extended features provided by Sfall) likely work, although there is no complete walkthrough confirmation yet. [Fallout 2 Restoration Project](https://github.com/BGforgeNet/Fallout2_Restoration_Project), [Fallout Et Tu](https://github.com/rotators/Fo1in2) and [Olympus 2207](https://olympus2207.com) are not yet supported. Other mods (particularly Resurrection and Yesterday) are not tested.
|
||||
|
||||
There is also [Fallout Community Edition](https://github.com/alexbatalov/fallout1-ce).
|
||||
|
||||
## Installation
|
||||
|
||||
You must own the game to play. Purchase your copy on [GOG](https://www.gog.com/game/fallout_2) or [Steam](https://store.steampowered.com/app/38410). Download latest release or build from source.
|
||||
You must own the game to play. Purchase your copy on [GOG](https://www.gog.com/game/fallout_2), [Epic Games](https://store.epicgames.com/p/fallout-2) or [Steam](https://store.steampowered.com/app/38410). Download latest [release](https://github.com/alexbatalov/fallout2-ce/releases) or build from source. You can also check latest [debug](https://github.com/alexbatalov/fallout2-ce/actions) build intended for testers.
|
||||
|
||||
### Windows
|
||||
|
||||
@@ -34,6 +40,56 @@ $ sudo apt install libsdl2-2.0-0
|
||||
|
||||
- Run `fallout2-ce.app`.
|
||||
|
||||
### Android
|
||||
|
||||
> **NOTE**: Fallout 2 was designed with mouse in mind. There are many controls that require precise cursor positioning, which is not possible with fingers. Current control scheme resembles trackpad usage:
|
||||
- One finger moves mouse cursor around.
|
||||
- Tap one finger for left mouse click.
|
||||
- Tap two fingers for right mouse click (switches mouse cursor mode).
|
||||
- Move two fingers to scroll current view (map view, worldmap view, inventory scrollers).
|
||||
|
||||
> **NOTE**: From Android standpoint release and debug builds are different apps. Both apps require their own copy of game assets and have their own savegames. This is intentional. As a gamer just stick with release version and check for updates.
|
||||
|
||||
- Use Windows installation as a base - it contains data assets needed to play. Copy `Fallout2` folder to your device, for example to `Downloads`. You need `master.dat`, `critter.dat`, `patch000.dat`, and `data` folder. Watch for file names - keep (or make) them lowercased (see [Configuration](#configuration)).
|
||||
|
||||
- Download `fallout2-ce.apk` and copy it to your device. Open it with file explorer, follow instructions (install from unknown source).
|
||||
|
||||
- When you run the game for the first time it will immediately present file picker. Select the folder from the first step. Wait until this data is copied. A loading dialog will appear, just wait for about 30 seconds. If you're installing total conversion mod or localized version with a large number of unpacked resources in `data` folder it can take up to 20 minutes. Once copied, the game will start automatically.
|
||||
|
||||
### iOS
|
||||
|
||||
> **NOTE**: See Android note on controls.
|
||||
|
||||
- Download `fallout2-ce.ipa`. Use sideloading applications ([AltStore](https://altstore.io/) or [Sideloadly](https://sideloadly.io/)) to install it to your device. Alternatively you can always build from source with your own signing certificate.
|
||||
|
||||
- Run the game once. You'll see error message saying "Couldn't find/load text fonts". This step is needed for iOS to expose the game via File Sharing feature.
|
||||
|
||||
- Use Finder (macOS Catalina and later) or iTunes (Windows and macOS Mojave or earlier) to copy `master.dat`, `critter.dat`, `patch000.dat`, and `data` folder to "Fallout 2" app ([how-to](https://support.apple.com/HT210598)). Watch for file names - keep (or make) them lowercased (see [Configuration](#configuration)).
|
||||
|
||||
## Configuration
|
||||
|
||||
The main configuration file is `fallout2.cfg`. There are several important settings you might need to adjust for your installation. Depending on your Fallout distribution main game assets `master.dat`, `critter.dat`, `patch000.dat`, and `data` folder might be either all lowercased, or all uppercased. You can either update `master_dat`, `critter_dat`, `master_patches` and `critter_patches` settings to match your file names, or rename files to match entries in your `fallout2.cfg`.
|
||||
|
||||
The `sound` folder (with `music` folder inside) might be located either in `data` folder, or be in the Fallout folder. Update `music_path1` setting to match your hierarchy, usually it's `data/sound/music/` or `sound/music/`. Make sure it matches your path exactly (so it might be `SOUND/MUSIC/` if you've installed Fallout from CD). Music files themselves (with `ACM` extension) should be all uppercased, regardless of `sound` and `music` folders.
|
||||
|
||||
The second configuration file is `f2_res.ini`. Use it to change game window size and enable/disable fullscreen mode.
|
||||
|
||||
```ini
|
||||
[MAIN]
|
||||
SCR_WIDTH=1280
|
||||
SCR_HEIGHT=720
|
||||
WINDOWED=1
|
||||
```
|
||||
|
||||
Recommendations:
|
||||
- **Desktops**: Use any size you see fit.
|
||||
- **Tablets**: Set these values to logical resolution of your device, for example iPad Pro 11 is 1668x2388 (pixels), but it's logical resolution is 834x1194 (points).
|
||||
- **Mobile phones**: Set height to 480, calculate width according to your device screen (aspect) ratio, for example Samsung S21 is 20:9 device, so the width should be 480 * 20 / 9 = 1067.
|
||||
|
||||
In time this stuff will receive in-game interface, right now you have to do it manually.
|
||||
|
||||
The third configuration file is `ddraw.ini` (part of Sfall). There are dozens of options that adjust or override engine behaviour and gameplay mechanics. This file is intended for modders and advanced users. Currently only a small subset of these settings are actually implemented.
|
||||
|
||||
## Contributing
|
||||
|
||||
Integrating Sfall goodies is the top priority. Quality of life updates are OK too. Please no large scale refactorings at this time as we need to reconcile changes from Reference Edition, which will make this process slow and error-prone. In any case open up an issue with your suggestion or to notify other people that something is being worked on.
|
||||
@@ -42,6 +98,6 @@ Integrating Sfall goodies is the top priority. Quality of life updates are OK to
|
||||
|
||||
There are literally hundreds if not thousands of fixes and features in sfall. I guess not all of them are needed in Community Edition, but for the sake of compatibility with big mods out there, let's integrate them all.
|
||||
|
||||
## Legal & License
|
||||
## License
|
||||
|
||||
See [Fallout 2 Reference Edition](https://github.com/alexbatalov/fallout2-re). Same conditions apply until the source code in this repository is changed significantly.
|
||||
The source code is this repository is available under the [Sustainable Use License](LICENSE.md).
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
set( CMAKE_SYSTEM_NAME "Linux" )
|
||||
set( CMAKE_SYSTEM_PROCESSOR "i386" )
|
||||
set( CMAKE_C_FLAGS "-m32" )
|
||||
set( CMAKE_CXX_FLAGS "-m32" )
|
||||
4
os/android/.gitignore
vendored
@@ -7,3 +7,7 @@
|
||||
/.idea/navEditor.xml
|
||||
/.idea/workspace.xml
|
||||
/local.properties
|
||||
/debug-keystore.properties
|
||||
/debug.keystore
|
||||
/release-keystore.properties
|
||||
/release.keystore
|
||||
|
||||
3
os/android/app/.gitignore
vendored
@@ -1,2 +1,5 @@
|
||||
/.cxx
|
||||
/build
|
||||
|
||||
# TODO: Cleanup root .gitignore
|
||||
!/src/debug
|
||||
|
||||
@@ -9,8 +9,8 @@ android {
|
||||
applicationId 'com.alexbatalov.fallout2ce'
|
||||
minSdk 21
|
||||
targetSdk 32
|
||||
versionCode 1
|
||||
versionName '1.0'
|
||||
versionCode 4
|
||||
versionName '1.3.0'
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments '-DANDROID_STL=c++_static'
|
||||
@@ -26,10 +26,49 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
// Override default debug signing config to make sure every CI runner
|
||||
// uses the same key for painless updates.
|
||||
def debugKeystorePropertiesFile = rootProject.file('debug-keystore.properties')
|
||||
if (debugKeystorePropertiesFile.exists()) {
|
||||
def debugKeystoreProperties = new Properties()
|
||||
debugKeystoreProperties.load(new FileInputStream(debugKeystorePropertiesFile))
|
||||
|
||||
debug {
|
||||
storeFile rootProject.file(debugKeystoreProperties.getProperty('storeFile'))
|
||||
storePassword debugKeystoreProperties.getProperty('storePassword')
|
||||
keyAlias debugKeystoreProperties.getProperty('keyAlias')
|
||||
keyPassword debugKeystoreProperties.getProperty('keyPassword')
|
||||
}
|
||||
}
|
||||
|
||||
def releaseKeystoreProperties = new Properties()
|
||||
def releaseKeystorePropertiesFile = rootProject.file('release-keystore.properties')
|
||||
if (releaseKeystorePropertiesFile.exists()) {
|
||||
releaseKeystoreProperties.load(new FileInputStream(releaseKeystorePropertiesFile))
|
||||
|
||||
release {
|
||||
storeFile rootProject.file(releaseKeystoreProperties.getProperty('storeFile'))
|
||||
storePassword releaseKeystoreProperties.getProperty('storePassword')
|
||||
keyAlias releaseKeystoreProperties.getProperty('keyAlias')
|
||||
keyPassword releaseKeystoreProperties.getProperty('keyPassword')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
// Prevents signing keys clashes between debug and release versions
|
||||
// for painless development.
|
||||
applicationIdSuffix '.debug'
|
||||
}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
|
||||
// Release signing config is optional and might not be present in CI
|
||||
// builds, hence `findByName`.
|
||||
signingConfig signingConfigs.findByName('release')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,4 +96,5 @@ android {
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||
}
|
||||
|
||||
3
os/android/app/src/debug/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Fallout 2 (Debug)</string>
|
||||
</resources>
|
||||
@@ -58,6 +58,7 @@
|
||||
An example Java class can be found in README-android.md
|
||||
-->
|
||||
<application android:label="@string/app_name"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:allowBackup="true"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||
android:hardwareAccelerated="true" >
|
||||
@@ -92,6 +93,10 @@
|
||||
</intent-filter>
|
||||
-->
|
||||
</activity>
|
||||
|
||||
<activity android:name=".ImportActivity"
|
||||
android:theme="@style/AppTheme">
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.alexbatalov.fallout2ce;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
static boolean copyRecursively(ContentResolver contentResolver, DocumentFile src, File dest) {
|
||||
final DocumentFile[] documentFiles = src.listFiles();
|
||||
for (final DocumentFile documentFile : documentFiles) {
|
||||
if (documentFile.isFile()) {
|
||||
if (!copyFile(contentResolver, documentFile, new File(dest, documentFile.getName()))) {
|
||||
return false;
|
||||
}
|
||||
} else if (documentFile.isDirectory()) {
|
||||
final File subdirectory = new File(dest, documentFile.getName());
|
||||
if (!subdirectory.exists()) {
|
||||
subdirectory.mkdir();
|
||||
}
|
||||
|
||||
if (!copyRecursively(contentResolver, documentFile, subdirectory)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean copyFile(ContentResolver contentResolver, DocumentFile src, File dest) {
|
||||
try {
|
||||
final InputStream inputStream = contentResolver.openInputStream(src.getUri());
|
||||
final OutputStream outputStream = new FileOutputStream(dest);
|
||||
|
||||
final byte[] buffer = new byte[16384];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
inputStream.close();
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.alexbatalov.fallout2ce;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class ImportActivity extends Activity {
|
||||
private static final int IMPORT_REQUEST_CODE = 1;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
startActivityForResult(intent, IMPORT_REQUEST_CODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent resultData) {
|
||||
if (requestCode == IMPORT_REQUEST_CODE) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
final Uri treeUri = resultData.getData();
|
||||
if (treeUri != null) {
|
||||
final DocumentFile treeDocument = DocumentFile.fromTreeUri(this, treeUri);
|
||||
if (treeDocument != null) {
|
||||
copyFiles(treeDocument);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finish();
|
||||
} else {
|
||||
super.onActivityResult(requestCode, resultCode, resultData);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyFiles(DocumentFile treeDocument) {
|
||||
ProgressDialog dialog = createProgressDialog();
|
||||
dialog.show();
|
||||
|
||||
new Thread(() -> {
|
||||
ContentResolver contentResolver = getContentResolver();
|
||||
File externalFilesDir = getExternalFilesDir(null);
|
||||
FileUtils.copyRecursively(contentResolver, treeDocument, externalFilesDir);
|
||||
|
||||
startMainActivity();
|
||||
dialog.dismiss();
|
||||
finish();
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void startMainActivity() {
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private ProgressDialog createProgressDialog() {
|
||||
ProgressDialog progressDialog = new ProgressDialog(this,
|
||||
android.R.style.Theme_Material_Light_Dialog);
|
||||
progressDialog.setTitle(R.string.loading_dialog_title);
|
||||
progressDialog.setMessage(getString(R.string.loading_dialog_message));
|
||||
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
progressDialog.setCancelable(false);
|
||||
|
||||
return progressDialog;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,47 @@
|
||||
package com.alexbatalov.fallout2ce;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.libsdl.app.SDLActivity;
|
||||
|
||||
public class MainActivity extends SDLActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
// Needed to initialize `files` folder (and make it publicly accessible
|
||||
// for file managers) for user to upload assets.
|
||||
getExternalFilesDir(null);
|
||||
import java.io.File;
|
||||
|
||||
public class MainActivity extends SDLActivity {
|
||||
private boolean noExit = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final File externalFilesDir = getExternalFilesDir(null);
|
||||
|
||||
final File configFile = new File(externalFilesDir, "fallout2.cfg");
|
||||
if (!configFile.exists()) {
|
||||
final File masterDatFile = new File(externalFilesDir, "master.dat");
|
||||
final File critterDatFile = new File(externalFilesDir, "critter.dat");
|
||||
if (!masterDatFile.exists() || !critterDatFile.exists()) {
|
||||
final Intent intent = new Intent(this, ImportActivity.class);
|
||||
startActivity(intent);
|
||||
|
||||
noExit = true;
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
if (!noExit) {
|
||||
// Needed to make sure libc calls exit handlers, which releases
|
||||
// in-game resources.
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getLibraries() {
|
||||
return new String[]{
|
||||
"fallout2-ce",
|
||||
|
||||
@@ -15,13 +15,9 @@ import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@@ -37,11 +33,8 @@ import android.view.Display;
|
||||
import android.view.Gravity;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.PointerIcon;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
@@ -51,6 +44,7 @@ import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
@@ -65,6 +59,9 @@ import java.util.Locale;
|
||||
*/
|
||||
public class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener {
|
||||
private static final String TAG = "SDL";
|
||||
private static final int SDL_MAJOR_VERSION = 2;
|
||||
private static final int SDL_MINOR_VERSION = 26;
|
||||
private static final int SDL_MICRO_VERSION = 1;
|
||||
/*
|
||||
// Display InputType.SOURCE/CLASS of events and devices
|
||||
//
|
||||
@@ -213,7 +210,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
// Main components
|
||||
protected static SDLActivity mSingleton;
|
||||
protected static SDLSurface mSurface;
|
||||
protected static View mTextEdit;
|
||||
protected static DummyEdit mTextEdit;
|
||||
protected static boolean mScreenKeyboardShown;
|
||||
protected static ViewGroup mLayout;
|
||||
protected static SDLClipboardHandler mClipboardHandler;
|
||||
@@ -314,6 +311,10 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
mNextNativeState = NativeState.INIT;
|
||||
mCurrentNativeState = NativeState.INIT;
|
||||
}
|
||||
|
||||
protected SDLSurface createSDLSurface(Context context) {
|
||||
return new SDLSurface(context);
|
||||
}
|
||||
|
||||
// Setup
|
||||
@Override
|
||||
@@ -344,8 +345,18 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
errorMsgBrokenLib = e.getMessage();
|
||||
}
|
||||
|
||||
if (mBrokenLibraries)
|
||||
{
|
||||
if (!mBrokenLibraries) {
|
||||
String expected_version = String.valueOf(SDL_MAJOR_VERSION) + "." +
|
||||
String.valueOf(SDL_MINOR_VERSION) + "." +
|
||||
String.valueOf(SDL_MICRO_VERSION);
|
||||
String version = nativeGetVersion();
|
||||
if (!version.equals(expected_version)) {
|
||||
mBrokenLibraries = true;
|
||||
errorMsgBrokenLib = "SDL C/Java version mismatch (expected " + expected_version + ", got " + version + ")";
|
||||
}
|
||||
}
|
||||
|
||||
if (mBrokenLibraries) {
|
||||
mSingleton = this;
|
||||
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this);
|
||||
dlgAlert.setMessage("An error occurred while trying to start the application. Please try again and/or reinstall."
|
||||
@@ -382,7 +393,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
mHIDDeviceManager = HIDDeviceManager.acquire(this);
|
||||
|
||||
// Set up the surface
|
||||
mSurface = new SDLSurface(getApplication());
|
||||
mSurface = createSDLSurface(getApplication());
|
||||
|
||||
mLayout = new RelativeLayout(this);
|
||||
mLayout.addView(mSurface);
|
||||
@@ -886,6 +897,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
}
|
||||
|
||||
// C functions we call
|
||||
public static native String nativeGetVersion();
|
||||
public static native int nativeSetupJNI();
|
||||
public static native int nativeRunMain(String library, String function, Object arguments);
|
||||
public static native void nativeLowMemory();
|
||||
@@ -1220,8 +1232,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
}
|
||||
|
||||
// This method is called by SDLControllerManager's API 26 Generic Motion Handler.
|
||||
public static View getContentView()
|
||||
{
|
||||
public static View getContentView() {
|
||||
return mLayout;
|
||||
}
|
||||
|
||||
@@ -1292,6 +1303,77 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
return event.isPrintingKey() || event.getKeyCode() == KeyEvent.KEYCODE_SPACE;
|
||||
}
|
||||
|
||||
public static boolean handleKeyEvent(View v, int keyCode, KeyEvent event, InputConnection ic) {
|
||||
int deviceId = event.getDeviceId();
|
||||
int source = event.getSource();
|
||||
|
||||
if (source == InputDevice.SOURCE_UNKNOWN) {
|
||||
InputDevice device = InputDevice.getDevice(deviceId);
|
||||
if (device != null) {
|
||||
source = device.getSources();
|
||||
}
|
||||
}
|
||||
|
||||
// if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
// Log.v("SDL", "key down: " + keyCode + ", deviceId = " + deviceId + ", source = " + source);
|
||||
// } else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
// Log.v("SDL", "key up: " + keyCode + ", deviceId = " + deviceId + ", source = " + source);
|
||||
// }
|
||||
|
||||
// Dispatch the different events depending on where they come from
|
||||
// Some SOURCE_JOYSTICK, SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
|
||||
// So, we try to process them as JOYSTICK/DPAD/GAMEPAD events first, if that fails we try them as KEYBOARD
|
||||
//
|
||||
// Furthermore, it's possible a game controller has SOURCE_KEYBOARD and
|
||||
// SOURCE_JOYSTICK, while its key events arrive from the keyboard source
|
||||
// So, retrieve the device itself and check all of its sources
|
||||
if (SDLControllerManager.isDeviceSDLJoystick(deviceId)) {
|
||||
// Note that we process events with specific key codes here
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (SDLControllerManager.onNativePadDown(deviceId, keyCode) == 0) {
|
||||
return true;
|
||||
}
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
if (SDLControllerManager.onNativePadUp(deviceId, keyCode) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD) {
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (isTextInputEvent(event)) {
|
||||
if (ic != null) {
|
||||
ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
|
||||
} else {
|
||||
SDLInputConnection.nativeCommitText(String.valueOf((char) event.getUnicodeChar()), 1);
|
||||
}
|
||||
}
|
||||
onNativeKeyDown(keyCode);
|
||||
return true;
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
onNativeKeyUp(keyCode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
|
||||
// on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
|
||||
// they are ignored here because sending them as mouse input to SDL is messy
|
||||
if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) {
|
||||
switch (event.getAction()) {
|
||||
case KeyEvent.ACTION_DOWN:
|
||||
case KeyEvent.ACTION_UP:
|
||||
// mark the event as handled or it will be handled by system
|
||||
// handling KEYCODE_BACK by system will call onBackPressed()
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by SDL using JNI.
|
||||
*/
|
||||
@@ -1809,455 +1891,6 @@ class SDLMain implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
SDLSurface. This is what we draw on, so we need to know when it's created
|
||||
in order to do anything useful.
|
||||
|
||||
Because of this, that's where we set up the SDL thread
|
||||
*/
|
||||
class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||
View.OnKeyListener, View.OnTouchListener, SensorEventListener {
|
||||
|
||||
// Sensors
|
||||
protected SensorManager mSensorManager;
|
||||
protected Display mDisplay;
|
||||
|
||||
// Keep track of the surface size to normalize touch events
|
||||
protected float mWidth, mHeight;
|
||||
|
||||
// Is SurfaceView ready for rendering
|
||||
public boolean mIsSurfaceReady;
|
||||
|
||||
// Startup
|
||||
public SDLSurface(Context context) {
|
||||
super(context);
|
||||
getHolder().addCallback(this);
|
||||
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
requestFocus();
|
||||
setOnKeyListener(this);
|
||||
setOnTouchListener(this);
|
||||
|
||||
mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
|
||||
mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
|
||||
|
||||
setOnGenericMotionListener(SDLActivity.getMotionListener());
|
||||
|
||||
// Some arbitrary defaults to avoid a potential division by zero
|
||||
mWidth = 1.0f;
|
||||
mHeight = 1.0f;
|
||||
|
||||
mIsSurfaceReady = false;
|
||||
}
|
||||
|
||||
public void handlePause() {
|
||||
enableSensor(Sensor.TYPE_ACCELEROMETER, false);
|
||||
}
|
||||
|
||||
public void handleResume() {
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
requestFocus();
|
||||
setOnKeyListener(this);
|
||||
setOnTouchListener(this);
|
||||
enableSensor(Sensor.TYPE_ACCELEROMETER, true);
|
||||
}
|
||||
|
||||
public Surface getNativeSurface() {
|
||||
return getHolder().getSurface();
|
||||
}
|
||||
|
||||
// Called when we have a valid drawing surface
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
Log.v("SDL", "surfaceCreated()");
|
||||
SDLActivity.onNativeSurfaceCreated();
|
||||
}
|
||||
|
||||
// Called when we lose the surface
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
Log.v("SDL", "surfaceDestroyed()");
|
||||
|
||||
// Transition to pause, if needed
|
||||
SDLActivity.mNextNativeState = SDLActivity.NativeState.PAUSED;
|
||||
SDLActivity.handleNativeState();
|
||||
|
||||
mIsSurfaceReady = false;
|
||||
SDLActivity.onNativeSurfaceDestroyed();
|
||||
}
|
||||
|
||||
// Called when the surface is resized
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder,
|
||||
int format, int width, int height) {
|
||||
Log.v("SDL", "surfaceChanged()");
|
||||
|
||||
if (SDLActivity.mSingleton == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
int nDeviceWidth = width;
|
||||
int nDeviceHeight = height;
|
||||
try
|
||||
{
|
||||
if (Build.VERSION.SDK_INT >= 17) {
|
||||
DisplayMetrics realMetrics = new DisplayMetrics();
|
||||
mDisplay.getRealMetrics( realMetrics );
|
||||
nDeviceWidth = realMetrics.widthPixels;
|
||||
nDeviceHeight = realMetrics.heightPixels;
|
||||
}
|
||||
} catch(Exception ignored) {
|
||||
}
|
||||
|
||||
synchronized(SDLActivity.getContext()) {
|
||||
// In case we're waiting on a size change after going fullscreen, send a notification.
|
||||
SDLActivity.getContext().notifyAll();
|
||||
}
|
||||
|
||||
Log.v("SDL", "Window size: " + width + "x" + height);
|
||||
Log.v("SDL", "Device size: " + nDeviceWidth + "x" + nDeviceHeight);
|
||||
SDLActivity.nativeSetScreenResolution(width, height, nDeviceWidth, nDeviceHeight, mDisplay.getRefreshRate());
|
||||
SDLActivity.onNativeResize();
|
||||
|
||||
// Prevent a screen distortion glitch,
|
||||
// for instance when the device is in Landscape and a Portrait App is resumed.
|
||||
boolean skip = false;
|
||||
int requestedOrientation = SDLActivity.mSingleton.getRequestedOrientation();
|
||||
|
||||
if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
|
||||
if (mWidth > mHeight) {
|
||||
skip = true;
|
||||
}
|
||||
} else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
|
||||
if (mWidth < mHeight) {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Special Patch for Square Resolution: Black Berry Passport
|
||||
if (skip) {
|
||||
double min = Math.min(mWidth, mHeight);
|
||||
double max = Math.max(mWidth, mHeight);
|
||||
|
||||
if (max / min < 1.20) {
|
||||
Log.v("SDL", "Don't skip on such aspect-ratio. Could be a square resolution.");
|
||||
skip = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't skip in MultiWindow.
|
||||
if (skip) {
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
if (SDLActivity.mSingleton.isInMultiWindowMode()) {
|
||||
Log.v("SDL", "Don't skip in Multi-Window");
|
||||
skip = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
Log.v("SDL", "Skip .. Surface is not ready.");
|
||||
mIsSurfaceReady = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */
|
||||
SDLActivity.onNativeSurfaceChanged();
|
||||
|
||||
/* Surface is ready */
|
||||
mIsSurfaceReady = true;
|
||||
|
||||
SDLActivity.mNextNativeState = SDLActivity.NativeState.RESUMED;
|
||||
SDLActivity.handleNativeState();
|
||||
}
|
||||
|
||||
// Key events
|
||||
@Override
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
|
||||
int deviceId = event.getDeviceId();
|
||||
int source = event.getSource();
|
||||
|
||||
if (source == InputDevice.SOURCE_UNKNOWN) {
|
||||
InputDevice device = InputDevice.getDevice(deviceId);
|
||||
if (device != null) {
|
||||
source = device.getSources();
|
||||
}
|
||||
}
|
||||
|
||||
// if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
// Log.v("SDL", "key down: " + keyCode + ", deviceId = " + deviceId + ", source = " + source);
|
||||
// } else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
// Log.v("SDL", "key up: " + keyCode + ", deviceId = " + deviceId + ", source = " + source);
|
||||
// }
|
||||
|
||||
// Dispatch the different events depending on where they come from
|
||||
// Some SOURCE_JOYSTICK, SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
|
||||
// So, we try to process them as JOYSTICK/DPAD/GAMEPAD events first, if that fails we try them as KEYBOARD
|
||||
//
|
||||
// Furthermore, it's possible a game controller has SOURCE_KEYBOARD and
|
||||
// SOURCE_JOYSTICK, while its key events arrive from the keyboard source
|
||||
// So, retrieve the device itself and check all of its sources
|
||||
if (SDLControllerManager.isDeviceSDLJoystick(deviceId)) {
|
||||
// Note that we process events with specific key codes here
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (SDLControllerManager.onNativePadDown(deviceId, keyCode) == 0) {
|
||||
return true;
|
||||
}
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
if (SDLControllerManager.onNativePadUp(deviceId, keyCode) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD) {
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (SDLActivity.isTextInputEvent(event)) {
|
||||
SDLInputConnection.nativeCommitText(String.valueOf((char) event.getUnicodeChar()), 1);
|
||||
}
|
||||
SDLActivity.onNativeKeyDown(keyCode);
|
||||
return true;
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
SDLActivity.onNativeKeyUp(keyCode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
|
||||
// on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
|
||||
// they are ignored here because sending them as mouse input to SDL is messy
|
||||
if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) {
|
||||
switch (event.getAction()) {
|
||||
case KeyEvent.ACTION_DOWN:
|
||||
case KeyEvent.ACTION_UP:
|
||||
// mark the event as handled or it will be handled by system
|
||||
// handling KEYCODE_BACK by system will call onBackPressed()
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Touch events
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
/* Ref: http://developer.android.com/training/gestures/multi.html */
|
||||
int touchDevId = event.getDeviceId();
|
||||
final int pointerCount = event.getPointerCount();
|
||||
int action = event.getActionMasked();
|
||||
int pointerFingerId;
|
||||
int i = -1;
|
||||
float x,y,p;
|
||||
|
||||
/*
|
||||
* Prevent id to be -1, since it's used in SDL internal for synthetic events
|
||||
* Appears when using Android emulator, eg:
|
||||
* adb shell input mouse tap 100 100
|
||||
* adb shell input touchscreen tap 100 100
|
||||
*/
|
||||
if (touchDevId < 0) {
|
||||
touchDevId -= 1;
|
||||
}
|
||||
|
||||
// 12290 = Samsung DeX mode desktop mouse
|
||||
// 12290 = 0x3002 = 0x2002 | 0x1002 = SOURCE_MOUSE | SOURCE_TOUCHSCREEN
|
||||
// 0x2 = SOURCE_CLASS_POINTER
|
||||
if (event.getSource() == InputDevice.SOURCE_MOUSE || event.getSource() == (InputDevice.SOURCE_MOUSE | InputDevice.SOURCE_TOUCHSCREEN)) {
|
||||
int mouseButton = 1;
|
||||
try {
|
||||
Object object = event.getClass().getMethod("getButtonState").invoke(event);
|
||||
if (object != null) {
|
||||
mouseButton = (Integer) object;
|
||||
}
|
||||
} catch(Exception ignored) {
|
||||
}
|
||||
|
||||
// We need to check if we're in relative mouse mode and get the axis offset rather than the x/y values
|
||||
// if we are. We'll leverage our existing mouse motion listener
|
||||
SDLGenericMotionListener_API12 motionListener = SDLActivity.getMotionListener();
|
||||
x = motionListener.getEventX(event);
|
||||
y = motionListener.getEventY(event);
|
||||
|
||||
SDLActivity.onNativeMouse(mouseButton, action, x, y, motionListener.inRelativeMode());
|
||||
} else {
|
||||
switch(action) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
for (i = 0; i < pointerCount; i++) {
|
||||
pointerFingerId = event.getPointerId(i);
|
||||
x = event.getX(i) / mWidth;
|
||||
y = event.getY(i) / mHeight;
|
||||
p = event.getPressure(i);
|
||||
if (p > 1.0f) {
|
||||
// may be larger than 1.0f on some devices
|
||||
// see the documentation of getPressure(i)
|
||||
p = 1.0f;
|
||||
}
|
||||
SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
// Primary pointer up/down, the index is always zero
|
||||
i = 0;
|
||||
/* fallthrough */
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
// Non primary pointer up/down
|
||||
if (i == -1) {
|
||||
i = event.getActionIndex();
|
||||
}
|
||||
|
||||
pointerFingerId = event.getPointerId(i);
|
||||
x = event.getX(i) / mWidth;
|
||||
y = event.getY(i) / mHeight;
|
||||
p = event.getPressure(i);
|
||||
if (p > 1.0f) {
|
||||
// may be larger than 1.0f on some devices
|
||||
// see the documentation of getPressure(i)
|
||||
p = 1.0f;
|
||||
}
|
||||
SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
for (i = 0; i < pointerCount; i++) {
|
||||
pointerFingerId = event.getPointerId(i);
|
||||
x = event.getX(i) / mWidth;
|
||||
y = event.getY(i) / mHeight;
|
||||
p = event.getPressure(i);
|
||||
if (p > 1.0f) {
|
||||
// may be larger than 1.0f on some devices
|
||||
// see the documentation of getPressure(i)
|
||||
p = 1.0f;
|
||||
}
|
||||
SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sensor events
|
||||
public void enableSensor(int sensortype, boolean enabled) {
|
||||
// TODO: This uses getDefaultSensor - what if we have >1 accels?
|
||||
if (enabled) {
|
||||
mSensorManager.registerListener(this,
|
||||
mSensorManager.getDefaultSensor(sensortype),
|
||||
SensorManager.SENSOR_DELAY_GAME, null);
|
||||
} else {
|
||||
mSensorManager.unregisterListener(this,
|
||||
mSensorManager.getDefaultSensor(sensortype));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
|
||||
|
||||
// Since we may have an orientation set, we won't receive onConfigurationChanged events.
|
||||
// We thus should check here.
|
||||
int newOrientation;
|
||||
|
||||
float x, y;
|
||||
switch (mDisplay.getRotation()) {
|
||||
case Surface.ROTATION_90:
|
||||
x = -event.values[1];
|
||||
y = event.values[0];
|
||||
newOrientation = SDLActivity.SDL_ORIENTATION_LANDSCAPE;
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
x = event.values[1];
|
||||
y = -event.values[0];
|
||||
newOrientation = SDLActivity.SDL_ORIENTATION_LANDSCAPE_FLIPPED;
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
x = -event.values[0];
|
||||
y = -event.values[1];
|
||||
newOrientation = SDLActivity.SDL_ORIENTATION_PORTRAIT_FLIPPED;
|
||||
break;
|
||||
case Surface.ROTATION_0:
|
||||
default:
|
||||
x = event.values[0];
|
||||
y = event.values[1];
|
||||
newOrientation = SDLActivity.SDL_ORIENTATION_PORTRAIT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (newOrientation != SDLActivity.mCurrentOrientation) {
|
||||
SDLActivity.mCurrentOrientation = newOrientation;
|
||||
SDLActivity.onNativeOrientationChanged(newOrientation);
|
||||
}
|
||||
|
||||
SDLActivity.onNativeAccel(-x / SensorManager.GRAVITY_EARTH,
|
||||
y / SensorManager.GRAVITY_EARTH,
|
||||
event.values[2] / SensorManager.GRAVITY_EARTH);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Captured pointer events for API 26.
|
||||
public boolean onCapturedPointerEvent(MotionEvent event)
|
||||
{
|
||||
int action = event.getActionMasked();
|
||||
|
||||
float x, y;
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_SCROLL:
|
||||
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
|
||||
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
|
||||
SDLActivity.onNativeMouse(0, action, x, y, false);
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_HOVER_MOVE:
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
x = event.getX(0);
|
||||
y = event.getY(0);
|
||||
SDLActivity.onNativeMouse(0, action, x, y, true);
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_BUTTON_PRESS:
|
||||
case MotionEvent.ACTION_BUTTON_RELEASE:
|
||||
|
||||
// Change our action value to what SDL's code expects.
|
||||
if (action == MotionEvent.ACTION_BUTTON_PRESS) {
|
||||
action = MotionEvent.ACTION_DOWN;
|
||||
} else { /* MotionEvent.ACTION_BUTTON_RELEASE */
|
||||
action = MotionEvent.ACTION_UP;
|
||||
}
|
||||
|
||||
x = event.getX(0);
|
||||
y = event.getY(0);
|
||||
int button = event.getButtonState();
|
||||
|
||||
SDLActivity.onNativeMouse(button, action, x, y, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* This is a fake invisible editor view that receives the input and defines the
|
||||
* pan&scan region
|
||||
*/
|
||||
@@ -2278,21 +1911,7 @@ class DummyEdit extends View implements View.OnKeyListener {
|
||||
|
||||
@Override
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
/*
|
||||
* This handles the hardware keyboard input
|
||||
*/
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (SDLActivity.isTextInputEvent(event)) {
|
||||
ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
|
||||
return true;
|
||||
}
|
||||
SDLActivity.onNativeKeyDown(keyCode);
|
||||
return true;
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
SDLActivity.onNativeKeyUp(keyCode);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return SDLActivity.handleKeyEvent(v, keyCode, event, ic);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -2316,9 +1935,10 @@ class DummyEdit extends View implements View.OnKeyListener {
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||
ic = new SDLInputConnection(this, true);
|
||||
|
||||
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
|
||||
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
|
||||
| EditorInfo.IME_FLAG_NO_FULLSCREEN /* API 11 */;
|
||||
outAttrs.inputType = InputType.TYPE_CLASS_TEXT |
|
||||
InputType.TYPE_TEXT_FLAG_MULTI_LINE;
|
||||
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI |
|
||||
EditorInfo.IME_FLAG_NO_FULLSCREEN /* API 11 */;
|
||||
|
||||
return ic;
|
||||
}
|
||||
@@ -2326,9 +1946,17 @@ class DummyEdit extends View implements View.OnKeyListener {
|
||||
|
||||
class SDLInputConnection extends BaseInputConnection {
|
||||
|
||||
protected EditText mEditText;
|
||||
protected String mCommittedText = "";
|
||||
|
||||
public SDLInputConnection(View targetView, boolean fullEditor) {
|
||||
super(targetView, fullEditor);
|
||||
mEditText = new EditText(SDL.getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editable getEditable() {
|
||||
return mEditText.getEditableText();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2351,79 +1979,84 @@ class SDLInputConnection extends BaseInputConnection {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return super.sendKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean commitText(CharSequence text, int newCursorPosition) {
|
||||
|
||||
/* Generate backspaces for the text we're going to replace */
|
||||
final Editable content = getEditable();
|
||||
if (content != null) {
|
||||
int a = getComposingSpanStart(content);
|
||||
int b = getComposingSpanEnd(content);
|
||||
if (a == -1 || b == -1) {
|
||||
a = Selection.getSelectionStart(content);
|
||||
b = Selection.getSelectionEnd(content);
|
||||
}
|
||||
if (a < 0) a = 0;
|
||||
if (b < 0) b = 0;
|
||||
if (b < a) {
|
||||
int tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
int backspaces = (b - a);
|
||||
|
||||
for (int i = 0; i < backspaces; i++) {
|
||||
nativeGenerateScancodeForUnichar('\b');
|
||||
}
|
||||
if (!super.commitText(text, newCursorPosition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
char c = text.charAt(i);
|
||||
if (c == '\n') {
|
||||
if (SDLActivity.onNativeSoftReturnKey()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
nativeGenerateScancodeForUnichar(c);
|
||||
}
|
||||
|
||||
SDLInputConnection.nativeCommitText(text.toString(), newCursorPosition);
|
||||
|
||||
return super.commitText(text, newCursorPosition);
|
||||
updateText();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setComposingText(CharSequence text, int newCursorPosition) {
|
||||
if (!super.setComposingText(text, newCursorPosition)) {
|
||||
return false;
|
||||
}
|
||||
updateText();
|
||||
return true;
|
||||
}
|
||||
|
||||
nativeSetComposingText(text.toString(), newCursorPosition);
|
||||
@Override
|
||||
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
||||
if (!super.deleteSurroundingText(beforeLength, afterLength)) {
|
||||
return false;
|
||||
}
|
||||
updateText();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.setComposingText(text, newCursorPosition);
|
||||
protected void updateText() {
|
||||
final Editable content = getEditable();
|
||||
if (content == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String text = content.toString();
|
||||
int compareLength = Math.min(text.length(), mCommittedText.length());
|
||||
int matchLength, offset;
|
||||
|
||||
/* Backspace over characters that are no longer in the string */
|
||||
for (matchLength = 0; matchLength < compareLength; ) {
|
||||
int codePoint = mCommittedText.codePointAt(matchLength);
|
||||
if (codePoint != text.codePointAt(matchLength)) {
|
||||
break;
|
||||
}
|
||||
matchLength += Character.charCount(codePoint);
|
||||
}
|
||||
/* FIXME: This doesn't handle graphemes, like '🌬️' */
|
||||
for (offset = matchLength; offset < mCommittedText.length(); ) {
|
||||
int codePoint = mCommittedText.codePointAt(offset);
|
||||
nativeGenerateScancodeForUnichar('\b');
|
||||
offset += Character.charCount(codePoint);
|
||||
}
|
||||
|
||||
if (matchLength < text.length()) {
|
||||
String pendingText = text.subSequence(matchLength, text.length()).toString();
|
||||
for (offset = 0; offset < pendingText.length(); ) {
|
||||
int codePoint = pendingText.codePointAt(offset);
|
||||
if (codePoint == '\n') {
|
||||
if (SDLActivity.onNativeSoftReturnKey()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Higher code points don't generate simulated scancodes */
|
||||
if (codePoint < 128) {
|
||||
nativeGenerateScancodeForUnichar((char)codePoint);
|
||||
}
|
||||
offset += Character.charCount(codePoint);
|
||||
}
|
||||
SDLInputConnection.nativeCommitText(pendingText, 0);
|
||||
}
|
||||
mCommittedText = text;
|
||||
}
|
||||
|
||||
public static native void nativeCommitText(String text, int newCursorPosition);
|
||||
|
||||
public native void nativeGenerateScancodeForUnichar(char c);
|
||||
|
||||
public native void nativeSetComposingText(String text, int newCursorPosition);
|
||||
|
||||
@Override
|
||||
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
||||
// Workaround to capture backspace key. Ref: http://stackoverflow.com/questions/14560344/android-backspace-in-webview-baseinputconnection
|
||||
// and https://bugzilla.libsdl.org/show_bug.cgi?id=2265
|
||||
if (beforeLength > 0 && afterLength == 0) {
|
||||
// backspace(s)
|
||||
while (beforeLength-- > 0) {
|
||||
nativeGenerateScancodeForUnichar('\b');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.deleteSurroundingText(beforeLength, afterLength);
|
||||
}
|
||||
public static native void nativeGenerateScancodeForUnichar(char c);
|
||||
}
|
||||
|
||||
class SDLClipboardHandler implements
|
||||
|
||||
405
os/android/app/src/main/java/org/libsdl/app/SDLSurface.java
Normal file
@@ -0,0 +1,405 @@
|
||||
package org.libsdl.app;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Build;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
|
||||
/**
|
||||
SDLSurface. This is what we draw on, so we need to know when it's created
|
||||
in order to do anything useful.
|
||||
|
||||
Because of this, that's where we set up the SDL thread
|
||||
*/
|
||||
public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||
View.OnKeyListener, View.OnTouchListener, SensorEventListener {
|
||||
|
||||
// Sensors
|
||||
protected SensorManager mSensorManager;
|
||||
protected Display mDisplay;
|
||||
|
||||
// Keep track of the surface size to normalize touch events
|
||||
protected float mWidth, mHeight;
|
||||
|
||||
// Is SurfaceView ready for rendering
|
||||
public boolean mIsSurfaceReady;
|
||||
|
||||
// Startup
|
||||
public SDLSurface(Context context) {
|
||||
super(context);
|
||||
getHolder().addCallback(this);
|
||||
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
requestFocus();
|
||||
setOnKeyListener(this);
|
||||
setOnTouchListener(this);
|
||||
|
||||
mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
|
||||
mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
|
||||
|
||||
setOnGenericMotionListener(SDLActivity.getMotionListener());
|
||||
|
||||
// Some arbitrary defaults to avoid a potential division by zero
|
||||
mWidth = 1.0f;
|
||||
mHeight = 1.0f;
|
||||
|
||||
mIsSurfaceReady = false;
|
||||
}
|
||||
|
||||
public void handlePause() {
|
||||
enableSensor(Sensor.TYPE_ACCELEROMETER, false);
|
||||
}
|
||||
|
||||
public void handleResume() {
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
requestFocus();
|
||||
setOnKeyListener(this);
|
||||
setOnTouchListener(this);
|
||||
enableSensor(Sensor.TYPE_ACCELEROMETER, true);
|
||||
}
|
||||
|
||||
public Surface getNativeSurface() {
|
||||
return getHolder().getSurface();
|
||||
}
|
||||
|
||||
// Called when we have a valid drawing surface
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
Log.v("SDL", "surfaceCreated()");
|
||||
SDLActivity.onNativeSurfaceCreated();
|
||||
}
|
||||
|
||||
// Called when we lose the surface
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
Log.v("SDL", "surfaceDestroyed()");
|
||||
|
||||
// Transition to pause, if needed
|
||||
SDLActivity.mNextNativeState = SDLActivity.NativeState.PAUSED;
|
||||
SDLActivity.handleNativeState();
|
||||
|
||||
mIsSurfaceReady = false;
|
||||
SDLActivity.onNativeSurfaceDestroyed();
|
||||
}
|
||||
|
||||
// Called when the surface is resized
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder,
|
||||
int format, int width, int height) {
|
||||
Log.v("SDL", "surfaceChanged()");
|
||||
|
||||
if (SDLActivity.mSingleton == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
int nDeviceWidth = width;
|
||||
int nDeviceHeight = height;
|
||||
try
|
||||
{
|
||||
if (Build.VERSION.SDK_INT >= 17) {
|
||||
DisplayMetrics realMetrics = new DisplayMetrics();
|
||||
mDisplay.getRealMetrics( realMetrics );
|
||||
nDeviceWidth = realMetrics.widthPixels;
|
||||
nDeviceHeight = realMetrics.heightPixels;
|
||||
}
|
||||
} catch(Exception ignored) {
|
||||
}
|
||||
|
||||
synchronized(SDLActivity.getContext()) {
|
||||
// In case we're waiting on a size change after going fullscreen, send a notification.
|
||||
SDLActivity.getContext().notifyAll();
|
||||
}
|
||||
|
||||
Log.v("SDL", "Window size: " + width + "x" + height);
|
||||
Log.v("SDL", "Device size: " + nDeviceWidth + "x" + nDeviceHeight);
|
||||
SDLActivity.nativeSetScreenResolution(width, height, nDeviceWidth, nDeviceHeight, mDisplay.getRefreshRate());
|
||||
SDLActivity.onNativeResize();
|
||||
|
||||
// Prevent a screen distortion glitch,
|
||||
// for instance when the device is in Landscape and a Portrait App is resumed.
|
||||
boolean skip = false;
|
||||
int requestedOrientation = SDLActivity.mSingleton.getRequestedOrientation();
|
||||
|
||||
if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
|
||||
if (mWidth > mHeight) {
|
||||
skip = true;
|
||||
}
|
||||
} else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
|
||||
if (mWidth < mHeight) {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Special Patch for Square Resolution: Black Berry Passport
|
||||
if (skip) {
|
||||
double min = Math.min(mWidth, mHeight);
|
||||
double max = Math.max(mWidth, mHeight);
|
||||
|
||||
if (max / min < 1.20) {
|
||||
Log.v("SDL", "Don't skip on such aspect-ratio. Could be a square resolution.");
|
||||
skip = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't skip in MultiWindow.
|
||||
if (skip) {
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
if (SDLActivity.mSingleton.isInMultiWindowMode()) {
|
||||
Log.v("SDL", "Don't skip in Multi-Window");
|
||||
skip = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
Log.v("SDL", "Skip .. Surface is not ready.");
|
||||
mIsSurfaceReady = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */
|
||||
SDLActivity.onNativeSurfaceChanged();
|
||||
|
||||
/* Surface is ready */
|
||||
mIsSurfaceReady = true;
|
||||
|
||||
SDLActivity.mNextNativeState = SDLActivity.NativeState.RESUMED;
|
||||
SDLActivity.handleNativeState();
|
||||
}
|
||||
|
||||
// Key events
|
||||
@Override
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
return SDLActivity.handleKeyEvent(v, keyCode, event, null);
|
||||
}
|
||||
|
||||
// Touch events
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
/* Ref: http://developer.android.com/training/gestures/multi.html */
|
||||
int touchDevId = event.getDeviceId();
|
||||
final int pointerCount = event.getPointerCount();
|
||||
int action = event.getActionMasked();
|
||||
int pointerFingerId;
|
||||
int i = -1;
|
||||
float x,y,p;
|
||||
|
||||
/*
|
||||
* Prevent id to be -1, since it's used in SDL internal for synthetic events
|
||||
* Appears when using Android emulator, eg:
|
||||
* adb shell input mouse tap 100 100
|
||||
* adb shell input touchscreen tap 100 100
|
||||
*/
|
||||
if (touchDevId < 0) {
|
||||
touchDevId -= 1;
|
||||
}
|
||||
|
||||
// 12290 = Samsung DeX mode desktop mouse
|
||||
// 12290 = 0x3002 = 0x2002 | 0x1002 = SOURCE_MOUSE | SOURCE_TOUCHSCREEN
|
||||
// 0x2 = SOURCE_CLASS_POINTER
|
||||
if (event.getSource() == InputDevice.SOURCE_MOUSE || event.getSource() == (InputDevice.SOURCE_MOUSE | InputDevice.SOURCE_TOUCHSCREEN)) {
|
||||
int mouseButton = 1;
|
||||
try {
|
||||
Object object = event.getClass().getMethod("getButtonState").invoke(event);
|
||||
if (object != null) {
|
||||
mouseButton = (Integer) object;
|
||||
}
|
||||
} catch(Exception ignored) {
|
||||
}
|
||||
|
||||
// We need to check if we're in relative mouse mode and get the axis offset rather than the x/y values
|
||||
// if we are. We'll leverage our existing mouse motion listener
|
||||
SDLGenericMotionListener_API12 motionListener = SDLActivity.getMotionListener();
|
||||
x = motionListener.getEventX(event);
|
||||
y = motionListener.getEventY(event);
|
||||
|
||||
SDLActivity.onNativeMouse(mouseButton, action, x, y, motionListener.inRelativeMode());
|
||||
} else {
|
||||
switch(action) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
for (i = 0; i < pointerCount; i++) {
|
||||
pointerFingerId = event.getPointerId(i);
|
||||
x = event.getX(i) / mWidth;
|
||||
y = event.getY(i) / mHeight;
|
||||
p = event.getPressure(i);
|
||||
if (p > 1.0f) {
|
||||
// may be larger than 1.0f on some devices
|
||||
// see the documentation of getPressure(i)
|
||||
p = 1.0f;
|
||||
}
|
||||
SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
// Primary pointer up/down, the index is always zero
|
||||
i = 0;
|
||||
/* fallthrough */
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
// Non primary pointer up/down
|
||||
if (i == -1) {
|
||||
i = event.getActionIndex();
|
||||
}
|
||||
|
||||
pointerFingerId = event.getPointerId(i);
|
||||
x = event.getX(i) / mWidth;
|
||||
y = event.getY(i) / mHeight;
|
||||
p = event.getPressure(i);
|
||||
if (p > 1.0f) {
|
||||
// may be larger than 1.0f on some devices
|
||||
// see the documentation of getPressure(i)
|
||||
p = 1.0f;
|
||||
}
|
||||
SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
for (i = 0; i < pointerCount; i++) {
|
||||
pointerFingerId = event.getPointerId(i);
|
||||
x = event.getX(i) / mWidth;
|
||||
y = event.getY(i) / mHeight;
|
||||
p = event.getPressure(i);
|
||||
if (p > 1.0f) {
|
||||
// may be larger than 1.0f on some devices
|
||||
// see the documentation of getPressure(i)
|
||||
p = 1.0f;
|
||||
}
|
||||
SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sensor events
|
||||
public void enableSensor(int sensortype, boolean enabled) {
|
||||
// TODO: This uses getDefaultSensor - what if we have >1 accels?
|
||||
if (enabled) {
|
||||
mSensorManager.registerListener(this,
|
||||
mSensorManager.getDefaultSensor(sensortype),
|
||||
SensorManager.SENSOR_DELAY_GAME, null);
|
||||
} else {
|
||||
mSensorManager.unregisterListener(this,
|
||||
mSensorManager.getDefaultSensor(sensortype));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
|
||||
|
||||
// Since we may have an orientation set, we won't receive onConfigurationChanged events.
|
||||
// We thus should check here.
|
||||
int newOrientation;
|
||||
|
||||
float x, y;
|
||||
switch (mDisplay.getRotation()) {
|
||||
case Surface.ROTATION_90:
|
||||
x = -event.values[1];
|
||||
y = event.values[0];
|
||||
newOrientation = SDLActivity.SDL_ORIENTATION_LANDSCAPE;
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
x = event.values[1];
|
||||
y = -event.values[0];
|
||||
newOrientation = SDLActivity.SDL_ORIENTATION_LANDSCAPE_FLIPPED;
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
x = -event.values[0];
|
||||
y = -event.values[1];
|
||||
newOrientation = SDLActivity.SDL_ORIENTATION_PORTRAIT_FLIPPED;
|
||||
break;
|
||||
case Surface.ROTATION_0:
|
||||
default:
|
||||
x = event.values[0];
|
||||
y = event.values[1];
|
||||
newOrientation = SDLActivity.SDL_ORIENTATION_PORTRAIT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (newOrientation != SDLActivity.mCurrentOrientation) {
|
||||
SDLActivity.mCurrentOrientation = newOrientation;
|
||||
SDLActivity.onNativeOrientationChanged(newOrientation);
|
||||
}
|
||||
|
||||
SDLActivity.onNativeAccel(-x / SensorManager.GRAVITY_EARTH,
|
||||
y / SensorManager.GRAVITY_EARTH,
|
||||
event.values[2] / SensorManager.GRAVITY_EARTH);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Captured pointer events for API 26.
|
||||
public boolean onCapturedPointerEvent(MotionEvent event)
|
||||
{
|
||||
int action = event.getActionMasked();
|
||||
|
||||
float x, y;
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_SCROLL:
|
||||
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
|
||||
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
|
||||
SDLActivity.onNativeMouse(0, action, x, y, false);
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_HOVER_MOVE:
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
x = event.getX(0);
|
||||
y = event.getY(0);
|
||||
SDLActivity.onNativeMouse(0, action, x, y, true);
|
||||
return true;
|
||||
|
||||
case MotionEvent.ACTION_BUTTON_PRESS:
|
||||
case MotionEvent.ACTION_BUTTON_RELEASE:
|
||||
|
||||
// Change our action value to what SDL's code expects.
|
||||
if (action == MotionEvent.ACTION_BUTTON_PRESS) {
|
||||
action = MotionEvent.ACTION_DOWN;
|
||||
} else { /* MotionEvent.ACTION_BUTTON_RELEASE */
|
||||
action = MotionEvent.ACTION_UP;
|
||||
}
|
||||
|
||||
x = event.getX(0);
|
||||
y = event.getY(0);
|
||||
int button = event.getButtonState();
|
||||
|
||||
SDLActivity.onNativeMouse(button, action, x, y, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
BIN
os/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 26 KiB |
BIN
os/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
os/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 12 KiB |
BIN
os/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
os/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 43 KiB |
BIN
os/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
os/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 90 KiB |
BIN
os/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
os/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 148 KiB |
BIN
os/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#000000</color>
|
||||
</resources>
|
||||
@@ -1,3 +1,5 @@
|
||||
<resources>
|
||||
<string name="app_name">Fallout 2 Community Edition</string>
|
||||
<string name="app_name">Fallout 2</string>
|
||||
<string name="loading_dialog_title">PLEASE STAND BY</string>
|
||||
<string name="loading_dialog_message">Copying files…</string>
|
||||
</resources>
|
||||
|
||||
178
os/android/gradlew.bat
vendored
@@ -1,89 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
|
||||
BIN
os/ios/AppIcon.xcassets/AppIcon.appiconset/AppIcon.png
Normal file
|
After Width: | Height: | Size: 1009 KiB |
14
os/ios/AppIcon.xcassets/AppIcon.appiconset/Contents.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "AppIcon.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
6
os/ios/AppIcon.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
52
os/ios/Info.plist
Normal file
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${MACOSX_BUNDLE_DISPLAY_NAME}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>11.0</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<true/>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<string>True</string>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiresFullScreen</key>
|
||||
<true/>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<true/>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
19
os/ios/LaunchScreen.storyboard
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="834" height="1194"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -3,7 +3,7 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${MACOSX_BUNDLE_DISPLAY_NAME}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
@@ -28,6 +28,8 @@
|
||||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<string>True</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.role-playing-games</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.11</string>
|
||||
<key>SDL_FILESYSTEM_BASE_DIR_TYPE</key>
|
||||
|
||||
BIN
os/macos/dmg/background.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
46
os/macos/dmg/setup.scpt
Normal file
@@ -0,0 +1,46 @@
|
||||
on run argv
|
||||
set image_name to item 1 of argv
|
||||
|
||||
tell application "Finder"
|
||||
tell disk image_name
|
||||
|
||||
set open_attempts to 0
|
||||
repeat while open_attempts < 4
|
||||
try
|
||||
open
|
||||
delay 1
|
||||
set open_attempts to 5
|
||||
close
|
||||
on error errStr number errorNumber
|
||||
set open_attempts to open_attempts + 1
|
||||
delay 10
|
||||
end try
|
||||
end repeat
|
||||
delay 5
|
||||
|
||||
open
|
||||
set current view of container window to icon view
|
||||
set theViewOptions to the icon view options of container window
|
||||
set background picture of theViewOptions to file ".background:background.png"
|
||||
set arrangement of theViewOptions to not arranged
|
||||
set icon size of theViewOptions to 128
|
||||
delay 5
|
||||
close
|
||||
|
||||
open
|
||||
update without registering applications
|
||||
tell container window
|
||||
set sidebar width to 0
|
||||
set statusbar visible to false
|
||||
set toolbar visible to false
|
||||
set the bounds to {400, 100, 1040, 609}
|
||||
set position of item "Fallout II Community Edition.app" to {160, 240}
|
||||
set position of item "Applications" to {480, 240}
|
||||
end tell
|
||||
update without registering applications
|
||||
delay 5
|
||||
close
|
||||
end tell
|
||||
delay 1
|
||||
end tell
|
||||
end run
|
||||
BIN
os/macos/fallout2-ce.icns
Normal file
BIN
os/windows/fallout2-ce.ico
Normal file
|
After Width: | Height: | Size: 97 KiB |
1
os/windows/fallout2-ce.rc
Normal file
@@ -0,0 +1 @@
|
||||
IDI_ICON1 ICON DISCARDABLE "fallout2-ce.ico"
|
||||
1293
src/actions.cc
@@ -4,21 +4,27 @@
|
||||
#include "combat_defs.h"
|
||||
#include "obj_types.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
extern int rotation;
|
||||
|
||||
int _action_attack(Attack* attack);
|
||||
int _action_use_an_item_on_object(Object* a1, Object* a2, Object* a3);
|
||||
int _action_use_an_object(Object* a1, Object* a2);
|
||||
int _action_use_an_item_on_object(Object* user, Object* targetObj, Object* item);
|
||||
int _action_use_an_object(Object* user, Object* targetObj);
|
||||
int actionPickUp(Object* critter, Object* item);
|
||||
int _action_loot_container(Object* critter, Object* container);
|
||||
int _action_skill_use(int a1);
|
||||
int actionUseSkill(Object* a1, Object* a2, int skill);
|
||||
bool _is_hit_from_front(Object* a1, Object* a2);
|
||||
int _action_skill_use(int skill);
|
||||
int actionUseSkill(Object* user, Object* target, int skill);
|
||||
bool _is_hit_from_front(Object* attacker, Object* defender);
|
||||
bool _can_see(Object* a1, Object* a2);
|
||||
bool _action_explode_running();
|
||||
int actionExplode(int tile, int elevation, int minDamage, int maxDamage, Object* a5, bool a6);
|
||||
int actionExplode(int tile, int elevation, int minDamage, int maxDamage, Object* sourceObj, bool animate);
|
||||
int actionTalk(Object* a1, Object* a2);
|
||||
void _action_dmg(int tile, int elevation, int minDamage, int maxDamage, int damageType, bool animated, bool bypassArmor);
|
||||
void actionDamage(int tile, int elevation, int minDamage, int maxDamage, int damageType, bool animated, bool bypassArmor);
|
||||
bool actionCheckPush(Object* a1, Object* a2);
|
||||
int actionPush(Object* a1, Object* a2);
|
||||
int _action_can_talk_to(Object* a1, Object* a2);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* ACTIONS_H */
|
||||
|
||||
1969
src/animation.cc
115
src/animation.h
@@ -3,36 +3,16 @@
|
||||
|
||||
#include "combat_defs.h"
|
||||
#include "obj_types.h"
|
||||
#include "sound.h"
|
||||
|
||||
typedef enum AnimKind {
|
||||
ANIM_KIND_OBJ_MOVE_TO_OBJ = 0,
|
||||
ANIM_KIND_OBJ_MOVE_TO_TILE = 1,
|
||||
ANIM_KIND_2 = 2,
|
||||
ANIM_KIND_KNOCKDOWN = 3,
|
||||
ANIM_KIND_ANIMATE = 4,
|
||||
ANIM_KIND_ANIMATE_REVERSE = 5,
|
||||
ANIM_KIND_6 = 6,
|
||||
ANIM_KIND_SET_ROTATION_TO_TILE = 7,
|
||||
ANIM_KIND_ROTATE_CLOCKWISE = 8,
|
||||
ANIM_KIND_ROTATE_COUNTER_CLOCKWISE = 9,
|
||||
ANIM_KIND_HIDE = 10,
|
||||
ANIM_KIND_EXEC = 11,
|
||||
ANIM_KIND_EXEC_2 = 12,
|
||||
ANIM_KIND_14 = 14,
|
||||
ANIM_KIND_15 = 15,
|
||||
ANIM_KIND_16 = 16,
|
||||
ANIM_KIND_17 = 17,
|
||||
ANIM_KIND_18 = 18,
|
||||
ANIM_KIND_19 = 19,
|
||||
ANIM_KIND_20 = 20,
|
||||
ANIM_KIND_23 = 23,
|
||||
ANIM_KIND_24 = 24,
|
||||
ANIM_KIND_ANIMATE_FOREVER = 25,
|
||||
ANIM_KIND_26 = 26,
|
||||
ANIM_KIND_27 = 27,
|
||||
ANIM_KIND_28 = 28,
|
||||
} AnimKind;
|
||||
namespace fallout {
|
||||
|
||||
typedef enum AnimationRequestOptions {
|
||||
ANIMATION_REQUEST_UNRESERVED = 0x01,
|
||||
ANIMATION_REQUEST_RESERVED = 0x02,
|
||||
ANIMATION_REQUEST_NO_STAND = 0x04,
|
||||
ANIMATION_REQUEST_PING = 0x100,
|
||||
ANIMATION_REQUEST_INSIGNIFICANT = 0x200,
|
||||
} AnimationRequestOptions;
|
||||
|
||||
// Basic animations: 0-19
|
||||
// Knockdown and death: 20-35
|
||||
@@ -112,16 +92,20 @@ typedef enum AnimationType {
|
||||
LAST_SF_DEATH_ANIM = ANIM_FALL_FRONT_BLOOD_SF,
|
||||
} AnimationType;
|
||||
|
||||
typedef int AnimationProc(Object*, Object*);
|
||||
typedef int AnimationSoundProc(Sound*);
|
||||
typedef int AnimationProc2(Object*, Object*, void*);
|
||||
#define FID_ANIM_TYPE(value) ((value) & 0xFF0000) >> 16
|
||||
|
||||
typedef struct STRUCT_530014_28 {
|
||||
// Signature of animation callback accepting 2 parameters.
|
||||
typedef int(AnimationCallback)(void* a1, void* a2);
|
||||
|
||||
// Signature of animation callback accepting 3 parameters.
|
||||
typedef int(AnimationCallback3)(void* a1, void* a2, void* a3);
|
||||
|
||||
typedef struct StraightPathNode {
|
||||
int tile;
|
||||
int elevation;
|
||||
int x;
|
||||
int y;
|
||||
} STRUCT_530014_28;
|
||||
} StraightPathNode;
|
||||
|
||||
typedef Object* PathBuilderCallback(Object* object, int tile, int elevation);
|
||||
|
||||
@@ -133,40 +117,47 @@ int _register_priority(int a1);
|
||||
int reg_anim_clear(Object* a1);
|
||||
int reg_anim_end();
|
||||
int animationIsBusy(Object* a1);
|
||||
int reg_anim_obj_move_to_obj(Object* a1, Object* a2, int actionPoints, int delay);
|
||||
int reg_anim_obj_run_to_obj(Object* owner, Object* destination, int actionPoints, int delay);
|
||||
int reg_anim_obj_move_to_tile(Object* obj, int tile_num, int elev, int actionPoints, int delay);
|
||||
int reg_anim_obj_run_to_tile(Object* obj, int tile_num, int elev, int actionPoints, int delay);
|
||||
int reg_anim_2(Object* obj, int tile_num, int elev, int a4, int a5);
|
||||
int reg_anim_knockdown(Object* obj, int tile, int elev, int anim, int delay);
|
||||
int reg_anim_animate(Object* obj, int anim, int delay);
|
||||
int reg_anim_animate_reverse(Object* obj, int anim, int delay);
|
||||
int reg_anim_6(Object* obj, int anim, int delay);
|
||||
int reg_anim_set_rotation_to_tile(Object* owner, int tile);
|
||||
int reg_anim_rotate_clockwise(Object* obj);
|
||||
int reg_anim_rotate_counter_clockwise(Object* obj);
|
||||
int reg_anim_hide(Object* obj);
|
||||
int reg_anim_11_0(Object* a1, Object* a2, AnimationProc* proc, int delay);
|
||||
int reg_anim_12(Object* a1, Object* a2, void* a3, AnimationProc2* proc, int delay);
|
||||
int reg_anim_11_1(Object* a1, Object* a2, AnimationProc* proc, int delay);
|
||||
int reg_anim_15(Object* obj, int a2, int a3);
|
||||
int reg_anim_17(Object* obj, int fid, int a3);
|
||||
int reg_anim_18(Object* obj, int a2, int a3);
|
||||
int reg_anim_update_light(Object* obj, int fid, int a3);
|
||||
int reg_anim_play_sfx(Object* obj, const char* a2, int a3);
|
||||
int reg_anim_animate_forever(Object* obj, int a2, int a3);
|
||||
int reg_anim_26(int a1, int a2);
|
||||
int animationRegisterMoveToObject(Object* owner, Object* destination, int actionPoints, int delay);
|
||||
int animationRegisterRunToObject(Object* owner, Object* destination, int actionPoints, int delay);
|
||||
int animationRegisterMoveToTile(Object* owner, int tile, int elevation, int actionPoints, int delay);
|
||||
int animationRegisterRunToTile(Object* owner, int tile, int elevation, int actionPoints, int delay);
|
||||
int animationRegisterMoveToTileStraight(Object* object, int tile, int elevation, int anim, int delay);
|
||||
int animationRegisterMoveToTileStraightAndWaitForComplete(Object* owner, int tile, int elev, int anim, int delay);
|
||||
int animationRegisterAnimate(Object* owner, int anim, int delay);
|
||||
int animationRegisterAnimateReversed(Object* owner, int anim, int delay);
|
||||
int animationRegisterAnimateAndHide(Object* owner, int anim, int delay);
|
||||
int animationRegisterRotateToTile(Object* owner, int tile);
|
||||
int animationRegisterRotateClockwise(Object* owner);
|
||||
int animationRegisterRotateCounterClockwise(Object* owner);
|
||||
int animationRegisterHideObject(Object* object);
|
||||
int animationRegisterHideObjectForced(Object* object);
|
||||
int animationRegisterCallback(void* a1, void* a2, AnimationCallback* proc, int delay);
|
||||
int animationRegisterCallback3(void* a1, void* a2, void* a3, AnimationCallback3* proc, int delay);
|
||||
int animationRegisterCallbackForced(void* a1, void* a2, AnimationCallback* proc, int delay);
|
||||
int animationRegisterSetFlag(Object* object, int flag, int delay);
|
||||
int animationRegisterUnsetFlag(Object* object, int flag, int delay);
|
||||
int animationRegisterSetFid(Object* owner, int fid, int delay);
|
||||
int animationRegisterTakeOutWeapon(Object* owner, int weaponAnimationCode, int delay);
|
||||
int animationRegisterSetLightDistance(Object* owner, int lightDistance, int delay);
|
||||
int animationRegisterToggleOutline(Object* object, bool outline, int delay);
|
||||
int animationRegisterPlaySoundEffect(Object* owner, const char* soundEffectName, int delay);
|
||||
int animationRegisterAnimateForever(Object* owner, int anim, int delay);
|
||||
int animationRegisterPing(int flags, int delay);
|
||||
int _make_path(Object* object, int from, int to, unsigned char* a4, int a5);
|
||||
int pathfinderFindPath(Object* object, int from, int to, unsigned char* rotations, int a5, PathBuilderCallback* callback);
|
||||
int _make_straight_path(Object* a1, int from, int to, STRUCT_530014_28* pathNodes, Object** a5, int a6);
|
||||
int _make_straight_path_func(Object* a1, int from, int to, STRUCT_530014_28* a4, Object** a5, int a6, Object* (*a7)(Object*, int, int));
|
||||
int _make_straight_path(Object* object, int from, int to, StraightPathNode* straightPathNodeList, Object** obstaclePtr, int a6);
|
||||
int _make_straight_path_func(Object* object, int from, int to, StraightPathNode* straightPathNodeList, Object** obstaclePtr, int a6, PathBuilderCallback* callback);
|
||||
void _object_animate();
|
||||
int _check_move(int* a1);
|
||||
int _dude_move(int a1);
|
||||
int _dude_run(int a1);
|
||||
int _check_move(int* actionPointsPtr);
|
||||
int _dude_move(int actionPoints);
|
||||
int _dude_run(int actionPoints);
|
||||
void _dude_fidget();
|
||||
void _dude_stand(Object* obj, int rotation, int fid);
|
||||
void _dude_standup(Object* a1);
|
||||
void animationStop();
|
||||
|
||||
int animationRegisterSetLightIntensity(Object* owner, int lightDistance, int lightIntensity, int delay);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* ANIMATION_H */
|
||||
|
||||
843
src/art.cc
38
src/art.h
@@ -8,6 +8,8 @@
|
||||
#include "platform_compat.h"
|
||||
#include "proto_types.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum Head {
|
||||
HEAD_INVALID,
|
||||
HEAD_MARCUS,
|
||||
@@ -65,7 +67,6 @@ typedef enum Background {
|
||||
BACKGROUND_COUNT,
|
||||
} Background;
|
||||
|
||||
#pragma pack(2)
|
||||
typedef struct Art {
|
||||
int field_0;
|
||||
short framesPerSecond;
|
||||
@@ -74,9 +75,9 @@ typedef struct Art {
|
||||
short xOffsets[6];
|
||||
short yOffsets[6];
|
||||
int dataOffsets[6];
|
||||
int field_3A;
|
||||
int padding[6];
|
||||
int dataSize;
|
||||
} Art;
|
||||
#pragma pack()
|
||||
|
||||
typedef struct ArtFrame {
|
||||
short width;
|
||||
@@ -122,12 +123,13 @@ char* artGetObjectTypeName(int objectType);
|
||||
int artIsObjectTypeHidden(int objectType);
|
||||
int artGetFidgetCount(int headFid);
|
||||
void artRender(int fid, unsigned char* dest, int width, int height, int pitch);
|
||||
int art_list_str(int fid, char* name);
|
||||
Art* artLock(int fid, CacheEntry** cache_entry);
|
||||
unsigned char* artLockFrameData(int fid, int frame, int direction, CacheEntry** out_cache_entry);
|
||||
unsigned char* artLockFrameDataReturningSize(int fid, CacheEntry** out_cache_entry, int* widthPtr, int* heightPtr);
|
||||
int artUnlock(CacheEntry* cache_entry);
|
||||
int artCacheFlush();
|
||||
int artCopyFileName(int a1, int a2, char* a3);
|
||||
int artCopyFileName(int objectType, int a2, char* a3);
|
||||
int _art_get_code(int a1, int a2, char* a3, char* a4);
|
||||
char* artBuildFilePath(int a1);
|
||||
int artGetFramesPerSecond(Art* art);
|
||||
@@ -144,8 +146,32 @@ bool artExists(int fid);
|
||||
bool _art_fid_valid(int fid);
|
||||
int _art_alias_num(int a1);
|
||||
int artCritterFidShouldRun(int a1);
|
||||
int _art_alias_fid(int a1);
|
||||
int buildFid(int a1, int a2, int a3, int a4, int a5);
|
||||
int artAliasFid(int fid);
|
||||
int buildFid(int objectType, int frmId, int animType, int weaponCode, int rotation);
|
||||
Art* artLoad(const char* path);
|
||||
int artRead(const char* path, unsigned char* data);
|
||||
int artWrite(const char* path, unsigned char* data);
|
||||
|
||||
class FrmImage {
|
||||
public:
|
||||
FrmImage();
|
||||
~FrmImage();
|
||||
|
||||
bool isLocked() const { return _key != nullptr; }
|
||||
bool lock(unsigned int fid);
|
||||
void unlock();
|
||||
|
||||
int getWidth() const { return _width; }
|
||||
int getHeight() const { return _height; }
|
||||
unsigned char* getData() const { return _data; }
|
||||
|
||||
private:
|
||||
CacheEntry* _key;
|
||||
unsigned char* _data;
|
||||
int _width;
|
||||
int _height;
|
||||
};
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif
|
||||
|
||||
156
src/audio.cc
@@ -1,109 +1,107 @@
|
||||
#include "audio.h"
|
||||
|
||||
#include "db.h"
|
||||
#include "debug.h"
|
||||
#include "memory_manager.h"
|
||||
#include "pointer_registry.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static bool _defaultCompressionFunc(char* filePath);
|
||||
static int audioSoundDecoderReadHandler(int fileHandle, void* buf, unsigned int size);
|
||||
#include "db.h"
|
||||
#include "debug.h"
|
||||
#include "memory_manager.h"
|
||||
#include "sound.h"
|
||||
#include "sound_decoder.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum AudioFlags {
|
||||
AUDIO_IN_USE = 0x01,
|
||||
AUDIO_COMPRESSED = 0x02,
|
||||
} AudioFileFlags;
|
||||
|
||||
typedef struct Audio {
|
||||
int flags;
|
||||
File* stream;
|
||||
SoundDecoder* soundDecoder;
|
||||
int fileSize;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
int position;
|
||||
} Audio;
|
||||
|
||||
static bool defaultCompressionFunc(char* filePath);
|
||||
static int audioSoundDecoderReadHandler(void* data, void* buf, unsigned int size);
|
||||
|
||||
// 0x5108BC
|
||||
static AudioFileIsCompressedProc* _queryCompressedFunc = _defaultCompressionFunc;
|
||||
static AudioQueryCompressedFunc* queryCompressedFunc = defaultCompressionFunc;
|
||||
|
||||
// 0x56CB00
|
||||
static int gAudioListLength;
|
||||
|
||||
// 0x56CB04
|
||||
static AudioFile* gAudioList;
|
||||
static Audio* gAudioList;
|
||||
|
||||
// 0x41A2B0
|
||||
static bool _defaultCompressionFunc(char* filePath)
|
||||
static bool defaultCompressionFunc(char* filePath)
|
||||
{
|
||||
char* pch = strrchr(filePath, '.');
|
||||
if (pch != NULL) {
|
||||
strcpy(pch + 1, "war");
|
||||
if (pch != nullptr) {
|
||||
strcpy(pch + 1, "raw");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x41A2D0
|
||||
static int audioSoundDecoderReadHandler(int fileHandle, void* buffer, unsigned int size)
|
||||
static int audioSoundDecoderReadHandler(void* data, void* buffer, unsigned int size)
|
||||
{
|
||||
return fileRead(buffer, 1, size, (File*)intToPtr(fileHandle));
|
||||
return fileRead(buffer, 1, size, reinterpret_cast<File*>(data));
|
||||
}
|
||||
|
||||
// AudioOpen
|
||||
// 0x41A2EC
|
||||
int audioOpen(const char* fname, int flags, ...)
|
||||
int audioOpen(const char* fname, int* sampleRate)
|
||||
{
|
||||
char path[80];
|
||||
sprintf(path, "%s", fname);
|
||||
snprintf(path, sizeof(path), "%s", fname);
|
||||
|
||||
int compression;
|
||||
if (_queryCompressedFunc(path)) {
|
||||
if (queryCompressedFunc(path)) {
|
||||
compression = 2;
|
||||
} else {
|
||||
compression = 0;
|
||||
}
|
||||
|
||||
char mode[4];
|
||||
memset(mode, 0, 4);
|
||||
|
||||
// NOTE: Original implementation is slightly different, it uses separate
|
||||
// variable to track index where to set 't' and 'b'.
|
||||
char* pm = mode;
|
||||
if (flags & 1) {
|
||||
*pm++ = 'w';
|
||||
} else if (flags & 2) {
|
||||
*pm++ = 'w';
|
||||
*pm++ = '+';
|
||||
} else {
|
||||
*pm++ = 'r';
|
||||
}
|
||||
|
||||
if (flags & 0x100) {
|
||||
*pm++ = 't';
|
||||
} else if (flags & 0x200) {
|
||||
*pm++ = 'b';
|
||||
}
|
||||
|
||||
File* stream = fileOpen(path, mode);
|
||||
if (stream == NULL) {
|
||||
File* stream = fileOpen(path, "rb");
|
||||
if (stream == nullptr) {
|
||||
debugPrint("AudioOpen: Couldn't open %s for read\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int index;
|
||||
for (index = 0; index < gAudioListLength; index++) {
|
||||
if ((gAudioList[index].flags & AUDIO_FILE_IN_USE) == 0) {
|
||||
if ((gAudioList[index].flags & AUDIO_IN_USE) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == gAudioListLength) {
|
||||
if (gAudioList != NULL) {
|
||||
gAudioList = (AudioFile*)internal_realloc_safe(gAudioList, sizeof(*gAudioList) * (gAudioListLength + 1), __FILE__, __LINE__); // "..\int\audio.c", 216
|
||||
if (gAudioList != nullptr) {
|
||||
gAudioList = (Audio*)internal_realloc_safe(gAudioList, sizeof(*gAudioList) * (gAudioListLength + 1), __FILE__, __LINE__); // "..\int\audio.c", 216
|
||||
} else {
|
||||
gAudioList = (AudioFile*)internal_malloc_safe(sizeof(*gAudioList), __FILE__, __LINE__); // "..\int\audio.c", 218
|
||||
gAudioList = (Audio*)internal_malloc_safe(sizeof(*gAudioList), __FILE__, __LINE__); // "..\int\audio.c", 218
|
||||
}
|
||||
gAudioListLength++;
|
||||
}
|
||||
|
||||
AudioFile* audioFile = &(gAudioList[index]);
|
||||
audioFile->flags = AUDIO_FILE_IN_USE;
|
||||
audioFile->fileHandle = ptrToInt(stream);
|
||||
Audio* audioFile = &(gAudioList[index]);
|
||||
audioFile->flags = AUDIO_IN_USE;
|
||||
audioFile->stream = stream;
|
||||
|
||||
if (compression == 2) {
|
||||
audioFile->flags |= AUDIO_FILE_COMPRESSED;
|
||||
audioFile->soundDecoder = soundDecoderInit(audioSoundDecoderReadHandler, audioFile->fileHandle, &(audioFile->field_14), &(audioFile->field_10), &(audioFile->fileSize));
|
||||
audioFile->flags |= AUDIO_COMPRESSED;
|
||||
audioFile->soundDecoder = soundDecoderInit(audioSoundDecoderReadHandler, audioFile->stream, &(audioFile->channels), &(audioFile->sampleRate), &(audioFile->fileSize));
|
||||
audioFile->fileSize *= 2;
|
||||
|
||||
*sampleRate = audioFile->sampleRate;
|
||||
} else {
|
||||
audioFile->fileSize = fileGetSize(stream);
|
||||
}
|
||||
@@ -114,30 +112,30 @@ int audioOpen(const char* fname, int flags, ...)
|
||||
}
|
||||
|
||||
// 0x41A50C
|
||||
int audioClose(int fileHandle)
|
||||
int audioClose(int handle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioList[fileHandle - 1]);
|
||||
fileClose((File*)intToPtr(audioFile->fileHandle, true));
|
||||
Audio* audioFile = &(gAudioList[handle - 1]);
|
||||
fileClose(audioFile->stream);
|
||||
|
||||
if ((audioFile->flags & AUDIO_FILE_COMPRESSED) != 0) {
|
||||
if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
|
||||
soundDecoderFree(audioFile->soundDecoder);
|
||||
}
|
||||
|
||||
memset(audioFile, 0, sizeof(AudioFile));
|
||||
memset(audioFile, 0, sizeof(Audio));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x41A574
|
||||
int audioRead(int fileHandle, void* buffer, unsigned int size)
|
||||
int audioRead(int handle, void* buffer, unsigned int size)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioList[fileHandle - 1]);
|
||||
Audio* audioFile = &(gAudioList[handle - 1]);
|
||||
|
||||
int bytesRead;
|
||||
if ((audioFile->flags & AUDIO_FILE_COMPRESSED) != 0) {
|
||||
if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
|
||||
bytesRead = soundDecoderDecode(audioFile->soundDecoder, buffer, size);
|
||||
} else {
|
||||
bytesRead = fileRead(buffer, 1, size, (File*)intToPtr(audioFile->fileHandle));
|
||||
bytesRead = fileRead(buffer, 1, size, audioFile->stream);
|
||||
}
|
||||
|
||||
audioFile->position += bytesRead;
|
||||
@@ -146,13 +144,13 @@ int audioRead(int fileHandle, void* buffer, unsigned int size)
|
||||
}
|
||||
|
||||
// 0x41A5E0
|
||||
long audioSeek(int fileHandle, long offset, int origin)
|
||||
long audioSeek(int handle, long offset, int origin)
|
||||
{
|
||||
int pos;
|
||||
unsigned char* buf;
|
||||
int v10;
|
||||
|
||||
AudioFile* audioFile = &(gAudioList[fileHandle - 1]);
|
||||
Audio* audioFile = &(gAudioList[handle - 1]);
|
||||
|
||||
switch (origin) {
|
||||
case SEEK_SET:
|
||||
@@ -168,11 +166,11 @@ long audioSeek(int fileHandle, long offset, int origin)
|
||||
assert(false && "Should be unreachable");
|
||||
}
|
||||
|
||||
if ((audioFile->flags & AUDIO_FILE_COMPRESSED) != 0) {
|
||||
if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
|
||||
if (pos < audioFile->position) {
|
||||
soundDecoderFree(audioFile->soundDecoder);
|
||||
fileSeek((File*)intToPtr(audioFile->fileHandle), 0, SEEK_SET);
|
||||
audioFile->soundDecoder = soundDecoderInit(audioSoundDecoderReadHandler, audioFile->fileHandle, &(audioFile->field_14), &(audioFile->field_10), &(audioFile->fileSize));
|
||||
fileSeek(audioFile->stream, 0, SEEK_SET);
|
||||
audioFile->soundDecoder = soundDecoderInit(audioSoundDecoderReadHandler, audioFile->stream, &(audioFile->channels), &(audioFile->sampleRate), &(audioFile->fileSize));
|
||||
audioFile->position = 0;
|
||||
audioFile->fileSize *= 2;
|
||||
|
||||
@@ -180,11 +178,11 @@ long audioSeek(int fileHandle, long offset, int origin)
|
||||
buf = (unsigned char*)internal_malloc_safe(4096, __FILE__, __LINE__); // "..\int\audio.c", 361
|
||||
while (pos > 4096) {
|
||||
pos -= 4096;
|
||||
audioRead(fileHandle, buf, 4096);
|
||||
audioRead(handle, buf, 4096);
|
||||
}
|
||||
|
||||
if (pos != 0) {
|
||||
audioRead(fileHandle, buf, pos);
|
||||
audioRead(handle, buf, pos);
|
||||
}
|
||||
|
||||
internal_free_safe(buf, __FILE__, __LINE__); // // "..\int\audio.c", 367
|
||||
@@ -194,11 +192,11 @@ long audioSeek(int fileHandle, long offset, int origin)
|
||||
v10 = audioFile->position - pos;
|
||||
while (v10 > 1024) {
|
||||
v10 -= 1024;
|
||||
audioRead(fileHandle, buf, 1024);
|
||||
audioRead(handle, buf, 1024);
|
||||
}
|
||||
|
||||
if (v10 != 0) {
|
||||
audioRead(fileHandle, buf, v10);
|
||||
audioRead(handle, buf, v10);
|
||||
}
|
||||
|
||||
// TODO: Probably leaks memory.
|
||||
@@ -206,21 +204,21 @@ long audioSeek(int fileHandle, long offset, int origin)
|
||||
|
||||
return audioFile->position;
|
||||
} else {
|
||||
return fileSeek((File*)intToPtr(audioFile->fileHandle), offset, origin);
|
||||
return fileSeek(audioFile->stream, offset, origin);
|
||||
}
|
||||
}
|
||||
|
||||
// 0x41A78C
|
||||
long audioGetSize(int fileHandle)
|
||||
long audioGetSize(int handle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioList[fileHandle - 1]);
|
||||
Audio* audioFile = &(gAudioList[handle - 1]);
|
||||
return audioFile->fileSize;
|
||||
}
|
||||
|
||||
// 0x41A7A8
|
||||
long audioTell(int fileHandle)
|
||||
long audioTell(int handle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioList[fileHandle - 1]);
|
||||
Audio* audioFile = &(gAudioList[handle - 1]);
|
||||
return audioFile->position;
|
||||
}
|
||||
|
||||
@@ -233,10 +231,10 @@ int audioWrite(int handle, const void* buf, unsigned int size)
|
||||
}
|
||||
|
||||
// 0x41A7D4
|
||||
int audioInit(AudioFileIsCompressedProc* isCompressedProc)
|
||||
int audioInit(AudioQueryCompressedFunc* func)
|
||||
{
|
||||
_queryCompressedFunc = isCompressedProc;
|
||||
gAudioList = NULL;
|
||||
queryCompressedFunc = func;
|
||||
gAudioList = nullptr;
|
||||
gAudioListLength = 0;
|
||||
|
||||
return soundSetDefaultFileIO(audioOpen, audioClose, audioRead, audioWrite, audioSeek, audioTell, audioGetSize);
|
||||
@@ -245,10 +243,12 @@ int audioInit(AudioFileIsCompressedProc* isCompressedProc)
|
||||
// 0x41A818
|
||||
void audioExit()
|
||||
{
|
||||
if (gAudioList != NULL) {
|
||||
if (gAudioList != nullptr) {
|
||||
internal_free_safe(gAudioList, __FILE__, __LINE__); // "..\int\audio.c", 406
|
||||
}
|
||||
|
||||
gAudioListLength = 0;
|
||||
gAudioList = NULL;
|
||||
gAudioList = nullptr;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
20
src/audio.h
@@ -1,16 +1,20 @@
|
||||
#ifndef AUDIO_H
|
||||
#define AUDIO_H
|
||||
|
||||
#include "audio_file.h"
|
||||
namespace fallout {
|
||||
|
||||
int audioOpen(const char* fname, int mode, ...);
|
||||
int audioClose(int fileHandle);
|
||||
int audioRead(int fileHandle, void* buffer, unsigned int size);
|
||||
long audioSeek(int fileHandle, long offset, int origin);
|
||||
long audioGetSize(int fileHandle);
|
||||
long audioTell(int fileHandle);
|
||||
typedef bool(AudioQueryCompressedFunc)(char* filePath);
|
||||
|
||||
int audioOpen(const char* fname, int* sampleRate);
|
||||
int audioClose(int handle);
|
||||
int audioRead(int handle, void* buffer, unsigned int size);
|
||||
long audioSeek(int handle, long offset, int origin);
|
||||
long audioGetSize(int handle);
|
||||
long audioTell(int handle);
|
||||
int audioWrite(int handle, const void* buf, unsigned int size);
|
||||
int audioInit(AudioFileIsCompressedProc* isCompressedProc);
|
||||
int audioInit(AudioQueryCompressedFunc* func);
|
||||
void audioExit();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* AUDIO_H */
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define AUDIO_ENGINE_SOUND_BUFFERS 8
|
||||
|
||||
struct AudioEngineSoundBuffer {
|
||||
@@ -32,6 +34,11 @@ static SDL_AudioSpec gAudioEngineSpec;
|
||||
static SDL_AudioDeviceID gAudioEngineDeviceId = -1;
|
||||
static AudioEngineSoundBuffer gAudioEngineSoundBuffers[AUDIO_ENGINE_SOUND_BUFFERS];
|
||||
|
||||
static bool audioEngineIsInitialized()
|
||||
{
|
||||
return gAudioEngineDeviceId != -1;
|
||||
}
|
||||
|
||||
static bool soundBufferIsValid(int soundBufferIndex)
|
||||
{
|
||||
return soundBufferIndex >= 0 && soundBufferIndex < AUDIO_ENGINE_SOUND_BUFFERS;
|
||||
@@ -99,7 +106,7 @@ bool audioEngineInit()
|
||||
desiredSpec.samples = 1024;
|
||||
desiredSpec.callback = audioEngineMixin;
|
||||
|
||||
gAudioEngineDeviceId = SDL_OpenAudioDevice(NULL, 0, &desiredSpec, &gAudioEngineSpec, SDL_AUDIO_ALLOW_ANY_CHANGE);
|
||||
gAudioEngineDeviceId = SDL_OpenAudioDevice(nullptr, 0, &desiredSpec, &gAudioEngineSpec, SDL_AUDIO_ALLOW_ANY_CHANGE);
|
||||
if (gAudioEngineDeviceId == -1) {
|
||||
return false;
|
||||
}
|
||||
@@ -111,30 +118,36 @@ bool audioEngineInit()
|
||||
|
||||
void audioEngineExit()
|
||||
{
|
||||
if (gAudioEngineDeviceId != -1) {
|
||||
if (audioEngineIsInitialized()) {
|
||||
SDL_CloseAudioDevice(gAudioEngineDeviceId);
|
||||
gAudioEngineDeviceId = -1;
|
||||
}
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
if (SDL_WasInit(SDL_INIT_AUDIO)) {
|
||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
}
|
||||
}
|
||||
|
||||
void audioEnginePause()
|
||||
{
|
||||
if (gAudioEngineDeviceId != -1) {
|
||||
if (audioEngineIsInitialized()) {
|
||||
SDL_PauseAudioDevice(gAudioEngineDeviceId, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void audioEngineResume()
|
||||
{
|
||||
if (gAudioEngineDeviceId != -1) {
|
||||
if (audioEngineIsInitialized()) {
|
||||
SDL_PauseAudioDevice(gAudioEngineDeviceId, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int audioEngineCreateSoundBuffer(unsigned int size, int bitsPerSample, int channels, int rate)
|
||||
{
|
||||
if (!audioEngineIsInitialized()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int index = 0; index < AUDIO_ENGINE_SOUND_BUFFERS; index++) {
|
||||
AudioEngineSoundBuffer* soundBuffer = &(gAudioEngineSoundBuffers[index]);
|
||||
std::lock_guard<std::recursive_mutex> lock(soundBuffer->mutex);
|
||||
@@ -160,6 +173,10 @@ int audioEngineCreateSoundBuffer(unsigned int size, int bitsPerSample, int chann
|
||||
|
||||
bool audioEngineSoundBufferRelease(int soundBufferIndex)
|
||||
{
|
||||
if (!audioEngineIsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!soundBufferIsValid(soundBufferIndex)) {
|
||||
return false;
|
||||
}
|
||||
@@ -174,16 +191,20 @@ bool audioEngineSoundBufferRelease(int soundBufferIndex)
|
||||
soundBuffer->active = false;
|
||||
|
||||
free(soundBuffer->data);
|
||||
soundBuffer->data = NULL;
|
||||
soundBuffer->data = nullptr;
|
||||
|
||||
SDL_FreeAudioStream(soundBuffer->stream);
|
||||
soundBuffer->stream = NULL;
|
||||
soundBuffer->stream = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool audioEngineSoundBufferSetVolume(int soundBufferIndex, int volume)
|
||||
{
|
||||
if (!audioEngineIsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!soundBufferIsValid(soundBufferIndex)) {
|
||||
return false;
|
||||
}
|
||||
@@ -202,6 +223,10 @@ bool audioEngineSoundBufferSetVolume(int soundBufferIndex, int volume)
|
||||
|
||||
bool audioEngineSoundBufferGetVolume(int soundBufferIndex, int* volumePtr)
|
||||
{
|
||||
if (!audioEngineIsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!soundBufferIsValid(soundBufferIndex)) {
|
||||
return false;
|
||||
}
|
||||
@@ -220,6 +245,10 @@ bool audioEngineSoundBufferGetVolume(int soundBufferIndex, int* volumePtr)
|
||||
|
||||
bool audioEngineSoundBufferSetPan(int soundBufferIndex, int pan)
|
||||
{
|
||||
if (!audioEngineIsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!soundBufferIsValid(soundBufferIndex)) {
|
||||
return false;
|
||||
}
|
||||
@@ -239,6 +268,10 @@ bool audioEngineSoundBufferSetPan(int soundBufferIndex, int pan)
|
||||
|
||||
bool audioEngineSoundBufferPlay(int soundBufferIndex, unsigned int flags)
|
||||
{
|
||||
if (!audioEngineIsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!soundBufferIsValid(soundBufferIndex)) {
|
||||
return false;
|
||||
}
|
||||
@@ -261,6 +294,10 @@ bool audioEngineSoundBufferPlay(int soundBufferIndex, unsigned int flags)
|
||||
|
||||
bool audioEngineSoundBufferStop(int soundBufferIndex)
|
||||
{
|
||||
if (!audioEngineIsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!soundBufferIsValid(soundBufferIndex)) {
|
||||
return false;
|
||||
}
|
||||
@@ -279,6 +316,10 @@ bool audioEngineSoundBufferStop(int soundBufferIndex)
|
||||
|
||||
bool audioEngineSoundBufferGetCurrentPosition(int soundBufferIndex, unsigned int* readPosPtr, unsigned int* writePosPtr)
|
||||
{
|
||||
if (!audioEngineIsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!soundBufferIsValid(soundBufferIndex)) {
|
||||
return false;
|
||||
}
|
||||
@@ -290,11 +331,11 @@ bool audioEngineSoundBufferGetCurrentPosition(int soundBufferIndex, unsigned int
|
||||
return false;
|
||||
}
|
||||
|
||||
if (readPosPtr != NULL) {
|
||||
if (readPosPtr != nullptr) {
|
||||
*readPosPtr = soundBuffer->pos;
|
||||
}
|
||||
|
||||
if (writePosPtr != NULL) {
|
||||
if (writePosPtr != nullptr) {
|
||||
*writePosPtr = soundBuffer->pos;
|
||||
|
||||
if (soundBuffer->playing) {
|
||||
@@ -310,6 +351,10 @@ bool audioEngineSoundBufferGetCurrentPosition(int soundBufferIndex, unsigned int
|
||||
|
||||
bool audioEngineSoundBufferSetCurrentPosition(int soundBufferIndex, unsigned int pos)
|
||||
{
|
||||
if (!audioEngineIsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!soundBufferIsValid(soundBufferIndex)) {
|
||||
return false;
|
||||
}
|
||||
@@ -328,6 +373,10 @@ bool audioEngineSoundBufferSetCurrentPosition(int soundBufferIndex, unsigned int
|
||||
|
||||
bool audioEngineSoundBufferLock(int soundBufferIndex, unsigned int writePos, unsigned int writeBytes, void** audioPtr1, unsigned int* audioBytes1, void** audioPtr2, unsigned int* audioBytes2, unsigned int flags)
|
||||
{
|
||||
if (!audioEngineIsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!soundBufferIsValid(soundBufferIndex)) {
|
||||
return false;
|
||||
}
|
||||
@@ -339,12 +388,12 @@ bool audioEngineSoundBufferLock(int soundBufferIndex, unsigned int writePos, uns
|
||||
return false;
|
||||
}
|
||||
|
||||
if (audioBytes1 == NULL) {
|
||||
if (audioBytes1 == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((flags & AUDIO_ENGINE_SOUND_BUFFER_LOCK_FROM_WRITE_POS) != 0) {
|
||||
if (!audioEngineSoundBufferGetCurrentPosition(soundBufferIndex, NULL, &writePos)) {
|
||||
if (!audioEngineSoundBufferGetCurrentPosition(soundBufferIndex, nullptr, &writePos)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -357,11 +406,11 @@ bool audioEngineSoundBufferLock(int soundBufferIndex, unsigned int writePos, uns
|
||||
*(unsigned char**)audioPtr1 = (unsigned char*)soundBuffer->data + writePos;
|
||||
*audioBytes1 = writeBytes;
|
||||
|
||||
if (audioPtr2 != NULL) {
|
||||
*audioPtr2 = NULL;
|
||||
if (audioPtr2 != nullptr) {
|
||||
*audioPtr2 = nullptr;
|
||||
}
|
||||
|
||||
if (audioBytes2 != NULL) {
|
||||
if (audioBytes2 != nullptr) {
|
||||
*audioBytes2 = 0;
|
||||
}
|
||||
} else {
|
||||
@@ -369,11 +418,11 @@ bool audioEngineSoundBufferLock(int soundBufferIndex, unsigned int writePos, uns
|
||||
*(unsigned char**)audioPtr1 = (unsigned char*)soundBuffer->data + writePos;
|
||||
*audioBytes1 = soundBuffer->size - writePos;
|
||||
|
||||
if (audioPtr2 != NULL) {
|
||||
if (audioPtr2 != nullptr) {
|
||||
*(unsigned char**)audioPtr2 = (unsigned char*)soundBuffer->data;
|
||||
}
|
||||
|
||||
if (audioBytes2 != NULL) {
|
||||
if (audioBytes2 != nullptr) {
|
||||
*audioBytes2 = writeBytes - (soundBuffer->size - writePos);
|
||||
}
|
||||
}
|
||||
@@ -385,6 +434,10 @@ bool audioEngineSoundBufferLock(int soundBufferIndex, unsigned int writePos, uns
|
||||
|
||||
bool audioEngineSoundBufferUnlock(int soundBufferIndex, void* audioPtr1, unsigned int audioBytes1, void* audioPtr2, unsigned int audioBytes2)
|
||||
{
|
||||
if (!audioEngineIsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!soundBufferIsValid(soundBufferIndex)) {
|
||||
return false;
|
||||
}
|
||||
@@ -403,6 +456,10 @@ bool audioEngineSoundBufferUnlock(int soundBufferIndex, void* audioPtr1, unsigne
|
||||
|
||||
bool audioEngineSoundBufferGetStatus(int soundBufferIndex, unsigned int* statusPtr)
|
||||
{
|
||||
if (!audioEngineIsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!soundBufferIsValid(soundBufferIndex)) {
|
||||
return false;
|
||||
}
|
||||
@@ -414,7 +471,7 @@ bool audioEngineSoundBufferGetStatus(int soundBufferIndex, unsigned int* statusP
|
||||
return false;
|
||||
}
|
||||
|
||||
if (statusPtr == NULL) {
|
||||
if (statusPtr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -430,3 +487,5 @@ bool audioEngineSoundBufferGetStatus(int soundBufferIndex, unsigned int* statusP
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef AUDIO_ENGINE_H
|
||||
#define AUDIO_ENGINE_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define AUDIO_ENGINE_SOUND_BUFFER_LOCK_FROM_WRITE_POS 0x00000001
|
||||
#define AUDIO_ENGINE_SOUND_BUFFER_LOCK_ENTIRE_BUFFER 0x00000002
|
||||
|
||||
@@ -26,4 +28,6 @@ bool audioEngineSoundBufferLock(int soundBufferIndex, unsigned int writePos, uns
|
||||
bool audioEngineSoundBufferUnlock(int soundBufferIndex, void* audioPtr1, unsigned int audioBytes1, void* audioPtr2, unsigned int audioBytes2);
|
||||
bool audioEngineSoundBufferGetStatus(int soundBufferIndex, unsigned int* status);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* AUDIO_ENGINE_H */
|
||||
|
||||
@@ -1,20 +1,37 @@
|
||||
#include "audio_file.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "memory_manager.h"
|
||||
#include "platform_compat.h"
|
||||
#include "pointer_registry.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static bool _defaultCompressionFunc__(char* filePath);
|
||||
static int audioFileSoundDecoderReadHandler(int fileHandle, void* buffer, unsigned int size);
|
||||
#include "debug.h"
|
||||
#include "memory_manager.h"
|
||||
#include "platform_compat.h"
|
||||
#include "sound.h"
|
||||
#include "sound_decoder.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum AudioFileFlags {
|
||||
AUDIO_FILE_IN_USE = 0x01,
|
||||
AUDIO_FILE_COMPRESSED = 0x02,
|
||||
} AudioFileFlags;
|
||||
|
||||
typedef struct AudioFile {
|
||||
int flags;
|
||||
FILE* stream;
|
||||
SoundDecoder* soundDecoder;
|
||||
int fileSize;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
int position;
|
||||
} AudioFile;
|
||||
|
||||
static bool defaultCompressionFunc(char* filePath);
|
||||
static int audioFileSoundDecoderReadHandler(void* data, void* buffer, unsigned int size);
|
||||
|
||||
// 0x5108C0
|
||||
static AudioFileIsCompressedProc* _queryCompressedFunc_2 = _defaultCompressionFunc__;
|
||||
static AudioFileQueryCompressedFunc* queryCompressedFunc = defaultCompressionFunc;
|
||||
|
||||
// 0x56CB10
|
||||
static AudioFile* gAudioFileList;
|
||||
@@ -23,58 +40,37 @@ static AudioFile* gAudioFileList;
|
||||
static int gAudioFileListLength;
|
||||
|
||||
// 0x41A850
|
||||
static bool _defaultCompressionFunc__(char* filePath)
|
||||
static bool defaultCompressionFunc(char* filePath)
|
||||
{
|
||||
char* pch = strrchr(filePath, '.');
|
||||
if (pch != NULL) {
|
||||
strcpy(pch + 1, "war");
|
||||
if (pch != nullptr) {
|
||||
strcpy(pch + 1, "raw");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x41A870
|
||||
static int audioFileSoundDecoderReadHandler(int fileHandle, void* buffer, unsigned int size)
|
||||
static int audioFileSoundDecoderReadHandler(void* data, void* buffer, unsigned int size)
|
||||
{
|
||||
return fread(buffer, 1, size, (FILE*)intToPtr(fileHandle));
|
||||
return fread(buffer, 1, size, reinterpret_cast<FILE*>(data));
|
||||
}
|
||||
|
||||
// 0x41A88C
|
||||
int audioFileOpen(const char* fname, int flags, ...)
|
||||
int audioFileOpen(const char* fname, int* sampleRate)
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
strcpy(path, fname);
|
||||
|
||||
int compression;
|
||||
if (_queryCompressedFunc_2(path)) {
|
||||
if (queryCompressedFunc(path)) {
|
||||
compression = 2;
|
||||
} else {
|
||||
compression = 0;
|
||||
}
|
||||
|
||||
char mode[4];
|
||||
memset(mode, '\0', 4);
|
||||
|
||||
// NOTE: Original implementation is slightly different, it uses separate
|
||||
// variable to track index where to set 't' and 'b'.
|
||||
char* pm = mode;
|
||||
if (flags & 0x01) {
|
||||
*pm++ = 'w';
|
||||
} else if (flags & 0x02) {
|
||||
*pm++ = 'w';
|
||||
*pm++ = '+';
|
||||
} else {
|
||||
*pm++ = 'r';
|
||||
}
|
||||
|
||||
if (flags & 0x0100) {
|
||||
*pm++ = 't';
|
||||
} else if (flags & 0x0200) {
|
||||
*pm++ = 'b';
|
||||
}
|
||||
|
||||
FILE* stream = compat_fopen(path, mode);
|
||||
if (stream == NULL) {
|
||||
FILE* stream = compat_fopen(path, "rb");
|
||||
if (stream == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -86,7 +82,7 @@ int audioFileOpen(const char* fname, int flags, ...)
|
||||
}
|
||||
|
||||
if (index == gAudioFileListLength) {
|
||||
if (gAudioFileList != NULL) {
|
||||
if (gAudioFileList != nullptr) {
|
||||
gAudioFileList = (AudioFile*)internal_realloc_safe(gAudioFileList, sizeof(*gAudioFileList) * (gAudioFileListLength + 1), __FILE__, __LINE__); // "..\int\audiof.c", 207
|
||||
} else {
|
||||
gAudioFileList = (AudioFile*)internal_malloc_safe(sizeof(*gAudioFileList), __FILE__, __LINE__); // "..\int\audiof.c", 209
|
||||
@@ -96,14 +92,16 @@ int audioFileOpen(const char* fname, int flags, ...)
|
||||
|
||||
AudioFile* audioFile = &(gAudioFileList[index]);
|
||||
audioFile->flags = AUDIO_FILE_IN_USE;
|
||||
audioFile->fileHandle = ptrToInt(stream);
|
||||
audioFile->stream = stream;
|
||||
|
||||
if (compression == 2) {
|
||||
audioFile->flags |= AUDIO_FILE_COMPRESSED;
|
||||
audioFile->soundDecoder = soundDecoderInit(audioFileSoundDecoderReadHandler, audioFile->fileHandle, &(audioFile->field_14), &(audioFile->field_10), &(audioFile->fileSize));
|
||||
audioFile->soundDecoder = soundDecoderInit(audioFileSoundDecoderReadHandler, audioFile->stream, &(audioFile->channels), &(audioFile->sampleRate), &(audioFile->fileSize));
|
||||
audioFile->fileSize *= 2;
|
||||
|
||||
*sampleRate = audioFile->sampleRate;
|
||||
} else {
|
||||
audioFile->fileSize = compat_filelength(fileno(stream));
|
||||
audioFile->fileSize = getFileSize(stream);
|
||||
}
|
||||
|
||||
audioFile->position = 0;
|
||||
@@ -112,10 +110,10 @@ int audioFileOpen(const char* fname, int flags, ...)
|
||||
}
|
||||
|
||||
// 0x41AAA0
|
||||
int audioFileClose(int fileHandle)
|
||||
int audioFileClose(int handle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioFileList[fileHandle - 1]);
|
||||
fclose((FILE*)intToPtr(audioFile->fileHandle, true));
|
||||
AudioFile* audioFile = &(gAudioFileList[handle - 1]);
|
||||
fclose(audioFile->stream);
|
||||
|
||||
if ((audioFile->flags & AUDIO_FILE_COMPRESSED) != 0) {
|
||||
soundDecoderFree(audioFile->soundDecoder);
|
||||
@@ -128,16 +126,16 @@ int audioFileClose(int fileHandle)
|
||||
}
|
||||
|
||||
// 0x41AB08
|
||||
int audioFileRead(int fileHandle, void* buffer, unsigned int size)
|
||||
int audioFileRead(int handle, void* buffer, unsigned int size)
|
||||
{
|
||||
|
||||
AudioFile* ptr = &(gAudioFileList[fileHandle - 1]);
|
||||
AudioFile* ptr = &(gAudioFileList[handle - 1]);
|
||||
|
||||
int bytesRead;
|
||||
if ((ptr->flags & AUDIO_FILE_COMPRESSED) != 0) {
|
||||
bytesRead = soundDecoderDecode(ptr->soundDecoder, buffer, size);
|
||||
} else {
|
||||
bytesRead = fread(buffer, 1, size, (FILE*)intToPtr(ptr->fileHandle));
|
||||
bytesRead = fread(buffer, 1, size, ptr->stream);
|
||||
}
|
||||
|
||||
ptr->position += bytesRead;
|
||||
@@ -146,13 +144,13 @@ int audioFileRead(int fileHandle, void* buffer, unsigned int size)
|
||||
}
|
||||
|
||||
// 0x41AB74
|
||||
long audioFileSeek(int fileHandle, long offset, int origin)
|
||||
long audioFileSeek(int handle, long offset, int origin)
|
||||
{
|
||||
void* buf;
|
||||
int remaining;
|
||||
int a4;
|
||||
|
||||
AudioFile* audioFile = &(gAudioFileList[fileHandle - 1]);
|
||||
AudioFile* audioFile = &(gAudioFileList[handle - 1]);
|
||||
|
||||
switch (origin) {
|
||||
case SEEK_SET:
|
||||
@@ -172,20 +170,20 @@ long audioFileSeek(int fileHandle, long offset, int origin)
|
||||
if (a4 <= audioFile->position) {
|
||||
soundDecoderFree(audioFile->soundDecoder);
|
||||
|
||||
fseek((FILE*)intToPtr(audioFile->fileHandle), 0, 0);
|
||||
fseek(audioFile->stream, 0, 0);
|
||||
|
||||
audioFile->soundDecoder = soundDecoderInit(audioFileSoundDecoderReadHandler, audioFile->fileHandle, &(audioFile->field_14), &(audioFile->field_10), &(audioFile->fileSize));
|
||||
audioFile->soundDecoder = soundDecoderInit(audioFileSoundDecoderReadHandler, audioFile->stream, &(audioFile->channels), &(audioFile->sampleRate), &(audioFile->fileSize));
|
||||
audioFile->fileSize *= 2;
|
||||
audioFile->position = 0;
|
||||
|
||||
if (a4) {
|
||||
buf = internal_malloc_safe(4096, __FILE__, __LINE__); // "..\int\audiof.c", 364
|
||||
while (a4 > 4096) {
|
||||
audioFileRead(fileHandle, buf, 4096);
|
||||
audioFileRead(handle, buf, 4096);
|
||||
a4 -= 4096;
|
||||
}
|
||||
if (a4 != 0) {
|
||||
audioFileRead(fileHandle, buf, a4);
|
||||
audioFileRead(handle, buf, a4);
|
||||
}
|
||||
internal_free_safe(buf, __FILE__, __LINE__); // "..\int\audiof.c", 370
|
||||
}
|
||||
@@ -193,47 +191,47 @@ long audioFileSeek(int fileHandle, long offset, int origin)
|
||||
buf = internal_malloc_safe(0x400, __FILE__, __LINE__); // "..\int\audiof.c", 316
|
||||
remaining = audioFile->position - a4;
|
||||
while (remaining > 1024) {
|
||||
audioFileRead(fileHandle, buf, 1024);
|
||||
audioFileRead(handle, buf, 1024);
|
||||
remaining -= 1024;
|
||||
}
|
||||
if (remaining != 0) {
|
||||
audioFileRead(fileHandle, buf, remaining);
|
||||
audioFileRead(handle, buf, remaining);
|
||||
}
|
||||
// TODO: Obiously leaks memory.
|
||||
}
|
||||
return audioFile->position;
|
||||
}
|
||||
|
||||
return fseek((FILE*)intToPtr(audioFile->fileHandle), offset, origin);
|
||||
return fseek(audioFile->stream, offset, origin);
|
||||
}
|
||||
|
||||
// 0x41AD20
|
||||
long audioFileGetSize(int fileHandle)
|
||||
long audioFileGetSize(int handle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioFileList[fileHandle - 1]);
|
||||
AudioFile* audioFile = &(gAudioFileList[handle - 1]);
|
||||
return audioFile->fileSize;
|
||||
}
|
||||
|
||||
// 0x41AD3C
|
||||
long audioFileTell(int fileHandle)
|
||||
long audioFileTell(int handle)
|
||||
{
|
||||
AudioFile* audioFile = &(gAudioFileList[fileHandle - 1]);
|
||||
AudioFile* audioFile = &(gAudioFileList[handle - 1]);
|
||||
return audioFile->position;
|
||||
}
|
||||
|
||||
// AudiofWrite
|
||||
// 0x41AD58
|
||||
int audioFileWrite(int fileHandle, const void* buffer, unsigned int size)
|
||||
int audioFileWrite(int handle, const void* buffer, unsigned int size)
|
||||
{
|
||||
debugPrint("AudiofWrite shouldn't be ever called\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x41AD68
|
||||
int audioFileInit(AudioFileIsCompressedProc* isCompressedProc)
|
||||
int audioFileInit(AudioFileQueryCompressedFunc* func)
|
||||
{
|
||||
_queryCompressedFunc_2 = isCompressedProc;
|
||||
gAudioFileList = NULL;
|
||||
queryCompressedFunc = func;
|
||||
gAudioFileList = nullptr;
|
||||
gAudioFileListLength = 0;
|
||||
|
||||
return soundSetDefaultFileIO(audioFileOpen, audioFileClose, audioFileRead, audioFileWrite, audioFileSeek, audioFileTell, audioFileGetSize);
|
||||
@@ -242,10 +240,12 @@ int audioFileInit(AudioFileIsCompressedProc* isCompressedProc)
|
||||
// 0x41ADAC
|
||||
void audioFileExit()
|
||||
{
|
||||
if (gAudioFileList != NULL) {
|
||||
if (gAudioFileList != nullptr) {
|
||||
internal_free_safe(gAudioFileList, __FILE__, __LINE__); // "..\int\audiof.c", 405
|
||||
}
|
||||
|
||||
gAudioFileListLength = 0;
|
||||
gAudioFileList = NULL;
|
||||
gAudioFileList = nullptr;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,33 +1,20 @@
|
||||
#ifndef AUDIO_FILE_H
|
||||
#define AUDIO_FILE_H
|
||||
|
||||
#include "sound_decoder.h"
|
||||
namespace fallout {
|
||||
|
||||
typedef enum AudioFileFlags {
|
||||
AUDIO_FILE_IN_USE = 0x01,
|
||||
AUDIO_FILE_COMPRESSED = 0x02,
|
||||
} AudioFileFlags;
|
||||
typedef bool(AudioFileQueryCompressedFunc)(char* filePath);
|
||||
|
||||
typedef struct AudioFile {
|
||||
int flags;
|
||||
int fileHandle;
|
||||
SoundDecoder* soundDecoder;
|
||||
int fileSize;
|
||||
int field_10;
|
||||
int field_14;
|
||||
int position;
|
||||
} AudioFile;
|
||||
|
||||
typedef bool(AudioFileIsCompressedProc)(char* filePath);
|
||||
|
||||
int audioFileOpen(const char* fname, int flags, ...);
|
||||
int audioFileClose(int a1);
|
||||
int audioFileRead(int a1, void* buf, unsigned int size);
|
||||
int audioFileOpen(const char* fname, int* sampleRate);
|
||||
int audioFileClose(int handle);
|
||||
int audioFileRead(int handle, void* buf, unsigned int size);
|
||||
long audioFileSeek(int handle, long offset, int origin);
|
||||
long audioFileGetSize(int a1);
|
||||
long audioFileTell(int a1);
|
||||
long audioFileGetSize(int handle);
|
||||
long audioFileTell(int handle);
|
||||
int audioFileWrite(int handle, const void* buf, unsigned int size);
|
||||
int audioFileInit(AudioFileIsCompressedProc* isCompressedProc);
|
||||
int audioFileInit(AudioFileQueryCompressedFunc* func);
|
||||
void audioFileExit();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* AUDIO_FILE_H */
|
||||
|
||||
200
src/automap.cc
@@ -1,30 +1,34 @@
|
||||
#include "automap.h"
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "config.h"
|
||||
#include "core.h"
|
||||
#include "dbox.h"
|
||||
#include "debug.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
#include "game_config.h"
|
||||
#include "game_mouse.h"
|
||||
#include "game_sound.h"
|
||||
#include "graph_lib.h"
|
||||
#include "item.h"
|
||||
#include "map.h"
|
||||
#include "memory.h"
|
||||
#include "object.h"
|
||||
#include "platform_compat.h"
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "config.h"
|
||||
#include "dbox.h"
|
||||
#include "debug.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
#include "game_mouse.h"
|
||||
#include "game_sound.h"
|
||||
#include "graph_lib.h"
|
||||
#include "input.h"
|
||||
#include "item.h"
|
||||
#include "kb.h"
|
||||
#include "map.h"
|
||||
#include "memory.h"
|
||||
#include "object.h"
|
||||
#include "platform_compat.h"
|
||||
#include "settings.h"
|
||||
#include "svga.h"
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define AUTOMAP_OFFSET_COUNT (AUTOMAP_MAP_COUNT * ELEVATION_COUNT)
|
||||
|
||||
#define AUTOMAP_WINDOW_WIDTH (519)
|
||||
@@ -66,7 +70,7 @@ static const int _defam[AUTOMAP_MAP_COUNT][ELEVATION_COUNT] = {
|
||||
};
|
||||
|
||||
// 0x41B560
|
||||
static const int _displayMapList[AUTOMAP_MAP_COUNT] = {
|
||||
static int _displayMapList[AUTOMAP_MAP_COUNT] = {
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
@@ -267,12 +271,9 @@ int automapReset()
|
||||
// 0x41B81C
|
||||
void automapExit()
|
||||
{
|
||||
char* masterPatchesPath;
|
||||
if (configGetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_PATCHES_KEY, &masterPatchesPath)) {
|
||||
char path[COMPAT_MAX_PATH];
|
||||
sprintf(path, "%s\\%s\\%s", masterPatchesPath, "MAPS", AUTOMAP_DB);
|
||||
compat_remove(path);
|
||||
}
|
||||
char path[COMPAT_MAX_PATH];
|
||||
snprintf(path, sizeof(path), "%s\\%s\\%s", settings.system.master_patches_path.c_str(), "MAPS", AUTOMAP_DB);
|
||||
compat_remove(path);
|
||||
}
|
||||
|
||||
// 0x41B87C
|
||||
@@ -296,18 +297,15 @@ int _automapDisplayMap(int map)
|
||||
// 0x41B8BC
|
||||
void automapShow(bool isInGame, bool isUsingScanner)
|
||||
{
|
||||
ScopedGameMode gm(GameMode::kAutomap);
|
||||
|
||||
int frmIds[AUTOMAP_FRM_COUNT];
|
||||
memcpy(frmIds, gAutomapFrmIds, sizeof(gAutomapFrmIds));
|
||||
|
||||
unsigned char* frmData[AUTOMAP_FRM_COUNT];
|
||||
CacheEntry* frmHandle[AUTOMAP_FRM_COUNT];
|
||||
FrmImage frmImages[AUTOMAP_FRM_COUNT];
|
||||
for (int index = 0; index < AUTOMAP_FRM_COUNT; index++) {
|
||||
int fid = buildFid(6, frmIds[index], 0, 0, 0);
|
||||
frmData[index] = artLockFrameData(fid, 0, 0, &(frmHandle[index]));
|
||||
if (frmData[index] == NULL) {
|
||||
while (--index >= 0) {
|
||||
artUnlock(frmHandle[index]);
|
||||
}
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, frmIds[index], 0, 0, 0);
|
||||
if (!frmImages[index].lock(fid)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -325,19 +323,55 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
|
||||
int automapWindowX = (screenGetWidth() - AUTOMAP_WINDOW_WIDTH) / 2;
|
||||
int automapWindowY = (screenGetHeight() - AUTOMAP_WINDOW_HEIGHT) / 2;
|
||||
int window = windowCreate(automapWindowX, automapWindowY, AUTOMAP_WINDOW_WIDTH, AUTOMAP_WINDOW_HEIGHT, color, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
|
||||
int window = windowCreate(automapWindowX, automapWindowY, AUTOMAP_WINDOW_WIDTH, AUTOMAP_WINDOW_HEIGHT, color, WINDOW_MODAL | WINDOW_MOVE_ON_TOP);
|
||||
|
||||
int scannerBtn = buttonCreate(window, 111, 454, 15, 16, -1, -1, -1, KEY_LOWERCASE_S, frmData[AUTOMAP_FRM_BUTTON_UP], frmData[AUTOMAP_FRM_BUTTON_DOWN], NULL, BUTTON_FLAG_TRANSPARENT);
|
||||
int scannerBtn = buttonCreate(window,
|
||||
111,
|
||||
454,
|
||||
15,
|
||||
16,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
KEY_LOWERCASE_S,
|
||||
frmImages[AUTOMAP_FRM_BUTTON_UP].getData(),
|
||||
frmImages[AUTOMAP_FRM_BUTTON_DOWN].getData(),
|
||||
nullptr,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (scannerBtn != -1) {
|
||||
buttonSetCallbacks(scannerBtn, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
}
|
||||
|
||||
int cancelBtn = buttonCreate(window, 277, 454, 15, 16, -1, -1, -1, KEY_ESCAPE, frmData[AUTOMAP_FRM_BUTTON_UP], frmData[AUTOMAP_FRM_BUTTON_DOWN], NULL, BUTTON_FLAG_TRANSPARENT);
|
||||
int cancelBtn = buttonCreate(window,
|
||||
277,
|
||||
454,
|
||||
15,
|
||||
16,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
KEY_ESCAPE,
|
||||
frmImages[AUTOMAP_FRM_BUTTON_UP].getData(),
|
||||
frmImages[AUTOMAP_FRM_BUTTON_DOWN].getData(),
|
||||
nullptr,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (cancelBtn != -1) {
|
||||
buttonSetCallbacks(cancelBtn, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
}
|
||||
|
||||
int switchBtn = buttonCreate(window, 457, 340, 42, 74, -1, -1, KEY_LOWERCASE_L, KEY_LOWERCASE_H, frmData[AUTOMAP_FRM_SWITCH_UP], frmData[AUTOMAP_FRM_SWITCH_DOWN], NULL, BUTTON_FLAG_TRANSPARENT | BUTTON_FLAG_0x01);
|
||||
int switchBtn = buttonCreate(window,
|
||||
457,
|
||||
340,
|
||||
42,
|
||||
74,
|
||||
-1,
|
||||
-1,
|
||||
KEY_LOWERCASE_L,
|
||||
KEY_LOWERCASE_H,
|
||||
frmImages[AUTOMAP_FRM_SWITCH_UP].getData(),
|
||||
frmImages[AUTOMAP_FRM_SWITCH_DOWN].getData(),
|
||||
nullptr,
|
||||
BUTTON_FLAG_TRANSPARENT | BUTTON_FLAG_0x01);
|
||||
if (switchBtn != -1) {
|
||||
buttonSetCallbacks(switchBtn, _gsound_toggle_butt_press_, _gsound_toggle_butt_press_);
|
||||
}
|
||||
@@ -358,18 +392,20 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
gAutomapFlags |= AUTOMAP_WITH_SCANNER;
|
||||
}
|
||||
|
||||
automapRenderInMapWindow(window, elevation, frmData[AUTOMAP_FRM_BACKGROUND], gAutomapFlags);
|
||||
automapRenderInMapWindow(window, elevation, frmImages[AUTOMAP_FRM_BACKGROUND].getData(), gAutomapFlags);
|
||||
|
||||
bool isoWasEnabled = isoDisable();
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
sharedFpsLimiter.mark();
|
||||
|
||||
bool needsRefresh = false;
|
||||
|
||||
// FIXME: There is minor bug in the interface - pressing H/L to toggle
|
||||
// high/low details does not update switch state.
|
||||
int keyCode = _get_input();
|
||||
int keyCode = inputGetInput();
|
||||
switch (keyCode) {
|
||||
case KEY_TAB:
|
||||
case KEY_ESCAPE:
|
||||
@@ -399,19 +435,19 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
}
|
||||
|
||||
if ((gAutomapFlags & AUTOMAP_WITH_SCANNER) == 0) {
|
||||
Object* scanner = NULL;
|
||||
Object* scanner = nullptr;
|
||||
|
||||
Object* item1 = critterGetItem1(gDude);
|
||||
if (item1 != NULL && item1->pid == PROTO_ID_MOTION_SENSOR) {
|
||||
if (item1 != nullptr && item1->pid == PROTO_ID_MOTION_SENSOR) {
|
||||
scanner = item1;
|
||||
} else {
|
||||
Object* item2 = critterGetItem2(gDude);
|
||||
if (item2 != NULL && item2->pid == PROTO_ID_MOTION_SENSOR) {
|
||||
if (item2 != nullptr && item2->pid == PROTO_ID_MOTION_SENSOR) {
|
||||
scanner = item2;
|
||||
}
|
||||
}
|
||||
|
||||
if (scanner != NULL && miscItemGetCharges(scanner) > 0) {
|
||||
if (scanner != nullptr && miscItemGetCharges(scanner) > 0) {
|
||||
needsRefresh = true;
|
||||
gAutomapFlags |= AUTOMAP_WITH_SCANNER;
|
||||
miscItemConsumeCharge(scanner);
|
||||
@@ -421,8 +457,8 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
MessageListItem messageListItem;
|
||||
// 17 - The motion sensor is not installed.
|
||||
// 18 - The motion sensor has no charges remaining.
|
||||
const char* title = getmsg(&gMiscMessageList, &messageListItem, scanner != NULL ? 18 : 17);
|
||||
showDialogBox(title, NULL, 0, 165, 140, _colorTable[32328], NULL, _colorTable[32328], 0);
|
||||
const char* title = getmsg(&gMiscMessageList, &messageListItem, scanner != nullptr ? 18 : 17);
|
||||
showDialogBox(title, nullptr, 0, 165, 140, _colorTable[32328], nullptr, _colorTable[32328], 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,9 +478,12 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
}
|
||||
|
||||
if (needsRefresh) {
|
||||
automapRenderInMapWindow(window, elevation, frmData[AUTOMAP_FRM_BACKGROUND], gAutomapFlags);
|
||||
automapRenderInMapWindow(window, elevation, frmImages[AUTOMAP_FRM_BACKGROUND].getData(), gAutomapFlags);
|
||||
needsRefresh = false;
|
||||
}
|
||||
|
||||
renderPresent();
|
||||
sharedFpsLimiter.throttle();
|
||||
}
|
||||
|
||||
if (isoWasEnabled) {
|
||||
@@ -453,10 +492,6 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
|
||||
windowDestroy(window);
|
||||
fontSetCurrent(oldFont);
|
||||
|
||||
for (int index = 0; index < AUTOMAP_FRM_COUNT; index++) {
|
||||
artUnlock(frmHandle[index]);
|
||||
}
|
||||
}
|
||||
|
||||
// Renders automap in Map window.
|
||||
@@ -477,12 +512,12 @@ static void automapRenderInMapWindow(int window, int elevation, unsigned char* b
|
||||
unsigned char* windowBuffer = windowGetBuffer(window);
|
||||
blitBufferToBuffer(backgroundData, AUTOMAP_WINDOW_WIDTH, AUTOMAP_WINDOW_HEIGHT, AUTOMAP_WINDOW_WIDTH, windowBuffer, AUTOMAP_WINDOW_WIDTH);
|
||||
|
||||
for (Object* object = objectFindFirstAtElevation(elevation); object != NULL; object = objectFindNextAtElevation()) {
|
||||
for (Object* object = objectFindFirstAtElevation(elevation); object != nullptr; object = objectFindNextAtElevation()) {
|
||||
if (object->tile == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int objectType = (object->fid & 0xF000000) >> 24;
|
||||
int objectType = FID_TYPE(object->fid);
|
||||
unsigned char objectColor;
|
||||
|
||||
if ((flags & AUTOMAP_IN_GAME) != 0) {
|
||||
@@ -591,7 +626,7 @@ int automapRenderInPipboyWindow(int window, int map, int elevation)
|
||||
unsigned char sceneryColor = _colorTable[480];
|
||||
|
||||
gAutomapEntry.data = (unsigned char*)internal_malloc(11024);
|
||||
if (gAutomapEntry.data == NULL) {
|
||||
if (gAutomapEntry.data == nullptr) {
|
||||
debugPrint("\nAUTOMAP: Error allocating data buffer!\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -659,9 +694,9 @@ int automapSaveCurrent()
|
||||
|
||||
bool dataBuffersAllocated = false;
|
||||
gAutomapEntry.data = (unsigned char*)internal_malloc(11024);
|
||||
if (gAutomapEntry.data != NULL) {
|
||||
if (gAutomapEntry.data != nullptr) {
|
||||
gAutomapEntry.compressedData = (unsigned char*)internal_malloc(11024);
|
||||
if (gAutomapEntry.compressedData != NULL) {
|
||||
if (gAutomapEntry.compressedData != nullptr) {
|
||||
dataBuffersAllocated = true;
|
||||
}
|
||||
}
|
||||
@@ -674,10 +709,10 @@ int automapSaveCurrent()
|
||||
|
||||
// NOTE: Not sure about the size.
|
||||
char path[256];
|
||||
sprintf(path, "%s\\%s", "MAPS", AUTOMAP_DB);
|
||||
snprintf(path, sizeof(path), "%s\\%s", "MAPS", AUTOMAP_DB);
|
||||
|
||||
File* stream1 = fileOpen(path, "r+b");
|
||||
if (stream1 == NULL) {
|
||||
if (stream1 == nullptr) {
|
||||
debugPrint("\nAUTOMAP: Error opening automap database file!\n");
|
||||
debugPrint("Error continued: automap_pip_save: path: %s", path);
|
||||
internal_free(gAutomapEntry.data);
|
||||
@@ -705,10 +740,10 @@ int automapSaveCurrent()
|
||||
}
|
||||
|
||||
if (entryOffset != 0) {
|
||||
sprintf(path, "%s\\%s", "MAPS", AUTOMAP_TMP);
|
||||
snprintf(path, sizeof(path), "%s\\%s", "MAPS", AUTOMAP_TMP);
|
||||
|
||||
File* stream2 = fileOpen(path, "wb");
|
||||
if (stream2 == NULL) {
|
||||
if (stream2 == nullptr) {
|
||||
debugPrint("\nAUTOMAP: Error creating temp file!\n");
|
||||
internal_free(gAutomapEntry.data);
|
||||
internal_free(gAutomapEntry.compressedData);
|
||||
@@ -799,15 +834,9 @@ int automapSaveCurrent()
|
||||
internal_free(gAutomapEntry.data);
|
||||
internal_free(gAutomapEntry.compressedData);
|
||||
|
||||
char* masterPatchesPath;
|
||||
if (!configGetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_PATCHES_KEY, &masterPatchesPath)) {
|
||||
debugPrint("\nAUTOMAP: Error reading config info!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE: Not sure about the size.
|
||||
char automapDbPath[512];
|
||||
sprintf(automapDbPath, "%s\\%s\\%s", masterPatchesPath, "MAPS", AUTOMAP_DB);
|
||||
snprintf(automapDbPath, sizeof(automapDbPath), "%s\\%s\\%s", settings.system.master_patches_path.c_str(), "MAPS", AUTOMAP_DB);
|
||||
if (compat_remove(automapDbPath) != 0) {
|
||||
debugPrint("\nAUTOMAP: Error removing database!\n");
|
||||
return -1;
|
||||
@@ -815,7 +844,7 @@ int automapSaveCurrent()
|
||||
|
||||
// NOTE: Not sure about the size.
|
||||
char automapTmpPath[512];
|
||||
sprintf(automapTmpPath, "%s\\%s\\%s", masterPatchesPath, "MAPS", AUTOMAP_TMP);
|
||||
snprintf(automapTmpPath, sizeof(automapTmpPath), "%s\\%s\\%s", settings.system.master_patches_path.c_str(), "MAPS", AUTOMAP_TMP);
|
||||
if (compat_rename(automapTmpPath, automapDbPath) != 0) {
|
||||
debugPrint("\nAUTOMAP: Error renaming database!\n");
|
||||
return -1;
|
||||
@@ -899,15 +928,15 @@ err:
|
||||
// 0x41C8CC
|
||||
static int automapLoadEntry(int map, int elevation)
|
||||
{
|
||||
gAutomapEntry.compressedData = NULL;
|
||||
gAutomapEntry.compressedData = nullptr;
|
||||
|
||||
char path[COMPAT_MAX_PATH];
|
||||
sprintf(path, "%s\\%s", "MAPS", AUTOMAP_DB);
|
||||
snprintf(path, sizeof(path), "%s\\%s", "MAPS", AUTOMAP_DB);
|
||||
|
||||
bool success = true;
|
||||
|
||||
File* stream = fileOpen(path, "r+b");
|
||||
if (stream == NULL) {
|
||||
if (stream == nullptr) {
|
||||
debugPrint("\nAUTOMAP: Error opening automap database file!\n");
|
||||
debugPrint("Error continued: AM_ReadEntry: path: %s", path);
|
||||
return -1;
|
||||
@@ -941,7 +970,7 @@ static int automapLoadEntry(int map, int elevation)
|
||||
|
||||
if (gAutomapEntry.isCompressed == 1) {
|
||||
gAutomapEntry.compressedData = (unsigned char*)internal_malloc(11024);
|
||||
if (gAutomapEntry.compressedData == NULL) {
|
||||
if (gAutomapEntry.compressedData == nullptr) {
|
||||
debugPrint("\nAUTOMAP: Error allocating decompression buffer!\n");
|
||||
fileClose(stream);
|
||||
return -1;
|
||||
@@ -974,7 +1003,7 @@ out:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gAutomapEntry.compressedData != NULL) {
|
||||
if (gAutomapEntry.compressedData != nullptr) {
|
||||
internal_free(gAutomapEntry.compressedData);
|
||||
}
|
||||
|
||||
@@ -1044,11 +1073,11 @@ static void _decode_map_data(int elevation)
|
||||
_obj_process_seen();
|
||||
|
||||
Object* object = objectFindFirstAtElevation(elevation);
|
||||
while (object != NULL) {
|
||||
while (object != nullptr) {
|
||||
if (object->tile != -1 && (object->flags & OBJECT_SEEN) != 0) {
|
||||
int contentType;
|
||||
|
||||
int objectType = (object->fid & 0xF000000) >> 24;
|
||||
int objectType = FID_TYPE(object->fid);
|
||||
if (objectType == OBJ_TYPE_SCENERY && object->pid != PROTO_ID_0x2000158) {
|
||||
contentType = 2;
|
||||
} else if (objectType == OBJ_TYPE_WALL) {
|
||||
@@ -1077,10 +1106,10 @@ static int automapCreate()
|
||||
memcpy(gAutomapHeader.offsets, _defam, sizeof(_defam));
|
||||
|
||||
char path[COMPAT_MAX_PATH];
|
||||
sprintf(path, "%s\\%s", "MAPS", AUTOMAP_DB);
|
||||
snprintf(path, sizeof(path), "%s\\%s", "MAPS", AUTOMAP_DB);
|
||||
|
||||
File* stream = fileOpen(path, "wb");
|
||||
if (stream == NULL) {
|
||||
if (stream == nullptr) {
|
||||
debugPrint("\nAUTOMAP: Error creating automap database file!\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -1100,7 +1129,7 @@ static int automapCreate()
|
||||
static int _copy_file_data(File* stream1, File* stream2, int length)
|
||||
{
|
||||
void* buffer = internal_malloc(0xFFFF);
|
||||
if (buffer == NULL) {
|
||||
if (buffer == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1132,10 +1161,10 @@ static int _copy_file_data(File* stream1, File* stream2, int length)
|
||||
int automapGetHeader(AutomapHeader** automapHeaderPtr)
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
sprintf(path, "%s\\%s", "MAPS", AUTOMAP_DB);
|
||||
snprintf(path, sizeof(path), "%s\\%s", "MAPS", AUTOMAP_DB);
|
||||
|
||||
File* stream = fileOpen(path, "rb");
|
||||
if (stream == NULL) {
|
||||
if (stream == nullptr) {
|
||||
debugPrint("\nAUTOMAP: Error opening database file for reading!\n");
|
||||
debugPrint("Error continued: ReadAMList: path: %s", path);
|
||||
return -1;
|
||||
@@ -1153,3 +1182,12 @@ int automapGetHeader(AutomapHeader** automapHeaderPtr)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void automapSetDisplayMap(int map, bool available)
|
||||
{
|
||||
if (map >= 0 && map < AUTOMAP_MAP_COUNT) {
|
||||
_displayMapList[map] = available ? 0 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "db.h"
|
||||
#include "map_defs.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define AUTOMAP_DB ("AUTOMAP.DB")
|
||||
#define AUTOMAP_TMP ("AUTOMAP.TMP")
|
||||
|
||||
@@ -54,4 +56,8 @@ int automapRenderInPipboyWindow(int win, int map, int elevation);
|
||||
int automapSaveCurrent();
|
||||
int automapGetHeader(AutomapHeader** automapHeaderPtr);
|
||||
|
||||
void automapSetDisplayMap(int map, bool available);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* AUTOMAP_H */
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "autorun.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
@@ -11,11 +9,13 @@
|
||||
static HANDLE gInterplayGenericAutorunMutex;
|
||||
#endif
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// 0x4139C0
|
||||
bool autorunMutexCreate()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
gInterplayGenericAutorunMutex = CreateMutexA(NULL, FALSE, "InterplayGenericAutorunMutex");
|
||||
gInterplayGenericAutorunMutex = CreateMutexA(nullptr, FALSE, "InterplayGenericAutorunMutex");
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||
CloseHandle(gInterplayGenericAutorunMutex);
|
||||
return false;
|
||||
@@ -29,8 +29,10 @@ bool autorunMutexCreate()
|
||||
void autorunMutexClose()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (gInterplayGenericAutorunMutex != NULL) {
|
||||
if (gInterplayGenericAutorunMutex != nullptr) {
|
||||
CloseHandle(gInterplayGenericAutorunMutex);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#ifndef AUTORUN_H
|
||||
#define AUTORUN_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
bool autorunMutexCreate();
|
||||
void autorunMutexClose();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* AUTORUN_H */
|
||||
|
||||
54
src/cache.cc
@@ -1,13 +1,15 @@
|
||||
#include "cache.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "memory.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
namespace fallout {
|
||||
|
||||
// The initial number of cache entries in new cache.
|
||||
#define CACHE_ENTRIES_INITIAL_CAPACITY (100)
|
||||
@@ -49,7 +51,7 @@ bool cacheInit(Cache* cache, CacheSizeProc* sizeProc, CacheReadProc* readProc, C
|
||||
cache->readProc = readProc;
|
||||
cache->freeProc = freeProc;
|
||||
|
||||
if (cache->entries == NULL) {
|
||||
if (cache->entries == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -62,7 +64,7 @@ bool cacheInit(Cache* cache, CacheSizeProc* sizeProc, CacheReadProc* readProc, C
|
||||
// 0x41FD50
|
||||
bool cacheFree(Cache* cache)
|
||||
{
|
||||
if (cache == NULL) {
|
||||
if (cache == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -76,14 +78,14 @@ bool cacheFree(Cache* cache)
|
||||
cache->entriesCapacity = 0;
|
||||
cache->hits = 0;
|
||||
|
||||
if (cache->entries != NULL) {
|
||||
if (cache->entries != nullptr) {
|
||||
internal_free(cache->entries);
|
||||
cache->entries = NULL;
|
||||
cache->entries = nullptr;
|
||||
}
|
||||
|
||||
cache->sizeProc = NULL;
|
||||
cache->readProc = NULL;
|
||||
cache->freeProc = NULL;
|
||||
cache->sizeProc = nullptr;
|
||||
cache->readProc = nullptr;
|
||||
cache->freeProc = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -91,11 +93,11 @@ bool cacheFree(Cache* cache)
|
||||
// 0x41FDE8
|
||||
bool cacheLock(Cache* cache, int key, void** data, CacheEntry** cacheEntryPtr)
|
||||
{
|
||||
if (cache == NULL || data == NULL || cacheEntryPtr == NULL) {
|
||||
if (cache == nullptr || data == nullptr || cacheEntryPtr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*cacheEntryPtr = NULL;
|
||||
*cacheEntryPtr = nullptr;
|
||||
|
||||
int index;
|
||||
int rc = cacheFindIndexForKey(cache, key, &index);
|
||||
@@ -146,7 +148,7 @@ bool cacheLock(Cache* cache, int key, void** data, CacheEntry** cacheEntryPtr)
|
||||
// 0x4200B8
|
||||
bool cacheUnlock(Cache* cache, CacheEntry* cacheEntry)
|
||||
{
|
||||
if (cache == NULL || cacheEntry == NULL) {
|
||||
if (cache == nullptr || cacheEntry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -167,7 +169,7 @@ bool cacheUnlock(Cache* cache, CacheEntry* cacheEntry)
|
||||
// 0x42012C
|
||||
bool cacheFlush(Cache* cache)
|
||||
{
|
||||
if (cache == NULL) {
|
||||
if (cache == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -192,13 +194,13 @@ bool cacheFlush(Cache* cache)
|
||||
}
|
||||
|
||||
// 0x42019C
|
||||
bool cachePrintStats(Cache* cache, char* dest)
|
||||
bool cachePrintStats(Cache* cache, char* dest, size_t size)
|
||||
{
|
||||
if (cache == NULL || dest == NULL) {
|
||||
if (cache == nullptr || dest == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sprintf(dest, "Cache stats are disabled.%s", "\n");
|
||||
snprintf(dest, size, "Cache stats are disabled.%s", "\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -209,7 +211,7 @@ bool cachePrintStats(Cache* cache, char* dest)
|
||||
static bool cacheFetchEntryForKey(Cache* cache, int key, int* indexPtr)
|
||||
{
|
||||
CacheEntry* cacheEntry = (CacheEntry*)internal_malloc(sizeof(*cacheEntry));
|
||||
if (cacheEntry == NULL) {
|
||||
if (cacheEntry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -374,7 +376,7 @@ static bool cacheEntryInit(CacheEntry* cacheEntry)
|
||||
{
|
||||
cacheEntry->key = 0;
|
||||
cacheEntry->size = 0;
|
||||
cacheEntry->data = NULL;
|
||||
cacheEntry->data = nullptr;
|
||||
cacheEntry->referenceCount = 0;
|
||||
cacheEntry->hits = 0;
|
||||
cacheEntry->flags = 0;
|
||||
@@ -387,7 +389,7 @@ static bool cacheEntryInit(CacheEntry* cacheEntry)
|
||||
// 0x420740
|
||||
static bool cacheEntryFree(Cache* cache, CacheEntry* cacheEntry)
|
||||
{
|
||||
if (cacheEntry->data != NULL) {
|
||||
if (cacheEntry->data != nullptr) {
|
||||
heapBlockDeallocate(&(cache->heap), &(cacheEntry->heapHandleIndex));
|
||||
}
|
||||
|
||||
@@ -418,12 +420,12 @@ static bool cacheClean(Cache* cache)
|
||||
// 0x4207D4
|
||||
static bool cacheResetStatistics(Cache* cache)
|
||||
{
|
||||
if (cache == NULL) {
|
||||
if (cache == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CacheEntry** entries = (CacheEntry**)internal_malloc(sizeof(*entries) * cache->entriesLength);
|
||||
if (entries == NULL) {
|
||||
if (entries == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -460,7 +462,7 @@ static bool cacheEnsureSize(Cache* cache, int size)
|
||||
}
|
||||
|
||||
CacheEntry** entries = (CacheEntry**)internal_malloc(sizeof(*entries) * cache->entriesLength);
|
||||
if (entries != NULL) {
|
||||
if (entries != nullptr) {
|
||||
memcpy(entries, cache->entries, sizeof(*entries) * cache->entriesLength);
|
||||
qsort(entries, cache->entriesLength, sizeof(*entries), cacheEntriesCompareByUsage);
|
||||
|
||||
@@ -560,7 +562,7 @@ static bool cacheSetCapacity(Cache* cache, int newCapacity)
|
||||
}
|
||||
|
||||
CacheEntry** entries = (CacheEntry**)internal_realloc(cache->entries, sizeof(*cache->entries) * newCapacity);
|
||||
if (entries == NULL) {
|
||||
if (entries == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -613,3 +615,5 @@ static int cacheEntriesCompareByMostRecentHit(const void* a1, const void* a2)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
#ifndef CACHE_H
|
||||
#define CACHE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "heap.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define INVALID_CACHE_ENTRY ((CacheEntry*)-1)
|
||||
|
||||
typedef enum CacheEntryFlags {
|
||||
@@ -64,6 +68,8 @@ bool cacheFree(Cache* cache);
|
||||
bool cacheLock(Cache* cache, int key, void** data, CacheEntry** cacheEntryPtr);
|
||||
bool cacheUnlock(Cache* cache, CacheEntry* cacheEntry);
|
||||
bool cacheFlush(Cache* cache);
|
||||
bool cachePrintStats(Cache* cache, char* dest);
|
||||
bool cachePrintStats(Cache* cache, char* dest, size_t size);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CACHE_H */
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "db.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
extern int gCharacterEditorRemainingCharacterPoints;
|
||||
|
||||
int characterEditorShow(bool isCreationMode);
|
||||
@@ -13,4 +15,6 @@ int characterEditorSave(File* stream);
|
||||
int characterEditorLoad(File* stream);
|
||||
void characterEditorReset();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CHARACTER_EDITOR_H */
|
||||
|
||||
@@ -1,30 +1,40 @@
|
||||
#include "character_selector.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "art.h"
|
||||
#include "character_editor.h"
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
#include "critter.h"
|
||||
#include "db.h"
|
||||
#include "debug.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
#include "game_sound.h"
|
||||
#include "input.h"
|
||||
#include "kb.h"
|
||||
#include "memory.h"
|
||||
#include "message.h"
|
||||
#include "mouse.h"
|
||||
#include "object.h"
|
||||
#include "options.h"
|
||||
#include "palette.h"
|
||||
#include "platform_compat.h"
|
||||
#include "preferences.h"
|
||||
#include "proto.h"
|
||||
#include "settings.h"
|
||||
#include "sfall_config.h"
|
||||
#include "skill.h"
|
||||
#include "stat.h"
|
||||
#include "svga.h"
|
||||
#include "text_font.h"
|
||||
#include "trait.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
namespace fallout {
|
||||
|
||||
#define CS_WINDOW_WIDTH (640)
|
||||
#define CS_WINDOW_HEIGHT (480)
|
||||
@@ -57,12 +67,28 @@
|
||||
#define CS_WINDOW_SECONDARY_STAT_MID_X (379)
|
||||
#define CS_WINDOW_BIO_X (438)
|
||||
|
||||
typedef enum PremadeCharacter {
|
||||
PREMADE_CHARACTER_NARG,
|
||||
PREMADE_CHARACTER_CHITSA,
|
||||
PREMADE_CHARACTER_MINGUN,
|
||||
PREMADE_CHARACTER_COUNT,
|
||||
} PremadeCharacter;
|
||||
|
||||
typedef struct PremadeCharacterDescription {
|
||||
char fileName[20];
|
||||
int face;
|
||||
char field_18[20];
|
||||
} PremadeCharacterDescription;
|
||||
|
||||
static bool characterSelectorWindowInit();
|
||||
static void characterSelectorWindowFree();
|
||||
static bool characterSelectorWindowRefresh();
|
||||
static bool characterSelectorWindowRenderFace();
|
||||
static bool characterSelectorWindowRenderStats();
|
||||
static bool characterSelectorWindowRenderBio();
|
||||
static bool characterSelectorWindowFatalError(bool result);
|
||||
|
||||
static void premadeCharactersLocalizePath(char* path);
|
||||
|
||||
// 0x51C84C
|
||||
static int gCurrentPremadeCharacter = PREMADE_CHARACTER_NARG;
|
||||
@@ -75,106 +101,49 @@ static PremadeCharacterDescription gPremadeCharacterDescriptions[PREMADE_CHARACT
|
||||
};
|
||||
|
||||
// 0x51C8D4
|
||||
static const int gPremadeCharacterCount = PREMADE_CHARACTER_COUNT;
|
||||
static int gPremadeCharacterCount = PREMADE_CHARACTER_COUNT;
|
||||
|
||||
// 0x51C7F8
|
||||
static int gCharacterSelectorWindow = -1;
|
||||
|
||||
// 0x51C7FC
|
||||
static unsigned char* gCharacterSelectorWindowBuffer = NULL;
|
||||
static unsigned char* gCharacterSelectorWindowBuffer = nullptr;
|
||||
|
||||
// 0x51C800
|
||||
static unsigned char* gCharacterSelectorBackground = NULL;
|
||||
static unsigned char* gCharacterSelectorBackground = nullptr;
|
||||
|
||||
// 0x51C804
|
||||
static int gCharacterSelectorWindowPreviousButton = -1;
|
||||
|
||||
// 0x51C808
|
||||
static CacheEntry* gCharacterSelectorWindowPreviousButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C80C
|
||||
static CacheEntry* gCharacterSelectorWindowPreviousButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C810
|
||||
static int gCharacterSelectorWindowNextButton = -1;
|
||||
|
||||
// 0x51C814
|
||||
static CacheEntry* gCharacterSelectorWindowNextButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C818
|
||||
static CacheEntry* gCharacterSelectorWindowNextButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C81C
|
||||
static int gCharacterSelectorWindowTakeButton = -1;
|
||||
|
||||
// 0x51C820
|
||||
static CacheEntry* gCharacterSelectorWindowTakeButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C824
|
||||
static CacheEntry* gCharacterSelectorWindowTakeButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C828
|
||||
static int gCharacterSelectorWindowModifyButton = -1;
|
||||
|
||||
// 0x51C82C
|
||||
static CacheEntry* gCharacterSelectorWindowModifyButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C830
|
||||
static CacheEntry* gCharacterSelectorWindowModifyButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C834
|
||||
static int gCharacterSelectorWindowCreateButton = -1;
|
||||
|
||||
// 0x51C838
|
||||
static CacheEntry* gCharacterSelectorWindowCreateButtonUpFrmHandle = NULL;
|
||||
|
||||
// 0x51C83C
|
||||
static CacheEntry* gCharacterSelectorWindowCreateButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x51C840
|
||||
static int gCharacterSelectorWindowBackButton = -1;
|
||||
|
||||
// 0x51C844
|
||||
static CacheEntry* gCharacterSelectorWindowBackButtonUpFrmHandle = NULL;
|
||||
static FrmImage _takeButtonNormalFrmImage;
|
||||
static FrmImage _takeButtonPressedFrmImage;
|
||||
static FrmImage _modifyButtonNormalFrmImage;
|
||||
static FrmImage _modifyButtonPressedFrmImage;
|
||||
static FrmImage _createButtonNormalFrmImage;
|
||||
static FrmImage _createButtonPressedFrmImage;
|
||||
static FrmImage _backButtonNormalFrmImage;
|
||||
static FrmImage _backButtonPressedFrmImage;
|
||||
static FrmImage _nextButtonNormalFrmImage;
|
||||
static FrmImage _nextButtonPressedFrmImage;
|
||||
static FrmImage _previousButtonNormalFrmImage;
|
||||
static FrmImage _previousButtonPressedFrmImage;
|
||||
|
||||
// 0x51C848
|
||||
static CacheEntry* gCharacterSelectorWindowBackButtonDownFrmHandle = NULL;
|
||||
|
||||
// 0x667764
|
||||
static unsigned char* gCharacterSelectorWindowTakeButtonUpFrmData;
|
||||
|
||||
// 0x667768
|
||||
static unsigned char* gCharacterSelectorWindowModifyButtonDownFrmData;
|
||||
|
||||
// 0x66776C
|
||||
static unsigned char* gCharacterSelectorWindowBackButtonUpFrmData;
|
||||
|
||||
// 0x667770
|
||||
static unsigned char* gCharacterSelectorWindowCreateButtonUpFrmData;
|
||||
|
||||
// 0x667774
|
||||
static unsigned char* gCharacterSelectorWindowModifyButtonUpFrmData;
|
||||
|
||||
// 0x667778
|
||||
static unsigned char* gCharacterSelectorWindowBackButtonDownFrmData;
|
||||
|
||||
// 0x66777C
|
||||
static unsigned char* gCharacterSelectorWindowCreateButtonDownFrmData;
|
||||
|
||||
// 0x667780
|
||||
static unsigned char* gCharacterSelectorWindowTakeButtonDownFrmData;
|
||||
|
||||
// 0x667784
|
||||
static unsigned char* gCharacterSelectorWindowNextButtonDownFrmData;
|
||||
|
||||
// 0x667788
|
||||
static unsigned char* gCharacterSelectorWindowNextButtonUpFrmData;
|
||||
|
||||
// 0x66778C
|
||||
static unsigned char* gCharacterSelectorWindowPreviousButtonUpFrmData;
|
||||
|
||||
// 0x667790
|
||||
static unsigned char* gCharacterSelectorWindowPreviousButtonDownFrmData;
|
||||
static std::vector<PremadeCharacterDescription> gCustomPremadeCharacterDescriptions;
|
||||
|
||||
// 0x4A71D0
|
||||
int characterSelectorOpen()
|
||||
@@ -194,11 +163,13 @@ int characterSelectorOpen()
|
||||
int rc = 0;
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
sharedFpsLimiter.mark();
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
int keyCode = _get_input();
|
||||
int keyCode = inputGetInput();
|
||||
|
||||
switch (keyCode) {
|
||||
case KEY_MINUS:
|
||||
@@ -221,6 +192,8 @@ int characterSelectorOpen()
|
||||
if (characterEditorShow(1) == 0) {
|
||||
rc = 2;
|
||||
done = true;
|
||||
} else {
|
||||
characterSelectorWindowRefresh();
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -229,6 +202,8 @@ int characterSelectorOpen()
|
||||
if (!characterEditorShow(1)) {
|
||||
rc = 2;
|
||||
done = true;
|
||||
} else {
|
||||
characterSelectorWindowRefresh();
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -264,6 +239,9 @@ int characterSelectorOpen()
|
||||
characterSelectorWindowRefresh();
|
||||
break;
|
||||
}
|
||||
|
||||
renderPresent();
|
||||
sharedFpsLimiter.throttle();
|
||||
}
|
||||
|
||||
paletteFadeTo(gPaletteBlack);
|
||||
@@ -279,9 +257,6 @@ int characterSelectorOpen()
|
||||
// 0x4A7468
|
||||
static bool characterSelectorWindowInit()
|
||||
{
|
||||
int backgroundFid;
|
||||
unsigned char* backgroundFrmData;
|
||||
|
||||
if (gCharacterSelectorWindow != -1) {
|
||||
return false;
|
||||
}
|
||||
@@ -290,22 +265,21 @@ static bool characterSelectorWindowInit()
|
||||
int characterSelectorWindowY = (screenGetHeight() - CS_WINDOW_HEIGHT) / 2;
|
||||
gCharacterSelectorWindow = windowCreate(characterSelectorWindowX, characterSelectorWindowY, CS_WINDOW_WIDTH, CS_WINDOW_HEIGHT, _colorTable[0], 0);
|
||||
if (gCharacterSelectorWindow == -1) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowBuffer = windowGetBuffer(gCharacterSelectorWindow);
|
||||
if (gCharacterSelectorWindowBuffer == NULL) {
|
||||
goto err;
|
||||
if (gCharacterSelectorWindowBuffer == nullptr) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
backgroundFid = buildFid(6, 174, 0, 0, 0);
|
||||
backgroundFrmData = artLockFrameData(backgroundFid, 0, 0, &backgroundFrmHandle);
|
||||
if (backgroundFrmData == NULL) {
|
||||
goto err;
|
||||
FrmImage backgroundFrmImage;
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 174, 0, 0, 0);
|
||||
if (!backgroundFrmImage.lock(backgroundFid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
blitBufferToBuffer(backgroundFrmData,
|
||||
blitBufferToBuffer(backgroundFrmImage.getData(),
|
||||
CS_WINDOW_WIDTH,
|
||||
CS_WINDOW_HEIGHT,
|
||||
CS_WINDOW_WIDTH,
|
||||
@@ -313,31 +287,29 @@ static bool characterSelectorWindowInit()
|
||||
CS_WINDOW_WIDTH);
|
||||
|
||||
gCharacterSelectorBackground = (unsigned char*)internal_malloc(CS_WINDOW_BACKGROUND_WIDTH * CS_WINDOW_BACKGROUND_HEIGHT);
|
||||
if (gCharacterSelectorBackground == NULL)
|
||||
goto err;
|
||||
if (gCharacterSelectorBackground == nullptr)
|
||||
return characterSelectorWindowFatalError(false);
|
||||
|
||||
blitBufferToBuffer(backgroundFrmData + CS_WINDOW_WIDTH * CS_WINDOW_BACKGROUND_Y + CS_WINDOW_BACKGROUND_X,
|
||||
blitBufferToBuffer(backgroundFrmImage.getData() + CS_WINDOW_WIDTH * CS_WINDOW_BACKGROUND_Y + CS_WINDOW_BACKGROUND_X,
|
||||
CS_WINDOW_BACKGROUND_WIDTH,
|
||||
CS_WINDOW_BACKGROUND_HEIGHT,
|
||||
CS_WINDOW_WIDTH,
|
||||
gCharacterSelectorBackground,
|
||||
CS_WINDOW_BACKGROUND_WIDTH);
|
||||
|
||||
artUnlock(backgroundFrmHandle);
|
||||
backgroundFrmImage.unlock();
|
||||
|
||||
int fid;
|
||||
|
||||
// Setup "Previous" button.
|
||||
fid = buildFid(6, 122, 0, 0, 0);
|
||||
gCharacterSelectorWindowPreviousButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowPreviousButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowPreviousButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 122, 0, 0, 0);
|
||||
if (!_previousButtonNormalFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
fid = buildFid(6, 123, 0, 0, 0);
|
||||
gCharacterSelectorWindowPreviousButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowPreviousButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowPreviousButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 123, 0, 0, 0);
|
||||
if (!_previousButtonPressedFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowPreviousButton = buttonCreate(gCharacterSelectorWindow,
|
||||
@@ -349,27 +321,25 @@ static bool characterSelectorWindowInit()
|
||||
-1,
|
||||
-1,
|
||||
500,
|
||||
gCharacterSelectorWindowPreviousButtonUpFrmData,
|
||||
gCharacterSelectorWindowPreviousButtonDownFrmData,
|
||||
NULL,
|
||||
_previousButtonNormalFrmImage.getData(),
|
||||
_previousButtonPressedFrmImage.getData(),
|
||||
nullptr,
|
||||
0);
|
||||
if (gCharacterSelectorWindowPreviousButton == -1) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowPreviousButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
||||
|
||||
// Setup "Next" button.
|
||||
fid = buildFid(6, 124, 0, 0, 0);
|
||||
gCharacterSelectorWindowNextButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowNextButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowNextButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 124, 0, 0, 0);
|
||||
if (!_nextButtonNormalFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
fid = buildFid(6, 125, 0, 0, 0);
|
||||
gCharacterSelectorWindowNextButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowNextButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowNextButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 125, 0, 0, 0);
|
||||
if (!_nextButtonPressedFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowNextButton = buttonCreate(gCharacterSelectorWindow,
|
||||
@@ -381,27 +351,25 @@ static bool characterSelectorWindowInit()
|
||||
-1,
|
||||
-1,
|
||||
501,
|
||||
gCharacterSelectorWindowNextButtonUpFrmData,
|
||||
gCharacterSelectorWindowNextButtonDownFrmData,
|
||||
NULL,
|
||||
_nextButtonNormalFrmImage.getData(),
|
||||
_nextButtonPressedFrmImage.getData(),
|
||||
nullptr,
|
||||
0);
|
||||
if (gCharacterSelectorWindowNextButton == -1) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowNextButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
||||
|
||||
// Setup "Take" button.
|
||||
fid = buildFid(6, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowTakeButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowTakeButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowTakeButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
if (!_takeButtonNormalFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
fid = buildFid(6, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowTakeButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowTakeButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowTakeButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
if (!_takeButtonPressedFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowTakeButton = buttonCreate(gCharacterSelectorWindow,
|
||||
@@ -413,26 +381,24 @@ static bool characterSelectorWindowInit()
|
||||
-1,
|
||||
-1,
|
||||
KEY_LOWERCASE_T,
|
||||
gCharacterSelectorWindowTakeButtonUpFrmData,
|
||||
gCharacterSelectorWindowTakeButtonDownFrmData,
|
||||
NULL,
|
||||
_takeButtonNormalFrmImage.getData(),
|
||||
_takeButtonPressedFrmImage.getData(),
|
||||
nullptr,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (gCharacterSelectorWindowTakeButton == -1) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowTakeButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
|
||||
// Setup "Modify" button.
|
||||
fid = buildFid(6, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowModifyButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowModifyButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowModifyButtonUpFrmData == NULL)
|
||||
goto err;
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
if (!_modifyButtonNormalFrmImage.lock(fid))
|
||||
return characterSelectorWindowFatalError(false);
|
||||
|
||||
fid = buildFid(6, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowModifyButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowModifyButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowModifyButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
if (!_modifyButtonPressedFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowModifyButton = buttonCreate(gCharacterSelectorWindow,
|
||||
@@ -444,27 +410,25 @@ static bool characterSelectorWindowInit()
|
||||
-1,
|
||||
-1,
|
||||
KEY_LOWERCASE_M,
|
||||
gCharacterSelectorWindowModifyButtonUpFrmData,
|
||||
gCharacterSelectorWindowModifyButtonDownFrmData,
|
||||
NULL,
|
||||
_modifyButtonNormalFrmImage.getData(),
|
||||
_modifyButtonPressedFrmImage.getData(),
|
||||
nullptr,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (gCharacterSelectorWindowModifyButton == -1) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowModifyButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
|
||||
// Setup "Create" button.
|
||||
fid = buildFid(6, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowCreateButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowCreateButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowCreateButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
if (!_createButtonNormalFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
fid = buildFid(6, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowCreateButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowCreateButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowCreateButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
if (!_createButtonPressedFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowCreateButton = buttonCreate(gCharacterSelectorWindow,
|
||||
@@ -476,27 +440,25 @@ static bool characterSelectorWindowInit()
|
||||
-1,
|
||||
-1,
|
||||
KEY_LOWERCASE_C,
|
||||
gCharacterSelectorWindowCreateButtonUpFrmData,
|
||||
gCharacterSelectorWindowCreateButtonDownFrmData,
|
||||
NULL,
|
||||
_createButtonNormalFrmImage.getData(),
|
||||
_createButtonPressedFrmImage.getData(),
|
||||
nullptr,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (gCharacterSelectorWindowCreateButton == -1) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowCreateButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
|
||||
// Setup "Back" button.
|
||||
fid = buildFid(6, 8, 0, 0, 0);
|
||||
gCharacterSelectorWindowBackButtonUpFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowBackButtonUpFrmHandle);
|
||||
if (gCharacterSelectorWindowBackButtonUpFrmData == NULL) {
|
||||
goto err;
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
||||
if (!_backButtonNormalFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
fid = buildFid(6, 9, 0, 0, 0);
|
||||
gCharacterSelectorWindowBackButtonDownFrmData = artLockFrameData(fid, 0, 0, &gCharacterSelectorWindowBackButtonDownFrmHandle);
|
||||
if (gCharacterSelectorWindowBackButtonDownFrmData == NULL) {
|
||||
goto err;
|
||||
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
||||
if (!_backButtonPressedFrmImage.lock(fid)) {
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
gCharacterSelectorWindowBackButton = buttonCreate(gCharacterSelectorWindow,
|
||||
@@ -508,12 +470,12 @@ static bool characterSelectorWindowInit()
|
||||
-1,
|
||||
-1,
|
||||
KEY_ESCAPE,
|
||||
gCharacterSelectorWindowBackButtonUpFrmData,
|
||||
gCharacterSelectorWindowBackButtonDownFrmData,
|
||||
NULL,
|
||||
_backButtonNormalFrmImage.getData(),
|
||||
_backButtonPressedFrmImage.getData(),
|
||||
nullptr,
|
||||
BUTTON_FLAG_TRANSPARENT);
|
||||
if (gCharacterSelectorWindowBackButton == -1) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
buttonSetCallbacks(gCharacterSelectorWindowBackButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
||||
@@ -523,16 +485,10 @@ static bool characterSelectorWindowInit()
|
||||
windowRefresh(gCharacterSelectorWindow);
|
||||
|
||||
if (!characterSelectorWindowRefresh()) {
|
||||
goto err;
|
||||
return characterSelectorWindowFatalError(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
err:
|
||||
|
||||
characterSelectorWindowFree();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x4A7AD4
|
||||
@@ -547,106 +503,52 @@ static void characterSelectorWindowFree()
|
||||
gCharacterSelectorWindowPreviousButton = -1;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowPreviousButtonDownFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowPreviousButtonDownFrmHandle);
|
||||
gCharacterSelectorWindowPreviousButtonDownFrmHandle = NULL;
|
||||
gCharacterSelectorWindowPreviousButtonDownFrmData = NULL;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowPreviousButtonUpFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowPreviousButtonUpFrmHandle);
|
||||
gCharacterSelectorWindowPreviousButtonUpFrmHandle = NULL;
|
||||
gCharacterSelectorWindowPreviousButtonUpFrmData = NULL;
|
||||
}
|
||||
_previousButtonNormalFrmImage.unlock();
|
||||
_previousButtonPressedFrmImage.unlock();
|
||||
|
||||
if (gCharacterSelectorWindowNextButton != -1) {
|
||||
buttonDestroy(gCharacterSelectorWindowNextButton);
|
||||
gCharacterSelectorWindowNextButton = -1;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowNextButtonDownFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowNextButtonDownFrmHandle);
|
||||
gCharacterSelectorWindowNextButtonDownFrmHandle = NULL;
|
||||
gCharacterSelectorWindowNextButtonDownFrmData = NULL;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowNextButtonUpFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowNextButtonUpFrmHandle);
|
||||
gCharacterSelectorWindowNextButtonUpFrmHandle = NULL;
|
||||
gCharacterSelectorWindowNextButtonUpFrmData = NULL;
|
||||
}
|
||||
_nextButtonNormalFrmImage.unlock();
|
||||
_nextButtonPressedFrmImage.unlock();
|
||||
|
||||
if (gCharacterSelectorWindowTakeButton != -1) {
|
||||
buttonDestroy(gCharacterSelectorWindowTakeButton);
|
||||
gCharacterSelectorWindowTakeButton = -1;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowTakeButtonDownFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowTakeButtonDownFrmHandle);
|
||||
gCharacterSelectorWindowTakeButtonDownFrmHandle = NULL;
|
||||
gCharacterSelectorWindowTakeButtonDownFrmData = NULL;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowTakeButtonUpFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowTakeButtonUpFrmHandle);
|
||||
gCharacterSelectorWindowTakeButtonUpFrmHandle = NULL;
|
||||
gCharacterSelectorWindowTakeButtonUpFrmData = NULL;
|
||||
}
|
||||
_takeButtonNormalFrmImage.unlock();
|
||||
_takeButtonPressedFrmImage.unlock();
|
||||
|
||||
if (gCharacterSelectorWindowModifyButton != -1) {
|
||||
buttonDestroy(gCharacterSelectorWindowModifyButton);
|
||||
gCharacterSelectorWindowModifyButton = -1;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowModifyButtonDownFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowModifyButtonDownFrmHandle);
|
||||
gCharacterSelectorWindowModifyButtonDownFrmHandle = NULL;
|
||||
gCharacterSelectorWindowModifyButtonDownFrmData = NULL;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowModifyButtonUpFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowModifyButtonUpFrmHandle);
|
||||
gCharacterSelectorWindowModifyButtonUpFrmHandle = NULL;
|
||||
gCharacterSelectorWindowModifyButtonUpFrmData = NULL;
|
||||
}
|
||||
_modifyButtonNormalFrmImage.unlock();
|
||||
_modifyButtonPressedFrmImage.unlock();
|
||||
|
||||
if (gCharacterSelectorWindowCreateButton != -1) {
|
||||
buttonDestroy(gCharacterSelectorWindowCreateButton);
|
||||
gCharacterSelectorWindowCreateButton = -1;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowCreateButtonDownFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowCreateButtonDownFrmHandle);
|
||||
gCharacterSelectorWindowCreateButtonDownFrmHandle = NULL;
|
||||
gCharacterSelectorWindowCreateButtonDownFrmData = NULL;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowCreateButtonUpFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowCreateButtonUpFrmHandle);
|
||||
gCharacterSelectorWindowCreateButtonUpFrmHandle = NULL;
|
||||
gCharacterSelectorWindowCreateButtonUpFrmData = NULL;
|
||||
}
|
||||
_createButtonNormalFrmImage.unlock();
|
||||
_createButtonPressedFrmImage.unlock();
|
||||
|
||||
if (gCharacterSelectorWindowBackButton != -1) {
|
||||
buttonDestroy(gCharacterSelectorWindowBackButton);
|
||||
gCharacterSelectorWindowBackButton = -1;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorWindowBackButtonDownFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowBackButtonDownFrmHandle);
|
||||
gCharacterSelectorWindowBackButtonDownFrmHandle = NULL;
|
||||
gCharacterSelectorWindowBackButtonDownFrmData = NULL;
|
||||
}
|
||||
_backButtonNormalFrmImage.unlock();
|
||||
_backButtonPressedFrmImage.unlock();
|
||||
|
||||
if (gCharacterSelectorWindowBackButtonUpFrmData != NULL) {
|
||||
artUnlock(gCharacterSelectorWindowBackButtonUpFrmHandle);
|
||||
gCharacterSelectorWindowBackButtonUpFrmHandle = NULL;
|
||||
gCharacterSelectorWindowBackButtonUpFrmData = NULL;
|
||||
}
|
||||
|
||||
if (gCharacterSelectorBackground != NULL) {
|
||||
if (gCharacterSelectorBackground != nullptr) {
|
||||
internal_free(gCharacterSelectorBackground);
|
||||
gCharacterSelectorBackground = NULL;
|
||||
gCharacterSelectorBackground = nullptr;
|
||||
}
|
||||
|
||||
windowDestroy(gCharacterSelectorWindow);
|
||||
@@ -657,7 +559,9 @@ static void characterSelectorWindowFree()
|
||||
static bool characterSelectorWindowRefresh()
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
sprintf(path, "%s.gcd", gPremadeCharacterDescriptions[gCurrentPremadeCharacter].fileName);
|
||||
snprintf(path, sizeof(path), "%s.gcd", gCustomPremadeCharacterDescriptions[gCurrentPremadeCharacter].fileName);
|
||||
premadeCharactersLocalizePath(path);
|
||||
|
||||
if (_proto_dude_init(path) == -1) {
|
||||
debugPrint("\n ** Error in dude init! **\n");
|
||||
return false;
|
||||
@@ -687,18 +591,17 @@ static bool characterSelectorWindowRenderFace()
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
CacheEntry* faceFrmHandle;
|
||||
int faceFid = buildFid(6, gPremadeCharacterDescriptions[gCurrentPremadeCharacter].face, 0, 0, 0);
|
||||
Art* frm = artLock(faceFid, &faceFrmHandle);
|
||||
if (frm != NULL) {
|
||||
unsigned char* data = artGetFrameData(frm, 0, 0);
|
||||
if (data != NULL) {
|
||||
int width = artGetWidth(frm, 0, 0);
|
||||
int height = artGetHeight(frm, 0, 0);
|
||||
FrmImage faceFrmImage;
|
||||
int faceFid = buildFid(OBJ_TYPE_INTERFACE, gCustomPremadeCharacterDescriptions[gCurrentPremadeCharacter].face, 0, 0, 0);
|
||||
if (faceFrmImage.lock(faceFid)) {
|
||||
unsigned char* data = faceFrmImage.getData();
|
||||
if (data != nullptr) {
|
||||
int width = faceFrmImage.getWidth();
|
||||
int height = faceFrmImage.getHeight();
|
||||
blitBufferToBufferTrans(data, width, height, width, (gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * 23 + 27), CS_WINDOW_WIDTH);
|
||||
success = true;
|
||||
}
|
||||
artUnlock(faceFrmHandle);
|
||||
faceFrmImage.unlock();
|
||||
}
|
||||
|
||||
return success;
|
||||
@@ -734,13 +637,13 @@ static bool characterSelectorWindowRenderStats()
|
||||
value = critterGetStat(gDude, STAT_STRENGTH);
|
||||
str = statGetName(STAT_STRENGTH);
|
||||
|
||||
sprintf(text, "%s %02d", str, value);
|
||||
snprintf(text, sizeof(text), "%s %02d", str, value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
str = statGetValueDescription(value);
|
||||
sprintf(text, " %s", str);
|
||||
snprintf(text, sizeof(text), " %s", str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
@@ -751,13 +654,13 @@ static bool characterSelectorWindowRenderStats()
|
||||
value = critterGetStat(gDude, STAT_PERCEPTION);
|
||||
str = statGetName(STAT_PERCEPTION);
|
||||
|
||||
sprintf(text, "%s %02d", str, value);
|
||||
snprintf(text, sizeof(text), "%s %02d", str, value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
str = statGetValueDescription(value);
|
||||
sprintf(text, " %s", str);
|
||||
snprintf(text, sizeof(text), " %s", str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
@@ -766,15 +669,15 @@ static bool characterSelectorWindowRenderStats()
|
||||
y += vh;
|
||||
|
||||
value = critterGetStat(gDude, STAT_ENDURANCE);
|
||||
str = statGetName(STAT_PERCEPTION);
|
||||
str = statGetName(STAT_ENDURANCE);
|
||||
|
||||
sprintf(text, "%s %02d", str, value);
|
||||
snprintf(text, sizeof(text), "%s %02d", str, value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
str = statGetValueDescription(value);
|
||||
sprintf(text, " %s", str);
|
||||
snprintf(text, sizeof(text), " %s", str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
@@ -785,13 +688,13 @@ static bool characterSelectorWindowRenderStats()
|
||||
value = critterGetStat(gDude, STAT_CHARISMA);
|
||||
str = statGetName(STAT_CHARISMA);
|
||||
|
||||
sprintf(text, "%s %02d", str, value);
|
||||
snprintf(text, sizeof(text), "%s %02d", str, value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
str = statGetValueDescription(value);
|
||||
sprintf(text, " %s", str);
|
||||
snprintf(text, sizeof(text), " %s", str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
@@ -802,13 +705,13 @@ static bool characterSelectorWindowRenderStats()
|
||||
value = critterGetStat(gDude, STAT_INTELLIGENCE);
|
||||
str = statGetName(STAT_INTELLIGENCE);
|
||||
|
||||
sprintf(text, "%s %02d", str, value);
|
||||
snprintf(text, sizeof(text), "%s %02d", str, value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
str = statGetValueDescription(value);
|
||||
sprintf(text, " %s", str);
|
||||
snprintf(text, sizeof(text), " %s", str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
@@ -819,13 +722,13 @@ static bool characterSelectorWindowRenderStats()
|
||||
value = critterGetStat(gDude, STAT_AGILITY);
|
||||
str = statGetName(STAT_AGILITY);
|
||||
|
||||
sprintf(text, "%s %02d", str, value);
|
||||
snprintf(text, sizeof(text), "%s %02d", str, value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
str = statGetValueDescription(value);
|
||||
sprintf(text, " %s", str);
|
||||
snprintf(text, sizeof(text), " %s", str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
@@ -836,13 +739,13 @@ static bool characterSelectorWindowRenderStats()
|
||||
value = critterGetStat(gDude, STAT_LUCK);
|
||||
str = statGetName(STAT_LUCK);
|
||||
|
||||
sprintf(text, "%s %02d", str, value);
|
||||
snprintf(text, sizeof(text), "%s %02d", str, value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
str = statGetValueDescription(value);
|
||||
sprintf(text, " %s", str);
|
||||
snprintf(text, sizeof(text), " %s", str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
@@ -862,7 +765,7 @@ static bool characterSelectorWindowRenderStats()
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
value = critterGetStat(gDude, STAT_MAXIMUM_HIT_POINTS);
|
||||
sprintf(text, " %d/%d", critterGetHitPoints(gDude), value);
|
||||
snprintf(text, sizeof(text), " %d/%d", critterGetHitPoints(gDude), value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
@@ -877,7 +780,7 @@ static bool characterSelectorWindowRenderStats()
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
value = critterGetStat(gDude, STAT_ARMOR_CLASS);
|
||||
sprintf(text, " %d", value);
|
||||
snprintf(text, sizeof(text), " %d", value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
@@ -895,7 +798,7 @@ static bool characterSelectorWindowRenderStats()
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
value = critterGetStat(gDude, STAT_MAXIMUM_ACTION_POINTS);
|
||||
sprintf(text, " %d", value);
|
||||
snprintf(text, sizeof(text), " %d", value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
@@ -903,14 +806,14 @@ static bool characterSelectorWindowRenderStats()
|
||||
// MELEE DAMAGE
|
||||
y += vh;
|
||||
|
||||
str = statGetName(STAT_ARMOR_CLASS);
|
||||
str = statGetName(STAT_MELEE_DAMAGE);
|
||||
strcpy(text, str);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
value = critterGetStat(gDude, STAT_ARMOR_CLASS);
|
||||
sprintf(text, " %d", value);
|
||||
value = critterGetStat(gDude, STAT_MELEE_DAMAGE);
|
||||
snprintf(text, sizeof(text), " %d", value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
@@ -931,7 +834,7 @@ static bool characterSelectorWindowRenderStats()
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
|
||||
value = skillGetValue(gDude, skills[index]);
|
||||
sprintf(text, " %d%%", value);
|
||||
snprintf(text, sizeof(text), " %d%%", value);
|
||||
|
||||
length = fontGetStringWidth(text);
|
||||
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
||||
@@ -963,10 +866,11 @@ static bool characterSelectorWindowRenderBio()
|
||||
fontSetCurrent(101);
|
||||
|
||||
char path[COMPAT_MAX_PATH];
|
||||
sprintf(path, "%s.bio", gPremadeCharacterDescriptions[gCurrentPremadeCharacter].fileName);
|
||||
snprintf(path, sizeof(path), "%s.bio", gCustomPremadeCharacterDescriptions[gCurrentPremadeCharacter].fileName);
|
||||
premadeCharactersLocalizePath(path);
|
||||
|
||||
File* stream = fileOpen(path, "rt");
|
||||
if (stream != NULL) {
|
||||
if (stream != nullptr) {
|
||||
int y = 40;
|
||||
int lineHeight = fontGetLineHeight();
|
||||
|
||||
@@ -983,3 +887,120 @@ static bool characterSelectorWindowRenderBio()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4A8BD0
|
||||
static bool characterSelectorWindowFatalError(bool result)
|
||||
{
|
||||
characterSelectorWindowFree();
|
||||
return result;
|
||||
}
|
||||
|
||||
void premadeCharactersInit()
|
||||
{
|
||||
char* fileNamesString;
|
||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PREMADE_CHARACTERS_FILE_NAMES_KEY, &fileNamesString);
|
||||
if (fileNamesString != nullptr && *fileNamesString == '\0') {
|
||||
fileNamesString = nullptr;
|
||||
}
|
||||
|
||||
char* faceFidsString;
|
||||
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PREMADE_CHARACTERS_FACE_FIDS_KEY, &faceFidsString);
|
||||
if (faceFidsString != nullptr && *faceFidsString == '\0') {
|
||||
faceFidsString = nullptr;
|
||||
}
|
||||
|
||||
if (fileNamesString != nullptr && faceFidsString != nullptr) {
|
||||
int fileNamesLength = 0;
|
||||
for (char* pch = fileNamesString; pch != nullptr; pch = strchr(pch + 1, ',')) {
|
||||
fileNamesLength++;
|
||||
}
|
||||
|
||||
int faceFidsLength = 0;
|
||||
for (char* pch = faceFidsString; pch != nullptr; pch = strchr(pch + 1, ',')) {
|
||||
faceFidsLength++;
|
||||
}
|
||||
|
||||
int premadeCharactersCount = std::min(fileNamesLength, faceFidsLength);
|
||||
gCustomPremadeCharacterDescriptions.resize(premadeCharactersCount);
|
||||
|
||||
for (int index = 0; index < premadeCharactersCount; index++) {
|
||||
char* pch;
|
||||
|
||||
pch = strchr(fileNamesString, ',');
|
||||
if (pch != nullptr) {
|
||||
*pch = '\0';
|
||||
}
|
||||
|
||||
if (strlen(fileNamesString) > 11) {
|
||||
// Sfall fails here.
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(gCustomPremadeCharacterDescriptions[index].fileName, sizeof(gCustomPremadeCharacterDescriptions[index].fileName), "premade\\%s", fileNamesString);
|
||||
|
||||
if (pch != nullptr) {
|
||||
*pch = ',';
|
||||
}
|
||||
|
||||
fileNamesString = pch + 1;
|
||||
|
||||
pch = strchr(faceFidsString, ',');
|
||||
if (pch != nullptr) {
|
||||
*pch = '\0';
|
||||
}
|
||||
|
||||
gCustomPremadeCharacterDescriptions[index].face = atoi(faceFidsString);
|
||||
|
||||
if (pch != nullptr) {
|
||||
*pch = ',';
|
||||
}
|
||||
|
||||
faceFidsString = pch + 1;
|
||||
|
||||
gCustomPremadeCharacterDescriptions[index].field_18[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (gCustomPremadeCharacterDescriptions.empty()) {
|
||||
gCustomPremadeCharacterDescriptions.resize(PREMADE_CHARACTER_COUNT);
|
||||
|
||||
for (int index = 0; index < PREMADE_CHARACTER_COUNT; index++) {
|
||||
strcpy(gCustomPremadeCharacterDescriptions[index].fileName, gPremadeCharacterDescriptions[index].fileName);
|
||||
gCustomPremadeCharacterDescriptions[index].face = gPremadeCharacterDescriptions[index].face;
|
||||
strcpy(gCustomPremadeCharacterDescriptions[index].field_18, gPremadeCharacterDescriptions[index].field_18);
|
||||
}
|
||||
}
|
||||
|
||||
gPremadeCharacterCount = gCustomPremadeCharacterDescriptions.size();
|
||||
}
|
||||
|
||||
void premadeCharactersExit()
|
||||
{
|
||||
gCustomPremadeCharacterDescriptions.clear();
|
||||
}
|
||||
|
||||
static void premadeCharactersLocalizePath(char* path)
|
||||
{
|
||||
if (compat_strnicmp(path, "premade\\", 8) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char* language = settings.system.language.c_str();
|
||||
if (compat_stricmp(language, ENGLISH) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
char localizedPath[COMPAT_MAX_PATH];
|
||||
strncpy(localizedPath, path, 8);
|
||||
strcpy(localizedPath + 8, language);
|
||||
strcpy(localizedPath + 8 + strlen(language), path + 7);
|
||||
|
||||
int fileSize;
|
||||
if (dbGetFileSize(localizedPath, &fileSize) == 0) {
|
||||
strcpy(path, localizedPath);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
#ifndef CHARACTER_SELECTOR_H
|
||||
#define CHARACTER_SELECTOR_H
|
||||
|
||||
typedef enum PremadeCharacter {
|
||||
PREMADE_CHARACTER_NARG,
|
||||
PREMADE_CHARACTER_CHITSA,
|
||||
PREMADE_CHARACTER_MINGUN,
|
||||
PREMADE_CHARACTER_COUNT,
|
||||
} PremadeCharacter;
|
||||
|
||||
typedef struct PremadeCharacterDescription {
|
||||
char fileName[20];
|
||||
int face;
|
||||
char field_18[20];
|
||||
} PremadeCharacterDescription;
|
||||
namespace fallout {
|
||||
|
||||
int characterSelectorOpen();
|
||||
|
||||
void premadeCharactersInit();
|
||||
void premadeCharactersExit();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CHARACTER_SELECTOR_H */
|
||||
|
||||
274
src/color.cc
@@ -1,18 +1,16 @@
|
||||
#include "color.h"
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
static int colorPaletteFileOpen(const char* filePath, int flags);
|
||||
static int colorPaletteFileRead(int fd, void* buffer, size_t size);
|
||||
static int colorPaletteFileClose(int fd);
|
||||
static void* colorPaletteMallocDefaultImpl(size_t size);
|
||||
static void* colorPaletteReallocDefaultImpl(void* ptr, size_t size);
|
||||
static void colorPaletteFreeDefaultImpl(void* ptr);
|
||||
#include "db.h"
|
||||
#include "memory.h"
|
||||
#include "svga.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
static void _setIntensityTableColor(int a1);
|
||||
static void _setIntensityTables();
|
||||
static void _setMixTableColor(int a1);
|
||||
@@ -25,6 +23,12 @@ static char _aColor_cNoError[] = "color.c: No errors\n";
|
||||
// 0x50F95C
|
||||
static char _aColor_cColorTa[] = "color.c: color table not found\n";
|
||||
|
||||
// 0x50F984
|
||||
static char _aColor_cColorpa[] = "color.c: colorpalettestack overflow";
|
||||
|
||||
// 0x50F9AC
|
||||
static char aColor_cColor_0[] = "color.c: colorpalettestack underflow";
|
||||
|
||||
// 0x51DF10
|
||||
static char* _errorStr = _aColor_cNoError;
|
||||
|
||||
@@ -35,19 +39,10 @@ static bool _colorsInited = false;
|
||||
static double gBrightness = 1.0;
|
||||
|
||||
// 0x51DF20
|
||||
static ColorTransitionCallback* gColorPaletteTransitionCallback = NULL;
|
||||
|
||||
// 0x51DF24
|
||||
static MallocProc* gColorPaletteMallocProc = colorPaletteMallocDefaultImpl;
|
||||
|
||||
// 0x51DF28
|
||||
static ReallocProc* gColorPaletteReallocProc = colorPaletteReallocDefaultImpl;
|
||||
|
||||
// 0x51DF2C
|
||||
static FreeProc* gColorPaletteFreeProc = colorPaletteFreeDefaultImpl;
|
||||
static ColorTransitionCallback* gColorPaletteTransitionCallback = nullptr;
|
||||
|
||||
// 0x51DF30
|
||||
static ColorFileNameManger* gColorFileNameMangler = NULL;
|
||||
static ColorFileNameManger* gColorFileNameMangler = nullptr;
|
||||
|
||||
// 0x51DF34
|
||||
unsigned char _cmap[768] = {
|
||||
@@ -67,105 +62,31 @@ unsigned char* _blendTable[256];
|
||||
unsigned char _mappedColor[256];
|
||||
|
||||
// 0x6738D0
|
||||
unsigned char _colorMixAddTable[65536];
|
||||
Color colorMixAddTable[256][256];
|
||||
|
||||
// 0x6838D0
|
||||
unsigned char _intensityColorTable[65536];
|
||||
Color intensityColorTable[256][256];
|
||||
|
||||
// 0x6938D0
|
||||
unsigned char _colorMixMulTable[65536];
|
||||
Color colorMixMulTable[256][256];
|
||||
|
||||
// 0x6A38D0
|
||||
unsigned char _colorTable[32768];
|
||||
|
||||
// 0x6AB928
|
||||
static ColorPaletteFileReadProc* gColorPaletteFileReadProc;
|
||||
|
||||
// 0x6AB92C
|
||||
static ColorPaletteCloseProc* gColorPaletteFileCloseProc;
|
||||
|
||||
// 0x6AB930
|
||||
static ColorPaletteFileOpenProc* gColorPaletteFileOpenProc;
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4C7200
|
||||
static int colorPaletteFileOpen(const char* filePath, int flags)
|
||||
{
|
||||
if (gColorPaletteFileOpenProc != NULL) {
|
||||
return gColorPaletteFileOpenProc(filePath, flags);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4C7218
|
||||
static int colorPaletteFileRead(int fd, void* buffer, size_t size)
|
||||
{
|
||||
if (gColorPaletteFileReadProc != NULL) {
|
||||
return gColorPaletteFileReadProc(fd, buffer, size);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4C7230
|
||||
static int colorPaletteFileClose(int fd)
|
||||
{
|
||||
if (gColorPaletteFileCloseProc != NULL) {
|
||||
return gColorPaletteFileCloseProc(fd);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x4C7248
|
||||
void colorPaletteSetFileIO(ColorPaletteFileOpenProc* openProc, ColorPaletteFileReadProc* readProc, ColorPaletteCloseProc* closeProc)
|
||||
{
|
||||
gColorPaletteFileOpenProc = openProc;
|
||||
gColorPaletteFileReadProc = readProc;
|
||||
gColorPaletteFileCloseProc = closeProc;
|
||||
}
|
||||
|
||||
// 0x4C725C
|
||||
static void* colorPaletteMallocDefaultImpl(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
// 0x4C7264
|
||||
static void* colorPaletteReallocDefaultImpl(void* ptr, size_t size)
|
||||
{
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
// 0x4C726C
|
||||
static void colorPaletteFreeDefaultImpl(void* ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
// 0x4C72B4
|
||||
int _calculateColor(int a1, int a2)
|
||||
int _calculateColor(int intensity, Color color)
|
||||
{
|
||||
int v1 = (a1 >> 9) + ((a2 & 0xFF) << 8);
|
||||
return _intensityColorTable[v1];
|
||||
return intensityColorTable[color][intensity / 512];
|
||||
}
|
||||
|
||||
// 0x4C72E0
|
||||
int _Color2RGB_(int a1)
|
||||
int Color2RGB(Color c)
|
||||
{
|
||||
int v1, v2, v3;
|
||||
int r = _cmap[3 * c] >> 1;
|
||||
int g = _cmap[3 * c + 1] >> 1;
|
||||
int b = _cmap[3 * c + 2] >> 1;
|
||||
|
||||
v1 = _cmap[3 * a1] >> 1;
|
||||
v2 = _cmap[3 * a1 + 1] >> 1;
|
||||
v3 = _cmap[3 * a1 + 2] >> 1;
|
||||
|
||||
return (((v1 << 5) | v2) << 5) | v3;
|
||||
return (r << 10) | (g << 5) | b;
|
||||
}
|
||||
|
||||
// Performs animated palette transition.
|
||||
@@ -174,22 +95,29 @@ int _Color2RGB_(int a1)
|
||||
void colorPaletteFadeBetween(unsigned char* oldPalette, unsigned char* newPalette, int steps)
|
||||
{
|
||||
for (int step = 0; step < steps; step++) {
|
||||
sharedFpsLimiter.mark();
|
||||
|
||||
unsigned char palette[768];
|
||||
|
||||
for (int index = 0; index < 768; index++) {
|
||||
palette[index] = oldPalette[index] - (oldPalette[index] - newPalette[index]) * step / steps;
|
||||
}
|
||||
|
||||
if (gColorPaletteTransitionCallback != NULL) {
|
||||
if (gColorPaletteTransitionCallback != nullptr) {
|
||||
if (step % 128 == 0) {
|
||||
gColorPaletteTransitionCallback();
|
||||
}
|
||||
}
|
||||
|
||||
_setSystemPalette(palette);
|
||||
renderPresent();
|
||||
sharedFpsLimiter.throttle();
|
||||
}
|
||||
|
||||
sharedFpsLimiter.mark();
|
||||
_setSystemPalette(newPalette);
|
||||
renderPresent();
|
||||
sharedFpsLimiter.throttle();
|
||||
}
|
||||
|
||||
// 0x4C73D4
|
||||
@@ -237,29 +165,28 @@ void _setSystemPaletteEntries(unsigned char* palette, int start, int end)
|
||||
}
|
||||
|
||||
// 0x4C7550
|
||||
static void _setIntensityTableColor(int a1)
|
||||
static void _setIntensityTableColor(int cc)
|
||||
{
|
||||
int v1, v2, v3, v4, v5, v6, v7, v8, v9, v10;
|
||||
|
||||
v5 = 0;
|
||||
v10 = a1 << 8;
|
||||
int shift = 0;
|
||||
|
||||
for (int index = 0; index < 128; index++) {
|
||||
v1 = (_Color2RGB_(a1) & 0x7C00) >> 10;
|
||||
v2 = (_Color2RGB_(a1) & 0x3E0) >> 5;
|
||||
v3 = (_Color2RGB_(a1) & 0x1F);
|
||||
int r = (Color2RGB(cc) & 0x7C00) >> 10;
|
||||
int g = (Color2RGB(cc) & 0x3E0) >> 5;
|
||||
int b = (Color2RGB(cc) & 0x1F);
|
||||
|
||||
v4 = (((v1 * v5) >> 16) << 10) | (((v2 * v5) >> 16) << 5) | ((v3 * v5) >> 16);
|
||||
_intensityColorTable[index + v10] = _colorTable[v4];
|
||||
int darkerR = ((r * shift) >> 16);
|
||||
int darkerG = ((g * shift) >> 16);
|
||||
int darkerB = ((b * shift) >> 16);
|
||||
int darkerColor = (darkerR << 10) | (darkerG << 5) | darkerB;
|
||||
intensityColorTable[cc][index] = _colorTable[darkerColor];
|
||||
|
||||
v6 = v1 + (((0x1F - v1) * v5) >> 16);
|
||||
v7 = v2 + (((0x1F - v2) * v5) >> 16);
|
||||
v8 = v3 + (((0x1F - v3) * v5) >> 16);
|
||||
int lighterR = r + (((0x1F - r) * shift) >> 16);
|
||||
int lighterG = g + (((0x1F - g) * shift) >> 16);
|
||||
int lighterB = b + (((0x1F - b) * shift) >> 16);
|
||||
int lighterColor = (lighterR << 10) | (lighterG << 5) | lighterB;
|
||||
intensityColorTable[cc][128 + index] = _colorTable[lighterColor];
|
||||
|
||||
v9 = (v6 << 10) | (v7 << 5) | v8;
|
||||
_intensityColorTable[0x7F + index + 1 + v10] = _colorTable[v9];
|
||||
|
||||
v5 += 0x200;
|
||||
shift += 512;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +197,7 @@ static void _setIntensityTables()
|
||||
if (_mappedColor[index] != 0) {
|
||||
_setIntensityTableColor(index);
|
||||
} else {
|
||||
memset(_intensityColorTable + index * 256, 0, 256);
|
||||
memset(intensityColorTable[index], 0, 256);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,20 +206,18 @@ static void _setIntensityTables()
|
||||
static void _setMixTableColor(int a1)
|
||||
{
|
||||
int i;
|
||||
int v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19;
|
||||
int v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19;
|
||||
int v20, v21, v22, v23, v24, v25, v26, v27, v28, v29;
|
||||
|
||||
v1 = a1 << 8;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (_mappedColor[a1] && _mappedColor[i]) {
|
||||
v2 = (_Color2RGB_(a1) & 0x7C00) >> 10;
|
||||
v3 = (_Color2RGB_(a1) & 0x3E0) >> 5;
|
||||
v4 = (_Color2RGB_(a1) & 0x1F);
|
||||
v2 = (Color2RGB(a1) & 0x7C00) >> 10;
|
||||
v3 = (Color2RGB(a1) & 0x3E0) >> 5;
|
||||
v4 = (Color2RGB(a1) & 0x1F);
|
||||
|
||||
v5 = (_Color2RGB_(i) & 0x7C00) >> 10;
|
||||
v6 = (_Color2RGB_(i) & 0x3E0) >> 5;
|
||||
v7 = (_Color2RGB_(i) & 0x1F);
|
||||
v5 = (Color2RGB(i) & 0x7C00) >> 10;
|
||||
v6 = (Color2RGB(i) & 0x3E0) >> 5;
|
||||
v7 = (Color2RGB(i) & 0x1F);
|
||||
|
||||
v8 = v2 + v5;
|
||||
v9 = v3 + v6;
|
||||
@@ -337,29 +262,29 @@ static void _setMixTableColor(int a1)
|
||||
v12 = _calculateColor(v19, v18);
|
||||
}
|
||||
|
||||
_colorMixAddTable[v1 + i] = v12;
|
||||
colorMixAddTable[a1][i] = v12;
|
||||
|
||||
v20 = (_Color2RGB_(a1) & 0x7C00) >> 10;
|
||||
v21 = (_Color2RGB_(a1) & 0x3E0) >> 5;
|
||||
v22 = (_Color2RGB_(a1) & 0x1F);
|
||||
v20 = (Color2RGB(a1) & 0x7C00) >> 10;
|
||||
v21 = (Color2RGB(a1) & 0x3E0) >> 5;
|
||||
v22 = (Color2RGB(a1) & 0x1F);
|
||||
|
||||
v23 = (_Color2RGB_(i) & 0x7C00) >> 10;
|
||||
v24 = (_Color2RGB_(i) & 0x3E0) >> 5;
|
||||
v25 = (_Color2RGB_(i) & 0x1F);
|
||||
v23 = (Color2RGB(i) & 0x7C00) >> 10;
|
||||
v24 = (Color2RGB(i) & 0x3E0) >> 5;
|
||||
v25 = (Color2RGB(i) & 0x1F);
|
||||
|
||||
v26 = (v20 * v23) >> 5;
|
||||
v27 = (v21 * v24) >> 5;
|
||||
v28 = (v22 * v25) >> 5;
|
||||
|
||||
v29 = (v26 << 10) | (v27 << 5) | v28;
|
||||
_colorMixMulTable[v1 + i] = _colorTable[v29];
|
||||
colorMixMulTable[a1][i] = _colorTable[v29];
|
||||
} else {
|
||||
if (_mappedColor[i]) {
|
||||
_colorMixAddTable[v1 + i] = i;
|
||||
_colorMixMulTable[v1 + i] = i;
|
||||
colorMixAddTable[a1][i] = i;
|
||||
colorMixMulTable[a1][i] = i;
|
||||
} else {
|
||||
_colorMixAddTable[v1 + i] = a1;
|
||||
_colorMixMulTable[v1 + i] = a1;
|
||||
colorMixAddTable[a1][i] = a1;
|
||||
colorMixMulTable[a1][i] = a1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -368,13 +293,12 @@ static void _setMixTableColor(int a1)
|
||||
// 0x4C78E4
|
||||
bool colorPaletteLoad(const char* path)
|
||||
{
|
||||
if (gColorFileNameMangler != NULL) {
|
||||
if (gColorFileNameMangler != nullptr) {
|
||||
path = gColorFileNameMangler(path);
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
int fd = colorPaletteFileOpen(path, 0x200);
|
||||
if (fd == -1) {
|
||||
File* stream = fileOpen(path, "rb");
|
||||
if (stream == nullptr) {
|
||||
_errorStr = _aColor_cColorTa;
|
||||
return false;
|
||||
}
|
||||
@@ -385,13 +309,13 @@ bool colorPaletteLoad(const char* path)
|
||||
unsigned char b;
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, &r, sizeof(r));
|
||||
fileRead(&r, sizeof(r), 1, stream);
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, &g, sizeof(g));
|
||||
fileRead(&g, sizeof(g), 1, stream);
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, &b, sizeof(b));
|
||||
fileRead(&b, sizeof(b), 1, stream);
|
||||
|
||||
if (r <= 0x3F && g <= 0x3F && b <= 0x3F) {
|
||||
_mappedColor[index] = 1;
|
||||
@@ -408,23 +332,23 @@ bool colorPaletteLoad(const char* path)
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, _colorTable, 0x8000);
|
||||
fileRead(_colorTable, 0x8000, 1, stream);
|
||||
|
||||
unsigned int type;
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, &type, sizeof(type));
|
||||
fileRead(&type, sizeof(type), 1, stream);
|
||||
|
||||
// NOTE: The value is "NEWC". Original code uses cmp opcode, not stricmp,
|
||||
// or comparing characters one-by-one.
|
||||
if (type == 0x4E455743) {
|
||||
if (type == 'NEWC') {
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, _intensityColorTable, 0x10000);
|
||||
fileRead(intensityColorTable, sizeof(intensityColorTable), 1, stream);
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, _colorMixAddTable, 0x10000);
|
||||
fileRead(colorMixAddTable, sizeof(colorMixAddTable), 1, stream);
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, _colorMixMulTable, 0x10000);
|
||||
fileRead(colorMixMulTable, sizeof(colorMixMulTable), 1, stream);
|
||||
} else {
|
||||
_setIntensityTables();
|
||||
|
||||
@@ -436,7 +360,7 @@ bool colorPaletteLoad(const char* path)
|
||||
_rebuildColorBlendTables();
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileClose(fd);
|
||||
fileClose(stream);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -457,9 +381,9 @@ static void _buildBlendTable(unsigned char* ptr, unsigned char ch)
|
||||
|
||||
beg = ptr;
|
||||
|
||||
r = (_Color2RGB_(ch) & 0x7C00) >> 10;
|
||||
g = (_Color2RGB_(ch) & 0x3E0) >> 5;
|
||||
b = (_Color2RGB_(ch) & 0x1F);
|
||||
r = (Color2RGB(ch) & 0x7C00) >> 10;
|
||||
g = (Color2RGB(ch) & 0x3E0) >> 5;
|
||||
b = (Color2RGB(ch) & 0x1F);
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
ptr[i] = i;
|
||||
@@ -478,9 +402,9 @@ static void _buildBlendTable(unsigned char* ptr, unsigned char ch)
|
||||
|
||||
for (j = 0; j < 7; j++) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
v12 = (_Color2RGB_(i) & 0x7C00) >> 10;
|
||||
v14 = (_Color2RGB_(i) & 0x3E0) >> 5;
|
||||
v16 = (_Color2RGB_(i) & 0x1F);
|
||||
v12 = (Color2RGB(i) & 0x7C00) >> 10;
|
||||
v14 = (Color2RGB(i) & 0x3E0) >> 5;
|
||||
v16 = (Color2RGB(i) & 0x1F);
|
||||
int index = 0;
|
||||
index |= (r_2 + v12 * v31) / 7 << 10;
|
||||
index |= (g_2 + v14 * v31) / 7 << 5;
|
||||
@@ -524,8 +448,8 @@ unsigned char* _getColorBlendTable(int ch)
|
||||
{
|
||||
unsigned char* ptr;
|
||||
|
||||
if (_blendTable[ch] == NULL) {
|
||||
ptr = (unsigned char*)gColorPaletteMallocProc(4100);
|
||||
if (_blendTable[ch] == nullptr) {
|
||||
ptr = (unsigned char*)internal_malloc(4100);
|
||||
*(int*)ptr = 1;
|
||||
_blendTable[ch] = ptr + 4;
|
||||
_buildBlendTable(_blendTable[ch], ch);
|
||||
@@ -541,24 +465,16 @@ unsigned char* _getColorBlendTable(int ch)
|
||||
void _freeColorBlendTable(int a1)
|
||||
{
|
||||
unsigned char* v2 = _blendTable[a1];
|
||||
if (v2 != NULL) {
|
||||
if (v2 != nullptr) {
|
||||
int* count = (int*)(v2 - sizeof(int));
|
||||
*count -= 1;
|
||||
if (*count == 0) {
|
||||
gColorPaletteFreeProc(count);
|
||||
_blendTable[a1] = NULL;
|
||||
internal_free(count);
|
||||
_blendTable[a1] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C7E58
|
||||
void colorPaletteSetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc)
|
||||
{
|
||||
gColorPaletteMallocProc = mallocProc;
|
||||
gColorPaletteReallocProc = reallocProc;
|
||||
gColorPaletteFreeProc = freeProc;
|
||||
}
|
||||
|
||||
// 0x4C7E6C
|
||||
void colorSetBrightness(double value)
|
||||
{
|
||||
@@ -598,6 +514,6 @@ void _colorsClose()
|
||||
for (int index = 0; index < 256; index++) {
|
||||
_freeColorBlendTable(index);
|
||||
}
|
||||
|
||||
// TODO: Incomplete.
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
21
src/color.h
@@ -1,29 +1,25 @@
|
||||
#ifndef COLOR_H
|
||||
#define COLOR_H
|
||||
|
||||
#include "memory_defs.h"
|
||||
namespace fallout {
|
||||
|
||||
typedef unsigned char Color;
|
||||
typedef const char*(ColorFileNameManger)(const char*);
|
||||
typedef void(ColorTransitionCallback)();
|
||||
|
||||
typedef int(ColorPaletteFileOpenProc)(const char* path, int mode);
|
||||
typedef int(ColorPaletteFileReadProc)(int fd, void* buffer, size_t size);
|
||||
typedef int(ColorPaletteCloseProc)(int fd);
|
||||
|
||||
extern unsigned char _cmap[768];
|
||||
|
||||
extern unsigned char _systemCmap[256 * 3];
|
||||
extern unsigned char _currentGammaTable[64];
|
||||
extern unsigned char* _blendTable[256];
|
||||
extern unsigned char _mappedColor[256];
|
||||
extern unsigned char _colorMixAddTable[65536];
|
||||
extern unsigned char _intensityColorTable[65536];
|
||||
extern unsigned char _colorMixMulTable[65536];
|
||||
extern Color colorMixAddTable[256][256];
|
||||
extern Color intensityColorTable[256][256];
|
||||
extern Color colorMixMulTable[256][256];
|
||||
extern unsigned char _colorTable[32768];
|
||||
|
||||
void colorPaletteSetFileIO(ColorPaletteFileOpenProc* openProc, ColorPaletteFileReadProc* readProc, ColorPaletteCloseProc* closeProc);
|
||||
int _calculateColor(int a1, int a2);
|
||||
int _Color2RGB_(int a1);
|
||||
int _calculateColor(int intensity, Color color);
|
||||
int Color2RGB(Color c);
|
||||
void colorPaletteFadeBetween(unsigned char* oldPalette, unsigned char* newPalette, int steps);
|
||||
void colorPaletteSetTransitionCallback(ColorTransitionCallback* callback);
|
||||
void _setSystemPalette(unsigned char* palette);
|
||||
@@ -33,9 +29,10 @@ bool colorPaletteLoad(const char* path);
|
||||
char* _colorError();
|
||||
unsigned char* _getColorBlendTable(int ch);
|
||||
void _freeColorBlendTable(int a1);
|
||||
void colorPaletteSetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc);
|
||||
void colorSetBrightness(double value);
|
||||
bool _initColors();
|
||||
void _colorsClose();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* COLOR_H */
|
||||
|
||||
2708
src/combat.cc
65
src/combat.h
@@ -1,11 +1,13 @@
|
||||
#ifndef COMBAT_H
|
||||
#define COMBAT_H
|
||||
|
||||
#include "db.h"
|
||||
#include "combat_defs.h"
|
||||
#include "db.h"
|
||||
#include "obj_types.h"
|
||||
#include "proto_types.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
extern int _combatNumTurns;
|
||||
extern unsigned int gCombatState;
|
||||
|
||||
@@ -17,28 +19,28 @@ void combatExit();
|
||||
int _find_cid(int a1, int a2, Object** a3, int a4);
|
||||
int combatLoad(File* stream);
|
||||
int combatSave(File* stream);
|
||||
bool _combat_safety_invalidate_weapon(Object* a1, Object* a2, int hitMode, Object* a4, int* a5);
|
||||
bool _combatTestIncidentalHit(Object* a1, Object* a2, Object* a3, Object* a4);
|
||||
bool _combat_safety_invalidate_weapon(Object* attacker, Object* weapon, int hitMode, Object* defender, int* safeDistancePtr);
|
||||
bool _combatTestIncidentalHit(Object* attacker, Object* defender, Object* attackerFriend, Object* weapon);
|
||||
Object* _combat_whose_turn();
|
||||
void _combat_data_init(Object* obj);
|
||||
Object* _combatAIInfoGetFriendlyDead(Object* obj);
|
||||
int _combatAIInfoSetFriendlyDead(Object* a1, Object* a2);
|
||||
Object* _combatAIInfoGetLastTarget(Object* obj);
|
||||
int _combatAIInfoSetLastTarget(Object* a1, Object* a2);
|
||||
Object* _combatAIInfoGetLastItem(Object* obj);
|
||||
int _combatAIInfoSetLastItem(Object* obj, Object* a2);
|
||||
Object* aiInfoGetFriendlyDead(Object* obj);
|
||||
int aiInfoSetFriendlyDead(Object* a1, Object* a2);
|
||||
Object* aiInfoGetLastTarget(Object* obj);
|
||||
int aiInfoSetLastTarget(Object* a1, Object* a2);
|
||||
Object* aiInfoGetLastItem(Object* obj);
|
||||
int aiInfoSetLastItem(Object* obj, Object* a2);
|
||||
void _combat_update_critter_outline_for_los(Object* critter, bool a2);
|
||||
void _combat_over_from_load();
|
||||
void _combat_give_exps(int exp_points);
|
||||
void _combat_turn_run();
|
||||
void _combat(STRUCT_664980* attack);
|
||||
void attackInit(Attack* attack, Object* a2, Object* a3, int a4, int a5);
|
||||
int _combat_attack(Object* a1, Object* a2, int a3, int a4);
|
||||
int _combat_bullet_start(const Object* a1, const Object* a2);
|
||||
void _compute_explosion_on_extras(Attack* attack, int a2, int a3, int a4);
|
||||
void _combat(CombatStartData* csd);
|
||||
void attackInit(Attack* attack, Object* attacker, Object* defender, int hitMode, int hitLocation);
|
||||
int _combat_attack(Object* attacker, Object* defender, int hitMode, int hitLocation);
|
||||
int _combat_bullet_start(const Object* attacker, const Object* target);
|
||||
void _compute_explosion_on_extras(Attack* attack, bool isFromAttacker, bool isGrenade, bool noDamage);
|
||||
int _determine_to_hit(Object* a1, Object* a2, int hitLocation, int hitMode);
|
||||
int _determine_to_hit_no_range(Object* a1, Object* a2, int a3, int a4, unsigned char* a5);
|
||||
int _determine_to_hit_from_tile(Object* a1, int a2, Object* a3, int a4, int a5);
|
||||
int _determine_to_hit_no_range(Object* attacker, Object* defender, int hitLocation, int hitMode, unsigned char* a5);
|
||||
int _determine_to_hit_from_tile(Object* attacker, int tile, Object* defender, int hitLocation, int hitMode);
|
||||
void attackComputeDeathFlags(Attack* attack);
|
||||
void _apply_damage(Attack* attack, bool animated);
|
||||
void _combat_display(Attack* attack);
|
||||
@@ -46,19 +48,46 @@ void _combat_anim_begin();
|
||||
void _combat_anim_finished();
|
||||
int _combat_check_bad_shot(Object* attacker, Object* defender, int hitMode, bool aiming);
|
||||
bool _combat_to_hit(Object* target, int* accuracy);
|
||||
void _combat_attack_this(Object* a1);
|
||||
void _combat_attack_this(Object* target);
|
||||
void _combat_outline_on();
|
||||
void _combat_outline_off();
|
||||
void _combat_highlight_change();
|
||||
bool _combat_is_shot_blocked(Object* a1, int from, int to, Object* a4, int* a5);
|
||||
bool _combat_is_shot_blocked(Object* sourceObj, int from, int to, Object* targetObj, int* numCrittersOnLof);
|
||||
int _combat_player_knocked_out_by();
|
||||
int _combat_explode_scenery(Object* a1, Object* a2);
|
||||
void _combat_delete_critter(Object* obj);
|
||||
void _combatKillCritterOutsideCombat(Object* critter_obj, char* msg);
|
||||
|
||||
int combatGetTargetHighlight();
|
||||
int criticalsGetValue(int killType, int hitLocation, int effect, int dataMember);
|
||||
void criticalsSetValue(int killType, int hitLocation, int effect, int dataMember, int value);
|
||||
void criticalsResetValue(int killType, int hitLocation, int effect, int dataMember);
|
||||
int unarmedGetDamage(int hitMode, int* minDamagePtr, int* maxDamagePtr);
|
||||
int unarmedGetBonusCriticalChance(int hitMode);
|
||||
int unarmedGetActionPointCost(int hitMode);
|
||||
bool unarmedIsPenetrating(int hitMode);
|
||||
int unarmedGetPunchHitMode(bool isSecondary);
|
||||
int unarmedGetKickHitMode(bool isSecondary);
|
||||
bool unarmedIsPenetrating(int hitMode);
|
||||
bool damageModGetBonusHthDamageFix();
|
||||
bool damageModGetDisplayBonusDamage();
|
||||
int combat_get_hit_location_penalty(int hit_location);
|
||||
void combat_set_hit_location_penalty(int hit_location, int penalty);
|
||||
void combat_reset_hit_location_penalty();
|
||||
Attack* combat_get_data();
|
||||
|
||||
static inline bool isInCombat()
|
||||
{
|
||||
return (gCombatState & COMBAT_STATE_0x01) != 0;
|
||||
}
|
||||
|
||||
static inline bool isUnarmedHitMode(int hitMode)
|
||||
{
|
||||
return hitMode == HIT_MODE_PUNCH
|
||||
|| hitMode == HIT_MODE_KICK
|
||||
|| (hitMode >= FIRST_ADVANCED_UNARMED_HIT_MODE && hitMode <= LAST_ADVANCED_UNARMED_HIT_MODE);
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* COMBAT_H */
|
||||
|
||||
1998
src/combat_ai.cc
@@ -6,6 +6,8 @@
|
||||
#include "db.h"
|
||||
#include "obj_types.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum AiMessageType {
|
||||
AI_MESSAGE_TYPE_RUN,
|
||||
AI_MESSAGE_TYPE_MOVE,
|
||||
@@ -28,6 +30,8 @@ void aiReset();
|
||||
int aiExit();
|
||||
int aiLoad(File* stream);
|
||||
int aiSave(File* stream);
|
||||
int combat_ai_num();
|
||||
char* combat_ai_name(int packet_num);
|
||||
int aiGetAreaAttackMode(Object* obj);
|
||||
int aiGetRunAwayMode(Object* obj);
|
||||
int aiGetBestWeapon(Object* obj);
|
||||
@@ -42,13 +46,13 @@ int aiSetAttackWho(Object* critter, int attackWho);
|
||||
int aiSetChemUse(Object* critter, int chemUse);
|
||||
int aiGetDisposition(Object* obj);
|
||||
int aiSetDisposition(Object* obj, int a2);
|
||||
int _caiSetupTeamCombat(Object* a1, Object* a2);
|
||||
int _caiTeamCombatInit(Object** a1, int a2);
|
||||
int _caiSetupTeamCombat(Object* attackerTeam, Object* defenderTeam);
|
||||
int _caiTeamCombatInit(Object** crittersList, int crittersListLength);
|
||||
void _caiTeamCombatExit();
|
||||
Object* _ai_search_inven_weap(Object* critter, int a2, Object* a3);
|
||||
Object* _ai_search_inven_weap(Object* critter, bool checkRequiredActionPoints, Object* defender);
|
||||
Object* _ai_search_inven_armor(Object* critter);
|
||||
int _cAIPrepWeaponItem(Object* critter, Object* item);
|
||||
void _cai_attempt_w_reload(Object* critter_obj, int a2);
|
||||
void aiAttemptWeaponReload(Object* critter, int animate);
|
||||
void _combat_ai_begin(int a1, void* a2);
|
||||
void _combat_ai_over();
|
||||
int _cai_perform_distance_prefs(Object* a1, Object* a2);
|
||||
@@ -57,13 +61,15 @@ bool _combatai_want_to_join(Object* a1);
|
||||
bool _combatai_want_to_stop(Object* a1);
|
||||
int critterSetTeam(Object* obj, int team);
|
||||
int critterSetAiPacket(Object* object, int aiPacket);
|
||||
int _combatai_msg(Object* a1, Attack* attack, int a3, int a4);
|
||||
int _combatai_msg(Object* critter, Attack* attack, int type, int delay);
|
||||
Object* _combat_ai_random_target(Attack* attack);
|
||||
int _combatai_check_retaliation(Object* a1, Object* a2);
|
||||
bool objectCanHearObject(Object* a1, Object* a2);
|
||||
void _combatai_check_retaliation(Object* a1, Object* a2);
|
||||
bool isWithinPerception(Object* a1, Object* a2);
|
||||
void aiMessageListReloadIfNeeded();
|
||||
void _combatai_notify_onlookers(Object* a1);
|
||||
void _combatai_notify_friends(Object* a1);
|
||||
void _combatai_delete_critter(Object* obj);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* COMBAT_AI_H */
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef COMBAT_AI_DEFS_H
|
||||
#define COMBAT_AI_DEFS_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum AreaAttackMode {
|
||||
AREA_ATTACK_MODE_ALWAYS,
|
||||
AREA_ATTACK_MODE_SOMETIMES,
|
||||
@@ -79,4 +81,6 @@ typedef enum HurtTooMuch {
|
||||
HURT_COUNT,
|
||||
} HurtTooMuch;
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* COMBAT_AI_DEFS_H */
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#define WEAPON_CRITICAL_FAILURE_TYPE_COUNT (7)
|
||||
#define WEAPON_CRITICAL_FAILURE_EFFECT_COUNT (5)
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum CombatState {
|
||||
COMBAT_STATE_0x01 = 0x01,
|
||||
COMBAT_STATE_0x02 = 0x02,
|
||||
@@ -84,14 +86,7 @@ typedef enum HitLocation {
|
||||
HIT_LOCATION_SPECIFIC_COUNT = HIT_LOCATION_COUNT - 1,
|
||||
} HitLocation;
|
||||
|
||||
typedef struct STRUCT_510948 {
|
||||
Object* field_0;
|
||||
Object* field_4;
|
||||
Object* field_8;
|
||||
int field_C;
|
||||
} STRUCT_510948;
|
||||
|
||||
typedef struct STRUCT_664980 {
|
||||
typedef struct CombatStartData {
|
||||
Object* attacker;
|
||||
Object* defender;
|
||||
int actionPointsBonus;
|
||||
@@ -99,10 +94,10 @@ typedef struct STRUCT_664980 {
|
||||
int damageBonus;
|
||||
int minDamage;
|
||||
int maxDamage;
|
||||
int field_1C; // probably bool, indicating field_20 and field_24 used
|
||||
int field_20; // flags on attacker
|
||||
int field_24; // flags on defender
|
||||
} STRUCT_664980;
|
||||
int overrideAttackResults;
|
||||
int attackerResults;
|
||||
int targetResults;
|
||||
} CombatStartData;
|
||||
|
||||
typedef struct Attack {
|
||||
Object* attacker;
|
||||
@@ -128,25 +123,54 @@ typedef struct Attack {
|
||||
int extrasKnockback[EXPLOSION_TARGET_COUNT];
|
||||
} Attack;
|
||||
|
||||
typedef enum CriticalHitDescriptionDataMember {
|
||||
CRIT_DATA_MEMBER_DAMAGE_MULTIPLIER,
|
||||
CRIT_DATA_MEMBER_FLAGS,
|
||||
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_STAT,
|
||||
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_STAT_MODIFIER,
|
||||
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_FLAGS,
|
||||
CRIT_DATA_MEMBER_MESSAGE_ID,
|
||||
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_MESSAGE_ID,
|
||||
CRIT_DATA_MEMBER_COUNT,
|
||||
} CriticalHitDescriptionDataMember;
|
||||
|
||||
// Provides metadata about critical hit effect.
|
||||
typedef struct CriticalHitDescription {
|
||||
int damageMultiplier;
|
||||
typedef union CriticalHitDescription {
|
||||
struct {
|
||||
int damageMultiplier;
|
||||
|
||||
// Damage flags that will be applied to defender.
|
||||
int flags;
|
||||
// Damage flags that will be applied to defender.
|
||||
int flags;
|
||||
|
||||
// Stat to check to upgrade this critical hit to massive critical hit or
|
||||
// -1 if there is no massive critical hit.
|
||||
int massiveCriticalStat;
|
||||
// Stat to check to upgrade this critical hit to massive critical hit or
|
||||
// -1 if there is no massive critical hit.
|
||||
int massiveCriticalStat;
|
||||
|
||||
// Bonus/penalty to massive critical stat.
|
||||
int massiveCriticalStatModifier;
|
||||
// Bonus/penalty to massive critical stat.
|
||||
int massiveCriticalStatModifier;
|
||||
|
||||
// Additional damage flags if this critical hit become massive critical.
|
||||
int massiveCriticalFlags;
|
||||
// Additional damage flags if this critical hit become massive critical.
|
||||
int massiveCriticalFlags;
|
||||
|
||||
int messageId;
|
||||
int massiveCriticalMessageId;
|
||||
int messageId;
|
||||
int massiveCriticalMessageId;
|
||||
};
|
||||
|
||||
// SFALL: Allow indexed access to the data above.
|
||||
int values[CRIT_DATA_MEMBER_COUNT];
|
||||
} CriticalHitDescription;
|
||||
|
||||
typedef enum CombatBadShot {
|
||||
COMBAT_BAD_SHOT_OK = 0,
|
||||
COMBAT_BAD_SHOT_NO_AMMO = 1,
|
||||
COMBAT_BAD_SHOT_OUT_OF_RANGE = 2,
|
||||
COMBAT_BAD_SHOT_NOT_ENOUGH_AP = 3,
|
||||
COMBAT_BAD_SHOT_ALREADY_DEAD = 4,
|
||||
COMBAT_BAD_SHOT_AIM_BLOCKED = 5,
|
||||
COMBAT_BAD_SHOT_ARM_CRIPPLED = 6,
|
||||
COMBAT_BAD_SHOT_BOTH_ARMS_CRIPPLED = 7,
|
||||
} CombatBadShot;
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* COMBAT_DEFS_H */
|
||||
|
||||
214
src/config.cc
@@ -1,9 +1,5 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "db.h"
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
@@ -11,6 +7,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "db.h"
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define CONFIG_FILE_MAX_LINE_LENGTH (256)
|
||||
|
||||
// The initial number of sections (or key-value) pairs in the config.
|
||||
@@ -29,11 +31,11 @@ static char gConfigLastSectionKey[CONFIG_FILE_MAX_LINE_LENGTH] = "unknown";
|
||||
// 0x42BD90
|
||||
bool configInit(Config* config)
|
||||
{
|
||||
if (config == NULL) {
|
||||
if (config == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dictionaryInit(config, CONFIG_INITIAL_CAPACITY, sizeof(ConfigSection), NULL) != 0) {
|
||||
if (dictionaryInit(config, CONFIG_INITIAL_CAPACITY, sizeof(ConfigSection), nullptr) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -43,7 +45,7 @@ bool configInit(Config* config)
|
||||
// 0x42BDBC
|
||||
void configFree(Config* config)
|
||||
{
|
||||
if (config == NULL) {
|
||||
if (config == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -56,7 +58,7 @@ void configFree(Config* config)
|
||||
|
||||
char** value = (char**)keyValueEntry->value;
|
||||
internal_free(*value);
|
||||
*value = NULL;
|
||||
*value = nullptr;
|
||||
}
|
||||
|
||||
dictionaryFree(section);
|
||||
@@ -76,30 +78,25 @@ void configFree(Config* config)
|
||||
// 0x42BE38
|
||||
bool configParseCommandLineArguments(Config* config, int argc, char** argv)
|
||||
{
|
||||
if (config == NULL) {
|
||||
if (config == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int arg = 0; arg < argc; arg++) {
|
||||
char* pch = argv[arg];
|
||||
char* pch;
|
||||
char* string = argv[arg];
|
||||
|
||||
// Find opening bracket.
|
||||
while (*pch != '\0' && *pch != '[') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch == '\0') {
|
||||
pch = strchr(string, '[');
|
||||
if (pch == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char* sectionKey = pch + 1;
|
||||
|
||||
// Find closing bracket.
|
||||
while (*pch != '\0' && *pch != ']') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch == '\0') {
|
||||
pch = strchr(sectionKey, ']');
|
||||
if (pch == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -123,7 +120,7 @@ bool configParseCommandLineArguments(Config* config, int argc, char** argv)
|
||||
// 0x42BF48
|
||||
bool configGetString(Config* config, const char* sectionKey, const char* key, char** valuePtr)
|
||||
{
|
||||
if (config == NULL || sectionKey == NULL || key == NULL || valuePtr == NULL) {
|
||||
if (config == nullptr || sectionKey == nullptr || key == nullptr || valuePtr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -149,7 +146,7 @@ bool configGetString(Config* config, const char* sectionKey, const char* key, ch
|
||||
// 0x42BF90
|
||||
bool configSetString(Config* config, const char* sectionKey, const char* key, const char* value)
|
||||
{
|
||||
if (config == NULL || sectionKey == NULL || key == NULL || value == NULL) {
|
||||
if (config == nullptr || sectionKey == nullptr || key == nullptr || value == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -170,13 +167,13 @@ bool configSetString(Config* config, const char* sectionKey, const char* key, co
|
||||
|
||||
char** existingValue = (char**)keyValueEntry->value;
|
||||
internal_free(*existingValue);
|
||||
*existingValue = NULL;
|
||||
*existingValue = nullptr;
|
||||
|
||||
dictionaryRemoveValue(section, key);
|
||||
}
|
||||
|
||||
char* valueCopy = internal_strdup(value);
|
||||
if (valueCopy == NULL) {
|
||||
if (valueCopy == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -188,10 +185,10 @@ bool configSetString(Config* config, const char* sectionKey, const char* key, co
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x42C05C customized: atoi() replaced with strtol()
|
||||
bool configGetInt(Config* config, const char* sectionKey, const char* key, int* valuePtr, unsigned char base /* = 0 */ )
|
||||
// 0x42C05C
|
||||
bool configGetInt(Config* config, const char* sectionKey, const char* key, int* valuePtr, unsigned char base /* = 0 */)
|
||||
{
|
||||
if (valuePtr == NULL) {
|
||||
if (valuePtr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -203,8 +200,17 @@ bool configGetInt(Config* config, const char* sectionKey, const char* key, int*
|
||||
char* end;
|
||||
errno = 0;
|
||||
long l = strtol(stringValue, &end, base); // see https://stackoverflow.com/a/6154614
|
||||
if (((errno == ERANGE && 1 == LONG_MAX) || l > INT_MAX) || ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) || (*stringValue == '\0' || *end != '\0'))
|
||||
return false;
|
||||
|
||||
// The link above says right things about converting strings to numbers,
|
||||
// however we need to maintain compatibility with atoi implementation and
|
||||
// original game data. One example of the problem is worldmap.txt where
|
||||
// frequency values expressed as percentages (Frequent=38%). If we handle
|
||||
// the result like the link above suggests (and what previous implementation
|
||||
// provided), we'll simply end up returning `false`, since there will be
|
||||
// unconverted characters left. On the other hand, this function is also
|
||||
// used to parse Sfall config values, which uses hexadecimal notation to
|
||||
// represent colors. We're not going to need any of these in the long run so
|
||||
// for now simply ignore any error that could arise during conversion.
|
||||
|
||||
*valuePtr = l;
|
||||
|
||||
@@ -214,7 +220,7 @@ bool configGetInt(Config* config, const char* sectionKey, const char* key, int*
|
||||
// 0x42C090
|
||||
bool configGetIntList(Config* config, const char* sectionKey, const char* key, int* arr, int count)
|
||||
{
|
||||
if (arr == NULL || count < 2) {
|
||||
if (arr == nullptr || count < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -224,36 +230,32 @@ bool configGetIntList(Config* config, const char* sectionKey, const char* key, i
|
||||
}
|
||||
|
||||
char temp[CONFIG_FILE_MAX_LINE_LENGTH];
|
||||
strncpy(temp, string, CONFIG_FILE_MAX_LINE_LENGTH - 1);
|
||||
string = strncpy(temp, string, CONFIG_FILE_MAX_LINE_LENGTH - 1);
|
||||
|
||||
char* beginning = temp;
|
||||
char* pch = beginning;
|
||||
while (*pch != '\0') {
|
||||
if (*pch == ',') {
|
||||
*pch = '\0';
|
||||
|
||||
*arr++ = atoi(beginning);
|
||||
|
||||
*pch = ',';
|
||||
|
||||
pch++;
|
||||
beginning = pch;
|
||||
|
||||
count--;
|
||||
|
||||
if (count < 0) {
|
||||
break;
|
||||
}
|
||||
while (1) {
|
||||
char* pch = strchr(string, ',');
|
||||
if (pch == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
pch++;
|
||||
count--;
|
||||
if (count == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
*pch = '\0';
|
||||
*arr++ = atoi(string);
|
||||
string = pch + 1;
|
||||
}
|
||||
|
||||
if (count <= 1) {
|
||||
*arr = atoi(beginning);
|
||||
// SFALL: Fix getting last item in a list if the list has less than the
|
||||
// requested number of values (for `chem_primary_desire`).
|
||||
if (count > 0) {
|
||||
*arr = atoi(string);
|
||||
count--;
|
||||
}
|
||||
|
||||
return true;
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
// 0x42C160
|
||||
@@ -270,7 +272,7 @@ bool configSetInt(Config* config, const char* sectionKey, const char* key, int v
|
||||
// 0x42C280
|
||||
bool configRead(Config* config, const char* filePath, bool isDb)
|
||||
{
|
||||
if (config == NULL || filePath == NULL) {
|
||||
if (config == nullptr || filePath == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -278,24 +280,28 @@ bool configRead(Config* config, const char* filePath, bool isDb)
|
||||
|
||||
if (isDb) {
|
||||
File* stream = fileOpen(filePath, "rb");
|
||||
if (stream != NULL) {
|
||||
while (fileReadString(string, sizeof(string), stream) != NULL) {
|
||||
configParseLine(config, string);
|
||||
}
|
||||
fileClose(stream);
|
||||
|
||||
// CE: Return `false` if file does not exists in database.
|
||||
if (stream == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (fileReadString(string, sizeof(string), stream) != nullptr) {
|
||||
configParseLine(config, string);
|
||||
}
|
||||
fileClose(stream);
|
||||
} else {
|
||||
FILE* stream = compat_fopen(filePath, "rt");
|
||||
if (stream != NULL) {
|
||||
while (fgets(string, sizeof(string), stream) != NULL) {
|
||||
configParseLine(config, string);
|
||||
}
|
||||
|
||||
fclose(stream);
|
||||
// CE: Return `false` if file does not exists on the file system.
|
||||
if (stream == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: This function returns `true` even if the file was not actually
|
||||
// read. I'm pretty sure it's bug.
|
||||
while (compat_fgets(string, sizeof(string), stream) != nullptr) {
|
||||
configParseLine(config, string);
|
||||
}
|
||||
fclose(stream);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -306,13 +312,13 @@ bool configRead(Config* config, const char* filePath, bool isDb)
|
||||
// 0x42C324
|
||||
bool configWrite(Config* config, const char* filePath, bool isDb)
|
||||
{
|
||||
if (config == NULL || filePath == NULL) {
|
||||
if (config == nullptr || filePath == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isDb) {
|
||||
File* stream = fileOpen(filePath, "wt");
|
||||
if (stream == NULL) {
|
||||
if (stream == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -332,7 +338,7 @@ bool configWrite(Config* config, const char* filePath, bool isDb)
|
||||
fileClose(stream);
|
||||
} else {
|
||||
FILE* stream = compat_fopen(filePath, "wt");
|
||||
if (stream == NULL) {
|
||||
if (stream == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -374,30 +380,34 @@ static bool configParseLine(Config* config, char* string)
|
||||
char* pch;
|
||||
|
||||
// Find comment marker and truncate the string.
|
||||
pch = string;
|
||||
while (*pch != '\0' && *pch != ';') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch != '\0') {
|
||||
pch = strchr(string, ';');
|
||||
if (pch != nullptr) {
|
||||
*pch = '\0';
|
||||
}
|
||||
|
||||
// Find opening bracket.
|
||||
pch = string;
|
||||
while (*pch != '\0' && *pch != '[') {
|
||||
pch++;
|
||||
// CE: Original implementation treats any line with brackets as section key.
|
||||
// The problem can be seen when loading Olympus settings (ddraw.ini), which
|
||||
// contains the following line:
|
||||
//
|
||||
// ```ini
|
||||
// VersionString=Olympus 2207 [Complete].
|
||||
// ```
|
||||
//
|
||||
// It thinks that [Complete] is a start of new section, and puts remaining
|
||||
// keys there.
|
||||
|
||||
// Skip leading whitespace.
|
||||
while (isspace(static_cast<unsigned char>(*string))) {
|
||||
string++;
|
||||
}
|
||||
|
||||
if (*pch == '[') {
|
||||
char* sectionKey = pch + 1;
|
||||
// Check if it's a section key.
|
||||
if (*string == '[') {
|
||||
char* sectionKey = string + 1;
|
||||
|
||||
// Find closing bracket.
|
||||
while (*pch != '\0' && *pch != ']') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch == ']') {
|
||||
pch = strchr(sectionKey, ']');
|
||||
if (pch != nullptr) {
|
||||
*pch = '\0';
|
||||
strcpy(gConfigLastSectionKey, sectionKey);
|
||||
return configTrimString(gConfigLastSectionKey);
|
||||
@@ -421,17 +431,13 @@ static bool configParseLine(Config* config, char* string)
|
||||
// 0x42C594
|
||||
static bool configParseKeyValue(char* string, char* key, char* value)
|
||||
{
|
||||
if (string == NULL || key == NULL || value == NULL) {
|
||||
if (string == nullptr || key == nullptr || value == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find equals character.
|
||||
char* pch = string;
|
||||
while (*pch != '\0' && *pch != '=') {
|
||||
pch++;
|
||||
}
|
||||
|
||||
if (*pch == '\0') {
|
||||
char* pch = strchr(string, '=');
|
||||
if (pch == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -456,7 +462,7 @@ static bool configParseKeyValue(char* string, char* key, char* value)
|
||||
// 0x42C638
|
||||
static bool configEnsureSectionExists(Config* config, const char* sectionKey)
|
||||
{
|
||||
if (config == NULL || sectionKey == NULL) {
|
||||
if (config == nullptr || sectionKey == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -466,7 +472,7 @@ static bool configEnsureSectionExists(Config* config, const char* sectionKey)
|
||||
}
|
||||
|
||||
ConfigSection section;
|
||||
if (dictionaryInit(§ion, CONFIG_INITIAL_CAPACITY, sizeof(char**), NULL) == -1) {
|
||||
if (dictionaryInit(§ion, CONFIG_INITIAL_CAPACITY, sizeof(char**), nullptr) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -482,11 +488,11 @@ static bool configEnsureSectionExists(Config* config, const char* sectionKey)
|
||||
// 0x42C698
|
||||
static bool configTrimString(char* string)
|
||||
{
|
||||
if (string == NULL) {
|
||||
if (string == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int length = strlen(string);
|
||||
size_t length = strlen(string);
|
||||
if (length == 0) {
|
||||
return true;
|
||||
}
|
||||
@@ -494,7 +500,7 @@ static bool configTrimString(char* string)
|
||||
// Starting from the end of the string, loop while it's a whitespace and
|
||||
// decrement string length.
|
||||
char* pch = string + length - 1;
|
||||
while (length != 0 && isspace(*pch)) {
|
||||
while (length != 0 && isspace(static_cast<unsigned char>(*pch))) {
|
||||
length--;
|
||||
pch--;
|
||||
}
|
||||
@@ -505,7 +511,7 @@ static bool configTrimString(char* string)
|
||||
// Starting from the beginning of the string loop while it's a whitespace
|
||||
// and decrement string length.
|
||||
pch = string;
|
||||
while (isspace(*pch)) {
|
||||
while (isspace(static_cast<unsigned char>(*pch))) {
|
||||
pch++;
|
||||
length--;
|
||||
}
|
||||
@@ -519,7 +525,7 @@ static bool configTrimString(char* string)
|
||||
// 0x42C718
|
||||
bool configGetDouble(Config* config, const char* sectionKey, const char* key, double* valuePtr)
|
||||
{
|
||||
if (valuePtr == NULL) {
|
||||
if (valuePtr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -528,7 +534,7 @@ bool configGetDouble(Config* config, const char* sectionKey, const char* key, do
|
||||
return false;
|
||||
}
|
||||
|
||||
*valuePtr = strtod(stringValue, NULL);
|
||||
*valuePtr = strtod(stringValue, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -537,7 +543,7 @@ bool configGetDouble(Config* config, const char* sectionKey, const char* key, do
|
||||
bool configSetDouble(Config* config, const char* sectionKey, const char* key, double value)
|
||||
{
|
||||
char stringValue[32];
|
||||
sprintf(stringValue, "%.6f", value);
|
||||
snprintf(stringValue, sizeof(stringValue), "%.6f", value);
|
||||
|
||||
return configSetString(config, sectionKey, key, stringValue);
|
||||
}
|
||||
@@ -545,7 +551,7 @@ bool configSetDouble(Config* config, const char* sectionKey, const char* key, do
|
||||
// NOTE: Boolean-typed variant of [configGetInt].
|
||||
bool configGetBool(Config* config, const char* sectionKey, const char* key, bool* valuePtr)
|
||||
{
|
||||
if (valuePtr == NULL) {
|
||||
if (valuePtr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -564,3 +570,5 @@ bool configSetBool(Config* config, const char* sectionKey, const char* key, bool
|
||||
{
|
||||
return configSetInt(config, sectionKey, key, value ? 1 : 0);
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "dictionary.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// A representation of .INI file.
|
||||
//
|
||||
// It's implemented as a [Dictionary] whos keys are section names of .INI file,
|
||||
@@ -31,4 +33,6 @@ bool configSetDouble(Config* config, const char* sectionKey, const char* key, do
|
||||
bool configGetBool(Config* config, const char* sectionKey, const char* key, bool* valuePtr);
|
||||
bool configSetBool(Config* config, const char* sectionKey, const char* key, bool value);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CONFIG_H */
|
||||
|
||||
639
src/core.h
@@ -1,639 +0,0 @@
|
||||
#ifndef CORE_H
|
||||
#define CORE_H
|
||||
|
||||
#include "db.h"
|
||||
#include "dinput.h"
|
||||
#include "geometry.h"
|
||||
#include "window.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#define MOUSE_DEFAULT_CURSOR_WIDTH 8
|
||||
#define MOUSE_DEFAULT_CURSOR_HEIGHT 8
|
||||
#define MOUSE_DEFAULT_CURSOR_SIZE (MOUSE_DEFAULT_CURSOR_WIDTH * MOUSE_DEFAULT_CURSOR_HEIGHT)
|
||||
|
||||
#define MOUSE_STATE_LEFT_BUTTON_DOWN 0x01
|
||||
#define MOUSE_STATE_RIGHT_BUTTON_DOWN 0x02
|
||||
|
||||
#define MOUSE_EVENT_LEFT_BUTTON_DOWN 0x01
|
||||
#define MOUSE_EVENT_RIGHT_BUTTON_DOWN 0x02
|
||||
#define MOUSE_EVENT_LEFT_BUTTON_REPEAT 0x04
|
||||
#define MOUSE_EVENT_RIGHT_BUTTON_REPEAT 0x08
|
||||
#define MOUSE_EVENT_LEFT_BUTTON_UP 0x10
|
||||
#define MOUSE_EVENT_RIGHT_BUTTON_UP 0x20
|
||||
#define MOUSE_EVENT_ANY_BUTTON_DOWN (MOUSE_EVENT_LEFT_BUTTON_DOWN | MOUSE_EVENT_RIGHT_BUTTON_DOWN)
|
||||
#define MOUSE_EVENT_ANY_BUTTON_REPEAT (MOUSE_EVENT_LEFT_BUTTON_REPEAT | MOUSE_EVENT_RIGHT_BUTTON_REPEAT)
|
||||
#define MOUSE_EVENT_ANY_BUTTON_UP (MOUSE_EVENT_LEFT_BUTTON_UP | MOUSE_EVENT_RIGHT_BUTTON_UP)
|
||||
#define MOUSE_EVENT_LEFT_BUTTON_DOWN_REPEAT (MOUSE_EVENT_LEFT_BUTTON_DOWN | MOUSE_EVENT_LEFT_BUTTON_REPEAT)
|
||||
#define MOUSE_EVENT_RIGHT_BUTTON_DOWN_REPEAT (MOUSE_EVENT_RIGHT_BUTTON_DOWN | MOUSE_EVENT_RIGHT_BUTTON_REPEAT)
|
||||
|
||||
#define BUTTON_REPEAT_TIME 250
|
||||
|
||||
#define KEY_STATE_UP 0
|
||||
#define KEY_STATE_DOWN 1
|
||||
#define KEY_STATE_REPEAT 2
|
||||
|
||||
#define MODIFIER_KEY_STATE_NUM_LOCK 0x01
|
||||
#define MODIFIER_KEY_STATE_CAPS_LOCK 0x02
|
||||
#define MODIFIER_KEY_STATE_SCROLL_LOCK 0x04
|
||||
|
||||
#define KEYBOARD_EVENT_MODIFIER_CAPS_LOCK 0x0001
|
||||
#define KEYBOARD_EVENT_MODIFIER_NUM_LOCK 0x0002
|
||||
#define KEYBOARD_EVENT_MODIFIER_SCROLL_LOCK 0x0004
|
||||
#define KEYBOARD_EVENT_MODIFIER_LEFT_SHIFT 0x0008
|
||||
#define KEYBOARD_EVENT_MODIFIER_RIGHT_SHIFT 0x0010
|
||||
#define KEYBOARD_EVENT_MODIFIER_LEFT_ALT 0x0020
|
||||
#define KEYBOARD_EVENT_MODIFIER_RIGHT_ALT 0x0040
|
||||
#define KEYBOARD_EVENT_MODIFIER_LEFT_CONTROL 0x0080
|
||||
#define KEYBOARD_EVENT_MODIFIER_RIGHT_CONTROL 0x0100
|
||||
#define KEYBOARD_EVENT_MODIFIER_ANY_SHIFT (KEYBOARD_EVENT_MODIFIER_LEFT_SHIFT | KEYBOARD_EVENT_MODIFIER_RIGHT_SHIFT)
|
||||
#define KEYBOARD_EVENT_MODIFIER_ANY_ALT (KEYBOARD_EVENT_MODIFIER_LEFT_ALT | KEYBOARD_EVENT_MODIFIER_RIGHT_ALT)
|
||||
#define KEYBOARD_EVENT_MODIFIER_ANY_CONTROL (KEYBOARD_EVENT_MODIFIER_LEFT_CONTROL | KEYBOARD_EVENT_MODIFIER_RIGHT_CONTROL)
|
||||
|
||||
#define KEY_QUEUE_SIZE 64
|
||||
|
||||
typedef enum Key {
|
||||
KEY_ESCAPE = '\x1b',
|
||||
KEY_TAB = '\x09',
|
||||
KEY_BACKSPACE = '\x08',
|
||||
KEY_RETURN = '\r',
|
||||
|
||||
KEY_SPACE = ' ',
|
||||
KEY_EXCLAMATION = '!',
|
||||
KEY_QUOTE = '"',
|
||||
KEY_NUMBER_SIGN = '#',
|
||||
KEY_DOLLAR = '$',
|
||||
KEY_PERCENT = '%',
|
||||
KEY_AMPERSAND = '&',
|
||||
KEY_SINGLE_QUOTE = '\'',
|
||||
KEY_PAREN_LEFT = '(',
|
||||
KEY_PAREN_RIGHT = ')',
|
||||
KEY_ASTERISK = '*',
|
||||
KEY_PLUS = '+',
|
||||
KEY_COMMA = ',',
|
||||
KEY_MINUS = '-',
|
||||
KEY_DOT = '.',
|
||||
KEY_SLASH = '/',
|
||||
KEY_0 = '0',
|
||||
KEY_1 = '1',
|
||||
KEY_2 = '2',
|
||||
KEY_3 = '3',
|
||||
KEY_4 = '4',
|
||||
KEY_5 = '5',
|
||||
KEY_6 = '6',
|
||||
KEY_7 = '7',
|
||||
KEY_8 = '8',
|
||||
KEY_9 = '9',
|
||||
KEY_COLON = ':',
|
||||
KEY_SEMICOLON = ';',
|
||||
KEY_LESS = '<',
|
||||
KEY_EQUAL = '=',
|
||||
KEY_GREATER = '>',
|
||||
KEY_QUESTION = '?',
|
||||
KEY_AT = '@',
|
||||
KEY_UPPERCASE_A = 'A',
|
||||
KEY_UPPERCASE_B = 'B',
|
||||
KEY_UPPERCASE_C = 'C',
|
||||
KEY_UPPERCASE_D = 'D',
|
||||
KEY_UPPERCASE_E = 'E',
|
||||
KEY_UPPERCASE_F = 'F',
|
||||
KEY_UPPERCASE_G = 'G',
|
||||
KEY_UPPERCASE_H = 'H',
|
||||
KEY_UPPERCASE_I = 'I',
|
||||
KEY_UPPERCASE_J = 'J',
|
||||
KEY_UPPERCASE_K = 'K',
|
||||
KEY_UPPERCASE_L = 'L',
|
||||
KEY_UPPERCASE_M = 'M',
|
||||
KEY_UPPERCASE_N = 'N',
|
||||
KEY_UPPERCASE_O = 'O',
|
||||
KEY_UPPERCASE_P = 'P',
|
||||
KEY_UPPERCASE_Q = 'Q',
|
||||
KEY_UPPERCASE_R = 'R',
|
||||
KEY_UPPERCASE_S = 'S',
|
||||
KEY_UPPERCASE_T = 'T',
|
||||
KEY_UPPERCASE_U = 'U',
|
||||
KEY_UPPERCASE_V = 'V',
|
||||
KEY_UPPERCASE_W = 'W',
|
||||
KEY_UPPERCASE_X = 'X',
|
||||
KEY_UPPERCASE_Y = 'Y',
|
||||
KEY_UPPERCASE_Z = 'Z',
|
||||
|
||||
KEY_BRACKET_LEFT = '[',
|
||||
KEY_BACKSLASH = '\\',
|
||||
KEY_BRACKET_RIGHT = ']',
|
||||
KEY_CARET = '^',
|
||||
KEY_UNDERSCORE = '_',
|
||||
|
||||
KEY_GRAVE = '`',
|
||||
KEY_LOWERCASE_A = 'a',
|
||||
KEY_LOWERCASE_B = 'b',
|
||||
KEY_LOWERCASE_C = 'c',
|
||||
KEY_LOWERCASE_D = 'd',
|
||||
KEY_LOWERCASE_E = 'e',
|
||||
KEY_LOWERCASE_F = 'f',
|
||||
KEY_LOWERCASE_G = 'g',
|
||||
KEY_LOWERCASE_H = 'h',
|
||||
KEY_LOWERCASE_I = 'i',
|
||||
KEY_LOWERCASE_J = 'j',
|
||||
KEY_LOWERCASE_K = 'k',
|
||||
KEY_LOWERCASE_L = 'l',
|
||||
KEY_LOWERCASE_M = 'm',
|
||||
KEY_LOWERCASE_N = 'n',
|
||||
KEY_LOWERCASE_O = 'o',
|
||||
KEY_LOWERCASE_P = 'p',
|
||||
KEY_LOWERCASE_Q = 'q',
|
||||
KEY_LOWERCASE_R = 'r',
|
||||
KEY_LOWERCASE_S = 's',
|
||||
KEY_LOWERCASE_T = 't',
|
||||
KEY_LOWERCASE_U = 'u',
|
||||
KEY_LOWERCASE_V = 'v',
|
||||
KEY_LOWERCASE_W = 'w',
|
||||
KEY_LOWERCASE_X = 'x',
|
||||
KEY_LOWERCASE_Y = 'y',
|
||||
KEY_LOWERCASE_Z = 'z',
|
||||
KEY_BRACE_LEFT = '{',
|
||||
KEY_BAR = '|',
|
||||
KEY_BRACE_RIGHT = '}',
|
||||
KEY_TILDE = '~',
|
||||
KEY_DEL = 127,
|
||||
|
||||
KEY_136 = 136,
|
||||
KEY_146 = 146,
|
||||
KEY_149 = 149,
|
||||
KEY_150 = 150,
|
||||
KEY_151 = 151,
|
||||
KEY_152 = 152,
|
||||
KEY_161 = 161,
|
||||
KEY_163 = 163,
|
||||
KEY_164 = 164,
|
||||
KEY_166 = 166,
|
||||
KEY_168 = 168,
|
||||
KEY_167 = 167,
|
||||
KEY_170 = 170,
|
||||
KEY_172 = 172,
|
||||
KEY_176 = 176,
|
||||
KEY_178 = 178,
|
||||
KEY_179 = 179,
|
||||
KEY_180 = 180,
|
||||
KEY_181 = 181,
|
||||
KEY_186 = 186,
|
||||
KEY_191 = 191,
|
||||
KEY_196 = 196,
|
||||
KEY_199 = 199,
|
||||
KEY_209 = 209,
|
||||
KEY_214 = 214,
|
||||
KEY_215 = 215,
|
||||
KEY_220 = 220,
|
||||
KEY_223 = 223,
|
||||
KEY_224 = 224,
|
||||
KEY_228 = 228,
|
||||
KEY_231 = 231,
|
||||
KEY_232 = 232,
|
||||
KEY_233 = 233,
|
||||
KEY_241 = 241,
|
||||
KEY_246 = 246,
|
||||
KEY_247 = 247,
|
||||
KEY_249 = 249,
|
||||
KEY_252 = 252,
|
||||
|
||||
KEY_ALT_Q = 272,
|
||||
KEY_ALT_W = 273,
|
||||
KEY_ALT_E = 274,
|
||||
KEY_ALT_R = 275,
|
||||
KEY_ALT_T = 276,
|
||||
KEY_ALT_Y = 277,
|
||||
KEY_ALT_U = 278,
|
||||
KEY_ALT_I = 279,
|
||||
KEY_ALT_O = 280,
|
||||
KEY_ALT_P = 281,
|
||||
KEY_ALT_A = 286,
|
||||
KEY_ALT_S = 287,
|
||||
KEY_ALT_D = 288,
|
||||
KEY_ALT_F = 289,
|
||||
KEY_ALT_G = 290,
|
||||
KEY_ALT_H = 291,
|
||||
KEY_ALT_J = 292,
|
||||
KEY_ALT_K = 293,
|
||||
KEY_ALT_L = 294,
|
||||
KEY_ALT_Z = 300,
|
||||
KEY_ALT_X = 301,
|
||||
KEY_ALT_C = 302,
|
||||
KEY_ALT_V = 303,
|
||||
KEY_ALT_B = 304,
|
||||
KEY_ALT_N = 305,
|
||||
KEY_ALT_M = 306,
|
||||
|
||||
KEY_CTRL_Q = 17,
|
||||
KEY_CTRL_W = 23,
|
||||
KEY_CTRL_E = 5,
|
||||
KEY_CTRL_R = 18,
|
||||
KEY_CTRL_T = 20,
|
||||
KEY_CTRL_Y = 25,
|
||||
KEY_CTRL_U = 21,
|
||||
KEY_CTRL_I = 9,
|
||||
KEY_CTRL_O = 15,
|
||||
KEY_CTRL_P = 16,
|
||||
KEY_CTRL_A = 1,
|
||||
KEY_CTRL_S = 19,
|
||||
KEY_CTRL_D = 4,
|
||||
KEY_CTRL_F = 6,
|
||||
KEY_CTRL_G = 7,
|
||||
KEY_CTRL_H = 8,
|
||||
KEY_CTRL_J = 10,
|
||||
KEY_CTRL_K = 11,
|
||||
KEY_CTRL_L = 12,
|
||||
KEY_CTRL_Z = 26,
|
||||
KEY_CTRL_X = 24,
|
||||
KEY_CTRL_C = 3,
|
||||
KEY_CTRL_V = 22,
|
||||
KEY_CTRL_B = 2,
|
||||
KEY_CTRL_N = 14,
|
||||
KEY_CTRL_M = 13,
|
||||
|
||||
KEY_F1 = 315,
|
||||
KEY_F2 = 316,
|
||||
KEY_F3 = 317,
|
||||
KEY_F4 = 318,
|
||||
KEY_F5 = 319,
|
||||
KEY_F6 = 320,
|
||||
KEY_F7 = 321,
|
||||
KEY_F8 = 322,
|
||||
KEY_F9 = 323,
|
||||
KEY_F10 = 324,
|
||||
KEY_F11 = 389,
|
||||
KEY_F12 = 390,
|
||||
|
||||
KEY_SHIFT_F1 = 340,
|
||||
KEY_SHIFT_F2 = 341,
|
||||
KEY_SHIFT_F3 = 342,
|
||||
KEY_SHIFT_F4 = 343,
|
||||
KEY_SHIFT_F5 = 344,
|
||||
KEY_SHIFT_F6 = 345,
|
||||
KEY_SHIFT_F7 = 346,
|
||||
KEY_SHIFT_F8 = 347,
|
||||
KEY_SHIFT_F9 = 348,
|
||||
KEY_SHIFT_F10 = 349,
|
||||
KEY_SHIFT_F11 = 391,
|
||||
KEY_SHIFT_F12 = 392,
|
||||
|
||||
KEY_CTRL_F1 = 350,
|
||||
KEY_CTRL_F2 = 351,
|
||||
KEY_CTRL_F3 = 352,
|
||||
KEY_CTRL_F4 = 353,
|
||||
KEY_CTRL_F5 = 354,
|
||||
KEY_CTRL_F6 = 355,
|
||||
KEY_CTRL_F7 = 356,
|
||||
KEY_CTRL_F8 = 357,
|
||||
KEY_CTRL_F9 = 358,
|
||||
KEY_CTRL_F10 = 359,
|
||||
KEY_CTRL_F11 = 393,
|
||||
KEY_CTRL_F12 = 394,
|
||||
|
||||
KEY_ALT_F1 = 360,
|
||||
KEY_ALT_F2 = 361,
|
||||
KEY_ALT_F3 = 362,
|
||||
KEY_ALT_F4 = 363,
|
||||
KEY_ALT_F5 = 364,
|
||||
KEY_ALT_F6 = 365,
|
||||
KEY_ALT_F7 = 366,
|
||||
KEY_ALT_F8 = 367,
|
||||
KEY_ALT_F9 = 368,
|
||||
KEY_ALT_F10 = 369,
|
||||
KEY_ALT_F11 = 395,
|
||||
KEY_ALT_F12 = 396,
|
||||
|
||||
KEY_HOME = 327,
|
||||
KEY_CTRL_HOME = 375,
|
||||
KEY_ALT_HOME = 407,
|
||||
|
||||
KEY_PAGE_UP = 329,
|
||||
KEY_CTRL_PAGE_UP = 388,
|
||||
KEY_ALT_PAGE_UP = 409,
|
||||
|
||||
KEY_INSERT = 338,
|
||||
KEY_CTRL_INSERT = 402,
|
||||
KEY_ALT_INSERT = 418,
|
||||
|
||||
KEY_DELETE = 339,
|
||||
KEY_CTRL_DELETE = 403,
|
||||
KEY_ALT_DELETE = 419,
|
||||
|
||||
KEY_END = 335,
|
||||
KEY_CTRL_END = 373,
|
||||
KEY_ALT_END = 415,
|
||||
|
||||
KEY_PAGE_DOWN = 337,
|
||||
KEY_ALT_PAGE_DOWN = 417,
|
||||
KEY_CTRL_PAGE_DOWN = 374,
|
||||
|
||||
KEY_ARROW_UP = 328,
|
||||
KEY_CTRL_ARROW_UP = 397,
|
||||
KEY_ALT_ARROW_UP = 408,
|
||||
|
||||
KEY_ARROW_DOWN = 336,
|
||||
KEY_CTRL_ARROW_DOWN = 401,
|
||||
KEY_ALT_ARROW_DOWN = 416,
|
||||
|
||||
KEY_ARROW_LEFT = 331,
|
||||
KEY_CTRL_ARROW_LEFT = 371,
|
||||
KEY_ALT_ARROW_LEFT = 411,
|
||||
|
||||
KEY_ARROW_RIGHT = 333,
|
||||
KEY_CTRL_ARROW_RIGHT = 372,
|
||||
KEY_ALT_ARROW_RIGHT = 413,
|
||||
|
||||
KEY_CTRL_BACKSLASH = 192,
|
||||
|
||||
KEY_NUMBERPAD_5 = 332,
|
||||
KEY_CTRL_NUMBERPAD_5 = 399,
|
||||
KEY_ALT_NUMBERPAD_5 = 9999,
|
||||
|
||||
KEY_FIRST_INPUT_CHARACTER = KEY_SPACE,
|
||||
KEY_LAST_INPUT_CHARACTER = KEY_LOWERCASE_Z,
|
||||
} Key;
|
||||
|
||||
typedef enum KeyboardLayout {
|
||||
KEYBOARD_LAYOUT_QWERTY,
|
||||
KEYBOARD_LAYOUT_FRENCH,
|
||||
KEYBOARD_LAYOUT_GERMAN,
|
||||
KEYBOARD_LAYOUT_ITALIAN,
|
||||
KEYBOARD_LAYOUT_SPANISH,
|
||||
} KeyboardLayout;
|
||||
|
||||
typedef struct STRUCT_6ABF50 {
|
||||
// Time when appropriate key was pressed down or -1 if it's up.
|
||||
int tick;
|
||||
int repeatCount;
|
||||
} STRUCT_6ABF50;
|
||||
|
||||
typedef struct InputEvent {
|
||||
// This is either logical key or input event id, which can be either
|
||||
// character code pressed or some other numbers used throughout the
|
||||
// game interface.
|
||||
int logicalKey;
|
||||
int mouseX;
|
||||
int mouseY;
|
||||
} InputEvent;
|
||||
|
||||
typedef void TickerProc();
|
||||
|
||||
typedef struct TickerListNode {
|
||||
int flags;
|
||||
TickerProc* proc;
|
||||
struct TickerListNode* next;
|
||||
} TickerListNode;
|
||||
|
||||
typedef struct STRUCT_51E2F0 {
|
||||
int type;
|
||||
int field_4;
|
||||
int field_8;
|
||||
union {
|
||||
struct {
|
||||
int type_1_field_C; // mouse x
|
||||
int type_1_field_10; // mouse y
|
||||
int type_1_field_14; // keyboard layout
|
||||
};
|
||||
struct {
|
||||
short type_2_field_C;
|
||||
};
|
||||
struct {
|
||||
int dx;
|
||||
int dy;
|
||||
int buttons;
|
||||
};
|
||||
};
|
||||
} STRUCT_51E2F0;
|
||||
|
||||
typedef struct LogicalKeyEntry {
|
||||
short field_0;
|
||||
short unmodified;
|
||||
short shift;
|
||||
short lmenu;
|
||||
short rmenu;
|
||||
short ctrl;
|
||||
} LogicalKeyEntry;
|
||||
|
||||
typedef struct KeyboardEvent {
|
||||
int scanCode;
|
||||
unsigned short modifiers;
|
||||
} KeyboardEvent;
|
||||
|
||||
typedef int(PauseHandler)();
|
||||
typedef int(ScreenshotHandler)(int width, int height, unsigned char* buffer, unsigned char* palette);
|
||||
|
||||
extern void (*_idle_func)();
|
||||
extern void (*_focus_func)(int);
|
||||
extern int gKeyboardKeyRepeatRate;
|
||||
extern int gKeyboardKeyRepeatDelay;
|
||||
extern bool _keyboard_hooked;
|
||||
extern unsigned char gMouseDefaultCursor[MOUSE_DEFAULT_CURSOR_SIZE];
|
||||
extern int _mouse_idling;
|
||||
extern unsigned char* gMouseCursorData;
|
||||
extern unsigned char* _mouse_shape;
|
||||
extern unsigned char* _mouse_fptr;
|
||||
extern double gMouseSensitivity;
|
||||
extern unsigned int _ticker_;
|
||||
extern int gMouseButtonsState;
|
||||
|
||||
extern void (*_update_palette_func)();
|
||||
extern bool gMmxEnabled;
|
||||
extern bool gMmxProbed;
|
||||
|
||||
extern unsigned char _kb_installed;
|
||||
extern bool gKeyboardDisabled;
|
||||
extern bool gKeyboardNumpadDisabled;
|
||||
extern bool gKeyboardNumlockDisabled;
|
||||
extern int gKeyboardEventQueueWriteIndex;
|
||||
extern int gKeyboardEventQueueReadIndex;
|
||||
extern short word_51E2E8;
|
||||
extern int gModifierKeysState;
|
||||
extern int (*_kb_scan_to_ascii)();
|
||||
extern STRUCT_51E2F0* _vcr_buffer;
|
||||
extern int _vcr_buffer_index;
|
||||
extern int _vcr_state;
|
||||
extern int _vcr_time;
|
||||
extern int _vcr_counter;
|
||||
extern int _vcr_terminate_flags;
|
||||
extern int _vcr_terminated_condition;
|
||||
extern int _vcr_start_time;
|
||||
extern int _vcr_registered_atexit;
|
||||
extern File* _vcr_file;
|
||||
extern int _vcr_buffer_end;
|
||||
|
||||
extern int gNormalizedQwertyKeys[SDL_NUM_SCANCODES];
|
||||
extern InputEvent gInputEventQueue[40];
|
||||
extern STRUCT_6ABF50 _GNW95_key_time_stamps[SDL_NUM_SCANCODES];
|
||||
extern int _input_mx;
|
||||
extern int _input_my;
|
||||
extern bool gPaused;
|
||||
extern int gScreenshotKeyCode;
|
||||
extern int _using_msec_timer;
|
||||
extern int gPauseKeyCode;
|
||||
extern ScreenshotHandler* gScreenshotHandler;
|
||||
extern int gInputEventQueueReadIndex;
|
||||
extern unsigned char* gScreenshotBuffer;
|
||||
extern PauseHandler* gPauseHandler;
|
||||
extern int gInputEventQueueWriteIndex;
|
||||
extern bool gRunLoopDisabled;
|
||||
extern TickerListNode* gTickerListHead;
|
||||
extern unsigned int gTickerLastTimestamp;
|
||||
extern bool gCursorIsHidden;
|
||||
extern int _raw_x;
|
||||
extern int gMouseCursorHeight;
|
||||
extern int _raw_y;
|
||||
extern int _raw_buttons;
|
||||
extern int gMouseCursorY;
|
||||
extern int gMouseCursorX;
|
||||
extern int _mouse_disabled;
|
||||
extern int gMouseEvent;
|
||||
extern unsigned int _mouse_speed;
|
||||
extern int _mouse_curr_frame;
|
||||
extern bool gMouseInitialized;
|
||||
extern int gMouseCursorPitch;
|
||||
extern int gMouseCursorWidth;
|
||||
extern int _mouse_num_frames;
|
||||
extern int _mouse_hoty;
|
||||
extern int _mouse_hotx;
|
||||
extern unsigned int _mouse_idle_start_time;
|
||||
extern WindowDrawingProc2* _mouse_blit_trans;
|
||||
extern WINDOWDRAWINGPROC _mouse_blit;
|
||||
extern unsigned char _mouse_trans;
|
||||
extern int gMouseRightButtonDownTimestamp;
|
||||
extern int gMouseLeftButtonDownTimestamp;
|
||||
extern int gMousePreviousEvent;
|
||||
extern unsigned short gSixteenBppPalette[256];
|
||||
extern Rect _scr_size;
|
||||
extern int gRedMask;
|
||||
extern int gGreenMask;
|
||||
extern int gBlueMask;
|
||||
extern int gBlueShift;
|
||||
extern int gRedShift;
|
||||
extern int gGreenShift;
|
||||
extern void (*_scr_blit)(unsigned char* src, int src_pitch, int a3, int src_x, int src_y, int src_width, int src_height, int dest_x, int dest_y);
|
||||
extern void (*_zero_mem)();
|
||||
extern bool gMmxSupported;
|
||||
extern unsigned char gLastVideoModePalette[268];
|
||||
extern KeyboardEvent gKeyboardEventsQueue[KEY_QUEUE_SIZE];
|
||||
extern LogicalKeyEntry gLogicalKeyEntries[SDL_NUM_SCANCODES];
|
||||
extern unsigned char gPressedPhysicalKeys[SDL_NUM_SCANCODES];
|
||||
extern unsigned int _kb_idle_start_time;
|
||||
extern KeyboardEvent gLastKeyboardEvent;
|
||||
extern int gKeyboardLayout;
|
||||
extern unsigned char gPressedPhysicalKeysCount;
|
||||
|
||||
extern SDL_Window* gSdlWindow;
|
||||
extern SDL_Surface* gSdlSurface;
|
||||
extern SDL_Renderer* gSdlRenderer;
|
||||
extern SDL_Texture* gSdlTexture;
|
||||
extern SDL_Surface* gSdlTextureSurface;
|
||||
|
||||
int coreInit(int a1);
|
||||
void coreExit();
|
||||
int _get_input();
|
||||
void _process_bk();
|
||||
void enqueueInputEvent(int a1);
|
||||
int dequeueInputEvent();
|
||||
void inputEventQueueReset();
|
||||
void tickersExecute();
|
||||
void tickersAdd(TickerProc* fn);
|
||||
void tickersRemove(TickerProc* fn);
|
||||
void tickersEnable();
|
||||
void tickersDisable();
|
||||
void pauseGame();
|
||||
int pauseHandlerDefaultImpl();
|
||||
void pauseHandlerConfigure(int keyCode, PauseHandler* fn);
|
||||
void takeScreenshot();
|
||||
void screenshotBlitter(unsigned char* src, int src_pitch, int a3, int x, int y, int width, int height, int dest_x, int dest_y);
|
||||
int screenshotHandlerDefaultImpl(int width, int height, unsigned char* data, unsigned char* palette);
|
||||
void screenshotHandlerConfigure(int keyCode, ScreenshotHandler* handler);
|
||||
unsigned int _get_time();
|
||||
void coreDelayProcessingEvents(unsigned int ms);
|
||||
void coreDelay(unsigned int ms);
|
||||
unsigned int getTicksSince(unsigned int a1);
|
||||
unsigned int getTicksBetween(unsigned int a1, unsigned int a2);
|
||||
unsigned int _get_bk_time();
|
||||
void buildNormalizedQwertyKeys();
|
||||
int _GNW95_input_init();
|
||||
void _GNW95_process_message();
|
||||
void _GNW95_clear_time_stamps();
|
||||
void _GNW95_process_key(KeyboardData* data);
|
||||
void _GNW95_lost_focus();
|
||||
int mouseInit();
|
||||
void mouseFree();
|
||||
void mousePrepareDefaultCursor();
|
||||
int mouseSetFrame(unsigned char* a1, int width, int height, int pitch, int a5, int a6, int a7);
|
||||
void _mouse_anim();
|
||||
void mouseShowCursor();
|
||||
void mouseHideCursor();
|
||||
void _mouse_info();
|
||||
void _mouse_simulate_input(int delta_x, int delta_y, int buttons);
|
||||
bool _mouse_in(int left, int top, int right, int bottom);
|
||||
bool _mouse_click_in(int left, int top, int right, int bottom);
|
||||
void mouseGetRect(Rect* rect);
|
||||
void mouseGetPosition(int* out_x, int* out_y);
|
||||
void _mouse_set_position(int a1, int a2);
|
||||
void _mouse_clip();
|
||||
int mouseGetEvent();
|
||||
bool cursorIsHidden();
|
||||
void _mouse_get_raw_state(int* out_x, int* out_y, int* out_buttons);
|
||||
void mouseSetSensitivity(double value);
|
||||
void mmxSetEnabled(bool a1);
|
||||
int _init_mode_320_200();
|
||||
int _init_mode_320_400();
|
||||
int _init_mode_640_480_16();
|
||||
int _init_mode_640_480();
|
||||
int _init_mode_640_400();
|
||||
int _init_mode_800_600();
|
||||
int _init_mode_1024_768();
|
||||
int _init_mode_1280_1024();
|
||||
void _get_start_mode_();
|
||||
void _zero_vid_mem();
|
||||
int _GNW95_init_mode_ex(int width, int height, int bpp);
|
||||
int _init_vesa_mode(int width, int height);
|
||||
int _GNW95_init_window(int width, int height, bool fullscreen);
|
||||
int getShiftForBitMask(int mask);
|
||||
int directDrawInit(int width, int height, int bpp);
|
||||
void directDrawFree();
|
||||
void directDrawSetPaletteInRange(unsigned char* a1, int a2, int a3);
|
||||
void directDrawSetPalette(unsigned char* palette);
|
||||
unsigned char* directDrawGetPalette();
|
||||
void _GNW95_ShowRect(unsigned char* src, int src_pitch, int a3, int src_x, int src_y, int src_width, int src_height, int dest_x, int dest_y);
|
||||
void _GNW95_MouseShowRect16(unsigned char* src, int srcPitch, int a3, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY);
|
||||
void _GNW95_ShowRect16(unsigned char* src, int srcPitch, int a3, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY);
|
||||
void _GNW95_MouseShowTransRect16(unsigned char* src, int srcPitch, int a3, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, unsigned char keyColor);
|
||||
void _GNW95_zero_vid_mem();
|
||||
int keyboardInit();
|
||||
void keyboardFree();
|
||||
void keyboardReset();
|
||||
int _kb_getch();
|
||||
void keyboardDisable();
|
||||
void keyboardEnable();
|
||||
int keyboardIsDisabled();
|
||||
void keyboardSetLayout(int new_language);
|
||||
int keyboardGetLayout();
|
||||
void _kb_simulate_key(KeyboardData* data);
|
||||
int _kb_next_ascii_English_US();
|
||||
int keyboardDequeueLogicalKeyCode();
|
||||
void keyboardBuildQwertyConfiguration();
|
||||
void keyboardBuildFrenchConfiguration();
|
||||
void keyboardBuildGermanConfiguration();
|
||||
void keyboardBuildItalianConfiguration();
|
||||
void keyboardBuildSpanishConfiguration();
|
||||
void _kb_init_lock_status();
|
||||
int keyboardPeekEvent(int index, KeyboardEvent** keyboardEventPtr);
|
||||
bool _vcr_record(const char* fileName);
|
||||
void _vcr_stop();
|
||||
int _vcr_status();
|
||||
int _vcr_update();
|
||||
bool _vcr_clear_buffer();
|
||||
int _vcr_dump_buffer();
|
||||
bool _vcr_save_record(STRUCT_51E2F0* ptr, File* stream);
|
||||
bool _vcr_load_record(STRUCT_51E2F0* ptr, File* stream);
|
||||
|
||||
int screenGetWidth();
|
||||
int screenGetHeight();
|
||||
int screenGetVisibleHeight();
|
||||
void mouseGetPositionInWindow(int win, int* x, int* y);
|
||||
bool mouseHitTestInWindow(int win, int left, int top, int right, int bottom);
|
||||
|
||||
#endif /* CORE_H */
|
||||
178
src/credits.cc
@@ -1,25 +1,30 @@
|
||||
#include "credits.h"
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
#include "cycle.h"
|
||||
#include "db.h"
|
||||
#include "debug.h"
|
||||
#include "draw.h"
|
||||
#include "game_mouse.h"
|
||||
#include "memory.h"
|
||||
#include "message.h"
|
||||
#include "palette.h"
|
||||
#include "platform_compat.h"
|
||||
#include "sound.h"
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define CREDITS_WINDOW_WIDTH (640)
|
||||
#define CREDITS_WINDOW_HEIGHT (480)
|
||||
#include <algorithm>
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "cycle.h"
|
||||
#include "db.h"
|
||||
#include "debug.h"
|
||||
#include "delay.h"
|
||||
#include "draw.h"
|
||||
#include "game_mouse.h"
|
||||
#include "input.h"
|
||||
#include "memory.h"
|
||||
#include "message.h"
|
||||
#include "mouse.h"
|
||||
#include "palette.h"
|
||||
#include "platform_compat.h"
|
||||
#include "sound.h"
|
||||
#include "svga.h"
|
||||
#include "text_font.h"
|
||||
#include "window_manager.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define CREDITS_WINDOW_SCROLLING_DELAY (38)
|
||||
|
||||
static bool creditsFileParseNextLine(char* dest, int* font, int* color);
|
||||
@@ -61,9 +66,9 @@ void creditsOpen(const char* filePath, int backgroundFid, bool useReversedStyle)
|
||||
soundContinueAll();
|
||||
|
||||
char localizedPath[COMPAT_MAX_PATH];
|
||||
if (_message_make_path(localizedPath, filePath)) {
|
||||
if (_message_make_path(localizedPath, sizeof(localizedPath), filePath)) {
|
||||
gCreditsFile = fileOpen(localizedPath, "rt");
|
||||
if (gCreditsFile != NULL) {
|
||||
if (gCreditsFile != nullptr) {
|
||||
soundContinueAll();
|
||||
|
||||
colorCycleDisable();
|
||||
@@ -74,39 +79,35 @@ void creditsOpen(const char* filePath, int backgroundFid, bool useReversedStyle)
|
||||
mouseShowCursor();
|
||||
}
|
||||
|
||||
int creditsWindowX = (screenGetWidth() - CREDITS_WINDOW_WIDTH) / 2;
|
||||
int creditsWindowY = (screenGetHeight() - CREDITS_WINDOW_HEIGHT) / 2;
|
||||
int window = windowCreate(creditsWindowX, creditsWindowY, CREDITS_WINDOW_WIDTH, CREDITS_WINDOW_HEIGHT, _colorTable[0], 20);
|
||||
int windowWidth = screenGetWidth();
|
||||
int windowHeight = screenGetHeight();
|
||||
int window = windowCreate(0, 0, windowWidth, windowHeight, _colorTable[0], 20);
|
||||
soundContinueAll();
|
||||
if (window != -1) {
|
||||
unsigned char* windowBuffer = windowGetBuffer(window);
|
||||
if (windowBuffer != NULL) {
|
||||
unsigned char* backgroundBuffer = (unsigned char*)internal_malloc(CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT);
|
||||
if (windowBuffer != nullptr) {
|
||||
unsigned char* backgroundBuffer = (unsigned char*)internal_malloc(windowWidth * windowHeight);
|
||||
if (backgroundBuffer) {
|
||||
soundContinueAll();
|
||||
|
||||
memset(backgroundBuffer, _colorTable[0], CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT);
|
||||
memset(backgroundBuffer, _colorTable[0], windowWidth * windowHeight);
|
||||
|
||||
if (backgroundFid != -1) {
|
||||
CacheEntry* backgroundFrmHandle;
|
||||
Art* frm = artLock(backgroundFid, &backgroundFrmHandle);
|
||||
if (frm != NULL) {
|
||||
int width = artGetWidth(frm, 0, 0);
|
||||
int height = artGetHeight(frm, 0, 0);
|
||||
unsigned char* backgroundFrmData = artGetFrameData(frm, 0, 0);
|
||||
blitBufferToBuffer(backgroundFrmData,
|
||||
width,
|
||||
height,
|
||||
width,
|
||||
backgroundBuffer + CREDITS_WINDOW_WIDTH * ((CREDITS_WINDOW_HEIGHT - height) / 2) + (CREDITS_WINDOW_WIDTH - width) / 2,
|
||||
CREDITS_WINDOW_WIDTH);
|
||||
artUnlock(backgroundFrmHandle);
|
||||
FrmImage backgroundFrmImage;
|
||||
if (backgroundFrmImage.lock(backgroundFid)) {
|
||||
blitBufferToBuffer(backgroundFrmImage.getData(),
|
||||
backgroundFrmImage.getWidth(),
|
||||
backgroundFrmImage.getHeight(),
|
||||
backgroundFrmImage.getWidth(),
|
||||
backgroundBuffer + windowWidth * ((windowHeight - backgroundFrmImage.getHeight()) / 2) + (windowWidth - backgroundFrmImage.getWidth()) / 2,
|
||||
windowWidth);
|
||||
backgroundFrmImage.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char* intermediateBuffer = (unsigned char*)internal_malloc(CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT);
|
||||
if (intermediateBuffer != NULL) {
|
||||
memset(intermediateBuffer, 0, CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT);
|
||||
unsigned char* intermediateBuffer = (unsigned char*)internal_malloc(windowWidth * windowHeight);
|
||||
if (intermediateBuffer != nullptr) {
|
||||
memset(intermediateBuffer, 0, windowWidth * windowHeight);
|
||||
|
||||
fontSetCurrent(gCreditsWindowTitleFont);
|
||||
int titleFontLineHeight = fontGetLineHeight();
|
||||
@@ -114,22 +115,21 @@ void creditsOpen(const char* filePath, int backgroundFid, bool useReversedStyle)
|
||||
fontSetCurrent(gCreditsWindowNameFont);
|
||||
int nameFontLineHeight = fontGetLineHeight();
|
||||
|
||||
int lineHeight = nameFontLineHeight + (titleFontLineHeight >= nameFontLineHeight ? titleFontLineHeight - nameFontLineHeight : 0);
|
||||
int stringBufferSize = CREDITS_WINDOW_WIDTH * lineHeight;
|
||||
int lineHeight = std::max(titleFontLineHeight, nameFontLineHeight);
|
||||
int stringBufferSize = windowWidth * lineHeight;
|
||||
unsigned char* stringBuffer = (unsigned char*)internal_malloc(stringBufferSize);
|
||||
if (stringBuffer != NULL) {
|
||||
if (stringBuffer != nullptr) {
|
||||
blitBufferToBuffer(backgroundBuffer,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
CREDITS_WINDOW_HEIGHT,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
windowWidth,
|
||||
windowHeight,
|
||||
windowWidth,
|
||||
windowBuffer,
|
||||
CREDITS_WINDOW_WIDTH);
|
||||
windowWidth);
|
||||
|
||||
windowRefresh(window);
|
||||
|
||||
paletteFadeTo(_cmap);
|
||||
|
||||
unsigned char* v40 = intermediateBuffer + CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT - CREDITS_WINDOW_WIDTH;
|
||||
char str[260];
|
||||
int font;
|
||||
int color;
|
||||
@@ -138,47 +138,51 @@ void creditsOpen(const char* filePath, int backgroundFid, bool useReversedStyle)
|
||||
while (creditsFileParseNextLine(str, &font, &color)) {
|
||||
fontSetCurrent(font);
|
||||
|
||||
int v19 = fontGetStringWidth(str);
|
||||
if (v19 >= CREDITS_WINDOW_WIDTH) {
|
||||
int stringWidth = fontGetStringWidth(str);
|
||||
if (stringWidth >= windowWidth) {
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(stringBuffer, 0, stringBufferSize);
|
||||
fontDrawText(stringBuffer, str, CREDITS_WINDOW_WIDTH, CREDITS_WINDOW_WIDTH, color);
|
||||
fontDrawText(stringBuffer, str, windowWidth, windowWidth, color);
|
||||
|
||||
unsigned char* dest = intermediateBuffer + CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT - CREDITS_WINDOW_WIDTH + (CREDITS_WINDOW_WIDTH - v19) / 2;
|
||||
unsigned char* dest = intermediateBuffer + windowWidth * windowHeight - windowWidth + (windowWidth - stringWidth) / 2;
|
||||
unsigned char* src = stringBuffer;
|
||||
for (int index = 0; index < lineHeight; index++) {
|
||||
if (_get_input() != -1) {
|
||||
sharedFpsLimiter.mark();
|
||||
|
||||
if (inputGetInput() != -1) {
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
|
||||
memmove(intermediateBuffer, intermediateBuffer + CREDITS_WINDOW_WIDTH, CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT - CREDITS_WINDOW_WIDTH);
|
||||
memcpy(dest, src, v19);
|
||||
memmove(intermediateBuffer, intermediateBuffer + windowWidth, windowWidth * windowHeight - windowWidth);
|
||||
memcpy(dest, src, stringWidth);
|
||||
|
||||
blitBufferToBuffer(backgroundBuffer,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
CREDITS_WINDOW_HEIGHT,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
windowWidth,
|
||||
windowHeight,
|
||||
windowWidth,
|
||||
windowBuffer,
|
||||
CREDITS_WINDOW_WIDTH);
|
||||
windowWidth);
|
||||
|
||||
blitBufferToBufferTrans(intermediateBuffer,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
CREDITS_WINDOW_HEIGHT,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
windowWidth,
|
||||
windowHeight,
|
||||
windowWidth,
|
||||
windowBuffer,
|
||||
CREDITS_WINDOW_WIDTH);
|
||||
windowWidth);
|
||||
|
||||
while (getTicksSince(tick) < CREDITS_WINDOW_SCROLLING_DELAY) {
|
||||
}
|
||||
delay_ms(CREDITS_WINDOW_SCROLLING_DELAY - (getTicks() - tick));
|
||||
|
||||
tick = _get_time();
|
||||
tick = getTicks();
|
||||
|
||||
windowRefresh(window);
|
||||
|
||||
src += CREDITS_WINDOW_WIDTH;
|
||||
src += windowWidth;
|
||||
|
||||
sharedFpsLimiter.throttle();
|
||||
renderPresent();
|
||||
}
|
||||
|
||||
if (stop) {
|
||||
@@ -187,34 +191,38 @@ void creditsOpen(const char* filePath, int backgroundFid, bool useReversedStyle)
|
||||
}
|
||||
|
||||
if (!stop) {
|
||||
for (int index = 0; index < CREDITS_WINDOW_HEIGHT; index++) {
|
||||
if (_get_input() != -1) {
|
||||
for (int index = 0; index < windowHeight; index++) {
|
||||
sharedFpsLimiter.mark();
|
||||
|
||||
if (inputGetInput() != -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
memmove(intermediateBuffer, intermediateBuffer + CREDITS_WINDOW_WIDTH, CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT - CREDITS_WINDOW_WIDTH);
|
||||
memset(intermediateBuffer + CREDITS_WINDOW_WIDTH * CREDITS_WINDOW_HEIGHT - CREDITS_WINDOW_WIDTH, 0, CREDITS_WINDOW_WIDTH);
|
||||
memmove(intermediateBuffer, intermediateBuffer + windowWidth, windowWidth * windowHeight - windowWidth);
|
||||
memset(intermediateBuffer + windowWidth * windowHeight - windowWidth, 0, windowWidth);
|
||||
|
||||
blitBufferToBuffer(backgroundBuffer,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
CREDITS_WINDOW_HEIGHT,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
windowWidth,
|
||||
windowHeight,
|
||||
windowWidth,
|
||||
windowBuffer,
|
||||
CREDITS_WINDOW_WIDTH);
|
||||
windowWidth);
|
||||
|
||||
blitBufferToBufferTrans(intermediateBuffer,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
CREDITS_WINDOW_HEIGHT,
|
||||
CREDITS_WINDOW_WIDTH,
|
||||
windowWidth,
|
||||
windowHeight,
|
||||
windowWidth,
|
||||
windowBuffer,
|
||||
CREDITS_WINDOW_WIDTH);
|
||||
windowWidth);
|
||||
|
||||
while (getTicksSince(tick) < CREDITS_WINDOW_SCROLLING_DELAY) {
|
||||
}
|
||||
delay_ms(CREDITS_WINDOW_SCROLLING_DELAY - (getTicks() - tick));
|
||||
|
||||
tick = _get_time();
|
||||
tick = getTicks();
|
||||
|
||||
windowRefresh(window);
|
||||
|
||||
sharedFpsLimiter.throttle();
|
||||
renderPresent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,3 +282,5 @@ static bool creditsFileParseNextLine(char* dest, int* font, int* color)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#ifndef CREDITS_H
|
||||
#define CREDITS_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
void creditsOpen(const char* path, int fid, bool useReversedStyle);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CREDITS_H */
|
||||
|
||||
239
src/critter.cc
@@ -1,5 +1,8 @@
|
||||
#include "critter.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "animation.h"
|
||||
#include "art.h"
|
||||
#include "character_editor.h"
|
||||
@@ -26,10 +29,9 @@
|
||||
#include "stat.h"
|
||||
#include "tile.h"
|
||||
#include "trait.h"
|
||||
#include "world_map.h"
|
||||
#include "worldmap.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
namespace fallout {
|
||||
|
||||
// Maximum length of dude's name length.
|
||||
#define DUDE_NAME_MAX_LENGTH (32)
|
||||
@@ -68,6 +70,7 @@ typedef enum RadiationLevel {
|
||||
} RadiationLevel;
|
||||
|
||||
static int _get_rad_damage_level(Object* obj, void* data);
|
||||
static int critter_kill_count_clear();
|
||||
static int _critterClearObjDrugs(Object* obj, void* data);
|
||||
|
||||
// 0x50141C
|
||||
@@ -132,7 +135,7 @@ static const int gRadiationEffectPenalties[RADIATION_LEVEL_COUNT][RADIATION_EFFE
|
||||
};
|
||||
|
||||
// 0x518438
|
||||
static Object* _critterClearObj = NULL;
|
||||
static Object* _critterClearObj = nullptr;
|
||||
|
||||
// scrname.msg
|
||||
//
|
||||
@@ -159,7 +162,8 @@ int critterInit()
|
||||
{
|
||||
dudeResetName();
|
||||
|
||||
memset(gKillsByType, 0, sizeof(gKillsByType));
|
||||
// NOTE: Uninline;
|
||||
critter_kill_count_clear();
|
||||
|
||||
if (!messageListInit(&gCritterMessageList)) {
|
||||
debugPrint("\nError: Initing critter name message file!");
|
||||
@@ -167,13 +171,15 @@ int critterInit()
|
||||
}
|
||||
|
||||
char path[COMPAT_MAX_PATH];
|
||||
sprintf(path, "%sscrname.msg", asc_5186C8);
|
||||
snprintf(path, sizeof(path), "%sscrname.msg", asc_5186C8);
|
||||
|
||||
if (!messageListLoad(&gCritterMessageList, path)) {
|
||||
debugPrint("\nError: Loading critter name message file!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_SCRNAME, &gCritterMessageList);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -181,12 +187,15 @@ int critterInit()
|
||||
void critterReset()
|
||||
{
|
||||
dudeResetName();
|
||||
memset(gKillsByType, 0, sizeof(gKillsByType));
|
||||
|
||||
// NOTE: Uninline;
|
||||
critter_kill_count_clear();
|
||||
}
|
||||
|
||||
// 0x42D004
|
||||
void critterExit()
|
||||
{
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_SCRNAME, nullptr);
|
||||
messageListFree(&gCritterMessageList);
|
||||
}
|
||||
|
||||
@@ -229,25 +238,25 @@ char* critterGetName(Object* obj)
|
||||
return gDudeName;
|
||||
}
|
||||
|
||||
if (obj->field_80 == -1) {
|
||||
if (obj->scriptIndex == -1) {
|
||||
if (obj->sid != -1) {
|
||||
Script* script;
|
||||
if (scriptGetScript(obj->sid, &script) != -1) {
|
||||
obj->field_80 = script->field_14;
|
||||
obj->scriptIndex = script->index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char* name = NULL;
|
||||
if (obj->field_80 != -1) {
|
||||
char* name = nullptr;
|
||||
if (obj->scriptIndex != -1) {
|
||||
MessageListItem messageListItem;
|
||||
messageListItem.num = 101 + obj->field_80;
|
||||
messageListItem.num = 101 + obj->scriptIndex;
|
||||
if (messageListGetItem(&gCritterMessageList, &messageListItem)) {
|
||||
name = messageListItem.text;
|
||||
}
|
||||
}
|
||||
|
||||
if (name == NULL || *name == '\0') {
|
||||
if (name == nullptr || *name == '\0') {
|
||||
name = protoGetName(obj->pid);
|
||||
}
|
||||
|
||||
@@ -276,18 +285,18 @@ void dudeResetName()
|
||||
// 0x42D18C
|
||||
int critterGetHitPoints(Object* critter)
|
||||
{
|
||||
return (critter->pid >> 24) == OBJ_TYPE_CRITTER ? critter->data.critter.hp : 0;
|
||||
return PID_TYPE(critter->pid) == OBJ_TYPE_CRITTER ? critter->data.critter.hp : 0;
|
||||
}
|
||||
|
||||
// 0x42D1A4
|
||||
int critterAdjustHitPoints(Object* critter, int a2)
|
||||
int critterAdjustHitPoints(Object* critter, int hp)
|
||||
{
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int maximumHp = critterGetStat(critter, STAT_MAXIMUM_HIT_POINTS);
|
||||
int newHp = critter->data.critter.hp + a2;
|
||||
int newHp = critter->data.critter.hp + hp;
|
||||
|
||||
critter->data.critter.hp = newHp;
|
||||
if (maximumHp >= newHp) {
|
||||
@@ -304,7 +313,7 @@ int critterAdjustHitPoints(Object* critter, int a2)
|
||||
// 0x42D1F8
|
||||
int critterGetPoison(Object* critter)
|
||||
{
|
||||
return (critter->pid >> 24) == OBJ_TYPE_CRITTER ? critter->data.critter.poison : 0;
|
||||
return PID_TYPE(critter->pid) == OBJ_TYPE_CRITTER ? critter->data.critter.poison : 0;
|
||||
}
|
||||
|
||||
// Adjust critter's current poison by specified amount.
|
||||
@@ -338,8 +347,8 @@ int critterAdjustPoison(Object* critter, int amount)
|
||||
if (newPoison > 0) {
|
||||
critter->data.critter.poison = newPoison;
|
||||
|
||||
_queue_clear_type(EVENT_TYPE_POISON, NULL);
|
||||
queueAddEvent(10 * (505 - 5 * newPoison), gDude, NULL, EVENT_TYPE_POISON);
|
||||
_queue_clear_type(EVENT_TYPE_POISON, nullptr);
|
||||
queueAddEvent(10 * (505 - 5 * newPoison), gDude, nullptr, EVENT_TYPE_POISON);
|
||||
|
||||
// You have been poisoned!
|
||||
messageListItem.num = 3000;
|
||||
@@ -396,7 +405,7 @@ int poisonEventProcess(Object* obj, void* data)
|
||||
// 0x42D38C
|
||||
int critterGetRadiation(Object* obj)
|
||||
{
|
||||
return (obj->pid >> 24) == OBJ_TYPE_CRITTER ? obj->data.critter.radiation : 0;
|
||||
return PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER ? obj->data.critter.radiation : 0;
|
||||
}
|
||||
|
||||
// 0x42D3A4
|
||||
@@ -416,27 +425,27 @@ int critterAdjustRadiation(Object* obj, int amount)
|
||||
}
|
||||
|
||||
if (amount > 0) {
|
||||
proto->critter.data.flags |= 0x02;
|
||||
proto->critter.data.flags |= CRITTER_RADIATED;
|
||||
}
|
||||
|
||||
if (amount > 0) {
|
||||
Object* geigerCounter = NULL;
|
||||
Object* geigerCounter = nullptr;
|
||||
|
||||
Object* item1 = critterGetItem1(gDude);
|
||||
if (item1 != NULL) {
|
||||
if (item1 != nullptr) {
|
||||
if (item1->pid == PROTO_ID_GEIGER_COUNTER_I || item1->pid == PROTO_ID_GEIGER_COUNTER_II) {
|
||||
geigerCounter = item1;
|
||||
}
|
||||
}
|
||||
|
||||
Object* item2 = critterGetItem2(gDude);
|
||||
if (item2 != NULL) {
|
||||
if (item2 != nullptr) {
|
||||
if (item2->pid == PROTO_ID_GEIGER_COUNTER_I || item2->pid == PROTO_ID_GEIGER_COUNTER_II) {
|
||||
geigerCounter = item2;
|
||||
}
|
||||
}
|
||||
|
||||
if (geigerCounter != NULL) {
|
||||
if (geigerCounter != nullptr) {
|
||||
if (miscItemIsOn(geigerCounter)) {
|
||||
if (amount > 5) {
|
||||
// The geiger counter is clicking wildly.
|
||||
@@ -483,7 +492,7 @@ int _critter_check_rads(Object* obj)
|
||||
|
||||
Proto* proto;
|
||||
protoGetProto(obj->pid, &proto);
|
||||
if ((proto->critter.data.flags & 0x02) == 0) {
|
||||
if ((proto->critter.data.flags & CRITTER_RADIATED) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -508,23 +517,23 @@ int _critter_check_rads(Object* obj)
|
||||
else
|
||||
radiationLevel = RADIATION_LEVEL_NONE;
|
||||
|
||||
if (statRoll(obj, STAT_ENDURANCE, gRadiationEnduranceModifiers[radiationLevel], NULL) <= ROLL_FAILURE) {
|
||||
if (statRoll(obj, STAT_ENDURANCE, gRadiationEnduranceModifiers[radiationLevel], nullptr) <= ROLL_FAILURE) {
|
||||
radiationLevel++;
|
||||
}
|
||||
|
||||
if (radiationLevel > _old_rad_level) {
|
||||
// Create timer event for applying radiation damage.
|
||||
RadiationEvent* radiationEvent = (RadiationEvent*)internal_malloc(sizeof(*radiationEvent));
|
||||
if (radiationEvent == NULL) {
|
||||
if (radiationEvent == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
radiationEvent->radiationLevel = radiationLevel;
|
||||
radiationEvent->isHealing = 0;
|
||||
queueAddEvent(36000 * randomBetween(4, 18), obj, radiationEvent, EVENT_TYPE_RADIATION);
|
||||
queueAddEvent(GAME_TIME_TICKS_PER_HOUR * randomBetween(4, 18), obj, radiationEvent, EVENT_TYPE_RADIATION);
|
||||
}
|
||||
|
||||
proto->critter.data.flags &= ~(0x02);
|
||||
proto->critter.data.flags &= ~CRITTER_RADIATED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -568,6 +577,13 @@ void _process_rads(Object* obj, int radiationLevel, bool isHealing)
|
||||
if (obj == gDude) {
|
||||
// Radiation level message, higher is worse.
|
||||
messageListItem.num = 1000 + radiationLevelIndex;
|
||||
|
||||
// SFALL: Fix radiation message when removing radiation effects.
|
||||
if (isHealing) {
|
||||
// You feel better.
|
||||
messageListItem.num = 3003;
|
||||
}
|
||||
|
||||
if (messageListGetItem(&gMiscMessageList, &messageListItem)) {
|
||||
displayMonitorAddMessage(messageListItem.text);
|
||||
}
|
||||
@@ -579,15 +595,18 @@ void _process_rads(Object* obj, int radiationLevel, bool isHealing)
|
||||
critterSetBonusStat(obj, gRadiationEffectStats[effect], value);
|
||||
}
|
||||
|
||||
if ((obj->data.critter.combat.results & DAM_DEAD) == 0) {
|
||||
// Loop thru effects affecting primary stats. If any of the primary stat
|
||||
// dropped below minimal value, kill it.
|
||||
for (int effect = 0; effect < RADIATION_EFFECT_PRIMARY_STAT_COUNT; effect++) {
|
||||
int base = critterGetBaseStatWithTraitModifier(obj, gRadiationEffectStats[effect]);
|
||||
int bonus = critterGetBonusStat(obj, gRadiationEffectStats[effect]);
|
||||
if (base + bonus < PRIMARY_STAT_MIN) {
|
||||
critterKill(obj, -1, 1);
|
||||
break;
|
||||
// SFALL: Prevent death when removing radiation effects.
|
||||
if (!isHealing) {
|
||||
if ((obj->data.critter.combat.results & DAM_DEAD) == 0) {
|
||||
// Loop thru effects affecting primary stats. If any of the primary stat
|
||||
// dropped below minimal value, kill it.
|
||||
for (int effect = 0; effect < RADIATION_EFFECT_PRIMARY_STAT_COUNT; effect++) {
|
||||
int base = critterGetBaseStatWithTraitModifier(obj, gRadiationEffectStats[effect]);
|
||||
int bonus = critterGetBonusStat(obj, gRadiationEffectStats[effect]);
|
||||
if (base + bonus < PRIMARY_STAT_MIN) {
|
||||
critterKill(obj, -1, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -597,7 +616,8 @@ void _process_rads(Object* obj, int radiationLevel, bool isHealing)
|
||||
// You have died from radiation sickness.
|
||||
messageListItem.num = 1006;
|
||||
if (messageListGetItem(&gMiscMessageList, &messageListItem)) {
|
||||
displayMonitorAddMessage(messageListItem.text);
|
||||
// SFALL: Display a pop-up message box about death from radiation.
|
||||
gameShowDeathDialog(messageListItem.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -610,7 +630,7 @@ int radiationEventProcess(Object* obj, void* data)
|
||||
if (!radiationEvent->isHealing) {
|
||||
// Schedule healing stats event in 7 days.
|
||||
RadiationEvent* newRadiationEvent = (RadiationEvent*)internal_malloc(sizeof(*newRadiationEvent));
|
||||
if (newRadiationEvent != NULL) {
|
||||
if (newRadiationEvent != nullptr) {
|
||||
_queue_clear_type(EVENT_TYPE_RADIATION, _clear_rad_damage);
|
||||
newRadiationEvent->radiationLevel = radiationEvent->radiationLevel;
|
||||
newRadiationEvent->isHealing = 1;
|
||||
@@ -627,7 +647,7 @@ int radiationEventProcess(Object* obj, void* data)
|
||||
int radiationEventRead(File* stream, void** dataPtr)
|
||||
{
|
||||
RadiationEvent* radiationEvent = (RadiationEvent*)internal_malloc(sizeof(*radiationEvent));
|
||||
if (radiationEvent == NULL) {
|
||||
if (radiationEvent == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -657,7 +677,7 @@ int radiationEventWrite(File* stream, void* data)
|
||||
// 0x42D82C
|
||||
int critterGetDamageType(Object* obj)
|
||||
{
|
||||
if ((obj->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -669,6 +689,15 @@ int critterGetDamageType(Object* obj)
|
||||
return proto->critter.data.damageType;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x42D860
|
||||
static int critter_kill_count_clear()
|
||||
{
|
||||
memset(gKillsByType, 0, sizeof(gKillsByType));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x42D878
|
||||
int killsIncByType(int killType)
|
||||
{
|
||||
@@ -723,7 +752,7 @@ int critterGetKillType(Object* obj)
|
||||
return KILL_TYPE_MAN;
|
||||
}
|
||||
|
||||
if ((obj->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -741,7 +770,7 @@ char* killTypeGetName(int killType)
|
||||
MessageListItem messageListItem;
|
||||
return getmsg(&gProtoMessageList, &messageListItem, 1450 + killType);
|
||||
} else {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
return byte_501494;
|
||||
@@ -756,7 +785,7 @@ char* killTypeGetDescription(int killType)
|
||||
MessageListItem messageListItem;
|
||||
return getmsg(&gProtoMessageList, &messageListItem, 1469 + killType);
|
||||
} else {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
return byte_501494;
|
||||
@@ -766,7 +795,7 @@ char* killTypeGetDescription(int killType)
|
||||
// 0x42D9F4
|
||||
int _critter_heal_hours(Object* critter, int a2)
|
||||
{
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -788,7 +817,7 @@ static int _critterClearObjDrugs(Object* obj, void* data)
|
||||
// 0x42DA64
|
||||
void critterKill(Object* critter, int anim, bool a3)
|
||||
{
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -800,20 +829,20 @@ void critterKill(Object* critter, int anim, bool a3)
|
||||
bool shouldChangeFid = false;
|
||||
int fid;
|
||||
if (_critter_is_prone(critter)) {
|
||||
int current = (critter->fid & 0xFF0000) >> 16;
|
||||
int current = FID_ANIM_TYPE(critter->fid);
|
||||
if (current == ANIM_FALL_BACK || current == ANIM_FALL_FRONT) {
|
||||
bool back = false;
|
||||
if (current == ANIM_FALL_BACK) {
|
||||
back = true;
|
||||
} else {
|
||||
fid = buildFid(1, critter->fid & 0xFFF, ANIM_FALL_FRONT_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, ANIM_FALL_FRONT_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
if (!artExists(fid)) {
|
||||
back = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (back) {
|
||||
fid = buildFid(1, critter->fid & 0xFFF, ANIM_FALL_BACK_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, ANIM_FALL_BACK_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
}
|
||||
|
||||
shouldChangeFid = true;
|
||||
@@ -828,12 +857,12 @@ void critterKill(Object* critter, int anim, bool a3)
|
||||
anim = LAST_SF_DEATH_ANIM;
|
||||
}
|
||||
|
||||
fid = buildFid(1, critter->fid & 0xFFF, anim, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, anim, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
_obj_fix_violence_settings(&fid);
|
||||
if (!artExists(fid)) {
|
||||
debugPrint("\nError: Critter Kill: Can't match fid!");
|
||||
|
||||
fid = buildFid(1, critter->fid & 0xFFF, ANIM_FALL_BACK_BLOOD_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, ANIM_FALL_BACK_BLOOD_SF, (critter->fid & 0xF000) >> 12, critter->rotation + 1);
|
||||
_obj_fix_violence_settings(&fid);
|
||||
}
|
||||
|
||||
@@ -850,7 +879,7 @@ void critterKill(Object* critter, int anim, bool a3)
|
||||
rectUnion(&updatedRect, &tempRect, &updatedRect);
|
||||
}
|
||||
|
||||
if (!_critter_flag_check(critter->pid, 2048)) {
|
||||
if (!_critter_flag_check(critter->pid, CRITTER_FLAT)) {
|
||||
critter->flags |= OBJECT_NO_BLOCK;
|
||||
_obj_toggle_flat(critter, &tempRect);
|
||||
}
|
||||
@@ -873,7 +902,7 @@ void critterKill(Object* critter, int anim, bool a3)
|
||||
_critterClearObj = critter;
|
||||
_queue_clear_type(EVENT_TYPE_DRUG, _critterClearObjDrugs);
|
||||
|
||||
_item_destroy_all_hidden(critter);
|
||||
itemDestroyAllHidden(critter);
|
||||
|
||||
if (a3) {
|
||||
tileWindowRefreshRect(&updatedRect, elevation);
|
||||
@@ -898,11 +927,11 @@ int critterGetExp(Object* critter)
|
||||
// 0x42DCDC
|
||||
bool critterIsActive(Object* critter)
|
||||
{
|
||||
if (critter == NULL) {
|
||||
if (critter == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -920,11 +949,11 @@ bool critterIsActive(Object* critter)
|
||||
// 0x42DD18
|
||||
bool critterIsDead(Object* critter)
|
||||
{
|
||||
if (critter == NULL) {
|
||||
if (critter == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -942,11 +971,11 @@ bool critterIsDead(Object* critter)
|
||||
// 0x42DD58
|
||||
bool critterIsCrippled(Object* critter)
|
||||
{
|
||||
if (critter == NULL) {
|
||||
if (critter == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -956,31 +985,31 @@ bool critterIsCrippled(Object* critter)
|
||||
// 0x42DD80
|
||||
bool _critter_is_prone(Object* critter)
|
||||
{
|
||||
if (critter == NULL) {
|
||||
if (critter == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int anim = (critter->fid & 0xFF0000) >> 16;
|
||||
int anim = FID_ANIM_TYPE(critter->fid);
|
||||
|
||||
return (critter->data.critter.combat.results & (DAM_KNOCKED_OUT | DAM_KNOCKED_DOWN)) != 0
|
||||
|| anim >= FIRST_KNOCKDOWN_AND_DEATH_ANIM && anim <= LAST_KNOCKDOWN_AND_DEATH_ANIM
|
||||
|| anim >= FIRST_SF_DEATH_ANIM && anim <= LAST_SF_DEATH_ANIM;
|
||||
|| (anim >= FIRST_KNOCKDOWN_AND_DEATH_ANIM && anim <= LAST_KNOCKDOWN_AND_DEATH_ANIM)
|
||||
|| (anim >= FIRST_SF_DEATH_ANIM && anim <= LAST_SF_DEATH_ANIM);
|
||||
}
|
||||
|
||||
// critter_body_type
|
||||
// 0x42DDC4
|
||||
int critterGetBodyType(Object* critter)
|
||||
{
|
||||
if (critter == NULL) {
|
||||
if (critter == nullptr) {
|
||||
debugPrint("\nError: critter_body_type: pobj was NULL!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -993,7 +1022,7 @@ int critterGetBodyType(Object* critter)
|
||||
int gcdLoad(const char* path)
|
||||
{
|
||||
File* stream = fileOpen(path, "rb");
|
||||
if (stream == NULL) {
|
||||
if (stream == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1065,7 +1094,7 @@ int protoCritterDataRead(File* stream, CritterProtoData* critterData)
|
||||
int gcdSave(const char* path)
|
||||
{
|
||||
File* stream = fileOpen(path, "wb");
|
||||
if (stream == NULL) {
|
||||
if (stream == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1137,7 +1166,7 @@ void dudeEnableState(int state)
|
||||
proto->critter.data.flags |= (1 << state);
|
||||
|
||||
if (state == DUDE_STATE_SNEAKING) {
|
||||
sneakEventProcess(NULL, NULL);
|
||||
sneakEventProcess(nullptr, nullptr);
|
||||
}
|
||||
|
||||
indicatorBarRefresh();
|
||||
@@ -1168,7 +1197,7 @@ int sneakEventProcess(Object* obj, void* data)
|
||||
int time;
|
||||
|
||||
int sneak = skillGetValue(gDude, SKILL_SNEAK);
|
||||
if (skillRoll(gDude, SKILL_SNEAK, 0, NULL) < ROLL_SUCCESS) {
|
||||
if (skillRoll(gDude, SKILL_SNEAK, 0, nullptr) < ROLL_SUCCESS) {
|
||||
time = 600;
|
||||
_sneak_working = false;
|
||||
|
||||
@@ -1189,7 +1218,7 @@ int sneakEventProcess(Object* obj, void* data)
|
||||
_sneak_working = true;
|
||||
}
|
||||
|
||||
queueAddEvent(time, gDude, NULL, EVENT_TYPE_SNEAK);
|
||||
queueAddEvent(time, gDude, nullptr, EVENT_TYPE_SNEAK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1225,7 +1254,7 @@ int knockoutEventProcess(Object* obj, void* data)
|
||||
obj->data.critter.combat.results |= DAM_KNOCKED_DOWN;
|
||||
|
||||
if (isInCombat()) {
|
||||
obj->data.critter.combat.maneuver |= CRITTER_MANEUVER_0x01;
|
||||
obj->data.critter.combat.maneuver |= CRITTER_MANEUVER_ENGAGING;
|
||||
} else {
|
||||
_dude_standup(obj);
|
||||
}
|
||||
@@ -1236,7 +1265,7 @@ int knockoutEventProcess(Object* obj, void* data)
|
||||
// 0x42E460
|
||||
int _critter_wake_clear(Object* obj, void* data)
|
||||
{
|
||||
if ((obj->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1246,8 +1275,8 @@ int _critter_wake_clear(Object* obj, void* data)
|
||||
|
||||
obj->data.critter.combat.results &= ~(DAM_KNOCKED_OUT | DAM_KNOCKED_DOWN);
|
||||
|
||||
int fid = buildFid((obj->fid & 0xF000000) >> 24, obj->fid & 0xFFF, ANIM_STAND, (obj->fid & 0xF000) >> 12, obj->rotation + 1);
|
||||
objectSetFid(obj, fid, 0);
|
||||
int fid = buildFid(FID_TYPE(obj->fid), obj->fid & 0xFFF, ANIM_STAND, (obj->fid & 0xF000) >> 12, obj->rotation + 1);
|
||||
objectSetFid(obj, fid, nullptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1255,16 +1284,16 @@ int _critter_wake_clear(Object* obj, void* data)
|
||||
// 0x42E4C0
|
||||
int _critter_set_who_hit_me(Object* a1, Object* a2)
|
||||
{
|
||||
if (a1 == NULL) {
|
||||
if (a1 == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a2 != NULL && ((a2->fid & 0xF000000) >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (a2 != nullptr && FID_TYPE(a2->fid) != OBJ_TYPE_CRITTER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((a1->pid >> 24) == OBJ_TYPE_CRITTER) {
|
||||
if (a2 == NULL || a1->data.critter.combat.team != a2->data.critter.combat.team || statRoll(a1, STAT_INTELLIGENCE, -1, NULL) < 2 && (!objectIsPartyMember(a1) || !objectIsPartyMember(a2))) {
|
||||
if (PID_TYPE(a1->pid) == OBJ_TYPE_CRITTER) {
|
||||
if (a2 == nullptr || a1->data.critter.combat.team != a2->data.critter.combat.team || (statRoll(a1, STAT_INTELLIGENCE, -1, nullptr) < 2 && (!objectIsPartyMember(a1) || !objectIsPartyMember(a2)))) {
|
||||
a1->data.critter.combat.whoHitMe = a2;
|
||||
if (a2 == gDude) {
|
||||
reactionSetValue(a1, -3);
|
||||
@@ -1279,7 +1308,7 @@ int _critter_set_who_hit_me(Object* a1, Object* a2)
|
||||
bool _critter_can_obj_dude_rest()
|
||||
{
|
||||
bool v1 = false;
|
||||
if (!_wmMapCanRestHere(gElevation)) {
|
||||
if (!wmMapCanRestHere(gElevation)) {
|
||||
v1 = true;
|
||||
}
|
||||
|
||||
@@ -1319,7 +1348,7 @@ bool _critter_can_obj_dude_rest()
|
||||
// 0x42E62C
|
||||
int critterGetMovementPointCostAdjustedForCrippledLegs(Object* critter, int actionPoints)
|
||||
{
|
||||
if ((critter->pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1344,7 +1373,7 @@ bool critterIsEncumbered(Object* critter)
|
||||
// 0x42E690
|
||||
bool critterIsFleeing(Object* critter)
|
||||
{
|
||||
return critter != NULL
|
||||
return critter != nullptr
|
||||
? (critter->data.critter.combat.maneuver & CRITTER_MANUEVER_FLEEING) != 0
|
||||
: false;
|
||||
}
|
||||
@@ -1358,7 +1387,7 @@ bool _critter_flag_check(int pid, int flag)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((pid >> 24) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(pid) != OBJ_TYPE_CRITTER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1366,3 +1395,41 @@ bool _critter_flag_check(int pid, int flag)
|
||||
protoGetProto(pid, &proto);
|
||||
return (proto->critter.data.flags & flag) != 0;
|
||||
}
|
||||
|
||||
// 0x42E6F0
|
||||
void critter_flag_set(int pid, int flag)
|
||||
{
|
||||
Proto* proto;
|
||||
|
||||
if (pid == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (PID_TYPE(pid) != OBJ_TYPE_CRITTER) {
|
||||
return;
|
||||
}
|
||||
|
||||
protoGetProto(pid, &proto);
|
||||
|
||||
proto->critter.data.flags |= flag;
|
||||
}
|
||||
|
||||
// 0x42E71C
|
||||
void critter_flag_unset(int pid, int flag)
|
||||
{
|
||||
Proto* proto;
|
||||
|
||||
if (pid == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (PID_TYPE(pid) != OBJ_TYPE_CRITTER) {
|
||||
return;
|
||||
}
|
||||
|
||||
protoGetProto(pid, &proto);
|
||||
|
||||
proto->critter.data.flags &= ~flag;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "obj_types.h"
|
||||
#include "proto_types.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum DudeState {
|
||||
DUDE_STATE_SNEAKING = 0,
|
||||
DUDE_STATE_LEVEL_UP_AVAILABLE = 3,
|
||||
@@ -21,7 +23,7 @@ void critterProtoDataCopy(CritterProtoData* dest, CritterProtoData* src);
|
||||
int dudeSetName(const char* name);
|
||||
void dudeResetName();
|
||||
int critterGetHitPoints(Object* critter);
|
||||
int critterAdjustHitPoints(Object* critter, int amount);
|
||||
int critterAdjustHitPoints(Object* critter, int hp);
|
||||
int critterGetPoison(Object* critter);
|
||||
int critterAdjustPoison(Object* obj, int amount);
|
||||
int poisonEventProcess(Object* obj, void* data);
|
||||
@@ -68,5 +70,9 @@ int critterGetMovementPointCostAdjustedForCrippledLegs(Object* critter, int a2);
|
||||
bool critterIsEncumbered(Object* critter);
|
||||
bool critterIsFleeing(Object* a1);
|
||||
bool _critter_flag_check(int pid, int flag);
|
||||
void critter_flag_set(int pid, int flag);
|
||||
void critter_flag_unset(int pid, int flag);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CRITTER_H */
|
||||
|
||||
207
src/cycle.cc
@@ -1,14 +1,17 @@
|
||||
#include "cycle.h"
|
||||
|
||||
#include "color.h"
|
||||
#include "core.h"
|
||||
#include "game_config.h"
|
||||
#include "input.h"
|
||||
#include "palette.h"
|
||||
#include "settings.h"
|
||||
#include "svga.h"
|
||||
|
||||
#define COLOR_CYCLE_PERIOD_1 (200U)
|
||||
#define COLOR_CYCLE_PERIOD_2 (142U)
|
||||
#define COLOR_CYCLE_PERIOD_3 (100U)
|
||||
#define COLOR_CYCLE_PERIOD_4 (33U)
|
||||
namespace fallout {
|
||||
|
||||
static constexpr unsigned int kSlowCyclePeriod = 1000 / 5;
|
||||
static constexpr unsigned int kMediumCyclePeriod = 1000 / 7;
|
||||
static constexpr unsigned int kFastCyclePeriod = 1000 / 10;
|
||||
static constexpr unsigned int kVeryFastCyclePeriod = 1000 / 30;
|
||||
|
||||
// 0x51843C
|
||||
static int gColorCycleSpeedFactor = 1;
|
||||
@@ -19,7 +22,7 @@ static int gColorCycleSpeedFactor = 1;
|
||||
// Green.
|
||||
//
|
||||
// 0x518440
|
||||
static unsigned char _slime[12] = {
|
||||
static unsigned char slime[12] = {
|
||||
0, 108, 0,
|
||||
11, 115, 7,
|
||||
27, 123, 15,
|
||||
@@ -29,7 +32,7 @@ static unsigned char _slime[12] = {
|
||||
// Light gray?
|
||||
//
|
||||
// 0x51844C
|
||||
static unsigned char _shoreline[18] = {
|
||||
static unsigned char shoreline[18] = {
|
||||
83, 63, 43,
|
||||
75, 59, 43,
|
||||
67, 55, 39,
|
||||
@@ -41,7 +44,7 @@ static unsigned char _shoreline[18] = {
|
||||
// Orange.
|
||||
//
|
||||
// 0x51845E
|
||||
static unsigned char _fire_slow[15] = {
|
||||
static unsigned char fire_slow[15] = {
|
||||
255, 0, 0,
|
||||
215, 0, 0,
|
||||
147, 43, 11,
|
||||
@@ -52,7 +55,7 @@ static unsigned char _fire_slow[15] = {
|
||||
// Red.
|
||||
//
|
||||
// 0x51846D
|
||||
static unsigned char _fire_fast[15] = {
|
||||
static unsigned char fire_fast[15] = {
|
||||
71, 0, 0,
|
||||
123, 0, 0,
|
||||
179, 0, 0,
|
||||
@@ -63,7 +66,7 @@ static unsigned char _fire_fast[15] = {
|
||||
// Light blue.
|
||||
//
|
||||
// 0x51847C
|
||||
static unsigned char _monitors[15] = {
|
||||
static unsigned char monitors[15] = {
|
||||
107, 107, 111,
|
||||
99, 103, 127,
|
||||
87, 107, 143,
|
||||
@@ -79,38 +82,17 @@ static bool gColorCycleInitialized = false;
|
||||
// 0x518490
|
||||
static bool gColorCycleEnabled = false;
|
||||
|
||||
// 0x518494
|
||||
static int _slime_start = 0;
|
||||
|
||||
// 0x518498
|
||||
static int _shoreline_start = 0;
|
||||
|
||||
// 0x51849C
|
||||
static int _fire_slow_start = 0;
|
||||
|
||||
// 0x5184A0
|
||||
static int _fire_fast_start = 0;
|
||||
|
||||
// 0x5184A4
|
||||
static int _monitors_start = 0;
|
||||
|
||||
// 0x5184A8
|
||||
static unsigned char _bobber_red = 0;
|
||||
|
||||
// 0x5184A9
|
||||
static signed char _bobber_diff = -4;
|
||||
|
||||
// 0x56D7D0
|
||||
static unsigned int gColorCycleTimestamp3;
|
||||
static unsigned int last_cycle_fast;
|
||||
|
||||
// 0x56D7D4
|
||||
static unsigned int gColorCycleTimestamp1;
|
||||
static unsigned int last_cycle_slow;
|
||||
|
||||
// 0x56D7D8
|
||||
static unsigned int gColorCycleTimestamp2;
|
||||
static unsigned int last_cycle_medium;
|
||||
|
||||
// 0x56D7DC
|
||||
static unsigned int gColorCycleTimestamp4;
|
||||
static unsigned int last_cycle_very_fast;
|
||||
|
||||
// 0x42E780
|
||||
void colorCycleInit()
|
||||
@@ -119,33 +101,28 @@ void colorCycleInit()
|
||||
return;
|
||||
}
|
||||
|
||||
bool colorCycling;
|
||||
if (!configGetBool(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_COLOR_CYCLING_KEY, &colorCycling)) {
|
||||
colorCycling = true;
|
||||
}
|
||||
|
||||
if (!colorCycling) {
|
||||
if (!settings.system.color_cycling) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int index = 0; index < 12; index++) {
|
||||
_slime[index] >>= 2;
|
||||
slime[index] >>= 2;
|
||||
}
|
||||
|
||||
for (int index = 0; index < 18; index++) {
|
||||
_shoreline[index] >>= 2;
|
||||
shoreline[index] >>= 2;
|
||||
}
|
||||
|
||||
for (int index = 0; index < 15; index++) {
|
||||
_fire_slow[index] >>= 2;
|
||||
fire_slow[index] >>= 2;
|
||||
}
|
||||
|
||||
for (int index = 0; index < 15; index++) {
|
||||
_fire_fast[index] >>= 2;
|
||||
fire_fast[index] >>= 2;
|
||||
}
|
||||
|
||||
for (int index = 0; index < 15; index++) {
|
||||
_monitors[index] >>= 2;
|
||||
monitors[index] >>= 2;
|
||||
}
|
||||
|
||||
tickersAdd(colorCycleTicker);
|
||||
@@ -153,22 +130,17 @@ void colorCycleInit()
|
||||
gColorCycleInitialized = true;
|
||||
gColorCycleEnabled = true;
|
||||
|
||||
int cycleSpeedFactor;
|
||||
if (!configGetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CYCLE_SPEED_FACTOR_KEY, &cycleSpeedFactor)) {
|
||||
cycleSpeedFactor = 1;
|
||||
}
|
||||
|
||||
cycleSetSpeedFactor(cycleSpeedFactor);
|
||||
cycleSetSpeedFactor(settings.system.cycle_speed_factor);
|
||||
}
|
||||
|
||||
// 0x42E8CC
|
||||
void colorCycleReset()
|
||||
{
|
||||
if (gColorCycleInitialized) {
|
||||
gColorCycleTimestamp1 = 0;
|
||||
gColorCycleTimestamp2 = 0;
|
||||
gColorCycleTimestamp3 = 0;
|
||||
gColorCycleTimestamp4 = 0;
|
||||
last_cycle_slow = 0;
|
||||
last_cycle_medium = 0;
|
||||
last_cycle_fast = 0;
|
||||
last_cycle_very_fast = 0;
|
||||
tickersAdd(colorCycleTicker);
|
||||
gColorCycleEnabled = true;
|
||||
}
|
||||
@@ -206,12 +178,33 @@ bool colorCycleEnabled()
|
||||
void cycleSetSpeedFactor(int value)
|
||||
{
|
||||
gColorCycleSpeedFactor = value;
|
||||
configSetInt(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_CYCLE_SPEED_FACTOR_KEY, value);
|
||||
settings.system.cycle_speed_factor = value;
|
||||
}
|
||||
|
||||
// 0x42E97C
|
||||
void colorCycleTicker()
|
||||
{
|
||||
// 0x518494
|
||||
static int slime_start = 0;
|
||||
|
||||
// 0x518498
|
||||
static int shoreline_start = 0;
|
||||
|
||||
// 0x51849C
|
||||
static int fire_slow_start = 0;
|
||||
|
||||
// 0x5184A0
|
||||
static int fire_fast_start = 0;
|
||||
|
||||
// 0x5184A4
|
||||
static int monitors_start = 0;
|
||||
|
||||
// 0x5184A8
|
||||
static unsigned char bobber_red = 0;
|
||||
|
||||
// 0x5184A9
|
||||
static signed char bobber_diff = -4;
|
||||
|
||||
if (!gColorCycleEnabled) {
|
||||
return;
|
||||
}
|
||||
@@ -219,111 +212,111 @@ void colorCycleTicker()
|
||||
bool changed = false;
|
||||
|
||||
unsigned char* palette = _getSystemPalette();
|
||||
unsigned int time = _get_time();
|
||||
unsigned int time = getTicks();
|
||||
|
||||
if (getTicksBetween(time, gColorCycleTimestamp1) >= COLOR_CYCLE_PERIOD_1 * gColorCycleSpeedFactor) {
|
||||
if (getTicksBetween(time, last_cycle_slow) >= kSlowCyclePeriod * gColorCycleSpeedFactor) {
|
||||
changed = true;
|
||||
gColorCycleTimestamp1 = time;
|
||||
last_cycle_slow = time;
|
||||
|
||||
int paletteIndex = 229 * 3;
|
||||
|
||||
for (int index = _slime_start; index < 12; index++) {
|
||||
palette[paletteIndex++] = _slime[index];
|
||||
for (int index = slime_start; index < 12; index++) {
|
||||
palette[paletteIndex++] = slime[index];
|
||||
}
|
||||
|
||||
for (int index = 0; index < _slime_start; index++) {
|
||||
palette[paletteIndex++] = _slime[index];
|
||||
for (int index = 0; index < slime_start; index++) {
|
||||
palette[paletteIndex++] = slime[index];
|
||||
}
|
||||
|
||||
_slime_start -= 3;
|
||||
if (_slime_start < 0) {
|
||||
_slime_start = 9;
|
||||
slime_start -= 3;
|
||||
if (slime_start < 0) {
|
||||
slime_start = 9;
|
||||
}
|
||||
|
||||
paletteIndex = 248 * 3;
|
||||
|
||||
for (int index = _shoreline_start; index < 18; index++) {
|
||||
palette[paletteIndex++] = _shoreline[index];
|
||||
for (int index = shoreline_start; index < 18; index++) {
|
||||
palette[paletteIndex++] = shoreline[index];
|
||||
}
|
||||
|
||||
for (int index = 0; index < _shoreline_start; index++) {
|
||||
palette[paletteIndex++] = _shoreline[index];
|
||||
for (int index = 0; index < shoreline_start; index++) {
|
||||
palette[paletteIndex++] = shoreline[index];
|
||||
}
|
||||
|
||||
_shoreline_start -= 3;
|
||||
if (_shoreline_start < 0) {
|
||||
_shoreline_start = 15;
|
||||
shoreline_start -= 3;
|
||||
if (shoreline_start < 0) {
|
||||
shoreline_start = 15;
|
||||
}
|
||||
|
||||
paletteIndex = 238 * 3;
|
||||
|
||||
for (int index = _fire_slow_start; index < 15; index++) {
|
||||
palette[paletteIndex++] = _fire_slow[index];
|
||||
for (int index = fire_slow_start; index < 15; index++) {
|
||||
palette[paletteIndex++] = fire_slow[index];
|
||||
}
|
||||
|
||||
for (int index = 0; index < _fire_slow_start; index++) {
|
||||
palette[paletteIndex++] = _fire_slow[index];
|
||||
for (int index = 0; index < fire_slow_start; index++) {
|
||||
palette[paletteIndex++] = fire_slow[index];
|
||||
}
|
||||
|
||||
_fire_slow_start -= 3;
|
||||
if (_fire_slow_start < 0) {
|
||||
_fire_slow_start = 12;
|
||||
fire_slow_start -= 3;
|
||||
if (fire_slow_start < 0) {
|
||||
fire_slow_start = 12;
|
||||
}
|
||||
}
|
||||
|
||||
if (getTicksBetween(time, gColorCycleTimestamp2) >= COLOR_CYCLE_PERIOD_2 * gColorCycleSpeedFactor) {
|
||||
if (getTicksBetween(time, last_cycle_medium) >= kMediumCyclePeriod * gColorCycleSpeedFactor) {
|
||||
changed = true;
|
||||
gColorCycleTimestamp2 = time;
|
||||
last_cycle_medium = time;
|
||||
|
||||
int paletteIndex = 243 * 3;
|
||||
|
||||
for (int index = _fire_fast_start; index < 15; index++) {
|
||||
palette[paletteIndex++] = _fire_fast[index];
|
||||
for (int index = fire_fast_start; index < 15; index++) {
|
||||
palette[paletteIndex++] = fire_fast[index];
|
||||
}
|
||||
|
||||
for (int index = 0; index < _fire_fast_start; index++) {
|
||||
palette[paletteIndex++] = _fire_fast[index];
|
||||
for (int index = 0; index < fire_fast_start; index++) {
|
||||
palette[paletteIndex++] = fire_fast[index];
|
||||
}
|
||||
|
||||
_fire_fast_start -= 3;
|
||||
if (_fire_fast_start < 0) {
|
||||
_fire_fast_start = 12;
|
||||
fire_fast_start -= 3;
|
||||
if (fire_fast_start < 0) {
|
||||
fire_fast_start = 12;
|
||||
}
|
||||
}
|
||||
|
||||
if (getTicksBetween(time, gColorCycleTimestamp3) >= COLOR_CYCLE_PERIOD_3 * gColorCycleSpeedFactor) {
|
||||
if (getTicksBetween(time, last_cycle_fast) >= kFastCyclePeriod * gColorCycleSpeedFactor) {
|
||||
changed = true;
|
||||
gColorCycleTimestamp3 = time;
|
||||
last_cycle_fast = time;
|
||||
|
||||
int paletteIndex = 233 * 3;
|
||||
|
||||
for (int index = _monitors_start; index < 15; index++) {
|
||||
palette[paletteIndex++] = _monitors[index];
|
||||
for (int index = monitors_start; index < 15; index++) {
|
||||
palette[paletteIndex++] = monitors[index];
|
||||
}
|
||||
|
||||
for (int index = 0; index < _monitors_start; index++) {
|
||||
palette[paletteIndex++] = _monitors[index];
|
||||
for (int index = 0; index < monitors_start; index++) {
|
||||
palette[paletteIndex++] = monitors[index];
|
||||
}
|
||||
|
||||
_monitors_start -= 3;
|
||||
monitors_start -= 3;
|
||||
|
||||
if (_monitors_start < 0) {
|
||||
_monitors_start = 12;
|
||||
if (monitors_start < 0) {
|
||||
monitors_start = 12;
|
||||
}
|
||||
}
|
||||
|
||||
if (getTicksBetween(time, gColorCycleTimestamp4) >= COLOR_CYCLE_PERIOD_4 * gColorCycleSpeedFactor) {
|
||||
if (getTicksBetween(time, last_cycle_very_fast) >= kVeryFastCyclePeriod * gColorCycleSpeedFactor) {
|
||||
changed = true;
|
||||
gColorCycleTimestamp4 = time;
|
||||
last_cycle_very_fast = time;
|
||||
|
||||
if (_bobber_red == 0 || _bobber_red == 60) {
|
||||
_bobber_diff = -_bobber_diff;
|
||||
if (bobber_red == 0 || bobber_red == 60) {
|
||||
bobber_diff = -bobber_diff;
|
||||
}
|
||||
|
||||
_bobber_red += _bobber_diff;
|
||||
bobber_red += bobber_diff;
|
||||
|
||||
int paletteIndex = 254 * 3;
|
||||
palette[paletteIndex++] = _bobber_red;
|
||||
palette[paletteIndex++] = bobber_red;
|
||||
palette[paletteIndex++] = 0;
|
||||
palette[paletteIndex++] = 0;
|
||||
}
|
||||
@@ -332,3 +325,5 @@ void colorCycleTicker()
|
||||
paletteSetEntriesInRange(palette + 229 * 3, 229, 255);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef CYCLE_H
|
||||
#define CYCLE_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
void colorCycleInit();
|
||||
void colorCycleReset();
|
||||
void colorCycleFree();
|
||||
@@ -10,4 +12,6 @@ bool colorCycleEnabled();
|
||||
void cycleSetSpeedFactor(int value);
|
||||
void colorCycleTicker();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* CYCLE_H */
|
||||
|
||||
195
src/datafile.cc
@@ -1,10 +1,199 @@
|
||||
#include "datafile.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "color.h"
|
||||
#include "db.h"
|
||||
#include "memory_manager.h"
|
||||
#include "pcx.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// 0x5184AC
|
||||
DatafileLoader* gDatafileLoader = nullptr;
|
||||
|
||||
// 0x5184B0
|
||||
DatafileNameMangler* gDatafileNameMangler = datafileDefaultNameManglerImpl;
|
||||
|
||||
// 0x56D7E0
|
||||
unsigned char _pal[768];
|
||||
unsigned char gDatafilePalette[768];
|
||||
|
||||
// 0x42EE70
|
||||
char* datafileDefaultNameManglerImpl(char* path)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x42EE74
|
||||
void datafileSetNameMangler(DatafileNameMangler* mangler)
|
||||
{
|
||||
gDatafileNameMangler = mangler;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x42EE7C
|
||||
void datafileSetLoader(DatafileLoader* loader)
|
||||
{
|
||||
gDatafileLoader = loader;
|
||||
}
|
||||
|
||||
// 0x42EE84
|
||||
void sub_42EE84(unsigned char* data, unsigned char* palette, int width, int height)
|
||||
{
|
||||
unsigned char indexedPalette[256];
|
||||
|
||||
indexedPalette[0] = 0;
|
||||
for (int index = 1; index < 256; index++) {
|
||||
// TODO: Check.
|
||||
int r = palette[index * 3 + 2] >> 3;
|
||||
int g = palette[index * 3 + 1] >> 3;
|
||||
int b = palette[index * 3] >> 3;
|
||||
int colorTableIndex = (r << 10) | (g << 5) | b;
|
||||
indexedPalette[index] = _colorTable[colorTableIndex];
|
||||
}
|
||||
|
||||
int size = width * height;
|
||||
for (int index = 0; index < size; index++) {
|
||||
data[index] = indexedPalette[data[index]];
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x42EEF8
|
||||
void sub_42EEF8(unsigned char* data, unsigned char* palette, int width, int height)
|
||||
{
|
||||
unsigned char indexedPalette[256];
|
||||
|
||||
indexedPalette[0] = 0;
|
||||
for (int index = 1; index < 256; index++) {
|
||||
// TODO: Check.
|
||||
int r = palette[index * 3 + 2] >> 1;
|
||||
int g = palette[index * 3 + 1] >> 1;
|
||||
int b = palette[index * 3] >> 1;
|
||||
int colorTableIndex = (r << 10) | (g << 5) | b;
|
||||
indexedPalette[index] = _colorTable[colorTableIndex];
|
||||
}
|
||||
|
||||
int size = width * height;
|
||||
for (int index = 0; index < size; index++) {
|
||||
data[index] = indexedPalette[data[index]];
|
||||
}
|
||||
}
|
||||
|
||||
// 0x42EF60
|
||||
unsigned char* datafileReadRaw(char* path, int* widthPtr, int* heightPtr)
|
||||
{
|
||||
char* mangledPath = gDatafileNameMangler(path);
|
||||
char* dot = strrchr(mangledPath, '.');
|
||||
if (dot != nullptr) {
|
||||
if (compat_stricmp(dot + 1, "pcx") == 0) {
|
||||
return pcxRead(mangledPath, widthPtr, heightPtr, gDatafilePalette);
|
||||
}
|
||||
}
|
||||
|
||||
if (gDatafileLoader != nullptr) {
|
||||
return gDatafileLoader(mangledPath, gDatafilePalette, widthPtr, heightPtr);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 0x42EFCC
|
||||
unsigned char* datafileRead(char* path, int* widthPtr, int* heightPtr)
|
||||
{
|
||||
unsigned char* v1 = datafileReadRaw(path, widthPtr, heightPtr);
|
||||
if (v1 != nullptr) {
|
||||
sub_42EE84(v1, gDatafilePalette, *widthPtr, *heightPtr);
|
||||
}
|
||||
return v1;
|
||||
}
|
||||
|
||||
// NOTE: Unused
|
||||
//
|
||||
// 0x42EFF4
|
||||
unsigned char* sub_42EFF4(char* path)
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
unsigned char* v3 = datafileReadRaw(path, &width, &height);
|
||||
if (v3 != nullptr) {
|
||||
internal_free_safe(v3, __FILE__, __LINE__); // "..\\int\\DATAFILE.C", 148
|
||||
return gDatafilePalette;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x42F024
|
||||
void sub_42F024(unsigned char* data, int* widthPtr, int* heightPtr)
|
||||
{
|
||||
int width = *widthPtr;
|
||||
int height = *heightPtr;
|
||||
unsigned char* temp = (unsigned char*)internal_malloc_safe(width * height, __FILE__, __LINE__); // "..\\int\\DATAFILE.C", 157
|
||||
|
||||
// NOTE: Original code does not initialize `x`.
|
||||
int y = 0;
|
||||
int x = 0;
|
||||
unsigned char* src1 = data;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
if (*src1 == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned char* src2 = src1;
|
||||
for (x = 0; x < width; x++) {
|
||||
if (*src2 == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
*temp++ = *src2++;
|
||||
}
|
||||
|
||||
src1 += width;
|
||||
}
|
||||
|
||||
memcpy(data, temp, x * y);
|
||||
internal_free_safe(temp, __FILE__, __LINE__); // // "..\\int\\DATAFILE.C", 171
|
||||
}
|
||||
|
||||
// 0x42F0E4
|
||||
unsigned char* _datafileGetPalette()
|
||||
unsigned char* datafileGetPalette()
|
||||
{
|
||||
return _pal;
|
||||
return gDatafilePalette;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x42F0EC
|
||||
unsigned char* datafileLoad(char* path, int* sizePtr)
|
||||
{
|
||||
const char* mangledPath = gDatafileNameMangler(path);
|
||||
File* stream = fileOpen(mangledPath, "rb");
|
||||
if (stream == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int size = fileGetSize(stream);
|
||||
unsigned char* data = (unsigned char*)internal_malloc_safe(size, __FILE__, __LINE__); // "..\\int\\DATAFILE.C", 185
|
||||
if (data == nullptr) {
|
||||
// NOTE: This code is unreachable, internal_malloc_safe never fails.
|
||||
// Otherwise it leaks stream.
|
||||
*sizePtr = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fileRead(data, 1, size, stream);
|
||||
fileClose(stream);
|
||||
*sizePtr = size;
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,8 +1,28 @@
|
||||
#ifndef DATAFILE_H
|
||||
#define DATAFILE_H
|
||||
|
||||
extern unsigned char _pal[768];
|
||||
namespace fallout {
|
||||
|
||||
unsigned char* _datafileGetPalette();
|
||||
typedef unsigned char*(DatafileLoader)(char* path, unsigned char* palette, int* widthPtr, int* heightPtr);
|
||||
typedef char*(DatafileNameMangler)(char* path);
|
||||
|
||||
extern DatafileLoader* gDatafileLoader;
|
||||
extern DatafileNameMangler* gDatafileNameMangler;
|
||||
|
||||
extern unsigned char gDatafilePalette[768];
|
||||
|
||||
char* datafileDefaultNameManglerImpl(char* path);
|
||||
void datafileSetNameMangler(DatafileNameMangler* mangler);
|
||||
void datafileSetLoader(DatafileLoader* loader);
|
||||
void sub_42EE84(unsigned char* data, unsigned char* palette, int width, int height);
|
||||
void sub_42EEF8(unsigned char* data, unsigned char* palette, int width, int height);
|
||||
unsigned char* datafileReadRaw(char* path, int* widthPtr, int* heightPtr);
|
||||
unsigned char* datafileRead(char* path, int* widthPtr, int* heightPtr);
|
||||
unsigned char* sub_42EFF4(char* path);
|
||||
void sub_42F024(unsigned char* data, int* widthPtr, int* heightPtr);
|
||||
unsigned char* datafileGetPalette();
|
||||
unsigned char* datafileLoad(char* path, int* sizePtr);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* DATAFILE_H */
|
||||
|
||||
100
src/db.cc
@@ -1,12 +1,14 @@
|
||||
#include "db.h"
|
||||
|
||||
#include "platform_compat.h"
|
||||
#include "xfile.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "platform_compat.h"
|
||||
#include "xfile.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef struct FileList {
|
||||
XList xlist;
|
||||
struct FileList* next;
|
||||
@@ -17,7 +19,7 @@ static int _db_list_compare(const void* p1, const void* p2);
|
||||
// Generic file progress report handler.
|
||||
//
|
||||
// 0x51DEEC
|
||||
static FileReadProgressHandler* gFileReadProgressHandler = NULL;
|
||||
static FileReadProgressHandler* gFileReadProgressHandler = nullptr;
|
||||
|
||||
// Bytes read so far while tracking progress.
|
||||
//
|
||||
@@ -48,39 +50,29 @@ static FileList* gFileListHead;
|
||||
// 0x4C5D30
|
||||
int dbOpen(const char* filePath1, int a2, const char* filePath2, int a4)
|
||||
{
|
||||
if (filePath1 != NULL) {
|
||||
if (filePath1 != nullptr) {
|
||||
if (!xbaseOpen(filePath1)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (filePath2 != NULL) {
|
||||
if (filePath2 != nullptr) {
|
||||
xbaseOpen(filePath2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: This function simply returns 0, but it definitely accept one parameter
|
||||
// via eax, as seen at every call site. This value is ignored. It's impossible
|
||||
// to guess it's name.
|
||||
//
|
||||
// 0x4C5D54
|
||||
int _db_current(int a1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4C5D58
|
||||
bool _db_total()
|
||||
int db_total()
|
||||
{
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 0x4C5D60
|
||||
void dbExit()
|
||||
{
|
||||
xbaseReopenAll(NULL);
|
||||
xbaseReopenAll(nullptr);
|
||||
}
|
||||
|
||||
// TODO: sizePtr should be long*.
|
||||
@@ -92,7 +84,7 @@ int dbGetFileSize(const char* filePath, int* sizePtr)
|
||||
assert(sizePtr); // "de", "db.c", 109
|
||||
|
||||
File* stream = xfileOpen(filePath, "rb");
|
||||
if (stream == NULL) {
|
||||
if (stream == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -110,12 +102,12 @@ int dbGetFileContents(const char* filePath, void* ptr)
|
||||
assert(ptr); // "buf", "db.c", 142
|
||||
|
||||
File* stream = xfileOpen(filePath, "rb");
|
||||
if (stream == NULL) {
|
||||
if (stream == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
long size = xfileGetSize(stream);
|
||||
if (gFileReadProgressHandler != NULL) {
|
||||
if (gFileReadProgressHandler != nullptr) {
|
||||
unsigned char* byteBuffer = (unsigned char*)ptr;
|
||||
|
||||
long remainingSize = size;
|
||||
@@ -174,7 +166,7 @@ int filePrintFormatted(File* stream, const char* format, ...)
|
||||
// 0x4C5F24
|
||||
int fileReadChar(File* stream)
|
||||
{
|
||||
if (gFileReadProgressHandler != NULL) {
|
||||
if (gFileReadProgressHandler != nullptr) {
|
||||
int ch = xfileReadChar(stream);
|
||||
|
||||
gFileReadProgressBytesRead++;
|
||||
@@ -192,9 +184,9 @@ int fileReadChar(File* stream)
|
||||
// 0x4C5F70
|
||||
char* fileReadString(char* string, size_t size, File* stream)
|
||||
{
|
||||
if (gFileReadProgressHandler != NULL) {
|
||||
if (xfileReadString(string, size, stream) == NULL) {
|
||||
return NULL;
|
||||
if (gFileReadProgressHandler != nullptr) {
|
||||
if (xfileReadString(string, size, stream) == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gFileReadProgressBytesRead += strlen(string);
|
||||
@@ -218,7 +210,7 @@ int fileWriteString(const char* string, File* stream)
|
||||
// 0x4C5FFC
|
||||
size_t fileRead(void* ptr, size_t size, size_t count, File* stream)
|
||||
{
|
||||
if (gFileReadProgressHandler != NULL) {
|
||||
if (gFileReadProgressHandler != nullptr) {
|
||||
unsigned char* byteBuffer = (unsigned char*)ptr;
|
||||
|
||||
size_t totalBytesRead = 0;
|
||||
@@ -334,7 +326,7 @@ int fileReadInt32(File* stream, int* valuePtr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
*valuePtr = ((value >> 24) & 0xFF) | ((value >> 8) & 0xFF00) | ((value << 8) & 0xFF0000) | ((value << 24) & 0xFF000000);
|
||||
*valuePtr = ((value & 0xFF000000) >> 24) | ((value & 0xFF0000) >> 8) | ((value & 0xFF00) << 8) | ((value & 0xFF) << 24);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -507,7 +499,7 @@ int fileReadInt32List(File* stream, int* arr, int count)
|
||||
|
||||
for (int index = 0; index < count; index++) {
|
||||
int value = arr[index];
|
||||
arr[index] = ((value >> 24) & 0xFF) | ((value >> 8) & 0xFF00) | ((value << 8) & 0xFF0000) | ((value << 24) & 0xFF000000);
|
||||
arr[index] = ((value & 0xFF000000) >> 24) | ((value & 0xFF0000) >> 8) | ((value & 0xFF00) << 8) | ((value & 0xFF) << 24);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -610,7 +602,7 @@ int fileWriteUInt32List(File* stream, unsigned int* arr, int count)
|
||||
int fileNameListInit(const char* pattern, char*** fileNameListPtr, int a3, int a4)
|
||||
{
|
||||
FileList* fileList = (FileList*)malloc(sizeof(*fileList));
|
||||
if (fileList == NULL) {
|
||||
if (fileList == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -638,31 +630,23 @@ int fileNameListInit(const char* pattern, char*** fileNameListPtr, int a3, int a
|
||||
}
|
||||
}
|
||||
|
||||
bool v1 = *pattern == '*';
|
||||
bool isWildcard = *pattern == '*';
|
||||
|
||||
for (int index = 0; index < fileNamesLength; index += 1) {
|
||||
const char* name = xlist->fileNames[index];
|
||||
char* name = xlist->fileNames[index];
|
||||
char dir[COMPAT_MAX_DIR];
|
||||
char fileName[COMPAT_MAX_FNAME];
|
||||
char extension[COMPAT_MAX_EXT];
|
||||
compat_splitpath(name, NULL, dir, fileName, extension);
|
||||
compat_windows_path_to_native(name);
|
||||
compat_splitpath(name, nullptr, dir, fileName, extension);
|
||||
|
||||
bool v2 = false;
|
||||
if (v1) {
|
||||
char* pch = dir;
|
||||
while (*pch != '\0' && *pch != '\\') {
|
||||
pch++;
|
||||
}
|
||||
v2 = *pch != '\0';
|
||||
}
|
||||
|
||||
if (!v2) {
|
||||
if (!isWildcard || *dir == '\0' || (strchr(dir, '\\') == nullptr && strchr(dir, '/') == nullptr)) {
|
||||
// NOTE: Quick and dirty fix to buffer overflow. See RE to
|
||||
// understand the problem.
|
||||
char path[COMPAT_MAX_PATH];
|
||||
sprintf(path, "%s%s", fileName, extension);
|
||||
snprintf(path, sizeof(path), "%s%s", fileName, extension);
|
||||
free(xlist->fileNames[length]);
|
||||
xlist->fileNames[length] = strdup(path);
|
||||
xlist->fileNames[length] = compat_strdup(path);
|
||||
length++;
|
||||
}
|
||||
}
|
||||
@@ -679,7 +663,7 @@ int fileNameListInit(const char* pattern, char*** fileNameListPtr, int a3, int a
|
||||
// 0x4C6868
|
||||
void fileNameListFree(char*** fileNameListPtr, int a2)
|
||||
{
|
||||
if (gFileListHead == NULL) {
|
||||
if (gFileListHead == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -688,7 +672,7 @@ void fileNameListFree(char*** fileNameListPtr, int a2)
|
||||
while (*fileNameListPtr != currentFileList->xlist.fileNames) {
|
||||
previousFileList = currentFileList;
|
||||
currentFileList = currentFileList->next;
|
||||
if (currentFileList == NULL) {
|
||||
if (currentFileList == nullptr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -704,14 +688,6 @@ void fileNameListFree(char*** fileNameListPtr, int a2)
|
||||
free(currentFileList);
|
||||
}
|
||||
|
||||
// NOTE: This function does nothing. It was probably used to set memory procs
|
||||
// for building file name list.
|
||||
//
|
||||
// 0x4C68B8
|
||||
void _db_register_mem(MallocProc* mallocProc, StrdupProc* strdupProc, FreeProc* freeProc)
|
||||
{
|
||||
}
|
||||
|
||||
// TODO: Return type should be long.
|
||||
//
|
||||
// 0x4C68BC
|
||||
@@ -723,25 +699,19 @@ int fileGetSize(File* stream)
|
||||
// 0x4C68C4
|
||||
void fileSetReadProgressHandler(FileReadProgressHandler* handler, int size)
|
||||
{
|
||||
if (handler != NULL && size != 0) {
|
||||
if (handler != nullptr && size != 0) {
|
||||
gFileReadProgressHandler = handler;
|
||||
gFileReadProgressChunkSize = size;
|
||||
} else {
|
||||
gFileReadProgressHandler = NULL;
|
||||
gFileReadProgressHandler = nullptr;
|
||||
gFileReadProgressChunkSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This function is called when fallout2.cfg has "hashing" enabled, but
|
||||
// it does nothing. It's impossible to guess it's name.
|
||||
//
|
||||
// 0x4C68E4
|
||||
void _db_enable_hash_table_()
|
||||
{
|
||||
}
|
||||
|
||||
// 0x4C68E8
|
||||
int _db_list_compare(const void* p1, const void* p2)
|
||||
{
|
||||
return compat_stricmp(*(const char**)p1, *(const char**)p2);
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
12
src/db.h
@@ -1,18 +1,18 @@
|
||||
#ifndef DB_H
|
||||
#define DB_H
|
||||
|
||||
#include "memory_defs.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#include "xfile.h"
|
||||
|
||||
#include <stddef.h>
|
||||
namespace fallout {
|
||||
|
||||
typedef XFile File;
|
||||
typedef void FileReadProgressHandler();
|
||||
typedef char* StrdupProc(const char* string);
|
||||
|
||||
int dbOpen(const char* filePath1, int a2, const char* filePath2, int a4);
|
||||
int _db_current(int a1);
|
||||
bool _db_total();
|
||||
int db_total();
|
||||
void dbExit();
|
||||
int dbGetFileSize(const char* filePath, int* sizePtr);
|
||||
int dbGetFileContents(const char* filePath, void* ptr);
|
||||
@@ -60,9 +60,9 @@ int _db_fwriteLongCount(File* stream, int* arr, int count);
|
||||
int fileWriteUInt32List(File* stream, unsigned int* arr, int count);
|
||||
int fileNameListInit(const char* pattern, char*** fileNames, int a3, int a4);
|
||||
void fileNameListFree(char*** fileNames, int a2);
|
||||
void _db_register_mem(MallocProc* mallocProc, StrdupProc* strdupProc, FreeProc* freeProc);
|
||||
int fileGetSize(File* stream);
|
||||
void fileSetReadProgressHandler(FileReadProgressHandler* handler, int size);
|
||||
void _db_enable_hash_table_();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* DB_H */
|
||||
|
||||
587
src/dbox.cc
@@ -1,6 +1,8 @@
|
||||
#ifndef DBOX_H
|
||||
#define DBOX_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum DialogBoxOptions {
|
||||
DIALOG_BOX_LARGE = 0x01,
|
||||
DIALOG_BOX_MEDIUM = 0x02,
|
||||
@@ -14,4 +16,6 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
|
||||
int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLength, int x, int y, int flags);
|
||||
int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLength, int x, int y, int flags);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* DBOX_H */
|
||||
|
||||
162
src/debug.cc
@@ -1,28 +1,28 @@
|
||||
#include "debug.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
#include "window_manager_private.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <SDL.h>
|
||||
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
#include "window_manager_private.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
static int _debug_puts(char* string);
|
||||
static void _debug_clear();
|
||||
static int _debug_mono(char* string);
|
||||
static int _debug_log(char* string);
|
||||
static int _debug_screen(char* string);
|
||||
static void _debug_putc(char ch);
|
||||
static void _debug_putc(int ch);
|
||||
static void _debug_scroll();
|
||||
|
||||
// 0x51DEF8
|
||||
static FILE* _fd = NULL;
|
||||
static FILE* _fd = nullptr;
|
||||
|
||||
// 0x51DEFC
|
||||
static int _curx = 0;
|
||||
@@ -31,7 +31,7 @@ static int _curx = 0;
|
||||
static int _cury = 0;
|
||||
|
||||
// 0x51DF04
|
||||
static DebugPrintProc* gDebugPrintProc = NULL;
|
||||
static DebugPrintProc* gDebugPrintProc = nullptr;
|
||||
|
||||
// 0x4C6CD0
|
||||
void _GNW_debug_init()
|
||||
@@ -43,9 +43,9 @@ void _GNW_debug_init()
|
||||
void _debug_register_mono()
|
||||
{
|
||||
if (gDebugPrintProc != _debug_mono) {
|
||||
if (_fd != NULL) {
|
||||
if (_fd != nullptr) {
|
||||
fclose(_fd);
|
||||
_fd = NULL;
|
||||
_fd = nullptr;
|
||||
}
|
||||
|
||||
gDebugPrintProc = _debug_mono;
|
||||
@@ -56,8 +56,8 @@ void _debug_register_mono()
|
||||
// 0x4C6D18
|
||||
void _debug_register_log(const char* fileName, const char* mode)
|
||||
{
|
||||
if ((mode[0] == 'w' && mode[1] == 'a') && mode[1] == 't') {
|
||||
if (_fd != NULL) {
|
||||
if ((mode[0] == 'w' || mode[0] == 'a') && mode[1] == 't') {
|
||||
if (_fd != nullptr) {
|
||||
fclose(_fd);
|
||||
}
|
||||
|
||||
@@ -70,9 +70,9 @@ void _debug_register_log(const char* fileName, const char* mode)
|
||||
void _debug_register_screen()
|
||||
{
|
||||
if (gDebugPrintProc != _debug_screen) {
|
||||
if (_fd != NULL) {
|
||||
if (_fd != nullptr) {
|
||||
fclose(_fd);
|
||||
_fd = NULL;
|
||||
_fd = nullptr;
|
||||
}
|
||||
|
||||
gDebugPrintProc = _debug_screen;
|
||||
@@ -83,12 +83,12 @@ void _debug_register_screen()
|
||||
void _debug_register_env()
|
||||
{
|
||||
const char* type = getenv("DEBUGACTIVE");
|
||||
if (type == NULL) {
|
||||
if (type == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
char* copy = (char*)internal_malloc(strlen(type) + 1);
|
||||
if (copy == NULL) {
|
||||
if (copy == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -104,14 +104,8 @@ void _debug_register_env()
|
||||
// NOTE: Uninline.
|
||||
_debug_register_screen();
|
||||
} else if (strcmp(copy, "gnw") == 0) {
|
||||
if (gDebugPrintProc != _win_debug) {
|
||||
if (_fd != NULL) {
|
||||
fclose(_fd);
|
||||
_fd = NULL;
|
||||
}
|
||||
|
||||
gDebugPrintProc = _win_debug;
|
||||
}
|
||||
// NOTE: Uninline.
|
||||
_debug_register_func(_win_debug);
|
||||
}
|
||||
|
||||
internal_free(copy);
|
||||
@@ -121,9 +115,9 @@ void _debug_register_env()
|
||||
void _debug_register_func(DebugPrintProc* proc)
|
||||
{
|
||||
if (gDebugPrintProc != proc) {
|
||||
if (_fd != NULL) {
|
||||
if (_fd != nullptr) {
|
||||
fclose(_fd);
|
||||
_fd = NULL;
|
||||
_fd = nullptr;
|
||||
}
|
||||
|
||||
gDebugPrintProc = proc;
|
||||
@@ -138,20 +132,14 @@ int debugPrint(const char* format, ...)
|
||||
|
||||
int rc;
|
||||
|
||||
if (gDebugPrintProc != NULL) {
|
||||
if (gDebugPrintProc != nullptr) {
|
||||
char string[260];
|
||||
vsprintf(string, format, args);
|
||||
vsnprintf(string, sizeof(string), format, args);
|
||||
|
||||
rc = gDebugPrintProc(string);
|
||||
} else {
|
||||
#ifdef _DEBUG
|
||||
char string[260];
|
||||
vsprintf(string, format, args);
|
||||
#ifdef _WIN32
|
||||
OutputDebugStringA(string);
|
||||
#else
|
||||
printf("%s", string);
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, format, args);
|
||||
#endif
|
||||
rc = -1;
|
||||
}
|
||||
@@ -164,7 +152,7 @@ int debugPrint(const char* format, ...)
|
||||
// 0x4C6F94
|
||||
static int _debug_puts(char* string)
|
||||
{
|
||||
if (gDebugPrintProc != NULL) {
|
||||
if (gDebugPrintProc != nullptr) {
|
||||
return gDebugPrintProc(string);
|
||||
}
|
||||
|
||||
@@ -174,7 +162,28 @@ static int _debug_puts(char* string)
|
||||
// 0x4C6FAC
|
||||
static void _debug_clear()
|
||||
{
|
||||
// TODO: Something with segments.
|
||||
char* buffer;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
buffer = nullptr;
|
||||
|
||||
if (gDebugPrintProc == _debug_mono) {
|
||||
buffer = (char*)0xB0000;
|
||||
} else if (gDebugPrintProc == _debug_screen) {
|
||||
buffer = (char*)0xB8000;
|
||||
}
|
||||
|
||||
if (buffer != nullptr) {
|
||||
for (y = 0; y < 25; y++) {
|
||||
for (x = 0; x < 80; x++) {
|
||||
*buffer++ = ' ';
|
||||
*buffer++ = 7;
|
||||
}
|
||||
}
|
||||
_cury = 0;
|
||||
_curx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C7004
|
||||
@@ -193,7 +202,7 @@ static int _debug_mono(char* string)
|
||||
static int _debug_log(char* string)
|
||||
{
|
||||
if (gDebugPrintProc == _debug_log) {
|
||||
if (_fd == NULL) {
|
||||
if (_fd == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -220,21 +229,80 @@ static int _debug_screen(char* string)
|
||||
}
|
||||
|
||||
// 0x4C709C
|
||||
static void _debug_putc(char ch)
|
||||
static void _debug_putc(int ch)
|
||||
{
|
||||
// TODO: Something with segments.
|
||||
char* buffer;
|
||||
|
||||
buffer = (char*)0xB0000;
|
||||
|
||||
switch (ch) {
|
||||
case 7:
|
||||
printf("\x07");
|
||||
return;
|
||||
case 8:
|
||||
if (_curx > 0) {
|
||||
_curx--;
|
||||
buffer += 2 * _curx + 2 * 80 * _cury;
|
||||
*buffer++ = ' ';
|
||||
*buffer = 7;
|
||||
}
|
||||
return;
|
||||
case 9:
|
||||
do {
|
||||
_debug_putc(' ');
|
||||
} while ((_curx - 1) % 4 != 0);
|
||||
return;
|
||||
case 13:
|
||||
_curx = 0;
|
||||
return;
|
||||
default:
|
||||
buffer += 2 * _curx + 2 * 80 * _cury;
|
||||
*buffer++ = ch;
|
||||
*buffer = 7;
|
||||
_curx++;
|
||||
if (_curx < 80) {
|
||||
return;
|
||||
}
|
||||
// FALLTHROUGH
|
||||
case 10:
|
||||
_curx = 0;
|
||||
_cury++;
|
||||
if (_cury > 24) {
|
||||
_cury = 24;
|
||||
_debug_scroll();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C71AC
|
||||
void _debug_scroll()
|
||||
static void _debug_scroll()
|
||||
{
|
||||
// TODO: Something with segments.
|
||||
char* buffer;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
buffer = (char*)0xB0000;
|
||||
|
||||
for (y = 0; y < 24; y++) {
|
||||
for (x = 0; x < 80 * 2; x++) {
|
||||
buffer[0] = buffer[80 * 2];
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; x < 80; x++) {
|
||||
*buffer++ = ' ';
|
||||
*buffer++ = 7;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C71E8
|
||||
void _debug_exit(void)
|
||||
{
|
||||
if (_fd != NULL) {
|
||||
if (_fd != nullptr) {
|
||||
fclose(_fd);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef int(DebugPrintProc)(char* string);
|
||||
|
||||
void _GNW_debug_init();
|
||||
@@ -12,4 +14,6 @@ void _debug_register_func(DebugPrintProc* proc);
|
||||
int debugPrint(const char* format, ...);
|
||||
void _debug_exit(void);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* DEBUG_H */
|
||||
|
||||
11
src/delay.cc
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "delay.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
void delay_ms(int ms)
|
||||
{
|
||||
if (ms <= 0) {
|
||||
return;
|
||||
}
|
||||
SDL_Delay(ms);
|
||||
}
|
||||