lsnes rr2-β24
[lsnes.git] / src / emulation / sky / level.cpp
blob15a31b722cf9ed2016443d06fa57da1b9975a824
1 #include "level.hpp"
2 #include "util.hpp"
3 #include "lzs.hpp"
4 #include "physics.hpp"
5 #include "library/string.hpp"
6 #include "library/sha256.hpp"
7 #include "library/zip.hpp"
9 namespace sky
11 struct tile_output_stream : public output_stream
13 tile_output_stream(std::vector<tile>& _out)
14 : out(_out)
16 polarity = false;
18 void put(unsigned char byte)
20 polarity = !polarity;
21 if(polarity)
22 buffered = byte;
23 else
24 out.push_back(tile(combine(buffered, byte)));
26 private:
27 std::vector<tile>& out;
28 uint8_t buffered;
29 bool polarity;
32 level::level()
34 memset(this, 0, sizeof(*this));
35 length = 0;
36 gravity = 8;
37 o2_amount = 1;
38 fuel_amount = 1;
41 level::level(rom_level& data)
43 length = data.get_length();
44 gravity = data.get_gravity();
45 o2_amount = data.get_o2_amount();
46 fuel_amount = data.get_fuel_amount();
47 for(unsigned i = 0; i < 72; i++)
48 palette[i] = data.get_palette_color(i);
49 for(unsigned i = 0; i < sizeof(tiles) / sizeof(tiles[0]); i++)
50 tiles[i] = data.get_tile(i).rawtile();
53 rom_level::rom_level(const std::vector<char>& data, size_t offset, size_t length)
55 gravity = combine(access_array(data, offset + 0), access_array(data, offset + 1));
56 fuel_amount = combine(access_array(data, offset + 2), access_array(data, offset + 3));
57 o2_amount = combine(access_array(data, offset + 4), access_array(data, offset + 5));
58 //Next 216 bytes are the palette table.
59 for(unsigned i = 0; i < 72; i++) {
60 uint8_t r = expand_color(access_array(data, offset + 3 * i + 6));
61 uint8_t g = expand_color(access_array(data, offset + 3 * i + 7));
62 uint8_t b = expand_color(access_array(data, offset + 3 * i + 8));
63 palette[i] = ((uint32_t)r << 16) | ((uint32_t)g << 8) | ((uint32_t)b);
65 //After 222 bytes, there is compressed data.
66 vector_input_stream in(data, offset + 222);
67 tile_output_stream out(tiles);
68 lzs_decompress(in, out, length >> 1 << 1);
71 tile level::at(uint32_t lpos, uint16_t hpos)
73 if(hpos < 12160 || hpos >= 53376)
74 return tile();
75 else {
76 size_t ptr = 7 * static_cast<size_t>(lpos >> 16) + (hpos - 12160) / 5888;
77 ptr = ptr * 2 + (reinterpret_cast<uint8_t*>(tiles) - reinterpret_cast<uint8_t*>(this));
78 ptr &= 0xFFFF;
79 return tile(*reinterpret_cast<uint16_t*>(reinterpret_cast<uint8_t*>(this) + ptr));
83 tile level::at_tile(int32_t l, int16_t h)
85 if(h < -3 || h > 3)
86 return tile();
87 else {
88 size_t ptr = 7 * static_cast<size_t>(l) + h + 3;
89 ptr = ptr * 2 + (reinterpret_cast<uint8_t*>(tiles) - reinterpret_cast<uint8_t*>(this));
90 ptr &= 0xFFFF;
91 return tile(*reinterpret_cast<uint16_t*>(reinterpret_cast<uint8_t*>(this) + ptr));
95 bool level::collides(uint32_t lpos, uint16_t hpos, int16_t vpos)
97 tile a = at(lpos, hpos - 1792);
98 tile b = at(lpos, hpos + 1792);
99 //Floor collision check.
100 if(a.is_colliding_floor(0, vpos) || b.is_colliding_floor(0, vpos))
101 return true;
102 if(a.is_block() || b.is_block()) {
103 tile c = at(lpos, hpos);
104 int hchunk = 23 - (hpos / 128 - 49) % 46;
105 int16_t offset = -5888;
106 if(hchunk < 0) {
107 hchunk = 1 - hchunk;
108 offset = 5888;
110 if(c.is_colliding(hchunk, vpos))
111 return true;
112 tile d = at(lpos, hpos + offset);
113 if(d.is_colliding(47 - hchunk, vpos))
114 return true;
116 return false;
118 bool level::in_pipe(uint32_t lpos, uint16_t hpos, int16_t vpos)
120 int hchunk = 23 - (hpos / 128 - 49) % 46;
121 if(hchunk <= 0)
122 hchunk = 1 - hchunk;
123 return at(lpos, hpos).in_pipe(hchunk, vpos);
126 inline void hash_uint16(sha256& h, uint16_t v)
128 uint8_t buf[2];
129 buf[0] = v;
130 buf[1] = v >> 8;
131 h.write(buf, 2);
134 void rom_level::sha256_hash(uint8_t* buffer)
136 sha256 h;
137 hash_uint16(h, gravity);
138 hash_uint16(h, fuel_amount);
139 hash_uint16(h, o2_amount);
140 for(auto i : tiles)
141 hash_uint16(h, i.rawtile());
142 h.read(buffer);
145 roads_lzs::roads_lzs()
147 for(size_t i = 0; i < 31; i++)
148 l[i] = NULL;
151 roads_lzs::roads_lzs(const std::vector<char>& file)
153 for(size_t i = 0; i < 31; i++)
154 l[i] = NULL;
155 for(size_t i = 0; i < 31; i++) {
156 try {
157 uint16_t off = combine(access_array(file, 4 * i + 0), access_array(file, 4 * i + 1));
158 uint16_t len = combine(access_array(file, 4 * i + 2), access_array(file, 4 * i + 3));
159 if(len)
160 l[i] = new rom_level(file, off, len);
161 } catch(...) {
162 for(size_t i = 0; i < 31; i++)
163 if(l[i] != NULL)
164 delete l[i];
165 throw;
170 roads_lzs::~roads_lzs()
172 for(size_t i = 0; i < 31; i++)
173 if(l[i] != NULL)
174 delete l[i];
177 roads_lzs::roads_lzs(const roads_lzs& x)
179 for(size_t i = 0; i < 31; i++)
180 l[i] = NULL;
181 try {
182 for(size_t i = 0; i < 31; i++)
183 l[i] = (x.l[i] != NULL) ? new rom_level(*x.l[i]) : NULL;
184 } catch(...) {
185 for(size_t i = 0; i < 31; i++)
186 if(l[i] != NULL)
187 delete l[i];
188 throw;
192 roads_lzs& roads_lzs::operator=(const roads_lzs& x)
194 if(this == &x)
195 return *this;
196 rom_level* tmp[31];
197 for(size_t i = 0; i < 31; i++)
198 tmp[i] = NULL;
199 try {
200 for(size_t i = 0; i < 31; i++)
201 tmp[i] = (x.l[i] != NULL) ? new rom_level(*x.l[i]) : NULL;
202 } catch(...) {
203 for(size_t i = 0; i < 31; i++)
204 if(tmp[i] != NULL)
205 delete tmp[i];
206 throw;
208 for(size_t i = 0; i < 31; i++) {
209 delete l[i];
210 l[i] = tmp[i];
212 return *this;
216 #ifdef LEVEL_CHECKSUMMER
217 int main(int argc, char** argv)
219 sky::roads_lzs levels(zip::readrel(argv[1], ""));
220 uint32_t democount = 0;
221 for(unsigned i = 0; i < 31; i++) {
222 if(levels.present(i)) {
223 uint8_t x[32];
224 levels[i].sha256_hash(x);
225 std::string demofile = (stringfmt() << argv[2] << i).str();
226 try {
227 std::vector<char> dem = zip::readrel(demofile, "");
228 if(dem.size() == 0)
229 continue;
230 char d = 1;
231 std::cout.write(&d, 1);
232 std::cout.write((char*)x, 32);
233 std::vector<char> comp;
234 size_t dpos = 0;
235 size_t run_start = 0;
236 size_t run_byte = dem[0];
237 while(dpos < dem.size()) {
238 if(dpos - run_start > 256 || dem[dpos] != run_byte) {
239 comp.push_back(dpos - run_start - 1);
240 comp.push_back(run_byte);
241 run_start = dpos;
242 run_byte = dem[dpos];
244 dpos++;
246 comp.push_back(dpos - run_start - 1);
247 comp.push_back(run_byte);
248 char cmplen[3];
249 cmplen[0] = comp.size() >> 16;
250 cmplen[1] = comp.size() >> 8;
251 cmplen[2] = comp.size();
252 std::cout.write(cmplen, 3);
253 std::cout.write(&comp[0], comp.size());
254 democount++;
255 std::cerr << "Demo entry for level " << i << ": " << dem.size() << " -> "
256 << comp.size() << std::endl;
257 } catch(...) {
261 std::cerr << "Wrote " << democount << " demo entries." << std::endl;
263 #endif