5 #include "library/string.hpp"
6 #include "library/sha256.hpp"
7 #include "library/zip.hpp"
11 struct tile_output_stream
: public output_stream
13 tile_output_stream(std::vector
<tile
>& _out
)
18 void put(unsigned char byte
)
24 out
.push_back(tile(combine(buffered
, byte
)));
27 std::vector
<tile
>& out
;
34 memset(this, 0, sizeof(*this));
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)
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));
79 return tile(*reinterpret_cast<uint16_t*>(reinterpret_cast<uint8_t*>(this) + ptr
));
83 tile
level::at_tile(int32_t l
, int16_t h
)
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));
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
))
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;
110 if(c
.is_colliding(hchunk
, vpos
))
112 tile d
= at(lpos
, hpos
+ offset
);
113 if(d
.is_colliding(47 - hchunk
, vpos
))
118 bool level::in_pipe(uint32_t lpos
, uint16_t hpos
, int16_t vpos
)
120 int hchunk
= 23 - (hpos
/ 128 - 49) % 46;
123 return at(lpos
, hpos
).in_pipe(hchunk
, vpos
);
126 inline void hash_uint16(sha256
& h
, uint16_t v
)
134 void rom_level::sha256_hash(uint8_t* buffer
)
137 hash_uint16(h
, gravity
);
138 hash_uint16(h
, fuel_amount
);
139 hash_uint16(h
, o2_amount
);
141 hash_uint16(h
, i
.rawtile());
145 roads_lzs::roads_lzs()
147 for(size_t i
= 0; i
< 31; i
++)
151 roads_lzs::roads_lzs(const std::vector
<char>& file
)
153 for(size_t i
= 0; i
< 31; i
++)
155 for(size_t i
= 0; i
< 31; i
++) {
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));
160 l
[i
] = new rom_level(file
, off
, len
);
162 for(size_t i
= 0; i
< 31; i
++)
170 roads_lzs::~roads_lzs()
172 for(size_t i
= 0; i
< 31; i
++)
177 roads_lzs::roads_lzs(const roads_lzs
& x
)
179 for(size_t i
= 0; i
< 31; i
++)
182 for(size_t i
= 0; i
< 31; i
++)
183 l
[i
] = (x
.l
[i
] != NULL
) ? new rom_level(*x
.l
[i
]) : NULL
;
185 for(size_t i
= 0; i
< 31; i
++)
192 roads_lzs
& roads_lzs::operator=(const roads_lzs
& x
)
197 for(size_t i
= 0; i
< 31; i
++)
200 for(size_t i
= 0; i
< 31; i
++)
201 tmp
[i
] = (x
.l
[i
] != NULL
) ? new rom_level(*x
.l
[i
]) : NULL
;
203 for(size_t i
= 0; i
< 31; i
++)
208 for(size_t i
= 0; i
< 31; i
++) {
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
)) {
224 levels
[i
].sha256_hash(x
);
225 std::string demofile
= (stringfmt() << argv
[2] << i
).str();
227 std::vector
<char> dem
= zip::readrel(demofile
, "");
231 std::cout
.write(&d
, 1);
232 std::cout
.write((char*)x
, 32);
233 std::vector
<char> comp
;
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
);
242 run_byte
= dem
[dpos
];
246 comp
.push_back(dpos
- run_start
- 1);
247 comp
.push_back(run_byte
);
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());
255 std::cerr
<< "Demo entry for level " << i
<< ": " << dem
.size() << " -> "
256 << comp
.size() << std::endl
;
261 std::cerr
<< "Wrote " << democount
<< " demo entries." << std::endl
;