Some bizarre stuff...
This commit is contained in:
parent
03d1ec9aae
commit
5ec61c864f
41 changed files with 5165 additions and 2 deletions
|
@ -9,4 +9,6 @@ struct controller_set
|
|||
std::vector<port_type*> ports;
|
||||
};
|
||||
|
||||
extern uint32_t magic_flags;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
CORES=bsnes-legacy gambatte
|
||||
CORES=bsnes-legacy gambatte sky
|
||||
ALLFILES=__all__.files
|
||||
ALLFLAGS=__all__.ldflags
|
||||
CORES_FILES=$(patsubst %,%/$(ALLFILES),$(CORES))
|
||||
|
@ -14,16 +14,21 @@ bsnes-legacy/$(ALLFILES): forcelook
|
|||
gambatte/$(ALLFILES): forcelook
|
||||
$(MAKE) -C gambatte
|
||||
|
||||
sky/$(ALLFILES): forcelook
|
||||
$(MAKE) -C sky
|
||||
|
||||
.PRECIOUS: %.$(OBJECT_SUFFIX) %.files
|
||||
|
||||
precheck:
|
||||
$(MAKE) -C bsnes-legacy precheck
|
||||
$(MAKE) -C gambatte precheck
|
||||
$(MAKE) -C sky precheck
|
||||
|
||||
clean:
|
||||
rm -f *.$(OBJECT_SUFFIX) __all__.ldflags __all__.files
|
||||
$(MAKE) -C bsnes-legacy clean
|
||||
$(MAKE) -C gambatte clean
|
||||
$(MAKE) -C sky clean
|
||||
|
||||
forcelook:
|
||||
@true
|
||||
|
|
|
@ -738,6 +738,7 @@ namespace
|
|||
old = SNES::interface;
|
||||
SNES::interface = &my_interface_obj;
|
||||
SNES::system.init();
|
||||
magic_flags |= 1;
|
||||
},
|
||||
//Uninstall handler
|
||||
[]() -> void { SNES::interface = old; },
|
||||
|
|
|
@ -374,7 +374,7 @@ namespace
|
|||
return std::make_pair(max(512 / width, (uint32_t)1), max(448 / height, (uint32_t)1));
|
||||
},
|
||||
//Install handler
|
||||
[]() -> void {},
|
||||
[]() -> void { magic_flags |= 2; },
|
||||
//Uninstall handler.
|
||||
[]() -> void {},
|
||||
//Emulate frame.
|
||||
|
|
19
src/emulation/sky/Makefile
Normal file
19
src/emulation/sky/Makefile
Normal file
|
@ -0,0 +1,19 @@
|
|||
OBJECTS=$(patsubst %.cpp,%.$(OBJECT_SUFFIX),$(wildcard *.cpp))
|
||||
|
||||
.PRECIOUS: %.$(OBJECT_SUFFIX) %.files
|
||||
|
||||
__all__.files: $(OBJECTS)
|
||||
lua ../../genfilelist.lua $^ >$@
|
||||
echo >__all__.ldflags
|
||||
|
||||
%.$(OBJECT_SUFFIX): %.cpp
|
||||
$(REALCC) -c -o $@ $< -I../../../include -I. $(CFLAGS)
|
||||
|
||||
forcelook:
|
||||
@true
|
||||
|
||||
precheck:
|
||||
@true
|
||||
|
||||
clean:
|
||||
rm -f *.$(OBJECT_SUFFIX) __all__.ldflags __all__.files
|
71
src/emulation/sky/demo.cpp
Normal file
71
src/emulation/sky/demo.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
#include "demo.hpp"
|
||||
#include <cstring>
|
||||
|
||||
namespace sky
|
||||
{
|
||||
uint16_t newdemo_lookup[] = {
|
||||
0x09, 0x08, 0x0A, 0x08, 0x01, 0x00, 0x02, 0x00, 0x05, 0x04, 0x06, 0x04, 0x01, 0x00, 0x02, 0x00,
|
||||
0x19, 0x18, 0x1A, 0x18, 0x11, 0x10, 0x12, 0x10, 0x15, 0x14, 0x16, 0x14, 0x11, 0x10, 0x12, 0x10
|
||||
};
|
||||
|
||||
uint16_t skyroads_lookup[] = {
|
||||
0x009, 0x001, 0x005, 0x201, 0x008, 0x000, 0x004, 0x200,
|
||||
0x00A, 0x002, 0x006, 0x202, 0x108, 0x100, 0x104, 0x300,
|
||||
0x019, 0x011, 0x015, 0x211, 0x018, 0x010, 0x014, 0x210,
|
||||
0x01A, 0x012, 0x016, 0x212, 0x118, 0x110, 0x114, 0x310
|
||||
};
|
||||
|
||||
demo::demo()
|
||||
{
|
||||
buffer[0] = 0;
|
||||
}
|
||||
|
||||
demo::demo(const std::vector<char>& demo, bool skyroads_fmt)
|
||||
{
|
||||
buffer[0] = skyroads_fmt ? 2 : 1;
|
||||
uint16_t dptr = 1;
|
||||
if(buffer[0] == 1) {
|
||||
//Uncompress RLE.
|
||||
size_t ptr = 0;
|
||||
while(ptr < demo.size()) {
|
||||
uint16_t count = (uint8_t)demo[ptr++];
|
||||
count++;
|
||||
uint8_t b = (ptr < demo.size()) ? demo[ptr++] : 5;
|
||||
for(unsigned i = 0; i < count; i++) {
|
||||
if(!dptr)
|
||||
break;
|
||||
buffer[dptr++] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(buffer[0] == 2) {
|
||||
for(unsigned i = 0; i < demo.size(); i++) {
|
||||
if(!dptr)
|
||||
break;
|
||||
buffer[dptr++] = demo[i];
|
||||
}
|
||||
}
|
||||
while(dptr)
|
||||
buffer[dptr++] = 5; //Neutral input.
|
||||
}
|
||||
|
||||
uint16_t demo::fetchkeys(uint16_t old, uint32_t lpos, uint32_t frame)
|
||||
{
|
||||
switch(buffer[0]) {
|
||||
case 1:
|
||||
old &= 96;
|
||||
if(frame < 65535)
|
||||
old |= newdemo_lookup[buffer[frame + 1] & 31];
|
||||
break;
|
||||
case 2:
|
||||
old &= 96;
|
||||
if(lpos / 1638 < 65535)
|
||||
old |= skyroads_lookup[buffer[lpos / 1638 + 1] & 31];
|
||||
break;
|
||||
default:
|
||||
old &= 127;
|
||||
break;
|
||||
}
|
||||
return old;
|
||||
}
|
||||
}
|
19
src/emulation/sky/demo.hpp
Normal file
19
src/emulation/sky/demo.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef _skycore__demo__hpp__included__
|
||||
#define _skycore__demo__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
namespace sky
|
||||
{
|
||||
struct demo
|
||||
{
|
||||
demo();
|
||||
demo(const std::vector<char>& demo, bool skyroads_fmt);
|
||||
uint16_t fetchkeys(uint16_t old, uint32_t lpos, uint32_t frame);
|
||||
private:
|
||||
uint8_t buffer[65536];
|
||||
};
|
||||
}
|
||||
#endif
|
909
src/emulation/sky/draw.cpp
Normal file
909
src/emulation/sky/draw.cpp
Normal file
|
@ -0,0 +1,909 @@
|
|||
#include "draw.hpp"
|
||||
#include <cmath>
|
||||
#include "romimage.hpp"
|
||||
#include "framebuffer.hpp"
|
||||
#include "messages.hpp"
|
||||
#include "library/minmax.hpp"
|
||||
|
||||
/*
|
||||
Point of escape is approximately at normalized y=0.16.
|
||||
Baseline is approximately at normalized y=0.52
|
||||
1st tile after starts approximately at y=0.38
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
namespace sky
|
||||
{
|
||||
//Projection parameters.
|
||||
//Inverse of normalized y0 at baseline.
|
||||
const double z0 = 1.9;
|
||||
//Depth projection scale.
|
||||
const double zscale = 0.6;
|
||||
//Point of escape on screen.
|
||||
const double yescape = 0.16;
|
||||
//Horizontal draw scale.
|
||||
const double hscale = 0.15;
|
||||
//Vertical draw scale.
|
||||
const double vscale = 0.1;
|
||||
//Normalized floor thickness.
|
||||
const double fthickness = 0.33;
|
||||
|
||||
const unsigned pipe_slices = 256;
|
||||
//Type of point representation.
|
||||
struct point_t
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
struct pipe_cache
|
||||
{
|
||||
double min_h;
|
||||
double min_v;
|
||||
double max_h;
|
||||
double max_v;
|
||||
//double dmin;
|
||||
//double dmax;
|
||||
//double raise[pipe_slices];
|
||||
uint32_t colors[pipe_slices];
|
||||
};
|
||||
struct pipe_cache pipecache[7];
|
||||
|
||||
unsigned top_palette[] = {61, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
unsigned front_palette[] = {62, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30};
|
||||
unsigned right_palette[] = {63, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45};
|
||||
unsigned left_palette[] = {64, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60};
|
||||
double slopepoints[] = {-3.45, -2.45, -1.45, 0, 1.45, 2.45, 3.45};
|
||||
double angles[] = {1.35, 1.07, 0.88, 0.745};
|
||||
const char thruster_pn[80] ="BCAAABACBBABCABBCAACBBBACBCCBBCABACACABCBABCBBACBABCCABACCAAABBCBABCAACBAABBACC";
|
||||
|
||||
double calc_slope(double x)
|
||||
{
|
||||
return 1.6 * (hscale * x) / (1 / z0 - yescape);
|
||||
}
|
||||
|
||||
std::pair<signed, signed> point_project(double x, double y, double z)
|
||||
{
|
||||
double c = (z0 + zscale * z);
|
||||
if(c < 0.001)
|
||||
c = 0.001;
|
||||
double y0 = 1 / c;
|
||||
double s = (y0 - yescape) / (1 / z0 - yescape);
|
||||
if(s >= 0)
|
||||
return std::make_pair(FB_WIDTH * (hscale * x * s + 0.5), FB_HEIGHT * (y0 - vscale * y * s));
|
||||
else
|
||||
return std::make_pair(FB_WIDTH / 2, FB_HEIGHT * yescape);
|
||||
}
|
||||
|
||||
point_t point_project_b(double x, double y, double z)
|
||||
{
|
||||
double c = (z0 + zscale * z);
|
||||
if(c < 0.001)
|
||||
c = 0.001;
|
||||
double y0 = 1 / c;
|
||||
double s = (y0 - yescape) / (1 / z0 - yescape);
|
||||
point_t p;
|
||||
if(s >= 0) {
|
||||
p.x = FB_WIDTH * (hscale * x * s + 0.5);
|
||||
p.y = FB_HEIGHT * (y0 - vscale * y * s);
|
||||
} else {
|
||||
p.x = FB_WIDTH / 2;
|
||||
p.y = FB_HEIGHT * yescape;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int32_t ship_sprite_normal(uint16_t hpos, int vdir, uint8_t thruster)
|
||||
{
|
||||
int hdir;
|
||||
if(hpos < 18048) hdir = 0;
|
||||
else if(hpos < 23936) hdir = 1;
|
||||
else if(hpos < 29824) hdir = 2;
|
||||
else if(hpos < 35712) hdir = 3;
|
||||
else if(hpos < 41600) hdir = 4;
|
||||
else if(hpos < 47488) hdir = 5;
|
||||
else hdir = 6;
|
||||
if(vdir == -1) vdir = 2;
|
||||
return 9 * hdir + 3 * vdir + thruster + 14;
|
||||
}
|
||||
|
||||
int32_t ship_sprite_explode(int32_t frame)
|
||||
{
|
||||
return (frame < 42) ? (frame / 3) : -1;
|
||||
}
|
||||
|
||||
int32_t ship_sprite(physics& p)
|
||||
{
|
||||
if(p.expframe)
|
||||
return ship_sprite_explode(p.expframe);
|
||||
if(p.death == physics::death_finished)
|
||||
return -1;
|
||||
int vdir;
|
||||
uint16_t thruster;
|
||||
if(p.vspeed > 300) vdir = 1;
|
||||
else if(p.vspeed < -300) vdir = -1;
|
||||
else vdir = 0;
|
||||
if(p.death == physics::death_fuel)
|
||||
thruster = 0;
|
||||
else {
|
||||
//Some kind of PN sequence.
|
||||
thruster = thruster_pn[p.framecounter % (sizeof(thruster_pn) - 1)] - 'A';
|
||||
}
|
||||
return ship_sprite_normal(p.hpos, vdir, thruster % 3);
|
||||
}
|
||||
|
||||
void draw_sprite(double h, double v, int32_t num)
|
||||
{
|
||||
if(num < 0)
|
||||
return;
|
||||
signed x = FB_WIDTH * hscale * h + FB_WIDTH / 2 - FB_SCALE * 15;
|
||||
signed y = FB_HEIGHT / z0 - FB_HEIGHT * vscale * v - FB_SCALE * ship.width + FB_SCALE;
|
||||
uint32_t offset = ship.width * 30 * num;
|
||||
//For some darn reason, CARS.LZS has the image rotated 90 degrees counterclockwise.
|
||||
for(signed j = 0; j < FB_SCALE * (int)ship.width; j++) {
|
||||
if(y + j < 0 || y + j > overlap_end)
|
||||
continue;
|
||||
uint32_t offset2 = offset + j / FB_SCALE;
|
||||
size_t base = FB_WIDTH * (y + j) + x;
|
||||
for(signed i = 0; i < 30 * FB_SCALE; i++) {
|
||||
if(x + i < 0)
|
||||
continue;
|
||||
if(x + i >= FB_WIDTH)
|
||||
break;
|
||||
uint8_t c = ship.decode[offset2 + ship.width * (i / FB_SCALE)];
|
||||
if(!c)
|
||||
continue;
|
||||
uint32_t pix = ship.palette[c] & 0xFFFFFF;
|
||||
if((framebuffer[base + i] >> 24) == 0)
|
||||
framebuffer[base + i] = pix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_grav_g_meter(gstate& s)
|
||||
{
|
||||
uint16_t realgrav = 100 * (s.p.gravity - 3);
|
||||
uint16_t x = 116;
|
||||
uint16_t y = 156;
|
||||
static size_t sep = strlen(_numbers_g) / 10;
|
||||
while(realgrav) {
|
||||
uint8_t digit = realgrav % 10;
|
||||
draw_block2(_numbers_g + sep * digit, y * 320 + (x - 5), dashpalette[6], dashpalette[5],
|
||||
true);
|
||||
x -= 5;
|
||||
realgrav /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_indicator(uint8_t& curval, uint8_t newval, gauge& g, uint8_t on1, uint8_t on2, uint8_t off1,
|
||||
uint8_t off2)
|
||||
{
|
||||
unsigned tmp = newval;
|
||||
if(tmp > g.maxlimit()) tmp = g.maxlimit();
|
||||
if(curval < tmp)
|
||||
for(unsigned i = curval; i < tmp; i++) {
|
||||
draw_block(g.get_data(i), g.get_position(i), dashpalette[on1], dashpalette[on2]);
|
||||
}
|
||||
else
|
||||
for(unsigned i = tmp; i < curval; i++) {
|
||||
draw_block(g.get_data(i), g.get_position(i), dashpalette[off1], dashpalette[off2]);
|
||||
}
|
||||
curval = tmp;
|
||||
}
|
||||
|
||||
void draw_gauges(gstate& s)
|
||||
{
|
||||
//draw_grav_g_meter(s);
|
||||
uint8_t timermod = ((s.p.framecounter % 9) > 4) ? 1 : 0;
|
||||
draw_indicator(s.speedind, (s.p.lspeed - s.p.speedbias) / 0x141, speed_dat, 2, 3, 0, 1);
|
||||
draw_indicator(s.o2ind, (s.p.o2_left + 0xbb7) / 0xbb8, oxydisp_dat, 2, 3, 0, 1);
|
||||
draw_indicator(s.fuelind, (s.p.fuel_left + 0xbb7) / 0xbb8, fueldisp_dat, 2, 3, 0, 1);
|
||||
//Lock indicator.
|
||||
bool lck = s.p.is_set(physics::flag_locked);
|
||||
if(lck != s.lockind)
|
||||
draw_block2(_lockind_g + (lck ? strlen(_lockind_g) / 2 : 0), 0x9c * 320 + 0xcb,
|
||||
dashpalette[6], dashpalette[5], true);
|
||||
s.lockind = lck;
|
||||
//Out of oxygen blink&beep.
|
||||
if(s.p.death == physics::death_o2 && s.beep_phase != timermod) {
|
||||
blink_between(0xa0, 0xa1, 7, 7, dashpalette[7], dashpalette[8]);
|
||||
if(timermod)
|
||||
gsfx(sound_beep);
|
||||
}
|
||||
//Out of fuel blink&beep.
|
||||
if(s.p.death == physics::death_fuel && s.beep_phase != timermod) {
|
||||
blink_between(0x9b, 0xa9, 16, 5, dashpalette[7], dashpalette[8]);
|
||||
if(timermod)
|
||||
gsfx(sound_beep);
|
||||
}
|
||||
//Distance gauge.
|
||||
uint32_t res = s.curlevel.apparent_length() / 88;
|
||||
size_t tmp = (s.p.lpos - 3 * 65536) / res;
|
||||
for(unsigned i = s.distind; i < tmp && i < 88; i++)
|
||||
draw_distance_column(i, dashpalette[4]);
|
||||
s.distind = tmp;
|
||||
s.beep_phase = timermod;
|
||||
}
|
||||
|
||||
inline double horizon_distance() { return (1 / yescape - z0) / zscale; }
|
||||
inline double near_distance() { return (600 / overlap_end - z0) / zscale; }
|
||||
|
||||
|
||||
void draw_quad_x(point_t p1, point_t p2, point_t p3, point_t p4, uint32_t color)
|
||||
{
|
||||
if(fabs(p1.x - p2.x) < 0.1)
|
||||
return;
|
||||
double qp1 = min(p1.x, p2.x);
|
||||
double qp2 = max(p1.x, p2.x);
|
||||
int x1 = floor(qp1);
|
||||
int x2 = ceil(qp2);
|
||||
double utmax = max(p1.y, p2.y);
|
||||
double utmin = min(p1.y, p2.y);
|
||||
double ltmax = max(p3.y, p4.y);
|
||||
double ltmin = min(p3.y, p4.y);
|
||||
signed y1 = max((int)floor(utmin), 0);
|
||||
signed y2 = min((int)ceil(ltmax), (int)overlap_end);
|
||||
for(signed j = y1; j < y2; j++) {
|
||||
signed xstart = x1, xend = x2;
|
||||
if(j < utmax) {
|
||||
if(p1.y > p2.y)
|
||||
xstart = floor((qp1 - qp2) * (j - p2.y) / (p1.y - p2.y) + qp2);
|
||||
else
|
||||
xend = ceil((qp2 - qp1) * (j - p1.y) / (p2.y - p1.y) + qp1);
|
||||
}
|
||||
if(j >= ltmin) {
|
||||
if(p3.y > p4.y)
|
||||
xend = ceil((qp1 - qp2) * (j - p4.y) / (p3.y - p4.y) + qp2);
|
||||
else
|
||||
xstart = floor((qp2 - qp1) * (j - p3.y) / (p4.y - p3.y) + qp1);
|
||||
}
|
||||
xstart = max(xstart, 0);
|
||||
xend = min(xend, FB_WIDTH);
|
||||
size_t base = FB_WIDTH * j;
|
||||
if(j < overlap_start)
|
||||
for(signed i = xstart; i < xend; i++)
|
||||
framebuffer[base + i] = color;
|
||||
else
|
||||
for(signed i = xstart; i < xend; i++)
|
||||
framebuffer_blend2(framebuffer[base + i], color);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_quad_y(point_t p1, point_t p2, point_t p3, point_t p4, uint32_t color)
|
||||
{
|
||||
if(fabs(p1.y - p3.y) < 0.1)
|
||||
return;
|
||||
signed y1 = max((int)floor(p1.y), 0);
|
||||
signed y2 = min((int)ceil(p3.y), (int)overlap_end);
|
||||
for(signed j = y1; j < y2; j++) {
|
||||
signed xstart, xend;
|
||||
xstart = floor((p3.x - p1.x) * (j - p1.y) / (p3.y - p1.y) + p1.x);
|
||||
xend = ceil((p4.x - p2.x) * (j - p1.y) / (p3.y - p1.y) + p2.x);
|
||||
xstart = max(xstart, 0);
|
||||
xend = min(xend, FB_WIDTH);
|
||||
size_t base = FB_WIDTH * j;
|
||||
if(j < overlap_start)
|
||||
for(signed i = xstart; i < xend; i++)
|
||||
framebuffer[base + i] = color;
|
||||
else
|
||||
for(signed i = xstart; i < xend; i++)
|
||||
framebuffer_blend2(framebuffer[base + i], color);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_quad_z(point_t p1, point_t p2, point_t p3, point_t p4, uint32_t color)
|
||||
{
|
||||
if(fabs(p1.x - p2.x) < 0.1 || fabs(p1.y - p3.y) < 0.1)
|
||||
return;
|
||||
signed x1 = max((int)floor(p1.x), 0);
|
||||
signed x2 = min((int)ceil(p2.x), FB_WIDTH);
|
||||
signed y1 = max((int)floor(p1.y), 0);
|
||||
signed y2 = min((int)ceil(p3.y), (int)overlap_end);
|
||||
for(signed j = y1; j < y2; j++) {
|
||||
size_t base = FB_WIDTH * j;
|
||||
if(j < overlap_start)
|
||||
for(signed i = x1; i < x2; i++)
|
||||
framebuffer[base + i] = color;
|
||||
else
|
||||
for(signed i = x1; i < x2; i++)
|
||||
framebuffer_blend2(framebuffer[base + i], color);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_quad_z_tunshadow(point_t p1, point_t p2, point_t p3, point_t p4, uint32_t color, int x)
|
||||
{
|
||||
if(fabs(p1.x - p2.x) < 0.1 || fabs(p1.y - p3.y) < 0.1)
|
||||
return;
|
||||
if(!x)
|
||||
return; //Center pipe has no shadow.
|
||||
signed x1 = max((int)floor(p1.x), 0);
|
||||
signed x2 = min((int)ceil(p2.x), FB_WIDTH);
|
||||
signed y1 = max((int)floor(p1.y), 0);
|
||||
signed y2 = min((int)ceil(p3.y), (int)overlap_end);
|
||||
double slope = calc_slope(slopepoints[x + 3]);
|
||||
const double width = p2.x - p1.x;
|
||||
const double hwidth = 0.45 * width;
|
||||
const double center = (p1.x + p2.x) / 2;
|
||||
for(signed j = y1; j < y2; j++) {
|
||||
signed c1 = x2, c2 = x1;
|
||||
size_t base = FB_WIDTH * j;
|
||||
double ry = (p3.y - j) / (0.625 * vscale / hscale * 2 * hwidth);
|
||||
if(ry < 1) {
|
||||
c1 = center - hwidth * sqrt(1 - ry * ry);
|
||||
c2 = center + hwidth * sqrt(1 - ry * ry);
|
||||
}
|
||||
if(x < 0) {
|
||||
//The shadow is on left.
|
||||
c2 = center - hwidth - slope * (p3.y - j);
|
||||
} else {
|
||||
//The shadow is on right.
|
||||
c1 = center + hwidth - slope * (p3.y - j);
|
||||
}
|
||||
c1 = max(c1, 0);
|
||||
c2 = min(c2, FB_WIDTH);
|
||||
if(j < overlap_start)
|
||||
for(signed i = c1; i < c2; i++)
|
||||
framebuffer[base + i] = color;
|
||||
else
|
||||
for(signed i = c1; i < c2; i++)
|
||||
framebuffer_blend2(framebuffer[base + i], color);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_quad_z_tunnel(point_t p1, point_t p2, point_t p3, point_t p4, uint32_t color)
|
||||
{
|
||||
if(fabs(p1.x - p2.x) < 0.1 || fabs(p1.y - p3.y) < 0.1)
|
||||
return;
|
||||
signed x1 = max((int)floor(p1.x), 0);
|
||||
signed x2 = min((int)ceil(p2.x), FB_WIDTH);
|
||||
signed y1 = max((int)floor(p1.y), 0);
|
||||
signed y2 = min((int)ceil(p3.y), (int)overlap_end);
|
||||
const double width = p2.x - p1.x;
|
||||
const double hwidth = 0.45 * width;
|
||||
const double center = (p1.x + p2.x) / 2;
|
||||
for(signed j = y1; j < y2; j++) {
|
||||
signed c1 = x2, c2 = x2;
|
||||
size_t base = FB_WIDTH * j;
|
||||
double ry = (p3.y - j) / (0.625 * vscale / hscale * 2 * hwidth);
|
||||
if(ry < 1) {
|
||||
c1 = center - hwidth * sqrt(1 - ry * ry);
|
||||
c2 = center + hwidth * sqrt(1 - ry * ry);
|
||||
}
|
||||
x1 = max(x1, 0);
|
||||
c2 = max(c2, 0);
|
||||
x2 = min(x2, FB_WIDTH);
|
||||
c1 = min(c1, FB_WIDTH);
|
||||
if(j < overlap_start) {
|
||||
for(signed i = x1; i < c1; i++)
|
||||
framebuffer[base + i] = color;
|
||||
for(signed i = c2; i < x2; i++)
|
||||
framebuffer[base + i] = color;
|
||||
} else {
|
||||
for(signed i = x1; i < c1; i++)
|
||||
framebuffer_blend2(framebuffer[base + i], color);
|
||||
for(signed i = c2; i < x2; i++)
|
||||
framebuffer_blend2(framebuffer[base + i], color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_quad_z_pipefront(double z, int x, uint32_t color)
|
||||
{
|
||||
struct pipe_cache& p = pipecache[x + 3];
|
||||
auto p5 = point_project_b(x - 0.5, 0, z);
|
||||
auto p6 = point_project_b(x, 1, z);
|
||||
auto p7 = point_project_b(x + 0.5, 0, z);
|
||||
double ymind = p6.y;
|
||||
double ymaxd = p5.y;
|
||||
int16_t ymin = floor(ymind);
|
||||
int16_t ymax = ceil(ymaxd);
|
||||
if(ymaxd - ymind < 0.1)
|
||||
return;
|
||||
int16_t cheight = floor(p5.y - p6.y);
|
||||
int16_t ciheight = floor(0.9 * (p5.y - p6.y));
|
||||
int16_t cwidth = floor((p7.x - p5.x) / 2);
|
||||
int16_t ciwidth = floor(0.9 * (p7.x - p5.x) / 2);
|
||||
int16_t ccenter = floor((p7.x + p5.x) / 2);
|
||||
int16_t nxs = ccenter - cwidth;
|
||||
int16_t nxe = ccenter + cwidth;
|
||||
for(signed j = ymax - cheight; j < ymax; j++) {
|
||||
if(j < 0 || j > overlap_end)
|
||||
continue;
|
||||
int16_t dstart = nxs;
|
||||
int16_t dend = nxe;
|
||||
int16_t cstart = ccenter;
|
||||
int16_t cend = ccenter;
|
||||
int16_t cistart = ccenter;
|
||||
int16_t ciend = ccenter;
|
||||
if(true) {
|
||||
int16_t o = ymax - j;
|
||||
double o2 = 1.0 * o / cheight;
|
||||
int16_t w = cwidth * sqrt(1 - o2 * o2);
|
||||
cstart -= w;
|
||||
cend += w;
|
||||
}
|
||||
if(j >= ymax - ciheight) {
|
||||
int16_t o = ymax - j;
|
||||
double o2 = 1.0 * o / ciheight;
|
||||
int16_t w = ciwidth * sqrt(1 - o2 * o2);
|
||||
cistart -= w;
|
||||
ciend += w;
|
||||
}
|
||||
dstart = max(cstart, (int16_t)0);
|
||||
dend = min(cend, (int16_t)FB_WIDTH);
|
||||
size_t base = FB_WIDTH * j;
|
||||
if(j < overlap_start)
|
||||
for(signed i = dstart; i < dend; i++) {
|
||||
if(i < cistart || i >= ciend)
|
||||
framebuffer[base + i] = color;
|
||||
}
|
||||
else
|
||||
for(signed i = dstart; i < dend; i++) {
|
||||
if(i < cistart || i >= ciend)
|
||||
framebuffer_blend2(framebuffer[base + i], color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// x = (k*y0+b)*c*(0.5*sin(alpha)+X0)
|
||||
// y = -(k*y0+b)*d*cos(alpha)+y0
|
||||
//
|
||||
// dx/dy0 = k*c*0.5*sin(alpha)+k*c*X0
|
||||
// dy/dy0 = k*d*cos(alpha)+1
|
||||
// dx/dy = (k*c*0.5*sin(alpha)+k*c*X0)/(k*d*cos(alpha)+1)
|
||||
// d/dalpha[(k*c*0.5*sin(alpha)+k*c*X0)/(k*d*cos(alpha)+1)]
|
||||
//=(k*c*0.5*cos(alpha))/(k*d*cos(alpha)+1) +(k*c*0.5*sin(alpha)+k*c*X0)*(k*d*sin(alpha))/(k*d*cos(alpha)+1)^2
|
||||
//
|
||||
// 0.5*k*d+0.5*cos(alpha)+X0*(k*d*sin(alpha)) = 0
|
||||
|
||||
uint32_t mix_color(uint32_t* c, uint32_t c2)
|
||||
{
|
||||
uint32_t low = c[c2 / 256];
|
||||
uint32_t high = c[c2 / 256 + 1];
|
||||
uint16_t mod = c2 % 256;
|
||||
uint16_t imod = 256 - mod;
|
||||
const uint32_t Lm = 0x00FF00FF;
|
||||
const uint32_t Hm = 0xFF00FF00;
|
||||
uint32_t L = (((low & Lm) * imod + (high & Lm) * mod) >> 8) & Lm;
|
||||
uint32_t H = (((low & Hm) >> 8) * imod + ((high & Hm) >> 8) * mod) & Hm;
|
||||
return L | H;
|
||||
}
|
||||
|
||||
void rebuild_pipe_quad_cache(pipe_cache& p, int x, uint32_t* c)
|
||||
{
|
||||
double k = 1 / (1 / z0 - yescape);
|
||||
double b = -yescape * k;
|
||||
double gmin = 999999;
|
||||
double gmax = -999999;
|
||||
double amin = 999999;
|
||||
double amax = -999999;
|
||||
double y00 = (1-b)/k;
|
||||
for(unsigned i = 0; i < 256; i++)
|
||||
p.colors[i] = 0xFFFFFFFF;
|
||||
//Compute span range.
|
||||
for(double a = -M_PI / 2; a < M_PI / 2; a += 0.01) {
|
||||
double A = vscale * cos(a);
|
||||
double y0 = (y00 + b * A) / (1 - k * A);
|
||||
double xp = (k * y0 + b) * (x + 0.5 * sin(a));
|
||||
if(xp < gmin) {
|
||||
p.min_h = x + 0.5 * sin(a);
|
||||
p.min_v = cos(a);
|
||||
gmin = xp;
|
||||
amin = a;
|
||||
}
|
||||
if(xp > gmax) {
|
||||
p.max_h = x + 0.5 * sin(a);
|
||||
p.max_v = cos(a);
|
||||
gmax = xp;
|
||||
amax = a;
|
||||
}
|
||||
}
|
||||
for(double a = amin; a < amax; a += 0.01) {
|
||||
double A = vscale * cos(a);
|
||||
double y0 = (y00 + b * A) / (1 - k * A);
|
||||
double xp = (k * y0 + b) * (x + 0.5 * sin(a));
|
||||
signed c2 = (a + M_PI / 2) * 1280 / M_PI;
|
||||
signed x = 255 * (xp - gmin) / (gmax - gmin);
|
||||
c2 = max(min(c2, 1280), 0);
|
||||
x = max(min(x, 255), 0);
|
||||
p.colors[x] = mix_color(c, c2);
|
||||
}
|
||||
for(unsigned i = 0; i < 256; i++) {
|
||||
if(p.colors[i] == 0xFFFFFFFF)
|
||||
if(i == 0) {
|
||||
for(unsigned j = 0; j < 255; j++)
|
||||
if(p.colors[j] != 0xFFFFFFFF) {
|
||||
p.colors[i] = p.colors[j];
|
||||
break;
|
||||
}
|
||||
} else
|
||||
p.colors[i] = p.colors[i - 1];
|
||||
}
|
||||
//for(unsigned i = 0; i < 256; i++)
|
||||
// p.colors[i] = 0xFF8000 + i;
|
||||
}
|
||||
|
||||
void rebuild_pipe_quad_caches(uint32_t color1, uint32_t color2, uint32_t color3, uint32_t color4)
|
||||
{
|
||||
uint32_t c[6];
|
||||
c[0] = color4;
|
||||
c[1] = color3;
|
||||
c[2] = color2;
|
||||
c[3] = color1;
|
||||
c[4] = color2;
|
||||
c[5] = color3;
|
||||
for(int x = 0; x < 7; x++)
|
||||
rebuild_pipe_quad_cache(pipecache[x], x - 3, c);
|
||||
}
|
||||
|
||||
void draw_quad_y_pipe_last(double z, int x, bool top)
|
||||
{
|
||||
struct pipe_cache& p = pipecache[x + 3];
|
||||
uint32_t fcolor = (!top && z < 0.2) ? 0x1000000 : 0;
|
||||
//We need these for slope projection.
|
||||
auto p1 = point_project_b(p.min_h, p.min_v, z);
|
||||
auto p2 = point_project_b(p.max_h, p.max_v, z);
|
||||
auto p3 = point_project_b(p.min_h, p.min_v, z - 1);
|
||||
auto p4 = point_project_b(p.max_h, p.max_v, z - 1);
|
||||
auto p5 = point_project_b(x - 0.5, 0, z);
|
||||
auto p6 = point_project_b(x, 1, z);
|
||||
auto p7 = point_project_b(x + 0.5, 0, z);
|
||||
if(p3.y - p1.y < 0.1)
|
||||
return;
|
||||
if(p4.y - p2.y < 0.1)
|
||||
return;
|
||||
double ymind = p6.y;
|
||||
double ymaxd = p5.y;
|
||||
int16_t ymin = floor(ymind);
|
||||
int16_t ymax = ceil(ymaxd);
|
||||
double sl1 = (p3.x - p1.x) / (p3.y - p1.y);
|
||||
double sl2 = (p4.x - p2.x) / (p4.y - p2.y);
|
||||
double c1 = p1.x - sl1 * p1.y;
|
||||
double c2 = p2.x - sl2 * p2.y;
|
||||
int16_t cheight = floor(p5.y - p6.y);
|
||||
int16_t cwidth = floor((p7.x - p5.x) / 2);
|
||||
int16_t ccenter = floor((p7.x + p5.x) / 2);
|
||||
for(signed j = ymax - cheight; j < ymax; j++) {
|
||||
if(j < 0 || j > overlap_end)
|
||||
continue;
|
||||
int16_t nxs = floor(sl1 * j + c1);
|
||||
int16_t nxe = ceil(sl2 * j + c2);
|
||||
int16_t dstart = nxs;
|
||||
int16_t dend = nxe;
|
||||
uint32_t cstep = 255 * 65536 / (nxe - nxs + 1);
|
||||
uint32_t color = 0;
|
||||
if(true) {
|
||||
int16_t o = ymax - j;
|
||||
double o2 = 1.0 * o / cheight;
|
||||
int16_t w = cwidth * sqrt(1 - o2 * o2);
|
||||
dstart = ccenter - w;
|
||||
dend = ccenter + w;
|
||||
}
|
||||
dstart = max(max(dstart, nxs), (int16_t)0);
|
||||
dend = min(min(dend, nxe), (int16_t)FB_WIDTH);
|
||||
if(dstart > nxs)
|
||||
color += (dstart - nxs) * cstep;
|
||||
size_t base = FB_WIDTH * j;
|
||||
if(j < overlap_start)
|
||||
for(signed i = dstart; i < dend; i++) {
|
||||
framebuffer[base + i] = fcolor | p.colors[color >> 16];
|
||||
color += cstep;
|
||||
}
|
||||
else
|
||||
for(signed i = dstart; i < dend; i++) {
|
||||
framebuffer_blend2(framebuffer[base + i], fcolor | p.colors[color >> 16]);
|
||||
color += cstep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_quad_y_pipe_first(double z1, double z2, int x, bool top)
|
||||
{
|
||||
struct pipe_cache& p = pipecache[x + 3];
|
||||
uint32_t fcolor = (!top && z1 < 0) ? 0x1000000 : 0;
|
||||
auto p1 = point_project_b(p.min_h, p.min_v, z2);
|
||||
auto p2 = point_project_b(p.max_h, p.max_v, z2);
|
||||
auto p3 = point_project_b(p.min_h, p.min_v, z1);
|
||||
auto p4 = point_project_b(p.max_h, p.max_v, z1);
|
||||
auto p5 = point_project_b(x - 0.5, 0, z1);
|
||||
auto p6 = point_project_b(x, 1, z1);
|
||||
auto p7 = point_project_b(x + 0.5, 0, z1);
|
||||
double ymind = min(p1.y, p2.y);
|
||||
double ymaxd = p5.y;
|
||||
int16_t ymin = floor(ymind);
|
||||
int16_t ymax = ceil(ymaxd);
|
||||
int16_t ymin2 = ceil(max(p1.y, p2.y));
|
||||
if(p3.y - p1.y < 0.1)
|
||||
return;
|
||||
if(p4.y - p2.y < 0.1)
|
||||
return;
|
||||
double sl1 = (p3.x - p1.x) / (p3.y - p1.y);
|
||||
double sl2 = (p4.x - p2.x) / (p4.y - p2.y);
|
||||
double c1 = p1.x - sl1 * p1.y;
|
||||
double c2 = p2.x - sl2 * p2.y;
|
||||
int16_t cheight = floor(p5.y - p6.y);
|
||||
int16_t cwidth = floor((p7.x - p5.x) / 2);
|
||||
int16_t ccenter = floor((p7.x + p5.x) / 2);
|
||||
bool hclip = false;
|
||||
uint16_t mindist = 65535;
|
||||
for(signed j = ymin; j < ymax; j++) {
|
||||
if(j < 0 || j > overlap_end)
|
||||
continue;
|
||||
int16_t nxs = floor(sl1 * j + c1);
|
||||
int16_t nxe = ceil(sl2 * j + c2);
|
||||
int16_t dstart = nxs;
|
||||
int16_t dend = nxe;
|
||||
uint32_t cstep = 255 * 65536 / (nxe - nxs + 1);
|
||||
uint32_t color = 0;
|
||||
int16_t cstart = ccenter;
|
||||
int16_t cend = ccenter;
|
||||
if(j < ymin2 && p1.y != p2.y) {
|
||||
//The upper triangular region.
|
||||
if(p1.y < p2.y)
|
||||
dend = ceil((p2.x - p1.x) * (j - p1.y) / (p2.y - p1.y) + p1.x);
|
||||
else
|
||||
dstart = floor((p2.x - p1.x) * (j - p1.y) / (p2.y - p1.y) + p1.x);
|
||||
}
|
||||
if(j >= ymax - cheight) {
|
||||
int16_t o = ymax - j;
|
||||
double o2 = 1.0 * o / cheight;
|
||||
int16_t w = cwidth * sqrt(1 - o2 * o2);
|
||||
cstart -= w;
|
||||
cend += w;
|
||||
if(hclip) {
|
||||
if(x < 0)
|
||||
dstart = max((int16_t)dstart, cstart);
|
||||
if(x > 0)
|
||||
dend = min((int16_t)dend, cend);
|
||||
} else {
|
||||
uint16_t dist;
|
||||
if(x < 0)
|
||||
dist = cstart - dstart;
|
||||
if(x > 0)
|
||||
dist = dend - cend;
|
||||
|
||||
if(dist > mindist)
|
||||
hclip = true;
|
||||
else
|
||||
mindist = dist;
|
||||
}
|
||||
}
|
||||
dstart = max(max(dstart, nxs), (int16_t)0);
|
||||
dend = min(min(dend, nxe), (int16_t)FB_WIDTH);
|
||||
if(dstart > nxs)
|
||||
color += (dstart - nxs) * cstep;
|
||||
size_t base = FB_WIDTH * j;
|
||||
if(j < overlap_start)
|
||||
for(signed i = dstart; i < dend; i++) {
|
||||
if(i < cstart || i >= cend)
|
||||
framebuffer[base + i] = fcolor | p.colors[color >> 16];
|
||||
color += cstep;
|
||||
}
|
||||
else
|
||||
for(signed i = dstart; i < dend; i++) {
|
||||
if(i < cstart || i >= cend)
|
||||
framebuffer_blend2(framebuffer[base + i], fcolor |
|
||||
p.colors[color >> 16]);
|
||||
color += cstep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_quad_y_pipe(double z1, double z2, int x, bool top)
|
||||
{
|
||||
struct pipe_cache& p = pipecache[x + 3];
|
||||
uint32_t fcolor = (!top && z1 < 0.2) ? 0x1000000 : 0;
|
||||
auto p1 = point_project_b(p.min_h, p.min_v, z2);
|
||||
auto p2 = point_project_b(p.max_h, p.max_v, z2);
|
||||
auto p3 = point_project_b(p.min_h, p.min_v, z1);
|
||||
auto p4 = point_project_b(p.max_h, p.max_v, z1);
|
||||
double ymind = min(p1.y, p2.y);
|
||||
double ymaxd = max(p3.y, p4.y);
|
||||
int16_t ymin = floor(ymind);
|
||||
int16_t ymax = ceil(ymaxd) + 1;
|
||||
int16_t ymin2 = ceil(max(p1.y, p2.y));
|
||||
int16_t ymax2 = floor(min(p3.y, p4.y));
|
||||
if(p3.y - p1.y < 0.1)
|
||||
return;
|
||||
if(p4.y - p2.y < 0.1)
|
||||
return;
|
||||
double sl1 = (p3.x - p1.x) / (p3.y - p1.y);
|
||||
double sl2 = (p4.x - p2.x) / (p4.y - p2.y);
|
||||
double c1 = p1.x - sl1 * p1.y;
|
||||
double c2 = p2.x - sl2 * p2.y;
|
||||
//FIXME: This leaves some graphical glitching in seams.
|
||||
for(signed j = ymin; j < ymax; j++) {
|
||||
if(j < 0 || j > overlap_end)
|
||||
continue;
|
||||
int16_t nxs = floor(sl1 * j + c1);
|
||||
int16_t nxe = ceil(sl2 * j + c2);
|
||||
int16_t dstart = nxs;
|
||||
int16_t dend = nxe;
|
||||
uint32_t cstep = 255 * 65536 / (nxe - nxs + 1);
|
||||
uint32_t color = 0;
|
||||
if(j < ymin2 && p1.y != p2.y) {
|
||||
//The upper triangular region.
|
||||
if(p1.y < p2.y)
|
||||
dend = ceil((p2.x - p1.x) * (j - p1.y) / (p2.y - p1.y) + p1.x);
|
||||
else
|
||||
dstart = floor((p2.x - p1.x) * (j - p1.y) / (p2.y - p1.y) + p1.x);
|
||||
}
|
||||
if(j >= ymax2 && p3.y != p4.y) {
|
||||
//The lower triangular region.
|
||||
if(p3.y < p4.y)
|
||||
dstart = floor((p4.x - p3.x) * (j - p3.y - 1) / (p4.y - p3.y) + p3.x);
|
||||
else
|
||||
dend = ceil((p4.x - p3.x) * (j - p3.y - 1) / (p4.y - p3.y) + p3.x);
|
||||
}
|
||||
dstart = max(max(dstart, nxs), (int16_t)0);
|
||||
dend = min(min(dend, nxe), (int16_t)FB_WIDTH);
|
||||
if(dstart > nxs)
|
||||
color += (dstart - nxs) * cstep;
|
||||
size_t base = FB_WIDTH * j;
|
||||
if(j < overlap_start)
|
||||
for(signed i = dstart; i < dend; i++) {
|
||||
framebuffer[base + i] = fcolor | p.colors[color >> 16];
|
||||
color += cstep;
|
||||
}
|
||||
else
|
||||
for(signed i = dstart; i < dend; i++) {
|
||||
framebuffer_blend2(framebuffer[base + i], fcolor | p.colors[color >> 16]);
|
||||
color += cstep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_level(gstate& s)
|
||||
{
|
||||
for(unsigned i = 0; i < overlap_start; i++)
|
||||
for(unsigned j = 0; j < FB_WIDTH; j++)
|
||||
framebuffer[i * FB_WIDTH + j] = origbuffer[(i / FB_SCALE) * 320 + (j / FB_SCALE)];
|
||||
for(unsigned i = overlap_start; i < overlap_end; i++)
|
||||
for(unsigned j = 0; j < FB_WIDTH; j++)
|
||||
framebuffer_blend2(framebuffer[i * FB_WIDTH + j], origbuffer[(i / FB_SCALE) * 320 +
|
||||
(j / FB_SCALE)]);
|
||||
static signed dorder[] = {-3, 3, -2, 2, -1, 1, 0};
|
||||
level& l = s.curlevel;
|
||||
double zship = s.p.lpos / 65536.0;
|
||||
double horizon = horizon_distance();
|
||||
double near = near_distance();
|
||||
signed maxtile = ceil(zship + horizon);
|
||||
signed mintile = floor(zship + near - 1);
|
||||
for(signed zt = maxtile; zt >= mintile; zt--) {
|
||||
for(signed dxt = 0; dxt < 7; dxt++) {
|
||||
signed xt = dorder[dxt];
|
||||
tile t = l.at_tile(zt, xt);
|
||||
tile tleft = l.at_tile(zt, xt - 1);
|
||||
tile tright = l.at_tile(zt, xt + 1);
|
||||
tile tfront = l.at_tile(zt - 1, xt);
|
||||
tile tback = l.at_tile(zt + 1, xt);
|
||||
//First, draw the floor level.
|
||||
if(t.lower_floor() && (!t.is_rblock() || t.is_tunnel())) {
|
||||
bool ifront = (s.p.vpos < 10240);
|
||||
ifront &= (xt >= 0 || s.p.hpos < 5888 * xt + 32768 - 2944);
|
||||
ifront &= (xt <= 0 || s.p.hpos > 5888 * xt + 32768 + 2944);
|
||||
draw_quad_y(point_project_b(xt - 0.5, 0, zt + 1 - zship),
|
||||
point_project_b(xt + 0.5, 0, zt + 1 - zship),
|
||||
point_project_b(xt - 0.5, 0, zt - zship),
|
||||
point_project_b(xt + 0.5, 0, zt - zship),
|
||||
l.get_palette_color(top_palette[t.lower_floor()], ifront));
|
||||
}
|
||||
//Draw pipe shadow.
|
||||
if(t.is_tunnel() && !tfront.is_block()) {
|
||||
//Pipe shadow never obscures the ship.
|
||||
draw_quad_z_tunshadow(point_project_b(xt - 0.5, 1, zt - zship),
|
||||
point_project_b(xt + 0.5, 1, zt - zship),
|
||||
point_project_b(xt - 0.5, 0, zt - zship),
|
||||
point_project_b(xt + 0.5, 0, zt - zship),
|
||||
l.get_palette_color(t.is_rblock() ? 65 : 67), xt);
|
||||
}
|
||||
//Draw the top surface.
|
||||
if(t.is_rblock()) {
|
||||
signed q = t.apparent_height();
|
||||
bool ifront = (s.p.vpos < 10240 + q * 2560);
|
||||
ifront &= (xt >= 0 || s.p.hpos < 5888 * xt + 32768 - 2944);
|
||||
ifront &= (xt <= 0 || s.p.hpos > 5888 * xt + 32768 + 2944);
|
||||
ifront |= (l.in_pipe(zt * 65536, s.p.hpos, s.p.vpos) && zt < zship);
|
||||
draw_quad_y(point_project_b(xt - 0.5, q, zt + 1 - zship),
|
||||
point_project_b(xt + 0.5, q, zt + 1 - zship),
|
||||
point_project_b(xt - 0.5, q, zt - zship),
|
||||
point_project_b(xt + 0.5, q, zt - zship),
|
||||
l.get_palette_color(top_palette[t.upper_floor()], ifront));
|
||||
}
|
||||
//Left/Right block surface.
|
||||
if(t.is_rblock() && xt < 0 && tright.apparent_height() < t.apparent_height()) {
|
||||
signed q1 = tright.apparent_height();
|
||||
signed q2 = t.apparent_height();
|
||||
bool ifront = (s.p.vpos < 10240 + q2 * 2560);
|
||||
ifront &= (s.p.hpos < 5888 * xt + 32768 + 2944);
|
||||
draw_quad_x(point_project_b(xt + 0.5, q2, zt - zship),
|
||||
point_project_b(xt + 0.5, q2, zt + 1 - zship),
|
||||
point_project_b(xt + 0.5, q1, zt - zship),
|
||||
point_project_b(xt + 0.5, q1, zt + 1 - zship),
|
||||
l.get_palette_color(63, ifront));
|
||||
}
|
||||
if(t.is_rblock() && xt > 0 && tleft.apparent_height() < t.apparent_height()) {
|
||||
signed q1 = tleft.apparent_height();
|
||||
signed q2 = t.apparent_height();
|
||||
bool ifront = (s.p.vpos < 10240 + q2 * 2560);
|
||||
ifront &= (s.p.hpos > 5888 * xt + 32768 - 2944);
|
||||
draw_quad_x(point_project_b(xt - 0.5, q2, zt + 1 - zship),
|
||||
point_project_b(xt - 0.5, q2, zt - zship),
|
||||
point_project_b(xt - 0.5, q1, zt + 1- zship),
|
||||
point_project_b(xt - 0.5, q1, zt - zship),
|
||||
l.get_palette_color(64, ifront));
|
||||
}
|
||||
//Front block surface.
|
||||
if(t.is_rblock() && tfront.apparent_height() < t.apparent_height()) {
|
||||
signed q1 = tfront.apparent_height();
|
||||
signed q2 = t.apparent_height();
|
||||
bool ifront = (zt < zship);
|
||||
if(t.is_tunnel() && !tfront.is_block())
|
||||
draw_quad_z_tunnel(point_project_b(xt - 0.5, q2, zt - zship),
|
||||
point_project_b(xt + 0.5, q2, zt - zship),
|
||||
point_project_b(xt - 0.5, q1, zt - zship),
|
||||
point_project_b(xt + 0.5, q1, zt - zship),
|
||||
l.get_palette_color(62, ifront));
|
||||
else {
|
||||
draw_quad_z(point_project_b(xt - 0.5, q2, zt - zship),
|
||||
point_project_b(xt + 0.5, q2, zt - zship),
|
||||
point_project_b(xt - 0.5, q1, zt - zship),
|
||||
point_project_b(xt + 0.5, q1, zt - zship),
|
||||
l.get_palette_color(62, ifront));
|
||||
}
|
||||
}
|
||||
//Last tunnel block.
|
||||
if(t.is_tunnel() && !t.is_rblock()) {
|
||||
bool top = (s.p.vpos > 10240);
|
||||
top &= !l.in_pipe(zt * 65536, s.p.hpos, s.p.vpos);
|
||||
if(tback.is_rblock() || !tback.is_block())
|
||||
draw_quad_y_pipe_last(zt + 1 - zship, xt, top);
|
||||
//Standalone tunnel top.
|
||||
if(tfront.is_block())
|
||||
draw_quad_y_pipe(zt - zship, zt + 1 - zship, xt, top);
|
||||
else
|
||||
draw_quad_y_pipe_first(zt - zship, zt + 1 - zship, xt, top);
|
||||
//Standalone tunnel front.
|
||||
if(!tfront.is_block()) {
|
||||
bool ifront = (zt < zship);
|
||||
draw_quad_z_pipefront(zt - zship, xt, l.get_palette_color(66, ifront));
|
||||
}
|
||||
}
|
||||
//Left/Right floor surface.
|
||||
if(xt < 0 && t.lower_floor() && !tright.lower_floor()) {
|
||||
bool ifront = (s.p.vpos < 10240);
|
||||
ifront &= (s.p.hpos > 5888 * xt + 32768);
|
||||
draw_quad_x(point_project_b(xt + 0.5, 0, zt - zship),
|
||||
point_project_b(xt + 0.5, 0, zt + 1 - zship),
|
||||
point_project_b(xt + 0.5, -fthickness, zt - zship),
|
||||
point_project_b(xt + 0.5, -fthickness, zt + 1 - zship),
|
||||
l.get_palette_color(right_palette[t.lower_floor()]));
|
||||
}
|
||||
if(xt > 0 && t.lower_floor() && !tleft.lower_floor()) {
|
||||
bool ifront = (s.p.vpos < 10240);
|
||||
ifront &= (s.p.hpos > 5888 * xt + 32768);
|
||||
draw_quad_x(point_project_b(xt - 0.5, 0, zt + 1 - zship),
|
||||
point_project_b(xt - 0.5, 0, zt - zship),
|
||||
point_project_b(xt - 0.5, -fthickness, zt + 1- zship),
|
||||
point_project_b(xt - 0.5, -fthickness, zt - zship),
|
||||
l.get_palette_color(left_palette[t.lower_floor()], ifront));
|
||||
}
|
||||
//Front floor surface.
|
||||
if(t.lower_floor() && !tfront.lower_floor()) {
|
||||
bool ifront = (s.p.vpos < 10240);
|
||||
ifront &= (s.p.hpos < 5888 * xt + 32768);
|
||||
draw_quad_z(point_project_b(xt - 0.5, 0, zt - zship),
|
||||
point_project_b(xt + 0.5, 0, zt - zship),
|
||||
point_project_b(xt - 0.5, -fthickness, zt - zship),
|
||||
point_project_b(xt + 0.5, -fthickness, zt - zship),
|
||||
l.get_palette_color(front_palette[t.lower_floor()], ifront));
|
||||
}
|
||||
}
|
||||
}
|
||||
draw_sprite((s.p.hpos - 32768.0) / 5888.0, (s.p.vpos - 10240.0) / 2560.0,
|
||||
ship_sprite(s.p));
|
||||
}
|
||||
}
|
13
src/emulation/sky/draw.hpp
Normal file
13
src/emulation/sky/draw.hpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef _skycore__draw__hpp__included__
|
||||
#define _skycore__draw__hpp__included__
|
||||
|
||||
#include "state.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
void draw_grav_g_meter(gstate& s);
|
||||
void draw_gauges(gstate& s);
|
||||
void draw_level(gstate& s);
|
||||
void rebuild_pipe_quad_caches(uint32_t color1, uint32_t color2, uint32_t color3, uint32_t color4);
|
||||
}
|
||||
#endif
|
180
src/emulation/sky/framebuffer.cpp
Normal file
180
src/emulation/sky/framebuffer.cpp
Normal file
|
@ -0,0 +1,180 @@
|
|||
#include "framebuffer.hpp"
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
namespace sky
|
||||
{
|
||||
uint32_t origbuffer[65536];
|
||||
uint32_t framebuffer[FB_WIDTH * FB_HEIGHT];
|
||||
uint16_t overlap_start;
|
||||
uint16_t overlap_end;
|
||||
|
||||
void render_backbuffer()
|
||||
{
|
||||
|
||||
for(unsigned i = 0; i < 200; i++) {
|
||||
for(unsigned j = 0; j < 320; j++) {
|
||||
for(unsigned k = 0; k < FB_SCALE; k++)
|
||||
framebuffer[FB_MAJSTRIDE * i + FB_SCALE * j + k] = origbuffer[320 * i + j];
|
||||
}
|
||||
for(unsigned k = 1; k < FB_SCALE; k++)
|
||||
memcpy(framebuffer + (FB_MAJSTRIDE * i + k * FB_WIDTH),
|
||||
framebuffer + FB_MAJSTRIDE * i, FB_WIDTH * sizeof(uint32_t));
|
||||
}
|
||||
//Calculate overlap region.
|
||||
for(unsigned i = 0; i < 200; i++) {
|
||||
uint32_t high = 0x00000000U;
|
||||
for(unsigned j = 0; j < 320; j++)
|
||||
high |= origbuffer[320 * i + j];
|
||||
if(high & 0xFF000000U) {
|
||||
overlap_start = FB_SCALE * i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(unsigned i = overlap_start / FB_SCALE; i < 200; i++) {
|
||||
uint32_t low = 0xFFFFFFFFU;
|
||||
for(unsigned j = 0; j < 320; j++)
|
||||
low &= origbuffer[320 * i + j];
|
||||
if((low & 0xFF000000U) == 0xFF000000U) {
|
||||
overlap_end = FB_SCALE * i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void render_framebuffer_update(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||
{
|
||||
if(x >= 320)
|
||||
return;
|
||||
for(unsigned i = y; i < y + h && i < 200; i++) {
|
||||
for(unsigned j = x; j < x + w && j < 320; j++) {
|
||||
for(unsigned k = 0; k < FB_SCALE; k++)
|
||||
framebuffer[FB_MAJSTRIDE * i + FB_SCALE * j + k] = origbuffer[320 * i + j];
|
||||
}
|
||||
for(unsigned k = 1; k < FB_SCALE; k++)
|
||||
memcpy(framebuffer + (FB_MAJSTRIDE * i + FB_SCALE * x + k * FB_WIDTH), framebuffer +
|
||||
FB_MAJSTRIDE * i + FB_SCALE * x, FB_SCALE * w * sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
|
||||
void render_framebuffer_vline(uint16_t x, uint16_t y1, uint16_t y2, uint32_t color)
|
||||
{
|
||||
for(unsigned i = y1; i <= y2 && i < 200; i++) {
|
||||
for(unsigned k = 0; k < FB_SCALE; k++)
|
||||
framebuffer[FB_MAJSTRIDE * i + x + k * FB_WIDTH] = 0xFF000000U | color;
|
||||
}
|
||||
}
|
||||
|
||||
char decode(const char* ch)
|
||||
{
|
||||
char c = *ch;
|
||||
if(c >= '\\')
|
||||
c--;
|
||||
return c - 35;
|
||||
}
|
||||
|
||||
void draw_block2(const char* pointer, uint16_t position, uint32_t c1, uint32_t c2, bool zero)
|
||||
{
|
||||
static uint8_t tbl[3][6] = {{27, 9, 3, 1}, {32, 16, 8, 4, 2, 1}, {32, 16, 8, 4, 2, 1}};
|
||||
static uint8_t tbl2[3][3] = {{4, 6, 6}, {3, 2, 2}, {0, 0, 1}};
|
||||
c1 |= 0xFF000000U;
|
||||
c2 |= 0xFF000000U;
|
||||
uint8_t type = decode(pointer++);
|
||||
uint16_t width = decode(pointer++);
|
||||
if(width > 63) width = (width - 64) * 64 + decode(pointer++);
|
||||
uint16_t height = decode(pointer++);
|
||||
if(height > 63) height = (height - 64) * 64 + decode(pointer++);
|
||||
uint16_t origptr = position;
|
||||
uint8_t mod = 0;
|
||||
uint8_t reg = 0;
|
||||
for(unsigned y = 0; y < height; y++) {
|
||||
for(unsigned x = 0; x < width; x++) {
|
||||
if(!mod)
|
||||
reg = decode(pointer++);
|
||||
uint8_t p = ((reg / tbl[type][mod]) % tbl2[1][type]) << tbl2[2][type];
|
||||
mod = (mod + 1) % tbl2[0][type];
|
||||
if(p)
|
||||
origbuffer[position] = (p > 1) ? c2 : c1;
|
||||
else if(zero)
|
||||
origbuffer[position] = 0;
|
||||
position++;
|
||||
}
|
||||
position += (320 - width);
|
||||
}
|
||||
render_framebuffer_update(origptr % 320, origptr / 320, width, height);
|
||||
}
|
||||
|
||||
void draw_block(const uint8_t* pointer, uint16_t position, uint32_t c1, uint32_t c2, bool zero)
|
||||
{
|
||||
c1 |= 0xFF000000U;
|
||||
c2 |= 0xFF000000U;
|
||||
uint16_t width = *(pointer++);
|
||||
uint16_t height = *(pointer++);
|
||||
uint16_t origptr = position;
|
||||
for(unsigned y = 0; y < height; y++) {
|
||||
for(unsigned x = 0; x < width; x++) {
|
||||
uint8_t p = *(pointer++);
|
||||
if(p)
|
||||
origbuffer[position] = (p > 1) ? c2 : c1;
|
||||
else if(zero)
|
||||
origbuffer[position] = 0;
|
||||
position++;
|
||||
}
|
||||
position += (320 - width);
|
||||
}
|
||||
render_framebuffer_update(origptr % 320, origptr / 320, width, height);
|
||||
}
|
||||
|
||||
void draw_message(const char* pointer, uint32_t c1, uint32_t c2)
|
||||
{
|
||||
auto op = pointer;
|
||||
pointer++;
|
||||
uint16_t width = decode(pointer++);
|
||||
if(width > 63) width = (width - 64) * 64 + decode(pointer++);
|
||||
uint16_t height = decode(pointer++);
|
||||
if(height > 63) height = (height - 64) * 64 + decode(pointer++);
|
||||
uint16_t x = (320 - width) / 2;
|
||||
uint16_t y = (200 - height) / 2;
|
||||
uint16_t p = 320 * y + x;
|
||||
draw_block2(op, p, c1, c2);
|
||||
}
|
||||
|
||||
void draw_distance_column(uint16_t col, uint32_t c)
|
||||
{
|
||||
uint16_t minline = 0x8f;
|
||||
uint16_t maxline = 0x8f;
|
||||
uint16_t ptr = 320 * 0x8f + 0x2a + (col / 3);
|
||||
uint32_t px = origbuffer[ptr] ;
|
||||
while(origbuffer[ptr] == px)
|
||||
ptr -= 320;
|
||||
ptr += 320;
|
||||
minline = ptr / 320;
|
||||
while(origbuffer[ptr] == px)
|
||||
ptr += 320;
|
||||
maxline = ptr / 320 - 1;
|
||||
render_framebuffer_vline(col + 3 * 0x2a, minline, maxline, c | 0xFF000000U);
|
||||
}
|
||||
|
||||
void blink_between(unsigned x, unsigned y, unsigned w, unsigned h, uint32_t c1, uint32_t c2)
|
||||
{
|
||||
c1 &= 0xFFFFFF;
|
||||
c2 &= 0xFFFFFF;
|
||||
uint32_t c1x = c1 | 0xFF000000U;
|
||||
uint32_t c2x = c2 | 0xFF000000U;
|
||||
for(unsigned j = y; j < y + h; j++)
|
||||
for(unsigned i = x; i < x + w; i++) {
|
||||
if((origbuffer[320 * j + i] & 0xFFFFFF) == c1)
|
||||
origbuffer[320 * j + i] = c2x;
|
||||
else if((origbuffer[320 * j + i] & 0xFFFFFF) == c2)
|
||||
origbuffer[320 * j + i] = c1x;
|
||||
}
|
||||
render_framebuffer_update(x, y, w, h);
|
||||
}
|
||||
|
||||
void draw_bitmap(const uint32_t* bitmap, unsigned x, unsigned y)
|
||||
{
|
||||
for(unsigned j = 0; j < bitmap[1]; j++)
|
||||
for(unsigned i = 0; i < bitmap[0]; i++)
|
||||
framebuffer[(y + j) * FB_WIDTH + (x + i)] = bitmap[j * bitmap[0] + i + 2];
|
||||
}
|
||||
}
|
48
src/emulation/sky/framebuffer.hpp
Normal file
48
src/emulation/sky/framebuffer.hpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef _skycore__framebuffer__hpp__included__
|
||||
#define _skycore__framebuffer__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define FB_SCALE 3
|
||||
#define FB_WIDTH (FB_SCALE * 320)
|
||||
#define FB_HEIGHT (FB_SCALE * 200)
|
||||
#define FB_MAJSTRIDE (FB_SCALE * FB_SCALE * 320)
|
||||
|
||||
namespace sky
|
||||
{
|
||||
extern uint32_t origbuffer[65536];
|
||||
extern uint32_t framebuffer[FB_WIDTH * FB_HEIGHT];
|
||||
extern uint16_t overlap_start;
|
||||
extern uint16_t overlap_end;
|
||||
|
||||
inline void framebuffer_blend1(uint32_t& fbpix, uint32_t rpixel)
|
||||
{
|
||||
fbpix = rpixel & 0x00FFFFFFU;
|
||||
}
|
||||
|
||||
inline void framebuffer_blend2(uint32_t& fbpix, uint32_t rpixel)
|
||||
{
|
||||
if((fbpix >> 31) == 0)
|
||||
fbpix = rpixel & 0x01FFFFFFU;
|
||||
}
|
||||
|
||||
//Take origbuffer and completely rerender framebuffer.
|
||||
void render_backbuffer();
|
||||
//Take a reigon of origbuffer and rerender that into framebuffer.
|
||||
void render_framebuffer_update(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
|
||||
//Render a vertical line into framebuffer. Uses n*320x200 screen size!
|
||||
void render_framebuffer_vline(uint16_t x, uint16_t y1, uint16_t y2, uint32_t color);
|
||||
//Render a gauge block.
|
||||
void draw_block(const uint8_t* pointer, uint16_t position, uint32_t c1, uint32_t c2, bool zero = false);
|
||||
void draw_block2(const char* pointer, uint16_t position, uint32_t c1, uint32_t c2, bool zero = false);
|
||||
//Render a message.
|
||||
void draw_message(const char* pointer, uint32_t c1, uint32_t c2);
|
||||
//Draw column in distance gauge.
|
||||
void draw_distance_column(uint16_t col, uint32_t c);
|
||||
//Blink between colors in specified block.
|
||||
void blink_between(unsigned x, unsigned y, unsigned w, unsigned h, uint32_t c1, uint32_t c2);
|
||||
//Draw a bitmap at full resolution.
|
||||
void draw_bitmap(const uint32_t* bitmap, unsigned x, unsigned y);
|
||||
}
|
||||
|
||||
#endif
|
36
src/emulation/sky/gauge.cpp
Normal file
36
src/emulation/sky/gauge.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include "gauge.hpp"
|
||||
#include "util.hpp"
|
||||
#include "library/string.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
gauge::gauge()
|
||||
{
|
||||
dummyimage[0] = dummyimage[1] = 0;
|
||||
}
|
||||
|
||||
gauge::gauge(const std::vector<char>& dispdat, size_t cells)
|
||||
{
|
||||
dummyimage[0] = dummyimage[1] = 0;
|
||||
if(dispdat.size() < 2 * cells)
|
||||
(stringfmt() << "Entry pointer table incomplete").throwex();
|
||||
data.resize(dispdat.size() - 2 * cells);
|
||||
memcpy(&data[0], &dispdat[2 * cells], data.size());
|
||||
for(unsigned i = 0; i < cells; i++)
|
||||
unpack_image(dispdat, i, cells);
|
||||
}
|
||||
|
||||
void gauge::unpack_image(const std::vector<char>& dispdat, size_t i, size_t total)
|
||||
{
|
||||
size_t offset = combine(dispdat[2 * i + 0], dispdat[2 * i + 1]);
|
||||
//Check that the offset is in-range.
|
||||
if(data.size() < offset)
|
||||
(stringfmt() << "Entry " << i << " points outside file").throwex();
|
||||
if(data.size() < offset + 4)
|
||||
(stringfmt() << "Entry " << i << " header incomplete").throwex();
|
||||
size_t imagesize = (uint16_t)data[offset + 2] * data[offset + 3];
|
||||
if(data.size() < offset + 4 + imagesize)
|
||||
(stringfmt() << "Entry " << i << " bitmap incomplete").throwex();
|
||||
ptr.push_back(offset);
|
||||
}
|
||||
}
|
29
src/emulation/sky/gauge.hpp
Normal file
29
src/emulation/sky/gauge.hpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef _skycore__gauge__hpp__included__
|
||||
#define _skycore__gauge__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include "util.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
struct gauge
|
||||
{
|
||||
gauge();
|
||||
gauge(const std::vector<char>& dispdat, size_t cells);
|
||||
uint16_t get_position(size_t idx)
|
||||
{
|
||||
return (idx < ptr.size()) ? combine(data[ptr[idx]], data[ptr[idx] + 1]) : 0;
|
||||
}
|
||||
uint8_t* get_data(size_t idx) { return (idx < ptr.size()) ? &data[ptr[idx]] + 2 : dummyimage; }
|
||||
size_t maxlimit() { return ptr.size(); }
|
||||
private:
|
||||
void unpack_image(const std::vector<char>& dispdat, size_t sequence, size_t total);
|
||||
std::vector<uint8_t> data;
|
||||
std::vector<size_t> ptr;
|
||||
uint8_t dummyimage[2];
|
||||
};
|
||||
}
|
||||
#endif
|
70
src/emulation/sky/image.cpp
Normal file
70
src/emulation/sky/image.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include "image.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
struct vector_output_stream : public output_stream
|
||||
{
|
||||
vector_output_stream(std::vector<uint8_t>& _data);
|
||||
~vector_output_stream();
|
||||
void put(uint8_t byte);
|
||||
private:
|
||||
std::vector<uint8_t>& data;
|
||||
};
|
||||
|
||||
vector_output_stream::vector_output_stream(std::vector<uint8_t>& _data)
|
||||
: data(_data)
|
||||
{
|
||||
}
|
||||
|
||||
vector_output_stream::~vector_output_stream()
|
||||
{
|
||||
}
|
||||
|
||||
void vector_output_stream::put(uint8_t byte)
|
||||
{
|
||||
data.push_back(byte);
|
||||
}
|
||||
|
||||
image::image()
|
||||
{
|
||||
memset(palette, 0, 256 * sizeof(uint32_t));
|
||||
memset(unknown2, 0, 512);
|
||||
unknown1 = 0;
|
||||
width = 0;
|
||||
height = 0;
|
||||
}
|
||||
|
||||
image::image(const std::vector<char>& data)
|
||||
{
|
||||
memset(palette, 0, 256 * sizeof(uint32_t));
|
||||
memset(unknown2, 0, 512);
|
||||
if(data.size() < 5)
|
||||
throw std::runtime_error("Expected CMAP magic, got EOF");
|
||||
if(data[0] != 'C' || data[1] != 'M' || data[2] != 'A' || data[3] != 'P')
|
||||
throw std::runtime_error("Bad CMAP magic");
|
||||
colors = data[4];
|
||||
if(data.size() < 5 * colors + 5)
|
||||
throw std::runtime_error("Expected CMAP, got EOF");
|
||||
for(unsigned i = 0; i < colors; i++) {
|
||||
palette[i] = ((uint32_t)expand_color(data[3 * i + 5]) << 16) |
|
||||
((uint32_t)expand_color(data[3 * i + 6]) << 8) |
|
||||
((uint32_t)expand_color(data[3 * i + 7]));
|
||||
unknown2[2 * i + 0] = data[3 * colors + 2 * i + 5];
|
||||
unknown2[2 * i + 1] = data[3 * colors + 2 * i + 6];
|
||||
}
|
||||
if(data.size() < 5 * colors + 9)
|
||||
throw std::runtime_error("Bad PICT magic");
|
||||
size_t x = 5 * colors + 5;
|
||||
if(data[x + 0] != 'P' || data[x + 1] != 'I' || data[x + 2] != 'C' || data[x + 3] != 'T')
|
||||
throw std::runtime_error("Bad PICT magic");
|
||||
if(data.size() < 5 * colors + 15)
|
||||
throw std::runtime_error("Expected PICT header, got EOF");
|
||||
unknown1 = combine(data[x + 4], data[x + 5]);
|
||||
height = combine(data[x + 6], data[x + 7]);
|
||||
width = combine(data[x + 8], data[x + 9]);
|
||||
vector_input_stream in(data, x + 10);
|
||||
vector_output_stream out(decode);
|
||||
lzs_decompress(in, out, (uint32_t)width * height);
|
||||
}
|
||||
}
|
27
src/emulation/sky/image.hpp
Normal file
27
src/emulation/sky/image.hpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef _skycore__image__hpp__included__
|
||||
#define _skycore__image__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace sky
|
||||
{
|
||||
struct image
|
||||
{
|
||||
image();
|
||||
image(const std::vector<char>& data);
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint8_t colors;
|
||||
uint16_t unknown1;
|
||||
std::vector<uint8_t> decode;
|
||||
uint32_t operator[](size_t ptr) { return palette[decode[ptr]]; }
|
||||
uint32_t palette[256];
|
||||
uint8_t unknown2[512];
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
266
src/emulation/sky/level.cpp
Normal file
266
src/emulation/sky/level.cpp
Normal file
|
@ -0,0 +1,266 @@
|
|||
#include "level.hpp"
|
||||
#include "util.hpp"
|
||||
#include "lzs.hpp"
|
||||
#include "physics.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include "library/sha256.hpp"
|
||||
#include "library/bintohex.hpp"
|
||||
#include "library/zip.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
struct tile_output_stream : public output_stream
|
||||
{
|
||||
tile_output_stream(std::vector<tile>& _out)
|
||||
: out(_out)
|
||||
{
|
||||
polarity = false;
|
||||
}
|
||||
void put(unsigned char byte)
|
||||
{
|
||||
polarity = !polarity;
|
||||
if(polarity)
|
||||
buffered = byte;
|
||||
else
|
||||
out.push_back(tile(combine(buffered, byte)));
|
||||
}
|
||||
private:
|
||||
std::vector<tile>& out;
|
||||
uint8_t buffered;
|
||||
bool polarity;
|
||||
};
|
||||
|
||||
level::level()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
length = 0;
|
||||
gravity = 8;
|
||||
o2_amount = 1;
|
||||
fuel_amount = 1;
|
||||
}
|
||||
|
||||
level::level(rom_level& data)
|
||||
{
|
||||
length = data.get_length();
|
||||
gravity = data.get_gravity();
|
||||
o2_amount = data.get_o2_amount();
|
||||
fuel_amount = data.get_fuel_amount();
|
||||
for(unsigned i = 0; i < 72; i++)
|
||||
palette[i] = data.get_palette_color(i);
|
||||
for(unsigned i = 0; i < sizeof(tiles) / sizeof(tiles[0]); i++)
|
||||
tiles[i] = data.get_tile(i).rawtile();
|
||||
}
|
||||
|
||||
rom_level::rom_level(const std::vector<char>& data, size_t offset, size_t length)
|
||||
{
|
||||
gravity = combine(access_array(data, offset + 0), access_array(data, offset + 1));
|
||||
fuel_amount = combine(access_array(data, offset + 2), access_array(data, offset + 3));
|
||||
o2_amount = combine(access_array(data, offset + 4), access_array(data, offset + 5));
|
||||
//Next 216 bytes are the palette table.
|
||||
for(unsigned i = 0; i < 72; i++) {
|
||||
uint8_t r = expand_color(access_array(data, offset + 3 * i + 6));
|
||||
uint8_t g = expand_color(access_array(data, offset + 3 * i + 7));
|
||||
uint8_t b = expand_color(access_array(data, offset + 3 * i + 8));
|
||||
palette[i] = ((uint32_t)r << 16) | ((uint32_t)g << 8) | ((uint32_t)b);
|
||||
}
|
||||
//After 222 bytes, there is compressed data.
|
||||
vector_input_stream in(data, offset + 222);
|
||||
tile_output_stream out(tiles);
|
||||
lzs_decompress(in, out, length >> 1 << 1);
|
||||
}
|
||||
|
||||
tile level::at(uint32_t lpos, uint16_t hpos)
|
||||
{
|
||||
if(hpos < 12160 || hpos >= 53376)
|
||||
return tile();
|
||||
else {
|
||||
size_t ptr = 7 * static_cast<size_t>(lpos >> 16) + (hpos - 12160) / 5888;
|
||||
ptr = ptr * 2 + (reinterpret_cast<uint8_t*>(tiles) - reinterpret_cast<uint8_t*>(this));
|
||||
ptr &= 0xFFFF;
|
||||
return tile(*reinterpret_cast<uint16_t*>(reinterpret_cast<uint8_t*>(this) + ptr));
|
||||
}
|
||||
}
|
||||
|
||||
tile level::at_tile(int32_t l, int16_t h)
|
||||
{
|
||||
if(h < -3 || h > 3)
|
||||
return tile();
|
||||
else {
|
||||
size_t ptr = 7 * static_cast<size_t>(l) + h + 3;
|
||||
ptr = ptr * 2 + (reinterpret_cast<uint8_t*>(tiles) - reinterpret_cast<uint8_t*>(this));
|
||||
ptr &= 0xFFFF;
|
||||
return tile(*reinterpret_cast<uint16_t*>(reinterpret_cast<uint8_t*>(this) + ptr));
|
||||
}
|
||||
}
|
||||
|
||||
bool level::collides(uint32_t lpos, uint16_t hpos, int16_t vpos)
|
||||
{
|
||||
bool debug = (lpos == 1248904);
|
||||
uint16_t ltile = lpos / 65536;
|
||||
tile a = at(lpos, hpos - 1792);
|
||||
tile b = at(lpos, hpos + 1792);
|
||||
//Floor collision check.
|
||||
if(a.is_colliding_floor(0, vpos) || b.is_colliding_floor(0, vpos))
|
||||
return true;
|
||||
if(a.is_block() || b.is_block()) {
|
||||
tile c = at(lpos, hpos);
|
||||
int hchunk = 23 - (hpos / 128 - 49) % 46;
|
||||
int16_t offset = -5888;
|
||||
if(hchunk < 0) {
|
||||
hchunk = 1 - hchunk;
|
||||
offset = 5888;
|
||||
}
|
||||
if(c.is_colliding(hchunk, vpos))
|
||||
return true;
|
||||
tile d = at(lpos, hpos + offset);
|
||||
if(d.is_colliding(47 - hchunk, vpos))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool level::in_pipe(uint32_t lpos, uint16_t hpos, int16_t vpos)
|
||||
{
|
||||
int hchunk = 23 - (hpos / 128 - 49) % 46;
|
||||
if(hchunk <= 0)
|
||||
hchunk = 1 - hchunk;
|
||||
return at(lpos, hpos).in_pipe(hchunk, vpos);
|
||||
}
|
||||
|
||||
inline void hash_uint16(sha256& h, uint16_t v)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
buf[0] = v;
|
||||
buf[1] = v >> 8;
|
||||
h.write(buf, 2);
|
||||
}
|
||||
|
||||
void rom_level::sha256_hash(uint8_t* buffer)
|
||||
{
|
||||
sha256 h;
|
||||
hash_uint16(h, gravity);
|
||||
hash_uint16(h, fuel_amount);
|
||||
hash_uint16(h, o2_amount);
|
||||
for(auto i : tiles)
|
||||
hash_uint16(h, i.rawtile());
|
||||
h.read(buffer);
|
||||
}
|
||||
|
||||
roads_lzs::roads_lzs()
|
||||
{
|
||||
for(size_t i = 0; i < 31; i++)
|
||||
l[i] = NULL;
|
||||
}
|
||||
|
||||
roads_lzs::roads_lzs(const std::vector<char>& file)
|
||||
{
|
||||
for(size_t i = 0; i < 31; i++)
|
||||
l[i] = NULL;
|
||||
for(size_t i = 0; i < 31; i++) {
|
||||
try {
|
||||
uint16_t off = combine(access_array(file, 4 * i + 0), access_array(file, 4 * i + 1));
|
||||
uint16_t len = combine(access_array(file, 4 * i + 2), access_array(file, 4 * i + 3));
|
||||
if(len)
|
||||
l[i] = new rom_level(file, off, len);
|
||||
} catch(...) {
|
||||
for(size_t i = 0; i < 31; i++)
|
||||
if(l[i] != NULL)
|
||||
delete l[i];
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
roads_lzs::~roads_lzs()
|
||||
{
|
||||
for(size_t i = 0; i < 31; i++)
|
||||
if(l[i] != NULL)
|
||||
delete l[i];
|
||||
}
|
||||
|
||||
roads_lzs::roads_lzs(const roads_lzs& x)
|
||||
{
|
||||
for(size_t i = 0; i < 31; i++)
|
||||
l[i] = NULL;
|
||||
try {
|
||||
for(size_t i = 0; i < 31; i++)
|
||||
l[i] = (x.l[i] != NULL) ? new rom_level(*x.l[i]) : NULL;
|
||||
} catch(...) {
|
||||
for(size_t i = 0; i < 31; i++)
|
||||
if(l[i] != NULL)
|
||||
delete l[i];
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
roads_lzs& roads_lzs::operator=(const roads_lzs& x)
|
||||
{
|
||||
if(this == &x)
|
||||
return *this;
|
||||
rom_level* tmp[31];
|
||||
for(size_t i = 0; i < 31; i++)
|
||||
tmp[i] = NULL;
|
||||
try {
|
||||
for(size_t i = 0; i < 31; i++)
|
||||
tmp[i] = (x.l[i] != NULL) ? new rom_level(*x.l[i]) : NULL;
|
||||
} catch(...) {
|
||||
for(size_t i = 0; i < 31; i++)
|
||||
if(tmp[i] != NULL)
|
||||
delete tmp[i];
|
||||
throw;
|
||||
}
|
||||
for(size_t i = 0; i < 31; i++) {
|
||||
delete l[i];
|
||||
l[i] = tmp[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LEVEL_CHECKSUMMER
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
sky::roads_lzs levels(read_file_relative(argv[1], ""));
|
||||
uint32_t democount = 0;
|
||||
for(unsigned i = 0; i < 31; i++) {
|
||||
if(levels.present(i)) {
|
||||
uint8_t x[32];
|
||||
levels[i].sha256_hash(x);
|
||||
std::string demofile = (stringfmt() << argv[2] << i).str();
|
||||
try {
|
||||
std::vector<char> dem = read_file_relative(demofile, "");
|
||||
if(dem.size() == 0)
|
||||
continue;
|
||||
char d = 1;
|
||||
std::cout.write(&d, 1);
|
||||
std::cout.write((char*)x, 32);
|
||||
std::vector<char> comp;
|
||||
size_t dpos = 0;
|
||||
size_t run_start = 0;
|
||||
size_t run_byte = dem[0];
|
||||
while(dpos < dem.size()) {
|
||||
if(dpos - run_start > 256 || dem[dpos] != run_byte) {
|
||||
comp.push_back(dpos - run_start - 1);
|
||||
comp.push_back(run_byte);
|
||||
run_start = dpos;
|
||||
run_byte = dem[dpos];
|
||||
}
|
||||
dpos++;
|
||||
}
|
||||
comp.push_back(dpos - run_start - 1);
|
||||
comp.push_back(run_byte);
|
||||
char cmplen[3];
|
||||
cmplen[0] = comp.size() >> 16;
|
||||
cmplen[1] = comp.size() >> 8;
|
||||
cmplen[2] = comp.size();
|
||||
std::cout.write(cmplen, 3);
|
||||
std::cout.write(&comp[0], comp.size());
|
||||
democount++;
|
||||
std::cerr << "Demo entry for level " << i << ": " << dem.size() << " -> "
|
||||
<< comp.size() << std::endl;
|
||||
} catch(...) {
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cerr << "Wrote " << democount << " demo entries." << std::endl;
|
||||
}
|
||||
#endif
|
72
src/emulation/sky/level.hpp
Normal file
72
src/emulation/sky/level.hpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
#ifndef _skycore__level__hpp__included__
|
||||
#define _skycore__level__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include "tile.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
struct rom_level;
|
||||
|
||||
struct level
|
||||
{
|
||||
level();
|
||||
level(rom_level& data);
|
||||
int16_t get_gravity() { return gravity; }
|
||||
int16_t get_o2_amount() { return o2_amount; }
|
||||
uint16_t get_fuel_amount() { return fuel_amount; }
|
||||
uint32_t get_palette_color(size_t idx, bool setC24 = false)
|
||||
{
|
||||
return (setC24 ? 0x1000000 : 0) | ((idx < 72) ? palette[idx] : 0);
|
||||
}
|
||||
tile at(uint32_t lpos, uint16_t hpos);
|
||||
tile at_tile(int32_t l, int16_t h);
|
||||
bool collides(uint32_t lpos, uint16_t hpos, int16_t vpos);
|
||||
bool in_pipe(uint32_t lpos, uint16_t hpos, int16_t vpos);
|
||||
uint32_t finish_line() { return 65536UL * length - 32768; }
|
||||
uint32_t apparent_length() { return 65536UL * (length - 3); }
|
||||
private:
|
||||
int16_t length;
|
||||
int16_t gravity;
|
||||
int16_t o2_amount;
|
||||
uint16_t fuel_amount;
|
||||
uint32_t palette[72];
|
||||
uint16_t tiles[32620];
|
||||
};
|
||||
|
||||
struct rom_level
|
||||
{
|
||||
rom_level(const std::vector<char>& data, size_t offset, size_t length);
|
||||
int16_t get_gravity() { return gravity; }
|
||||
int16_t get_o2_amount() { return o2_amount; }
|
||||
uint16_t get_fuel_amount() { return fuel_amount; }
|
||||
uint16_t get_length() { return tiles.size() / 7; }
|
||||
uint32_t get_palette_color(size_t idx) { return (idx < 72) ? palette[idx] : 0; }
|
||||
tile get_tile(size_t idx) { return (idx < tiles.size()) ? tiles[idx] : tile(); }
|
||||
void sha256_hash(uint8_t* buffer);
|
||||
private:
|
||||
int16_t gravity;
|
||||
int16_t o2_amount;
|
||||
uint16_t fuel_amount;
|
||||
uint32_t palette[72];
|
||||
std::vector<tile> tiles;
|
||||
tile blank;
|
||||
};
|
||||
|
||||
struct roads_lzs
|
||||
{
|
||||
roads_lzs();
|
||||
~roads_lzs();
|
||||
roads_lzs(const std::vector<char>& file);
|
||||
roads_lzs(const roads_lzs& l);
|
||||
roads_lzs& operator=(const roads_lzs& l);
|
||||
bool present(size_t idx) { return (idx < 31 && l[idx] != NULL); }
|
||||
rom_level& operator[](size_t idx) { return *l[idx]; }
|
||||
private:
|
||||
rom_level* l[31];
|
||||
};
|
||||
}
|
||||
#endif
|
432
src/emulation/sky/logic.cpp
Normal file
432
src/emulation/sky/logic.cpp
Normal file
|
@ -0,0 +1,432 @@
|
|||
#include "logic.hpp"
|
||||
#include "framebuffer.hpp"
|
||||
#include "music.hpp"
|
||||
#include "messages.hpp"
|
||||
#include "romimage.hpp"
|
||||
#include "draw.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "library/zip.hpp"
|
||||
|
||||
#define DEMO_WAIT 1080
|
||||
|
||||
namespace sky
|
||||
{
|
||||
const uint8_t hash1[32] = {
|
||||
66,234,24,74,51,217,34,32,61,153,253,130,17,157,160,183,62,231,155,167,135,216,249,116,41,95,216,
|
||||
97,168,163,129,23
|
||||
};
|
||||
const uint8_t hash2[32] = {
|
||||
68,57,232,117,27,127,113,87,161,78,208,193,235,97,13,131,227,152,229,127,31,114,47,235,97,248,103,
|
||||
11,159,217,129,136
|
||||
};
|
||||
uint32_t fadeffect_buffer[FB_WIDTH * FB_HEIGHT];
|
||||
bool indirect_flag;
|
||||
|
||||
uint32_t framecnt_to_songno(uint64_t fc)
|
||||
{
|
||||
return fc;
|
||||
}
|
||||
|
||||
void reload_song(bool menu, uint32_t num)
|
||||
{
|
||||
if(menu) {
|
||||
mplayer.set_song(NULL);
|
||||
if(bsong)
|
||||
delete bsong;
|
||||
bsong = NULL;
|
||||
std::string filename = rom_filename + "/menu.opus";
|
||||
std::istream* s = NULL;
|
||||
try {
|
||||
s = &open_file_relative(filename, "");
|
||||
bsong = new background_song(*s);
|
||||
mplayer.set_song(bsong);
|
||||
delete s;
|
||||
} catch(std::exception& e) {
|
||||
if(s)
|
||||
delete s;
|
||||
}
|
||||
} else {
|
||||
mplayer.set_song(NULL);
|
||||
if(bsong)
|
||||
delete bsong;
|
||||
bsong = NULL;
|
||||
std::istream* s = NULL;
|
||||
try {
|
||||
zip_reader r(rom_filename);
|
||||
std::string iname;
|
||||
std::vector<std::string> inames;
|
||||
for(auto i : r)
|
||||
if(regex_match("music[0-9]+.opus", i))
|
||||
inames.push_back(i);
|
||||
if(inames.empty())
|
||||
return;
|
||||
iname = inames[num % inames.size()];
|
||||
s = &r[iname];
|
||||
bsong = new background_song(*s);
|
||||
mplayer.set_song(bsong);
|
||||
delete s;
|
||||
} catch(std::exception& e) {
|
||||
if(s)
|
||||
delete s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void faded_framebuffer(uint16_t alpha)
|
||||
{
|
||||
indirect_flag = true;
|
||||
for(unsigned i = 0; i < sizeof(framebuffer) / sizeof(framebuffer[0]); i++) {
|
||||
uint32_t L = (((framebuffer[i] & 0x00FF00FF) * alpha) >> 8) & 0x00FF00FF;
|
||||
uint32_t H = (((framebuffer[i] & 0xFF00FF00U) >> 8) * alpha) & 0xFF00FF00U;
|
||||
fadeffect_buffer[i] = L | H;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t stage_to_xpos(uint8_t stage)
|
||||
{
|
||||
return (stage > 15) ? 224 : 64;
|
||||
}
|
||||
|
||||
uint16_t stage_to_ypos(uint8_t stage)
|
||||
{
|
||||
return 13 + (((stage - 1) % 15) / 3) * 39 + ((stage - 1) % 3) * 9;;
|
||||
}
|
||||
|
||||
uint8_t do_menu_fadein(gstate& s, uint16_t b)
|
||||
{
|
||||
faded_framebuffer(8 * s.fadecount);
|
||||
return (++s.fadecount == 32) ? state_menu : state_menu_fadein;
|
||||
}
|
||||
|
||||
uint8_t do_menu_fadeout(gstate& s, uint16_t b)
|
||||
{
|
||||
faded_framebuffer(256 - 8 * s.fadecount);
|
||||
return (++s.fadecount == 32) ? state_load_level : state_menu_fadeout;
|
||||
}
|
||||
|
||||
uint8_t do_level_fadein(gstate& s, uint16_t b)
|
||||
{
|
||||
faded_framebuffer(8 * s.fadecount);
|
||||
return (++s.fadecount == 32) ? state_level_play : state_level_fadein;
|
||||
}
|
||||
|
||||
uint8_t do_level_fadeout(gstate& s, uint16_t b)
|
||||
{
|
||||
faded_framebuffer(256 - 8 * s.fadecount);
|
||||
return (++s.fadecount == 32) ? state_load_menu : state_level_fadeout;
|
||||
}
|
||||
|
||||
uint8_t do_level_fadeout_retry(gstate& s, uint16_t b)
|
||||
{
|
||||
faded_framebuffer(256 - 8 * s.fadecount);
|
||||
return (++s.fadecount == 32) ? state_load_level_nomus : state_level_fadeout_retry;
|
||||
}
|
||||
|
||||
uint8_t do_level_unavail(gstate& s, uint16_t b)
|
||||
{
|
||||
indirect_flag = false;
|
||||
if(!s.fadecount) {
|
||||
memset(framebuffer, 0, sizeof(framebuffer));
|
||||
memset(origbuffer, 0, sizeof(origbuffer));
|
||||
draw_message(_lvlunavail_g, 0xFFFFFF, 0);
|
||||
}
|
||||
s.fadecount = 1;
|
||||
return ((b & ~s.lastkeys) & 0x30) ? state_load_menu : state_level_unavail;
|
||||
}
|
||||
|
||||
uint8_t do_demo_unavail(gstate& s, uint16_t b)
|
||||
{
|
||||
indirect_flag = false;
|
||||
if(!s.fadecount) {
|
||||
memset(framebuffer, 0, sizeof(framebuffer));
|
||||
memset(origbuffer, 0, sizeof(origbuffer));
|
||||
draw_message(_demounavail_g, 0xFFFFFF, 0);
|
||||
}
|
||||
s.fadecount = 1;
|
||||
return ((b & ~s.lastkeys) & 0x30) ? state_load_menu : state_demo_unavail;
|
||||
}
|
||||
|
||||
uint8_t do_level_complete(gstate& s, uint16_t b)
|
||||
{
|
||||
indirect_flag = false;
|
||||
if(!s.fadecount) {
|
||||
if(s.secret == 0x81 && !s.demo_flag)
|
||||
draw_message(_lvlcomplete2_g, 0xFFFFFF, 0);
|
||||
else if(s.secret == 0x82 && !s.demo_flag)
|
||||
draw_message(_lvlcomplete3_g, 0xFFFFFF, 0);
|
||||
else
|
||||
draw_message(_lvlcomplete_g, 0xFFFFFF, 0);
|
||||
if(!s.demo_flag && s.stage > 0 && s.sram[s.stage] < 255)
|
||||
s.sram[s.stage]++;
|
||||
if(!s.demo_flag && s.stage > 0 && s.stage < 30)
|
||||
s.stage++;
|
||||
}
|
||||
if(b & 112)
|
||||
return state_level_fadeout;
|
||||
return (++s.fadecount == 48) ? state_level_fadeout : state_level_complete;
|
||||
}
|
||||
|
||||
uint8_t do_menu(gstate& s, uint16_t b)
|
||||
{
|
||||
indirect_flag = false;
|
||||
if(s.savestage) {
|
||||
s.stage = s.savestage;
|
||||
s.savestage = 0;
|
||||
}
|
||||
if(s.stage == 0)
|
||||
s.stage = 1;
|
||||
if(s.oldstage != s.stage) {
|
||||
if(s.oldstage) {
|
||||
//Erase old mark.
|
||||
uint16_t txpos = stage_to_xpos(s.oldstage);
|
||||
uint16_t typos = stage_to_ypos(s.oldstage);
|
||||
render_framebuffer_update(txpos, typos, 45, 7);
|
||||
}
|
||||
s.oldstage = s.stage;
|
||||
uint16_t txpos = stage_to_xpos(s.stage);
|
||||
uint16_t typos = stage_to_ypos(s.stage);
|
||||
uint32_t color = origbuffer[320 * typos + txpos];
|
||||
for(unsigned i = 0; i < FB_SCALE * 7; i++)
|
||||
for(unsigned j = 0; j < FB_SCALE * 45; j++) {
|
||||
size_t p = (i + FB_SCALE * typos) * FB_WIDTH + (j + FB_SCALE * txpos);
|
||||
if(framebuffer[p] == color)
|
||||
framebuffer[p] = 0xFFC080;
|
||||
}
|
||||
}
|
||||
uint16_t rising = b & ~s.lastkeys;
|
||||
if(rising & 1) //Left.
|
||||
s.stage = (s.stage > 15) ? (s.stage - 15) : (s.stage + 15);
|
||||
if(rising & 2) //Right.
|
||||
s.stage = (s.stage > 15) ? (s.stage - 15) : (s.stage + 15);
|
||||
if(rising & 4) //Up.
|
||||
s.stage = ((s.stage % 15) == 1) ? (s.stage + 14) : (s.stage - 1);
|
||||
if(rising & 8) //Down.
|
||||
s.stage = ((s.stage % 15) == 0) ? (s.stage - 14) : (s.stage + 1);
|
||||
if(rising & 48) { //A or Start.
|
||||
if((b & 3) == 3) {
|
||||
s.savestage = s.stage;
|
||||
s.stage = 0;
|
||||
}
|
||||
s.demo_flag = ((b & 64) != 0);
|
||||
return state_menu_fadeout;
|
||||
}
|
||||
if(b != s.lastkeys)
|
||||
s.waited = 0;
|
||||
else
|
||||
if(++s.waited == DEMO_WAIT) {
|
||||
s.savestage = s.stage;
|
||||
s.stage = 0;
|
||||
s.demo_flag = 2;
|
||||
return state_menu_fadeout;
|
||||
}
|
||||
return state_menu;
|
||||
}
|
||||
|
||||
uint8_t do_load_menu(gstate& s, uint16_t b)
|
||||
{
|
||||
s.cursong = framecnt_to_songno(s.frames_ran);
|
||||
reload_song(true, s.cursong);
|
||||
mplayer.rewind();
|
||||
s.oldstage = 0;
|
||||
for(unsigned i = 0; i < 64000; i++)
|
||||
origbuffer[i] = levelselect[i];
|
||||
render_backbuffer();
|
||||
for(unsigned i = 1; i < 31; i++)
|
||||
for(unsigned j = 0; j < s.sram[i] && j < 7; j++)
|
||||
draw_bitmap(complete_mark, 3 * stage_to_xpos(i) + 21 * j + 141,
|
||||
3 * stage_to_ypos(i) + 3);
|
||||
indirect_flag = true;
|
||||
memset(fadeffect_buffer, 0, sizeof(fadeffect_buffer));
|
||||
s.waited = 0;
|
||||
return state_menu_fadein;
|
||||
}
|
||||
|
||||
uint8_t do_load_level(gstate& s, uint16_t b)
|
||||
{
|
||||
s.secret = 0;
|
||||
if(s.state == state_load_level) {
|
||||
s.cursong = framecnt_to_songno(s.frames_ran);
|
||||
reload_song(false, s.cursong);
|
||||
mplayer.rewind();
|
||||
}
|
||||
indirect_flag = true;
|
||||
memset(fadeffect_buffer, 0, sizeof(fadeffect_buffer));
|
||||
if(!levels.present(s.stage)) {
|
||||
return state_level_unavail;
|
||||
}
|
||||
s.curlevel = level(levels[s.stage]);
|
||||
if((s.curlevel.get_o2_amount() * 36) % 65536 == 0 || s.curlevel.get_fuel_amount() == 0)
|
||||
return state_lockup;
|
||||
s.level_init(s.stage);
|
||||
combine_background(s.stage ? (s.stage - 1) / 3 : 0);
|
||||
uint8_t hash[32];
|
||||
levels[s.stage].sha256_hash(hash);
|
||||
std::cerr << std::endl;
|
||||
if(!memcmp(hash, hash1, 32)) s.secret = 1;
|
||||
if(!memcmp(hash, hash2, 32)) s.secret = 2;
|
||||
try {
|
||||
if(s.demo_flag == 2) {
|
||||
s.curdemo = builtin_demo;
|
||||
} else if(s.demo_flag) {
|
||||
s.curdemo = lookup_demo(hash);
|
||||
} else {
|
||||
s.curdemo = demo();
|
||||
}
|
||||
} catch(...) {
|
||||
return state_demo_unavail;
|
||||
}
|
||||
rebuild_pipe_quad_caches(s.curlevel.get_palette_color(68), s.curlevel.get_palette_color(69),
|
||||
s.curlevel.get_palette_color(70), s.curlevel.get_palette_color(71));
|
||||
draw_grav_g_meter(s);
|
||||
draw_level(s);
|
||||
return state_level_fadein;
|
||||
}
|
||||
|
||||
uint8_t do_level_play(gstate& s, uint16_t b)
|
||||
{
|
||||
indirect_flag = false;
|
||||
//Handle demo.
|
||||
b = s.curdemo.fetchkeys(b, s.p.lpos, s.p.framecounter);
|
||||
if((b & 96) == 96) {
|
||||
s.p.death = physics::death_escaped;
|
||||
return state_level_fadeout;
|
||||
}
|
||||
if((b & ~s.lastkeys) & 32)
|
||||
s.paused = s.paused ? 0 : 1;
|
||||
if(s.paused)
|
||||
return state_level_play;
|
||||
int lr = 0, ad = 0;
|
||||
bool jump = ((b & 16) != 0);
|
||||
if((b & 1) != 0) lr--;
|
||||
if((b & 2) != 0) lr++;
|
||||
if((b & 4) != 0) ad++;
|
||||
if((b & 8) != 0) ad--;
|
||||
if((b & 256) != 0) lr = 2; //Cheat for demo.
|
||||
if((b & 512) != 0) ad = 2; //Cheat for demo.
|
||||
uint8_t death = s.simulate_frame(lr, ad, jump);
|
||||
draw_level(s);
|
||||
draw_gauges(s);
|
||||
if(death == physics::death_finished)
|
||||
return state_level_complete;
|
||||
else if(death)
|
||||
return state_level_fadeout_retry;
|
||||
else
|
||||
return state_level_play;
|
||||
}
|
||||
|
||||
uint8_t do_lockup(gstate& s, uint16_t b)
|
||||
{
|
||||
mplayer.set_song(NULL);
|
||||
return state_lockup;
|
||||
}
|
||||
|
||||
void lstate_lockup(gstate& s)
|
||||
{
|
||||
mplayer.set_song(NULL);
|
||||
memset(framebuffer, 0, sizeof(framebuffer));
|
||||
memset(origbuffer, 0, sizeof(origbuffer));
|
||||
}
|
||||
|
||||
void lstate_demo_unavail(gstate& s)
|
||||
{
|
||||
mplayer.set_song(NULL);
|
||||
memset(framebuffer, 0, sizeof(framebuffer));
|
||||
memset(origbuffer, 0, sizeof(origbuffer));
|
||||
draw_message(_demounavail_g, 0xFFFFFF, 0);
|
||||
}
|
||||
|
||||
void lstate_level_unavail(gstate& s)
|
||||
{
|
||||
mplayer.set_song(NULL);
|
||||
memset(framebuffer, 0, sizeof(framebuffer));
|
||||
memset(origbuffer, 0, sizeof(origbuffer));
|
||||
draw_message(_lvlunavail_g, 0xFFFFFF, 0);
|
||||
}
|
||||
|
||||
void lstate_level(gstate& s)
|
||||
{
|
||||
reload_song(false, s.cursong);
|
||||
mplayer.do_preroll();
|
||||
combine_background(s.stage ? (s.stage - 1) / 3 : 0);
|
||||
s.speedind = 0;
|
||||
s.fuelind = 0;
|
||||
s.o2ind = 0;
|
||||
s.distind = 0;
|
||||
s.lockind = 0;
|
||||
level& c = s.curlevel;
|
||||
rebuild_pipe_quad_caches(c.get_palette_color(68), c.get_palette_color(69), c.get_palette_color(70),
|
||||
c.get_palette_color(71));
|
||||
draw_grav_g_meter(s);
|
||||
draw_gauges(s);
|
||||
draw_level(s);
|
||||
}
|
||||
|
||||
void lstate_menu(gstate& s)
|
||||
{
|
||||
reload_song(true, s.cursong);
|
||||
mplayer.do_preroll();
|
||||
for(unsigned i = 0; i < 64000; i++)
|
||||
origbuffer[i] = levelselect[i];
|
||||
render_backbuffer();
|
||||
for(unsigned i = 1; i < 31; i++)
|
||||
for(unsigned j = 0; j < s.sram[i] && j < 7; j++)
|
||||
draw_bitmap(complete_mark, FB_SCALE * stage_to_xpos(i) + 21 * j + FB_SCALE * 47,
|
||||
FB_SCALE * stage_to_ypos(i) + FB_SCALE);
|
||||
if(s.state == state_menu || s.state == state_menu_fadeout) {
|
||||
uint16_t txpos = stage_to_xpos(s.stage);
|
||||
uint16_t typos = stage_to_ypos(s.stage);
|
||||
uint32_t color = origbuffer[320 * typos + txpos];
|
||||
for(unsigned i = 0; i < FB_SCALE * 7; i++)
|
||||
for(unsigned j = 0; j < FB_SCALE * 45; j++) {
|
||||
size_t p = (i + FB_SCALE * typos) * FB_WIDTH + (j + FB_SCALE * txpos);
|
||||
if(framebuffer[p] == color)
|
||||
framebuffer[p] = 0xFFC080;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef uint8_t (*do_state_t)(gstate& s, uint16_t b);
|
||||
do_state_t statefn[] = {
|
||||
do_menu_fadein,do_menu,do_menu_fadeout,do_load_level,do_level_fadein,do_level_play,
|
||||
do_level_complete, do_level_fadeout,do_load_menu,do_level_unavail,do_demo_unavail,
|
||||
do_level_fadeout_retry, do_load_level, do_lockup
|
||||
};
|
||||
|
||||
typedef void (*do_lstate_t)(gstate& s);
|
||||
do_lstate_t lstatefn[] = {
|
||||
lstate_menu,lstate_menu,lstate_menu,NULL,lstate_level,lstate_level,
|
||||
lstate_level,lstate_level,NULL,lstate_level_unavail,lstate_demo_unavail,
|
||||
lstate_level, lstate_level, lstate_lockup
|
||||
};
|
||||
|
||||
void rom_boot_vector(gstate& s)
|
||||
{
|
||||
s.stage = s.savestage = s.oldstage = 0;
|
||||
s.change_state(state_load_menu);
|
||||
}
|
||||
|
||||
void simulate_frame(gstate& s, uint16_t b)
|
||||
{
|
||||
uint8_t retstate;
|
||||
s.frames_ran++;
|
||||
if(s.state > state_lockup) {
|
||||
messages << "Invalid state in simulate: " << (int)s.state << std::endl;
|
||||
s.change_state(state_load_menu); //Reboot.
|
||||
}
|
||||
retstate = statefn[s.state](s, b);
|
||||
if(retstate != s.state)
|
||||
s.change_state(retstate);
|
||||
s.lastkeys = b;
|
||||
}
|
||||
|
||||
void handle_loadstate(gstate& s)
|
||||
{
|
||||
messages << "Loadstate status: " << (int)s.state << std::endl;
|
||||
if(s.state > state_lockup) {
|
||||
messages << "Invalid state in loadstate: " << (int)s.state << std::endl;
|
||||
s.change_state(state_load_menu); //Reboot.
|
||||
}
|
||||
if(lstatefn[s.state])
|
||||
lstatefn[s.state](s);
|
||||
}
|
||||
}
|
17
src/emulation/sky/logic.hpp
Normal file
17
src/emulation/sky/logic.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef _skycore__logic__hpp__included__
|
||||
#define _skycore__logic__hpp__included__
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include "state.hpp"
|
||||
#include "framebuffer.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
void simulate_frame(gstate& s, uint16_t b);
|
||||
void rom_boot_vector(gstate& s);
|
||||
void handle_loadstate(gstate& s);
|
||||
extern uint32_t fadeffect_buffer[FB_WIDTH * FB_HEIGHT];
|
||||
extern bool indirect_flag;
|
||||
}
|
||||
#endif
|
137
src/emulation/sky/lzs.cpp
Normal file
137
src/emulation/sky/lzs.cpp
Normal file
|
@ -0,0 +1,137 @@
|
|||
#include "lzs.hpp"
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
|
||||
namespace sky
|
||||
{
|
||||
data_error::data_error(const char* errmsg) : std::runtime_error(errmsg) {}
|
||||
|
||||
input_stream::~input_stream()
|
||||
{
|
||||
}
|
||||
|
||||
inline void reload(input_stream& in, unsigned char& byte, unsigned char& bits)
|
||||
{
|
||||
assert(bits <= 8);
|
||||
if(bits == 0) {
|
||||
int r = in.read("Unexpected end of compressed data");
|
||||
byte = r;
|
||||
bits = 8;
|
||||
}
|
||||
assert(bits <= 8);
|
||||
}
|
||||
|
||||
inline bool read1(input_stream& in, unsigned char& byte, unsigned char& bits)
|
||||
{
|
||||
assert(bits <= 8);
|
||||
reload(in, byte, bits);
|
||||
bool ret = ((byte & 0x80) != 0);
|
||||
byte <<= 1;
|
||||
bits--;
|
||||
assert(bits <= 8);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline size_t read_n(input_stream& in, unsigned char& byte, unsigned char& bits, unsigned count)
|
||||
{
|
||||
assert(bits <= 8);
|
||||
if(count == 0)
|
||||
return 0;
|
||||
if(count <= bits) {
|
||||
//Satisfiable immediately.
|
||||
size_t ret = byte >> (8 - count);
|
||||
bits -= count;
|
||||
byte <<= count;
|
||||
return ret;
|
||||
}
|
||||
size_t readc = 0;
|
||||
size_t ret = 0;
|
||||
//Read the first incomplete byte if any.
|
||||
if(bits > 0) {
|
||||
ret = byte >> (8 - bits);
|
||||
readc = bits;
|
||||
bits = 0;
|
||||
}
|
||||
//Read complete bytes.
|
||||
while(readc + 8 <= count) {
|
||||
int r = in.read("Unexpected end of compressed data");
|
||||
ret = (ret << 8) | (r & 0xFF);
|
||||
readc += 8;
|
||||
}
|
||||
size_t tailbits = count - readc;
|
||||
if(tailbits > 0) {
|
||||
//Read the tail bits.
|
||||
reload(in, byte, bits);
|
||||
ret = (ret << tailbits) | (byte >> (8 - tailbits));
|
||||
byte <<= tailbits;
|
||||
bits -= tailbits;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void lzs_decompress(input_stream& in, output_stream& out, size_t size)
|
||||
{
|
||||
unsigned char cbits = in.read("Incomplete compression header");
|
||||
unsigned char sbits = in.read("Incomplete compression header");
|
||||
unsigned char lbits = in.read("Incomplete compression header");
|
||||
size_t maxbits = sizeof(size_t) * CHAR_BIT;
|
||||
if((sbits >= maxbits || lbits >= maxbits) || (sbits == maxbits - 1 && lbits == maxbits - 1))
|
||||
throw data_error("Can't handle the backward offset space");
|
||||
if(cbits >= maxbits)
|
||||
throw data_error("Can't handle the copy length space");
|
||||
|
||||
size_t maxoffset = 2 + (size_t(1) << sbits) + (size_t(1) << lbits);
|
||||
size_t shortbias = 2;
|
||||
size_t longbias = 2 + (size_t(1) << sbits);
|
||||
maxoffset = (size < maxoffset) ? size : maxoffset;
|
||||
std::vector<unsigned char> tmp;
|
||||
tmp.resize(maxoffset);
|
||||
|
||||
uint8_t pending_byte = 0;
|
||||
uint8_t pending_bits = 0;
|
||||
int pending_mode = 0;
|
||||
size_t output = 0;
|
||||
size_t copy_remaining = 0;
|
||||
size_t copy_backward = 0;
|
||||
size_t cyclic_pointer = 0;
|
||||
while(output < size) {
|
||||
assert(pending_bits <= 8);
|
||||
if(copy_remaining) {
|
||||
size_t cindex;
|
||||
if(copy_backward <= cyclic_pointer)
|
||||
cindex = cyclic_pointer - copy_backward;
|
||||
else
|
||||
cindex = maxoffset + cyclic_pointer - copy_backward;
|
||||
copy_remaining--;
|
||||
out.put(tmp[cyclic_pointer++] = tmp[cindex]);
|
||||
if(cyclic_pointer == maxoffset)
|
||||
cyclic_pointer = 0;
|
||||
output++;
|
||||
continue;
|
||||
}
|
||||
if(read1(in, pending_byte, pending_bits)) {
|
||||
if(read1(in, pending_byte, pending_bits)) {
|
||||
//Literial insert.
|
||||
out.put(tmp[cyclic_pointer++] = static_cast<unsigned char>(read_n(in,
|
||||
pending_byte, pending_bits, 8)));
|
||||
if(cyclic_pointer == maxoffset)
|
||||
cyclic_pointer = 0;
|
||||
output++;
|
||||
} else {
|
||||
//Long copy.
|
||||
copy_backward = longbias + read_n(in, pending_byte, pending_bits, lbits);
|
||||
copy_remaining = 2 + read_n(in, pending_byte, pending_bits, cbits);
|
||||
if(copy_backward > output)
|
||||
throw data_error("Backward copy offset too large");
|
||||
}
|
||||
} else {
|
||||
//Short copy.
|
||||
copy_backward = shortbias + read_n(in, pending_byte, pending_bits, sbits);
|
||||
copy_remaining = 2 + read_n(in, pending_byte, pending_bits, cbits);
|
||||
if(copy_backward > output)
|
||||
throw data_error("Backward copy offset too large");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
35
src/emulation/sky/lzs.hpp
Normal file
35
src/emulation/sky/lzs.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef _skycore__lzs__hpp__included__
|
||||
#define _skycore__lzs__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace sky
|
||||
{
|
||||
struct data_error : public std::runtime_error
|
||||
{
|
||||
data_error(const char* errmsg);
|
||||
};
|
||||
|
||||
struct input_stream
|
||||
{
|
||||
virtual ~input_stream();
|
||||
virtual int get() = 0;
|
||||
unsigned char read(const char* msg)
|
||||
{
|
||||
int r = get();
|
||||
if(r < 0) throw data_error(msg);
|
||||
return (r & 0xFF);
|
||||
}
|
||||
};
|
||||
|
||||
struct output_stream
|
||||
{
|
||||
virtual void put(unsigned char byte) = 0;
|
||||
};
|
||||
|
||||
void lzs_decompress(input_stream& in, output_stream& out, size_t size);
|
||||
}
|
||||
#endif
|
51
src/emulation/sky/messages.cpp
Normal file
51
src/emulation/sky/messages.cpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include "messages.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
const char* _lockind_g = "%=(bFA*cN:Rc^X[cbPAccKSD`%=(4c='(RYR@>aK49c>XXRSD#";
|
||||
const char* _numbers_g = "#'(#;/;##'(JVJVJ#'(#V#<##'(#V#V##'(/;#VJ#'(#<#V##'(#<#;##'(#VJVJ#'(#;#;##'(#;#V#";
|
||||
const char* _lvlcomplete_g = "$e5-###$#####%###.S##'&C###+%##KC##34####C+#%E112%#?aVU@]T_T'('+%-+KM-+KL'6W"
|
||||
"3C+KEERKbEE444$'EE--CE%-']``&DU+R,_JJC########C############%#####";
|
||||
const char* _lvlunavail_g = "$e#+#####'####-'####3####O3###$####%L*$^,ZC]TT^GE'+K4%+CKL5+1ED'+EAEF+C--'3E-"
|
||||
"--'?*JJ4%*2JC";
|
||||
const char* _demounavail_g = "$e)+#####'#%###%'####3#+###/3###$##C###L*$^,ZCA?aTUGE'+K4%--+KL5+1ED'+RKEEF+"
|
||||
"C--'3ECE--'?*JJ4$]^+J#";
|
||||
const char* _lvlcomplete2_g = "$eE-############$###+3####C######3##&'####+######'###L*#[]cJ1&FVZD[]VM5+4$3"
|
||||
"E-$(((#444)7E*VVKbCB441':WBF+D$'-++''73D($'+4S2BA]^#``a[423`#########$$##############&FC#####";
|
||||
const char* _lvlcomplete3_g = "$eW-#####%#######K+$###+#####C#C####+%'3##%#####+#+####%#D'###C`[[,.TZD']'*"
|
||||
"L[a[]VK+44%ME%C444%-E'444)$ZZSMKJK%G73EKD':WBC($#'5--#L('+M+4($'+222$'Eb['12$^A*423`########$####"
|
||||
"##############$C##########";
|
||||
const uint32_t complete_mark[] = {
|
||||
18, 15,
|
||||
0x000000, 0x000000, 0x000000, 0x000000, 0x613e1a, 0xb67a3d, 0xeaa45f, 0xfcb977, 0xeab47f,
|
||||
0xb6926e, 0x615141, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
|
||||
0x000000, 0x000000, 0x2e1903, 0xc7711b, 0xff9934, 0xffa245, 0xffab56, 0xffb367, 0xffbc78,
|
||||
0xffc489, 0xffcd9a, 0xc7a686, 0x2e2822, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
|
||||
0x000000, 0x2d1600, 0xe97401, 0xff8912, 0xff9123, 0xff9a34, 0xffa145, 0xffab56, 0xffb367,
|
||||
0xffbc79, 0xffc489, 0xffcd9b, 0xe9c39c, 0x2e2822, 0x000000, 0x000000, 0x000000, 0x000000,
|
||||
0x000000, 0xba5d00, 0xf77c00, 0xff8000, 0xff8812, 0xff9123, 0xff9934, 0xffa245, 0xffab56,
|
||||
0xffb367, 0xffbb77, 0xffc489, 0xffcd9a, 0xc7a685, 0x000000, 0x000000, 0x000000, 0x000000,
|
||||
0x542a00, 0xe67300, 0xee7700, 0xf77c00, 0xff7f01, 0xff8812, 0xff9023, 0xff9933, 0xffa245,
|
||||
0xffaa56, 0xffb367, 0xffbc78, 0xffc489, 0xffcd9a, 0x615141, 0x000000, 0x000000, 0x000000,
|
||||
0x974c00, 0xdd6e00, 0xe67300, 0xee7700, 0xf77b00, 0xff7f01, 0xff8811, 0xff9123, 0xff9934,
|
||||
0xffa244, 0xffab56, 0xffb267, 0xffbb78, 0xffc489, 0xb6926e, 0x000000, 0x000000, 0x000000,
|
||||
0xbb5e00, 0xd56a00, 0xdd6e00, 0xe67200, 0xee7700, 0xf77b00, 0xff8000, 0xff8812, 0xff9123,
|
||||
0xff9933, 0xffa245, 0xffaa56, 0xffb367, 0xffbb78, 0xeab47e, 0x000000, 0x000000, 0x000000,
|
||||
0xc26100, 0xcc6600, 0xd46b00, 0xdd6e00, 0xe67200, 0xee7700, 0xf67b00, 0xff8001, 0xff8811,
|
||||
0xff9023, 0xff9933, 0xffa244, 0xffab55, 0xffb367, 0xfcba76, 0x000000, 0x000000, 0x000000,
|
||||
0xac5600, 0xc46100, 0xcc6600, 0xd56a00, 0xde6f00, 0xe67200, 0xee7700, 0xf67c00, 0xff8001,
|
||||
0xff8811, 0xff9023, 0xff9934, 0xffa244, 0xffaa56, 0xeaa45f, 0x000000, 0x000000, 0x000000,
|
||||
0x804000, 0xbb5d00, 0xc36200, 0xcc6600, 0xd46a00, 0xdd6f00, 0xe57300, 0xef7700, 0xf77b00,
|
||||
0xff8000, 0xff8812, 0xff9122, 0xff9934, 0xffa244, 0xb6793d, 0x000000, 0x000000, 0x000000,
|
||||
0x412000, 0xb25900, 0xbb5e00, 0xc46100, 0xcc6600, 0xd56a00, 0xdd6e00, 0xe57300, 0xee7700,
|
||||
0xf67c00, 0xff7f01, 0xff8912, 0xff9123, 0xff9933, 0x613e1a, 0x000000, 0x000000, 0x000000,
|
||||
0x000000, 0x854200, 0xb25900, 0xba5e00, 0xc36200, 0xcc6600, 0xd56b00, 0xdd6e00, 0xe67200,
|
||||
0xee7700, 0xf67b00, 0xff8000, 0xff8812, 0xc7701b, 0x000000, 0x000000, 0x000000, 0x000000,
|
||||
0x000000, 0x1d0e00, 0x9b4e00, 0xb35900, 0xbb5d00, 0xc46200, 0xcc6600, 0xd46b00, 0xdd6e00,
|
||||
0xe57300, 0xee7700, 0xf67b00, 0xe97401, 0x2e1903, 0x000000, 0x000000, 0x000000, 0x000000,
|
||||
0x000000, 0x000000, 0x1d0e00, 0x854200, 0xb25a00, 0xbb5d00, 0xc46200, 0xcc6600, 0xd46a00,
|
||||
0xdc6f00, 0xe67300, 0xba5d00, 0x2d1600, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
|
||||
0x000000, 0x000000, 0x000000, 0x000000, 0x412000, 0x804000, 0xac5600, 0xc16100, 0xbb5d00,
|
||||
0x984c00, 0x542a00, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000,
|
||||
};
|
||||
}
|
19
src/emulation/sky/messages.hpp
Normal file
19
src/emulation/sky/messages.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef _skycore__messages__hpp__included__
|
||||
#define _skycore__messages__hpp__included__
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
|
||||
namespace sky
|
||||
{
|
||||
extern const char* _lockind_g;
|
||||
extern const char* _numbers_g;
|
||||
extern const char* _lvlcomplete_g;
|
||||
extern const char* _lvlcomplete2_g;
|
||||
extern const char* _lvlcomplete3_g;
|
||||
extern const char* _lvlunavail_g;
|
||||
extern const char* _demounavail_g;
|
||||
extern const uint32_t complete_mark[];
|
||||
}
|
||||
|
||||
#endif
|
342
src/emulation/sky/music.cpp
Normal file
342
src/emulation/sky/music.cpp
Normal file
|
@ -0,0 +1,342 @@
|
|||
#include "music.hpp"
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include "library/minmax.hpp"
|
||||
#include "library/ogg.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include "core/window.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
const uint64_t past_end = 0xFFFFFFFFFFFFFFFFULL;
|
||||
|
||||
background_song* bsong = NULL;
|
||||
|
||||
uint8_t ticks_per_frame[32] = {
|
||||
4, 8, 16, 24,
|
||||
4, 8, 16, 24,
|
||||
4, 8, 16, 24,
|
||||
4, 8, 4, 8,
|
||||
1, 2, 4, 8,
|
||||
1, 2, 4, 8,
|
||||
1, 2, 4, 8,
|
||||
1, 2, 4, 8
|
||||
};
|
||||
|
||||
uint8_t opus_packet_tick_count(const uint8_t* packet, size_t packetsize)
|
||||
{
|
||||
if(packetsize < 1)
|
||||
return 0;
|
||||
uint8_t x = ticks_per_frame[packet[0] >> 3];
|
||||
uint8_t y = (packetsize < 2) ? 255 : (packet[1] & 0x3F);
|
||||
uint16_t z = (uint16_t)x * y;
|
||||
switch(packet[0] & 3) {
|
||||
case 0: return x;
|
||||
case 1: return x << 1;
|
||||
case 2: return x << 1;
|
||||
case 3: return (z <= 48) ? z : 0;
|
||||
};
|
||||
}
|
||||
|
||||
uint64_t background_song::find_timecode_down(uint64_t pts)
|
||||
{
|
||||
if(pts == past_end)
|
||||
return past_end;
|
||||
auto i = packets.upper_bound(pts);
|
||||
if(i == packets.end())
|
||||
return packets.rbegin()->first;
|
||||
else {
|
||||
i--;
|
||||
return i->first;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t background_song::find_timecode_up(uint64_t pts)
|
||||
{
|
||||
if(pts == past_end)
|
||||
return past_end;
|
||||
auto i = packets.lower_bound(pts);
|
||||
if(i == packets.end())
|
||||
return past_end;
|
||||
else
|
||||
return i->first;
|
||||
|
||||
}
|
||||
|
||||
uint64_t background_song::pcm_to_pts1(uint64_t pcm)
|
||||
{
|
||||
// | |
|
||||
//1: PPIIIIIILLLLLLC LLLLLLC LLLLLLC LLLLLLC L...
|
||||
//2: LLLLLLC LLLLLLC LLLLLLC LLLLLLC...
|
||||
uint64_t C = total - crossfade_start;
|
||||
uint64_t L = total - loop_start;
|
||||
uint64_t LminusC = L - C;
|
||||
uint64_t Lminus2C = L - 2 * C;
|
||||
|
||||
if(pcm == past_end)
|
||||
return past_end;
|
||||
pcm += pregap;
|
||||
if(pcm < total)
|
||||
return pcm;
|
||||
pcm -= total;
|
||||
pcm %= 2 * LminusC;
|
||||
//There is first a gap.
|
||||
if(pcm < Lminus2C)
|
||||
return past_end;
|
||||
pcm -= Lminus2C;
|
||||
//Then there's a new looping section.
|
||||
return pcm + loop_start;
|
||||
}
|
||||
|
||||
uint64_t background_song::pcm_to_pts2(uint64_t pcm)
|
||||
{
|
||||
// | |
|
||||
//1: PPIIIIIILLLLLLC LLLLLLC LLLLLLC LLLLLLC L...
|
||||
//2: LLLLLLC LLLLLLC LLLLLLC LLLLLLC...
|
||||
uint64_t C = total - crossfade_start;
|
||||
uint64_t L = total - loop_start;
|
||||
uint64_t LminusC = L - C;
|
||||
uint64_t Lminus2C = L - 2 * C;
|
||||
if(pcm == past_end)
|
||||
return past_end;
|
||||
pcm += pregap;
|
||||
//Before crossfade_start, there's nothing.
|
||||
if(pcm < crossfade_start)
|
||||
return past_end;
|
||||
pcm -= crossfade_start;
|
||||
pcm %= 2 * LminusC;
|
||||
//First there is loop region.
|
||||
if(pcm < L)
|
||||
return pcm + loop_start;
|
||||
//Then there's a gap.
|
||||
return past_end;
|
||||
}
|
||||
|
||||
int32_t background_song::gain_factor()
|
||||
{
|
||||
if(!gain)
|
||||
return 256;
|
||||
double g = pow(10, gain / 20.0);
|
||||
if(g >= 256)
|
||||
return 65536;
|
||||
return 256 * g;
|
||||
}
|
||||
|
||||
background_song::background_song(std::istream& stream)
|
||||
{
|
||||
ogg_stream_reader_iostreams r(stream);
|
||||
r.set_errors_to(messages);
|
||||
ogg_page p;
|
||||
uint64_t pnum = 0;
|
||||
bool loop_spec = false, cf_spec = false;
|
||||
loop_start = 0;
|
||||
crossfade_start = 0;
|
||||
std::vector<uint8_t> pending_data;
|
||||
uint64_t last_gpos = ogg_page::granulepos_none;
|
||||
uint64_t rpos = 0;
|
||||
uint64_t old_rpos = 0;
|
||||
while(r.get_page(p)) {
|
||||
if(pnum == 0) {
|
||||
//Header page.
|
||||
struct oggopus_header h = parse_oggopus_header(p);
|
||||
if(h.map_family != 0)
|
||||
(stringfmt() << "Unsupported mapping family " << h.map_family).throwex();
|
||||
pregap = h.preskip;
|
||||
gain = h.gain;
|
||||
} else if(pnum == 1) {
|
||||
//Tags page.
|
||||
struct oggopus_tags t = parse_oggopus_tags(p);
|
||||
for(auto i : t.comments) {
|
||||
regex_results r = regex("([^=]+)=(.*)", i);
|
||||
if(!r)
|
||||
continue;
|
||||
if(r[1] == "LSNES_LOOP_START") {
|
||||
loop_start = parse_value<uint64_t>(r[2]) + pregap;
|
||||
loop_spec = true;
|
||||
} else if(r[1] == "LSNES_XFADE_START") {
|
||||
crossfade_start = parse_value<uint64_t>(r[2]) + pregap;
|
||||
cf_spec = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Data page.
|
||||
uint64_t gpos = p.get_granulepos();
|
||||
uint8_t pkts = p.get_packet_count();
|
||||
bool e = p.get_eos();
|
||||
bool c = p.get_continue();
|
||||
bool i = p.get_last_packet_incomplete();
|
||||
for(unsigned j = 0; j < pkts; j++) {
|
||||
if(i > 0 || !c)
|
||||
pending_data.clear();
|
||||
size_t b = pending_data.size();
|
||||
auto pkt = p.get_packet(j);
|
||||
pending_data.resize(b + pkt.second);
|
||||
memcpy(&pending_data[b], pkt.first, pkt.second);
|
||||
if(i && j == pkts - 1)
|
||||
break; //Next page.
|
||||
//Pending_data is now opus packet.
|
||||
uint8_t tcnt = opus_packet_tick_count(&pending_data[0], pending_data.size());
|
||||
if(tcnt > 0)
|
||||
packets[rpos] = pending_data;
|
||||
rpos += 120 * tcnt;
|
||||
total = rpos;
|
||||
}
|
||||
if(e) {
|
||||
uint64_t pscnt = gpos - ((last_gpos == ogg_page::granulepos_none) ? 0 :
|
||||
last_gpos);
|
||||
total = old_rpos + pscnt;
|
||||
if(total > rpos)
|
||||
total = rpos;
|
||||
break;
|
||||
}
|
||||
if(gpos != ogg_page::granulepos_none) {
|
||||
last_gpos = gpos;
|
||||
old_rpos = rpos;
|
||||
}
|
||||
}
|
||||
pnum++;
|
||||
}
|
||||
|
||||
if(!cf_spec)
|
||||
crossfade_start = total;
|
||||
if(!loop_spec)
|
||||
loop_start = pregap;
|
||||
if(loop_start >= total) {
|
||||
messages << "Bad loop point, assuming start of song" << std::endl;
|
||||
loop_start = pregap;
|
||||
}
|
||||
if(crossfade_start - loop_start < total - crossfade_start) {
|
||||
messages << "Bad XFADE point, assuming end of song." << std::endl;
|
||||
crossfade_start = total;
|
||||
}
|
||||
}
|
||||
|
||||
music_player_int::music_player_int()
|
||||
#ifdef WITH_OPUS_CODEC
|
||||
: d(opus::samplerate::r48k, true)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
void music_player_int::decode_packet(const std::vector<uint8_t>& data)
|
||||
{
|
||||
pcmlen = 120 * opus_packet_tick_count(&data[0], data.size());
|
||||
pcmpos = 0;
|
||||
memset(&pcmbuf[0], 0, 11520 * sizeof(int16_t));
|
||||
try {
|
||||
d.decode(&data[0], data.size(), &pcmbuf[0], 5760);
|
||||
} catch(std::exception& e) {
|
||||
messages << "Music: Failed to decode opus packet: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void music_player::seek_channel(music_player_int& i, uint64_t& spts, uint64_t pts)
|
||||
{
|
||||
if(pts == past_end) {
|
||||
i.pcmpos = i.pcmlen = 0;
|
||||
spts = past_end;
|
||||
return;
|
||||
}
|
||||
#ifdef WITH_OPUS_CODEC
|
||||
i.d.ctl(opus::reset);
|
||||
#endif
|
||||
uint64_t ptsr = song->find_timecode_down((pts >= 3840) ? (pts - 3840) : 0);
|
||||
while(ptsr < pts) {
|
||||
ptsr = song->find_timecode_up(ptsr);
|
||||
if(ptsr == past_end)
|
||||
break;
|
||||
i.decode_packet(song->packets[ptsr]);
|
||||
if(ptsr + i.pcmlen > pts) {
|
||||
i.pcmpos = pts - ptsr;
|
||||
ptsr = pts;
|
||||
} else
|
||||
ptsr += i.pcmlen;
|
||||
}
|
||||
spts = pts;
|
||||
}
|
||||
|
||||
void music_player::do_preroll()
|
||||
{
|
||||
if(!song || song->packets.empty())
|
||||
return;
|
||||
uint64_t pts1 = song->pcm_to_pts1(pcmpos);
|
||||
uint64_t pts2 = song->pcm_to_pts2(pcmpos);
|
||||
uint64_t pts1p;
|
||||
uint64_t pts2p;
|
||||
seek_channel(i1, pts1p, pts1);
|
||||
seek_channel(i2, pts2p, pts2);
|
||||
}
|
||||
|
||||
void music_player::decode(std::pair<int16_t, int16_t>* output, size_t samples)
|
||||
{
|
||||
if(!song) {
|
||||
memset(output, 0, samples * sizeof(std::pair<int16_t, int16_t>));
|
||||
pcmpos += samples;
|
||||
return;
|
||||
}
|
||||
int32_t gfactor = builtin_gain ? 256 : song->gain_factor();
|
||||
uint64_t pts1 = song->pcm_to_pts1(pcmpos);
|
||||
uint64_t pts2 = song->pcm_to_pts2(pcmpos);
|
||||
uint64_t cfstart = song->crossfade_start;
|
||||
uint64_t cflen = song->total - song->crossfade_start;
|
||||
for(; samples > 0; output++, samples--, pcmpos++) {
|
||||
if(song->crossfade_start == pts1)
|
||||
seek_channel(i2, pts2, song->loop_start);
|
||||
if(song->crossfade_start == pts2)
|
||||
seek_channel(i1, pts1, song->loop_start);
|
||||
if(song->total == pts1)
|
||||
seek_channel(i1, pts1, past_end);
|
||||
if(song->total == pts2)
|
||||
seek_channel(i2, pts2, past_end);
|
||||
if(i1.pcmpos == i1.pcmlen && pts1 != past_end) {
|
||||
uint64_t pts = song->find_timecode_up(pts1);
|
||||
if(pts != past_end)
|
||||
i1.decode_packet(song->packets[pts]);
|
||||
}
|
||||
if(i2.pcmpos == i2.pcmlen && pts2 != past_end) {
|
||||
uint64_t pts = song->find_timecode_up(pts2);
|
||||
if(pts != past_end)
|
||||
i2.decode_packet(song->packets[pts]);
|
||||
}
|
||||
uint32_t cf = 0, icf = 0;
|
||||
if(i1.pcmpos < i1.pcmlen)
|
||||
cf = (pts1 > cfstart) ? (256 - 256 * (pts1 - cfstart) / cflen) : 256;
|
||||
if(i2.pcmpos < i2.pcmlen)
|
||||
icf = (pts2 > cfstart) ? (256 - 256 * (pts2 - cfstart) / cflen) : 256;
|
||||
int32_t l = (cf * i1.pcmbuf[2 * i1.pcmpos + 0] + icf * i2.pcmbuf[2 * i2.pcmpos + 0]) >> 8;
|
||||
int32_t r = (cf * i1.pcmbuf[2 * i1.pcmpos + 1] + icf * i2.pcmbuf[2 * i2.pcmpos + 1]) >> 8;
|
||||
output->first = max(min((gfactor * l) >> 8, 32767), -32768);
|
||||
output->second = max(min((gfactor * r) >> 8, 32767), -32768);
|
||||
if(i1.pcmpos < i1.pcmlen)
|
||||
i1.pcmpos++;
|
||||
if(i2.pcmpos < i2.pcmlen)
|
||||
i2.pcmpos++;
|
||||
if(pts1 != past_end)
|
||||
pts1++;
|
||||
if(pts2 != past_end)
|
||||
pts2++;
|
||||
}
|
||||
}
|
||||
|
||||
void music_player::set_gain()
|
||||
{
|
||||
if(!song)
|
||||
return;
|
||||
try {
|
||||
#ifdef WITH_OPUS_CODEC
|
||||
i1.d.ctl(opus::gain(song->gain));
|
||||
i2.d.ctl(opus::gain(song->gain));
|
||||
#endif
|
||||
builtin_gain = true;
|
||||
} catch(...) {
|
||||
builtin_gain = false;
|
||||
}
|
||||
}
|
||||
|
||||
music_player::music_player(uint64_t& pcm)
|
||||
: pcmpos(pcm)
|
||||
{
|
||||
song = NULL;
|
||||
}
|
||||
}
|
||||
|
99
src/emulation/sky/music.hpp
Normal file
99
src/emulation/sky/music.hpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
#ifndef _skycore__music__hpp__included__
|
||||
#define _skycore__music__hpp__included__
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#ifdef WITH_OPUS_CODEC
|
||||
#include "library/opus.hpp"
|
||||
#endif
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
namespace sky
|
||||
{
|
||||
struct song_buffer;
|
||||
extern const uint64_t past_end; //Position past the end of song.
|
||||
|
||||
struct background_song
|
||||
{
|
||||
//Load song from stream.
|
||||
background_song(std::istream& stream);
|
||||
//The song data.
|
||||
std::map<uint64_t, std::vector<uint8_t>> packets;
|
||||
//Pregap length.
|
||||
uint64_t pregap;
|
||||
//Song length, including pregap.
|
||||
uint64_t total;
|
||||
//Loop start start pts.
|
||||
uint64_t loop_start;
|
||||
//Start of crossfade pts.
|
||||
uint64_t crossfade_start;
|
||||
//Gain.
|
||||
uint16_t gain;
|
||||
//Find valid timecode, rounding down.
|
||||
uint64_t find_timecode_down(uint64_t pts);
|
||||
//Find valid timecode, rounding up. Returns past_end if called with too great pts.
|
||||
uint64_t find_timecode_up(uint64_t pts);
|
||||
//Translate pcm position to pts for track 1.
|
||||
uint64_t pcm_to_pts1(uint64_t pcm);
|
||||
//Translate pcm position to pts for track 2.
|
||||
uint64_t pcm_to_pts2(uint64_t pcm);
|
||||
//Translate gain into gain factor.
|
||||
int32_t gain_factor();
|
||||
};
|
||||
|
||||
extern background_song* bsong;
|
||||
|
||||
uint8_t opus_packet_tick_count(const uint8_t* packet, size_t packetsize);
|
||||
|
||||
#ifdef WITH_OPUS_CODEC
|
||||
typedef opus::decoder opus_decoder;
|
||||
#else
|
||||
struct opus_decoder
|
||||
{
|
||||
size_t decode(const uint8_t* a, size_t b, int16_t* c, size_t d)
|
||||
{
|
||||
uint8_t t = opus_packet_tick_count(a, b);
|
||||
if(!t)
|
||||
throw std::runtime_error("Bad packet");
|
||||
return 120 * t;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
struct music_player_int
|
||||
{
|
||||
music_player_int();
|
||||
void decode_packet(const std::vector<uint8_t>& data);
|
||||
uint16_t pcmpos;
|
||||
uint16_t pcmlen;
|
||||
int16_t pcmbuf[11522];
|
||||
opus_decoder d;
|
||||
};
|
||||
|
||||
struct music_player
|
||||
{
|
||||
music_player(uint64_t& _pcmpos);
|
||||
void set_song(background_song* _song) { song = _song; set_gain(); }
|
||||
void rewind() { pcmpos = 0; do_preroll(); }
|
||||
void do_preroll();
|
||||
void decode(std::pair<int16_t, int16_t>* output, size_t samples);
|
||||
private:
|
||||
void set_gain();
|
||||
void seek_channel(music_player_int& i, uint64_t& spts, uint64_t pts);
|
||||
bool builtin_gain;
|
||||
uint64_t& pcmpos;
|
||||
music_player_int i1;
|
||||
music_player_int i2;
|
||||
background_song* song;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
441
src/emulation/sky/physics.cpp
Normal file
441
src/emulation/sky/physics.cpp
Normal file
|
@ -0,0 +1,441 @@
|
|||
#include "physics.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
noise_maker::~noise_maker()
|
||||
{
|
||||
}
|
||||
|
||||
void physics::force_flag(uint8_t b, bool s)
|
||||
{
|
||||
if(s)
|
||||
flags |= b;
|
||||
else
|
||||
flags &= ~b;
|
||||
}
|
||||
|
||||
void physics::set_flag(uint8_t b)
|
||||
{
|
||||
flags |= b;
|
||||
}
|
||||
|
||||
void physics::clear_flag(uint8_t b)
|
||||
{
|
||||
flags &= ~b;
|
||||
}
|
||||
|
||||
bool physics::is_masked(uint8_t b, uint8_t c)
|
||||
{
|
||||
return ((flags & b) == c);
|
||||
}
|
||||
|
||||
bool physics::is_set(uint8_t b)
|
||||
{
|
||||
return ((flags & b) == b);
|
||||
}
|
||||
|
||||
bool physics::is_any_of(uint8_t b)
|
||||
{
|
||||
return ((flags & b) != 0);
|
||||
}
|
||||
|
||||
bool physics::is_clear(uint8_t b)
|
||||
{
|
||||
return ((flags & b) == 0);
|
||||
}
|
||||
|
||||
void physics::adjust_speed(level& stage, int adjust) throw()
|
||||
{
|
||||
lspeed += adjust;
|
||||
if(lspeed < 0)
|
||||
lspeed = 0;
|
||||
if(lspeed > 10922)
|
||||
lspeed = 10922;
|
||||
}
|
||||
void physics::die(level& stage, uint8_t cause)
|
||||
{
|
||||
if(death)
|
||||
return;
|
||||
death = cause;
|
||||
deathframe = framecounter;
|
||||
}
|
||||
void physics::explode(level& stage, noise_maker& noise)
|
||||
{
|
||||
if(expframe)
|
||||
return;
|
||||
expframe = 1;
|
||||
noise(sound_explode);
|
||||
}
|
||||
void physics::apply_floor_effects(level& stage, noise_maker& noise, unsigned floor)
|
||||
{
|
||||
if(is_clear(flag_landed)) {
|
||||
clear_flag(flag_sticky);
|
||||
return;
|
||||
}
|
||||
switch(floor) {
|
||||
case tile::sticky:
|
||||
if(!expframe)
|
||||
adjust_speed(stage, -303);
|
||||
break;
|
||||
case tile::suppiles:
|
||||
if(death)
|
||||
break;
|
||||
if(o2_left < 27000 || fuel_left < 27000)
|
||||
noise(sound_suppiles);
|
||||
o2_left = 30000;
|
||||
fuel_left = 30000;
|
||||
break;
|
||||
case tile::boost:
|
||||
if(!expframe)
|
||||
adjust_speed(stage, 303);
|
||||
break;
|
||||
case tile::burning:
|
||||
die(stage, death_burning);
|
||||
explode(stage, noise);
|
||||
break;
|
||||
}
|
||||
force_flag(flag_slippery, floor == tile::slippery);
|
||||
force_flag(flag_sticky, floor == tile::sticky);
|
||||
}
|
||||
void physics::check_exit(level& stage) throw()
|
||||
{
|
||||
if(lpos < stage.finish_line())
|
||||
return;
|
||||
if(!stage.in_pipe(lpos, hpos, vpos))
|
||||
return;
|
||||
//Die preserves death reason if one exists.
|
||||
die(stage, death_finished);
|
||||
}
|
||||
void physics::use_suppiles(level& stage) throw()
|
||||
{
|
||||
if(death)
|
||||
return;
|
||||
o2_left -= o2_factor;
|
||||
if(o2_left > 30000)
|
||||
o2_left = 0;
|
||||
fuel_left -= (fuel_factor * lspeed) / 65536;
|
||||
if(fuel_left > 30000)
|
||||
fuel_left = 0;
|
||||
}
|
||||
void physics::check_death(level& stage) throw()
|
||||
{
|
||||
if(!death) {
|
||||
if(vpos < 10240)
|
||||
die(stage, death_drifting);
|
||||
else if(fuel_left == 0)
|
||||
die(stage, death_fuel);
|
||||
else if(o2_left == 0)
|
||||
die(stage, death_o2);
|
||||
} else
|
||||
postdeath++;
|
||||
if(expframe)
|
||||
expframe++;
|
||||
}
|
||||
void physics::apply_steering(level& stage, int lr, int ad, bool jump) throw()
|
||||
{
|
||||
if(death)
|
||||
return;
|
||||
adjust_speed(stage, 75 * ad);
|
||||
if(is_clear(flag_slippery)) {
|
||||
if(is_any_of(flag_blank | flag_jumping)) {
|
||||
if(hspeed == 0 && vspeed > 0 && vpos - jump_ground < 3840)
|
||||
hspeed = 29 * lr;
|
||||
} else
|
||||
hspeed = 29 * lr;
|
||||
}
|
||||
if(jump && is_clear(flag_blank | flag_jumping | flag_no_jump)) {
|
||||
vspeed = 1152;
|
||||
set_flag(flag_jumping);
|
||||
jump_ground = vpos;
|
||||
}
|
||||
}
|
||||
void physics::apply_gravity(level& stage) throw()
|
||||
{
|
||||
if(!expframe) {
|
||||
if(vpos >= 10240)
|
||||
vspeed = vspeed + gravity_accel;
|
||||
else if(vspeed > -106)
|
||||
vspeed = -106;
|
||||
} else {
|
||||
if(vspeed < 0)
|
||||
vspeed = 0;
|
||||
else if(vspeed < 71)
|
||||
vspeed += 39;
|
||||
else
|
||||
vspeed = 71;
|
||||
}
|
||||
}
|
||||
void physics::project_position(level& stage) throw()
|
||||
{
|
||||
lprojected = lpos + lspeed;
|
||||
hprojected = hpos + (hspeed * (lspeed + (is_set(flag_sticky) ? 0 : 1560))) / 512 + hdrift;
|
||||
vprojected = vpos + vspeed;
|
||||
//Don't wrap around horizontally.
|
||||
if((hpos < 12160 && hprojected >= 53376) && (hpos >= 53376 && hprojected < 12160))
|
||||
hprojected = hpos;
|
||||
}
|
||||
uint8_t physics::get_death(level& stage) throw()
|
||||
{
|
||||
if(!death)
|
||||
return 0; //Still alive.
|
||||
else if(death == death_finished) {
|
||||
framecounter++;
|
||||
lpos += lspeed;
|
||||
return (++postdeath > 72) ? death : 0;
|
||||
} else if(death == death_collided || death == death_burning)
|
||||
return (expframe > 42) ? death : 0;
|
||||
else if(death == death_drifting)
|
||||
return (expframe > 42 || postdeath > 108) ? death : 0;
|
||||
else
|
||||
return (postdeath > 108) ? death : 0;
|
||||
}
|
||||
void physics::check_scratching(level& stage) throw()
|
||||
{
|
||||
if(hprojected == hpos)
|
||||
return;
|
||||
hspeed = 0;
|
||||
if(hdrift < 0 && hpos > hprojected)
|
||||
hdrift = 0;
|
||||
if(hdrift > 0 && hpos < hprojected)
|
||||
hdrift = 0;
|
||||
adjust_speed(stage, -151);
|
||||
}
|
||||
void physics::check_collisions(level& stage, noise_maker& noise) throw()
|
||||
{
|
||||
if(lprojected == lpos)
|
||||
return;
|
||||
if(lspeed >= 3640) {
|
||||
die(stage, death_collided);
|
||||
explode(stage, noise);
|
||||
} else {
|
||||
if(lpos > lprojected - lspeed)
|
||||
noise(sound_blow);
|
||||
}
|
||||
lspeed = 0;
|
||||
}
|
||||
void physics::try_locking(level& stage, int lr, int ad, bool jump) throw()
|
||||
{
|
||||
if(vpos < 14080 || !is_masked(flag_tried_lock | flag_jumping, flag_jumping))
|
||||
return;
|
||||
set_flag(flag_tried_lock);
|
||||
if(!dangerous_jump(stage, ad, lpos, hpos, vpos, lspeed, hspeed, vspeed, hdrift))
|
||||
return;
|
||||
for(int32_t a = 1; a < 7; a++) {
|
||||
if(!dangerous_jump(stage, ad, lpos, hpos, vpos, lspeed, hspeed + (a * hspeed) / 10, vspeed,
|
||||
hdrift)) {
|
||||
hspeed = hspeed + (a * hspeed) / 10;
|
||||
set_flag(flag_locked);
|
||||
return;
|
||||
}
|
||||
if(!dangerous_jump(stage, ad, lpos, hpos, vpos, lspeed, hspeed - (a * hspeed) / 10, vspeed,
|
||||
hdrift)) {
|
||||
hspeed = hspeed - (a * hspeed) / 10;
|
||||
set_flag(flag_locked);
|
||||
return;
|
||||
}
|
||||
int32_t tmp = lspeed + (a * lspeed) / 10;
|
||||
if(tmp < 10922)
|
||||
if(!dangerous_jump(stage, ad, lpos, hpos, vpos, tmp, hspeed, vspeed, hdrift)) {
|
||||
speedbias = tmp - lspeed;
|
||||
lspeed = tmp;
|
||||
set_flag(flag_locked);
|
||||
return;
|
||||
}
|
||||
if(!dangerous_jump(stage, ad, lpos, hpos, vpos, lspeed - (a * lspeed) / 10, hspeed, vspeed,
|
||||
hdrift)) {
|
||||
speedbias = - (a * lspeed) / 10;
|
||||
lspeed = lspeed - (a * lspeed) / 10;
|
||||
set_flag(flag_locked);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
void physics::check_horizontal_eject(level& stage, noise_maker& noise) throw()
|
||||
{
|
||||
if(lprojected == lpos || hpos != hprojected)
|
||||
return;
|
||||
if(!stage.collides(lprojected, hpos, vpos))
|
||||
return;
|
||||
if(!stage.collides(lprojected, hpos - 928, vpos)) {
|
||||
hpos -= 928;
|
||||
lprojected = lpos;
|
||||
noise(sound_blow);
|
||||
} else if(!stage.collides(lprojected, hpos + 928, vpos)) {
|
||||
hpos += 928;
|
||||
lprojected = lpos;
|
||||
noise(sound_blow);
|
||||
}
|
||||
}
|
||||
void physics::apply_bounce(level& stage, noise_maker& noise) throw()
|
||||
{
|
||||
if(vprojected == vpos)
|
||||
return;
|
||||
if(hdrift != 0 && nosupport < 2) {
|
||||
vspeed = 0;
|
||||
return;
|
||||
}
|
||||
if(expframe || std::abs(vspeed) < bounce_limit) {
|
||||
vspeed = 0;
|
||||
return;
|
||||
}
|
||||
if(!death && vspeed < 0)
|
||||
noise(sound_bounce);
|
||||
vspeed = -((5 * static_cast<int16_t>(vspeed)) / 10);
|
||||
}
|
||||
void physics::check_landing(level& stage) throw()
|
||||
{
|
||||
if(vprojected == vpos || vspeed >= 0)
|
||||
return;
|
||||
clear_flag(flag_locked | flag_tried_lock | flag_jumping);
|
||||
set_flag(flag_landed);
|
||||
adjust_speed(stage, -speedbias);
|
||||
speedbias = 0;
|
||||
nosupport_d = 0;
|
||||
for(int i = 1; i <= 14; i++)
|
||||
if(!stage.collides(lpos, hpos + 128 * i, vpos - 1)) {
|
||||
nosupport = i;
|
||||
nosupport_d++;
|
||||
break;
|
||||
}
|
||||
for(int i = 1; i <= 14; i++)
|
||||
if(!stage.collides(lpos, hpos - 128 * i, vpos - 1)) {
|
||||
nosupport = i;
|
||||
nosupport_d--;
|
||||
break;
|
||||
}
|
||||
if(nosupport_d)
|
||||
hdrift += 17 * nosupport_d;
|
||||
else
|
||||
hdrift = 0;
|
||||
}
|
||||
void physics::move_ship(level& stage) throw()
|
||||
{
|
||||
if(lprojected == lpos && hprojected == hpos && vprojected == vpos)
|
||||
return;
|
||||
uint32_t tmp_l;
|
||||
uint16_t tmp_h;
|
||||
int32_t tmp_v;
|
||||
int32_t delta_l = lprojected - lpos;
|
||||
int16_t delta_h = hprojected - hpos;
|
||||
int16_t delta_v = vprojected - vpos;
|
||||
int i;
|
||||
for(i = 1; i <= 5; i++) {
|
||||
tmp_l = lpos + i * delta_l / 5;
|
||||
tmp_h = hpos + i * delta_h / 5;
|
||||
tmp_v = vpos + i * delta_v / 5;
|
||||
if(stage.collides(tmp_l, tmp_h, tmp_v)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
lpos = lpos + (i - 1) * delta_l / 5;
|
||||
hpos = hpos + (i - 1) * delta_h / 5;
|
||||
vpos = vpos + (i - 1) * delta_v / 5;
|
||||
for(i = 16384; i > 0; i /= 2)
|
||||
if(i <= abs(lprojected - lpos))
|
||||
if(!stage.collides(lpos + sgn(delta_l) * i, hpos, vpos))
|
||||
lpos = lpos + sgn(delta_l) * i;
|
||||
for(i = 16384; i > 0; i /= 2)
|
||||
if(i <= abs(hprojected - hpos))
|
||||
if(!stage.collides(lpos, hpos + sgn(delta_h) * i, vpos))
|
||||
hpos = hpos + sgn(delta_h) * i;
|
||||
for(i = 16384; i > 0; i /= 2)
|
||||
if(i <= abs(vprojected - vpos))
|
||||
if(!stage.collides(lpos, hpos, vpos + sgn(delta_v) * i))
|
||||
vpos = vpos + sgn(delta_v) * i;
|
||||
}
|
||||
bool physics::dangerous_jump(level& stage, int ad, uint32_t lp, uint16_t hp, int16_t vp, int32_t lv,
|
||||
int16_t hv, int16_t vv, int16_t hd)
|
||||
{
|
||||
uint16_t old_hp;
|
||||
uint32_t old_lp;
|
||||
do {
|
||||
old_hp = hp;
|
||||
old_lp = lp;
|
||||
vv = vv + gravity_accel;
|
||||
lp = lp + lv;
|
||||
hp = hp + hv * (lv + 1560) / 512 + hd;
|
||||
if(hp < 12160 || hp > 53376)
|
||||
return true;
|
||||
vp = vp + vv;
|
||||
lv = lv + 75 * ad;
|
||||
if(lv < 0)
|
||||
lv = 0;
|
||||
if(lv > 10922)
|
||||
lv = 10922;
|
||||
} while(vp > 10240);
|
||||
tile A = stage.at(old_lp, old_hp);
|
||||
tile B = stage.at(lp, hp);
|
||||
return A.is_dangerous() || B.is_dangerous();
|
||||
}
|
||||
uint8_t physics::simulate_frame(level& stage, noise_maker& noise, int lr, int ad, bool jump)
|
||||
{
|
||||
uint8_t cod = get_death(stage);
|
||||
if(cod)
|
||||
return cod;
|
||||
if(death == death_finished)
|
||||
return 0; //The animation to scroll.
|
||||
tile t = stage.at(lpos, hpos);
|
||||
force_flag(flag_blank, t.is_blank());
|
||||
apply_floor_effects(stage, noise, t.surface_type(vpos));
|
||||
check_exit(stage);
|
||||
if(death == death_finished)
|
||||
return 0; //If check_exit changed things.
|
||||
apply_bounce(stage, noise);
|
||||
apply_steering(stage, lr, ad, jump);
|
||||
try_locking(stage, lr, ad, jump);
|
||||
apply_gravity(stage);
|
||||
project_position(stage);
|
||||
move_ship(stage);
|
||||
check_horizontal_eject(stage, noise);
|
||||
check_collisions(stage, noise);
|
||||
check_scratching(stage);
|
||||
clear_flag(flag_landed);
|
||||
check_landing(stage);
|
||||
if(vpos < 0) vpos = 0;
|
||||
use_suppiles(stage);
|
||||
check_death(stage);
|
||||
framecounter++;
|
||||
return 0;
|
||||
}
|
||||
void physics::level_init(level& stage)
|
||||
{
|
||||
gravity = stage.get_gravity();
|
||||
o2_amount = stage.get_o2_amount();
|
||||
fuel_amount = stage.get_fuel_amount();
|
||||
gravity_accel = -((72 * static_cast<int32_t>(gravity) / 5) & 0xFFFF);
|
||||
bounce_limit = (260 * static_cast<int32_t>(gravity) / 8) & 0xFFFF;
|
||||
if(o2_amount)
|
||||
o2_factor = 30000 / ((36 * (int32_t)o2_amount) & 0xFFFF);
|
||||
else
|
||||
o2_factor = 30000;
|
||||
if(fuel_amount)
|
||||
fuel_factor = 30000 / fuel_amount;
|
||||
else
|
||||
fuel_factor = 65535;
|
||||
framecounter = 0;
|
||||
deathframe = 0;
|
||||
lpos = 3 << 16;
|
||||
lprojected = 1999185; //Crap from memory.
|
||||
lspeed = 0;
|
||||
speedbias = 0;
|
||||
expframe = 0;
|
||||
postdeath = 0;
|
||||
hpos = 32768;
|
||||
vpos = 10240;
|
||||
hprojected = 47370; //Crap from memory.
|
||||
vprojected = 0; //Crap from memory.
|
||||
hspeed = 0;
|
||||
vspeed = 0;
|
||||
hdrift = 0;
|
||||
jump_ground = 10240;
|
||||
nosupport = 19422; //Crap from memory.
|
||||
nosupport_d = 16199; //Crap from memory.
|
||||
jump_ground = 0;
|
||||
fuel_left = 30000;
|
||||
o2_left = 30000;
|
||||
death = 0;
|
||||
flags = flag_landed | ((gravity >= 20) ? flag_no_jump : 0);
|
||||
}
|
||||
}
|
103
src/emulation/sky/physics.hpp
Normal file
103
src/emulation/sky/physics.hpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
#ifndef _skycore__physics__hpp__included__
|
||||
#define _skycore__physics__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include "level.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
struct noise_maker
|
||||
{
|
||||
virtual ~noise_maker();
|
||||
virtual void operator()(int sound, bool hipri = true) = 0;
|
||||
};
|
||||
|
||||
struct physics
|
||||
{
|
||||
const static uint8_t death_none = 0; //Playing.
|
||||
const static uint8_t death_burning = 1; //Hit burning floor.
|
||||
const static uint8_t death_drifting = 2; //Drifting forever in space.
|
||||
const static uint8_t death_fuel = 3; //Ran out of fuel.
|
||||
const static uint8_t death_o2 = 4; //Suffocated.
|
||||
const static uint8_t death_collided = 5; //Ram wall too fast.
|
||||
const static uint8_t death_escaped = 6; //Escaped level.
|
||||
const static uint8_t death_finished = 255; //Exited level (finished).
|
||||
const static uint8_t flag_locked = 1; //In locked jump.
|
||||
const static uint8_t flag_tried_lock = 2; //Tried to lock this jump.
|
||||
const static uint8_t flag_jumping = 4; //Currently in jump.
|
||||
const static uint8_t flag_landed = 8; //Currently landed.
|
||||
const static uint8_t flag_slippery = 16; //Slippery effect.
|
||||
const static uint8_t flag_sticky = 32; //Sticky effect.
|
||||
const static uint8_t flag_blank = 64; //Tile blank.
|
||||
const static uint8_t flag_no_jump = 128; //Disable jumping.
|
||||
//This class MUST NOT contain pointers and MUST be prepared to deal with any values!
|
||||
uint32_t framecounter; //Frame counter.
|
||||
uint32_t deathframe; //Frame of death.
|
||||
uint32_t lpos; //Longitudial position.
|
||||
uint32_t lprojected; //Longitudial projected position.
|
||||
int32_t lspeed; //Longitudial speed.
|
||||
int32_t speedbias; //Temporary jump speed boost
|
||||
uint16_t expframe; //Explosion frame (0 if not exploded).
|
||||
uint16_t postdeath; //Number of frames after death.
|
||||
int16_t gravity_accel; //Acceleration of gravity (negative)
|
||||
uint16_t hpos; //Horizontal position.
|
||||
int16_t vpos; //Vertical position.
|
||||
uint16_t hprojected; //Horizontal projected position.
|
||||
int16_t vprojected; //Vertical projected position.
|
||||
int16_t hspeed; //Horizontal speed.
|
||||
int16_t vspeed; //Vertical speed.
|
||||
int16_t hdrift; //Speed of horizontal drift.
|
||||
int16_t jump_ground; //Jumping ground level.
|
||||
int16_t nosupport; //Amount of lack of support.
|
||||
int16_t nosupport_d; //Balance of lack of support.
|
||||
uint16_t fuel_left; //Amount of fuel left.
|
||||
uint16_t o2_left; //Amount of O2 left.
|
||||
int16_t gravity; //Level gravity.
|
||||
uint16_t o2_factor; //O2 use factor.
|
||||
uint16_t fuel_factor; //Fuel use factor.
|
||||
uint16_t bounce_limit; //Minimum speed ship bounces on.
|
||||
int16_t o2_amount; //Level amount of O2.
|
||||
uint16_t fuel_amount; //Level amount of fuel
|
||||
uint8_t death; //Cause of death (0 => Not dead)
|
||||
uint8_t flags; //Flags.
|
||||
//Padding to multiple of 8 bytes.
|
||||
uint8_t padA;
|
||||
uint8_t padB;
|
||||
uint8_t padC;
|
||||
uint8_t padD;
|
||||
|
||||
void level_init(level& stage);
|
||||
uint8_t simulate_frame(level& stage, noise_maker& noise, int lr, int ad, bool jump);
|
||||
bool is_set(uint8_t b);
|
||||
private:
|
||||
void adjust_speed(level& stage, int adjust) throw();
|
||||
void die(level& stage, uint8_t cause);
|
||||
void explode(level& stage, noise_maker& noise);
|
||||
void apply_floor_effects(level& stage, noise_maker& noise, unsigned floor);
|
||||
void check_exit(level& stage) throw();
|
||||
void use_suppiles(level& stage) throw();
|
||||
void check_death(level& stage) throw();
|
||||
void apply_steering(level& stage, int lr, int ad, bool jump) throw();
|
||||
void apply_gravity(level& stage) throw();
|
||||
void project_position(level& stage) throw();
|
||||
uint8_t get_death(level& stage) throw();
|
||||
void check_scratching(level& stage) throw();
|
||||
void check_collisions(level& stage, noise_maker& noise) throw();
|
||||
void try_locking(level& stage, int lr, int ad, bool jump) throw();
|
||||
void check_horizontal_eject(level& stage, noise_maker& noise) throw();
|
||||
void apply_bounce(level& stage, noise_maker& noise) throw();
|
||||
void check_landing(level& stage) throw();
|
||||
void move_ship(level& stage) throw();
|
||||
bool dangerous_jump(level& stage, int ad, uint32_t lp, uint16_t hp, int16_t vp, int32_t lv,
|
||||
int16_t hv, int16_t vv, int16_t hd);
|
||||
void force_flag(uint8_t b, bool s);
|
||||
void set_flag(uint8_t b);
|
||||
void clear_flag(uint8_t b);
|
||||
bool is_masked(uint8_t b, uint8_t c);
|
||||
bool is_any_of(uint8_t b);
|
||||
bool is_clear(uint8_t b);
|
||||
};
|
||||
}
|
||||
#endif
|
233
src/emulation/sky/romimage.cpp
Normal file
233
src/emulation/sky/romimage.cpp
Normal file
|
@ -0,0 +1,233 @@
|
|||
#include "romimage.hpp"
|
||||
#include "framebuffer.hpp"
|
||||
#include "tasdemos.hpp"
|
||||
#include "physics.hpp"
|
||||
#include "library/bintohex.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include "library/zip.hpp"
|
||||
#include <sys/time.h>
|
||||
#include <boost/iostreams/categories.hpp>
|
||||
#include <boost/iostreams/copy.hpp>
|
||||
#include <boost/iostreams/stream.hpp>
|
||||
#include <boost/iostreams/stream_buffer.hpp>
|
||||
#include <boost/iostreams/filter/symmetric.hpp>
|
||||
#include <boost/iostreams/filter/zlib.hpp>
|
||||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
#include <boost/iostreams/device/back_inserter.hpp>
|
||||
|
||||
namespace sky
|
||||
{
|
||||
uint64_t get_utime()
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return static_cast<uint64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||
}
|
||||
|
||||
std::string rom_filename;
|
||||
gauge speed_dat;
|
||||
gauge oxydisp_dat;
|
||||
gauge fueldisp_dat;
|
||||
roads_lzs levels;
|
||||
image ship;
|
||||
image dashboard;
|
||||
image levelselect;
|
||||
image backgrounds[10];
|
||||
sounds soundfx;
|
||||
demo builtin_demo;
|
||||
uint32_t dashpalette[16];
|
||||
|
||||
struct demoset_entry
|
||||
{
|
||||
uint8_t hash[32];
|
||||
std::vector<char> demodata;
|
||||
};
|
||||
std::vector<demoset_entry> demos;
|
||||
|
||||
void load_builtin_demos(std::vector<demoset_entry>& _demos)
|
||||
{
|
||||
const unsigned char* ptr = tasdemos_data;
|
||||
while(*ptr) {
|
||||
ptr++;
|
||||
demoset_entry e;
|
||||
memcpy(e.hash, ptr, 32);
|
||||
ptr += 32;
|
||||
uint32_t l = 0;
|
||||
l = (l << 8) | *(ptr++);
|
||||
l = (l << 8) | *(ptr++);
|
||||
l = (l << 8) | *(ptr++);
|
||||
e.demodata.resize(l);
|
||||
memcpy(&e.demodata[0], ptr, l);
|
||||
ptr += l;
|
||||
_demos.push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
void load_demos(std::vector<demoset_entry>& _demos, const std::string& filename)
|
||||
{
|
||||
zip_reader r(filename);
|
||||
for(auto i : r) {
|
||||
regex_results rx;
|
||||
if(rx = regex("([0-9A-Fa-f]{64}).rec", i)) {
|
||||
demoset_entry e;
|
||||
memset(e.hash, 0, 32);
|
||||
for(unsigned j = 0; j < 64; j++) {
|
||||
unsigned x = i[j];
|
||||
x = (x & 0x1F) ^ 0x10;
|
||||
x = x - (x >> 4) * 7;
|
||||
e.hash[j / 2] = 16 * e.hash[j / 2] + x;
|
||||
}
|
||||
std::istream& z = r[i];
|
||||
boost::iostreams::back_insert_device<std::vector<char>> rd(e.demodata);
|
||||
boost::iostreams::copy(z, rd);
|
||||
delete &z;
|
||||
_demos.push_back(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void load_rom(const std::string& filename)
|
||||
{
|
||||
std::string errfile;
|
||||
try {
|
||||
errfile = "/SPEED.DAT";
|
||||
gauge _speed_dat(read_file_relative(filename + errfile, ""), 0x22);
|
||||
errfile = "/OXY_DISP.DAT";
|
||||
gauge _oxydisp_dat(read_file_relative(filename + errfile, ""), 0x0a);
|
||||
errfile = "/FUL_DISP.DAT";
|
||||
gauge _fueldisp_dat(read_file_relative(filename + errfile, ""), 0x0a);
|
||||
errfile = "/ROADS.LZS";
|
||||
roads_lzs _levels(read_file_relative(filename + errfile, ""));
|
||||
errfile = "/CARS.LZS";
|
||||
image _ship(read_file_relative(filename + errfile, ""));
|
||||
errfile = "/DASHBRD.LZS";
|
||||
image _dashboard(read_file_relative(filename + errfile, ""));
|
||||
if(_dashboard.width != 320 || _dashboard.height > 200) {
|
||||
std::cerr << _dashboard.width << "x" << _dashboard.height << std::endl;
|
||||
throw std::runtime_error("Must be 320 wide and at most 200 high");
|
||||
}
|
||||
errfile = "/GOMENU.LZS";
|
||||
image _levelselect(read_file_relative(filename + errfile, ""));
|
||||
if(_levelselect.width != 320 || _levelselect.height != 200)
|
||||
throw std::runtime_error("Must be 320x200");
|
||||
errfile = "/SFX.SND";
|
||||
sounds _soundfx(read_file_relative(filename + errfile, ""), 5);
|
||||
errfile = "/DEMO.REC";
|
||||
demo _builtin_demo(read_file_relative(filename + errfile, ""), true);
|
||||
image _backgrounds[10];
|
||||
for(unsigned i = 0; i < 10; i++) {
|
||||
std::string n = "/WORLDx.LZS";
|
||||
n[6] = '0' + i;
|
||||
errfile = n;
|
||||
//Skip nonexistent backgrounds.
|
||||
try {
|
||||
std::istream& x = open_file_relative(filename + errfile, "");
|
||||
delete &x;
|
||||
} catch(...) {
|
||||
continue;
|
||||
}
|
||||
_backgrounds[i] = image(read_file_relative(filename + errfile, ""));
|
||||
if(_backgrounds[i].width != 320 || _backgrounds[i].height > 200)
|
||||
throw std::runtime_error("Must be 320 wide and at most 200 high");
|
||||
}
|
||||
std::vector<demoset_entry> _demos;
|
||||
load_builtin_demos(_demos);
|
||||
errfile = "<demos>";
|
||||
load_demos(_demos, filename);
|
||||
|
||||
speed_dat = _speed_dat;
|
||||
oxydisp_dat = _oxydisp_dat;
|
||||
fueldisp_dat = _fueldisp_dat;
|
||||
levels = _levels;
|
||||
ship = _ship;
|
||||
dashboard = _dashboard;
|
||||
levelselect = _levelselect;
|
||||
soundfx = _soundfx;
|
||||
builtin_demo = _builtin_demo;
|
||||
demos = _demos;
|
||||
memcpy(dashpalette, dashboard.palette, sizeof(dashpalette));
|
||||
for(unsigned i = 0; i < 10; i++)
|
||||
backgrounds[i] = _backgrounds[i];
|
||||
rom_filename = filename;
|
||||
} catch(std::exception& e) { throw std::runtime_error(errfile + ": " + e.what()); }
|
||||
}
|
||||
|
||||
//Combine background and dashboard into origbuffer and render.
|
||||
void combine_background(size_t back)
|
||||
{
|
||||
memset(origbuffer, 0, sizeof(origbuffer));
|
||||
image& bg = backgrounds[back];
|
||||
if(bg.width && bg.height) {
|
||||
size_t pixels = 320 * bg.height;
|
||||
for(unsigned i = 0; i < pixels; i++)
|
||||
origbuffer[i] = bg[i] & 0x00FFFFFFU;
|
||||
}
|
||||
{
|
||||
size_t pixels = 320 * dashboard.height;
|
||||
size_t writestart = 64000 - 320 * dashboard.height;
|
||||
for(unsigned i = 0; i < pixels; i++)
|
||||
if(dashboard.decode[i])
|
||||
origbuffer[i + writestart] = dashboard[i] | 0xFF000000U;
|
||||
}
|
||||
render_backbuffer();
|
||||
}
|
||||
|
||||
demo lookup_demo(const uint8_t* levelhash)
|
||||
{
|
||||
for(auto i = demos.rbegin(); i != demos.rend(); i++) {
|
||||
if(!memcmp(i->hash, levelhash, 32))
|
||||
return demo(i->demodata, false);
|
||||
}
|
||||
throw std::runtime_error("No demo found for level");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEMO_PLAYER
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
sky::load_rom(argv[1]);
|
||||
int lvl = atoi(argv[2]);
|
||||
if(!sky::levels.present(lvl)) {
|
||||
std::cerr << "Level " << lvl << " not found" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
sky::level& l = sky::levels[lvl];
|
||||
uint8_t hash[32];
|
||||
l.sha256_hash(hash);
|
||||
std::cerr << "Level hash is " << binary_to_hex(hash, 32) << std::endl;
|
||||
sky::demo d;
|
||||
try {
|
||||
if(lvl)
|
||||
d = sky::lookup_demo(hash);
|
||||
else
|
||||
d = sky::builtin_demo;
|
||||
} catch(std::exception& e) {
|
||||
std::cerr << "Demo lookup failed" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cerr << "Found a demo." << std::endl;
|
||||
sky::physics p;
|
||||
p.level_init(l);
|
||||
uint64_t t1 = sky::get_utime();
|
||||
while(!p.death) {
|
||||
uint16_t buttons = d.fetchkeys(0, p.lpos, p.framecounter);
|
||||
int lr = 0, ad = 0;
|
||||
bool jump = ((buttons & 16) != 0);
|
||||
if((buttons & 1) != 0) lr--;
|
||||
if((buttons & 2) != 0) lr++;
|
||||
if((buttons & 4) != 0) ad++;
|
||||
if((buttons & 8) != 0) ad--;
|
||||
if((buttons & 256) != 0) lr = 2; //Cheat for demo.
|
||||
if((buttons & 512) != 0) ad = 2; //Cheat for demo.
|
||||
p.simulate_frame(l, lr, ad, jump);
|
||||
//std::cerr << p.framecounter << " pos: l=" << p.lpos << " h=" << p.hpos
|
||||
// << " v=" << p.vpos << " death=" << (int)p.death << std::endl;
|
||||
}
|
||||
uint64_t t2 = sky::get_utime();
|
||||
std::cerr << "Simulated " << p.framecounter << " frames in " << (t2 - t1) << "usec ("
|
||||
<< 1000000 * p.framecounter / (t2 - t1) << " fps)" << std::endl;
|
||||
if(p.death == 255)
|
||||
std::cerr << "LEVEL COMPLETED!" << std::endl;
|
||||
return (p.death == 255) ? 0 : 2;
|
||||
}
|
||||
#endif
|
35
src/emulation/sky/romimage.hpp
Normal file
35
src/emulation/sky/romimage.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef _skycore__romimage__hpp__included__
|
||||
#define _skycore__romimage__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include "gauge.hpp"
|
||||
#include "level.hpp"
|
||||
#include "image.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "demo.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
extern std::string rom_filename;
|
||||
extern gauge speed_dat;
|
||||
extern gauge oxydisp_dat;
|
||||
extern gauge fueldisp_dat;
|
||||
extern roads_lzs levels;
|
||||
extern image ship;
|
||||
extern image dashboard;
|
||||
extern image levelselect;
|
||||
extern image backgrounds[10];
|
||||
extern sounds soundfx;
|
||||
extern demo builtin_demo;
|
||||
extern uint32_t dashpalette[16];
|
||||
void load_rom(const std::string& filename);
|
||||
void combine_background(size_t back);
|
||||
demo lookup_demo(const uint8_t* levelhash);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
404
src/emulation/sky/sky.cpp
Normal file
404
src/emulation/sky/sky.cpp
Normal file
|
@ -0,0 +1,404 @@
|
|||
#include "state.hpp"
|
||||
#include "romimage.hpp"
|
||||
#include "framebuffer.hpp"
|
||||
#include "logic.hpp"
|
||||
#include "demo.hpp"
|
||||
#include "core/audioapi.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "interface/romtype.hpp"
|
||||
#include "interface/callbacks.hpp"
|
||||
#include "library/pixfmt-rgb32.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
bool pflag;
|
||||
int cstyle = 0;
|
||||
const unsigned iindexes[3][7] = {
|
||||
{0, 1, 2, 3, 4, 5, 6},
|
||||
{6, 7, 4, 5, 8, 3, 2},
|
||||
{5, 4, 6, 7, 0, 3, 2}
|
||||
};
|
||||
|
||||
//Framebuffer.
|
||||
uint32_t cover_fbmem[320*200];
|
||||
struct framebuffer_info cover_fbinfo = {
|
||||
&_pixel_format_rgb32, //Format.
|
||||
(char*)cover_fbmem, //Memory.
|
||||
320, 200, 1280, //Physical size.
|
||||
320, 200, 1280, //Logical size.
|
||||
0, 0 //Offset.
|
||||
};
|
||||
|
||||
port_controller_button X5 = {port_controller_button::TYPE_BUTTON, 'F', "framesync", true};
|
||||
port_controller_button* X3[] = {&X5};
|
||||
port_controller X4 = {"(system)", "(system)", 1, X3};
|
||||
port_controller_button X9 = {port_controller_button::TYPE_BUTTON, 'L', "left", true};
|
||||
port_controller_button X10 = {port_controller_button::TYPE_BUTTON, 'R', "right", true};
|
||||
port_controller_button X11 = {port_controller_button::TYPE_BUTTON, 'A', "up", true};
|
||||
port_controller_button X12 = {port_controller_button::TYPE_BUTTON, 'D', "down", true};
|
||||
port_controller_button X13 = {port_controller_button::TYPE_BUTTON, 'J', "A", true};
|
||||
port_controller_button X14 = {port_controller_button::TYPE_BUTTON, 'S', "start", true};
|
||||
port_controller_button X15 = {port_controller_button::TYPE_BUTTON, 's', "select", true};
|
||||
port_controller_button X16 = {port_controller_button::TYPE_NULL, '\0', "", true};
|
||||
port_controller_button X17 = {port_controller_button::TYPE_NULL, '\0', "", true};
|
||||
port_controller_button* X7[] = {&X9,&X10,&X11,&X12,&X13,&X14,&X15,&X16,&X17};
|
||||
|
||||
port_controller X8 = {"sky", "sky", 7, X7};
|
||||
port_controller* X1[] = {&X4,&X8};
|
||||
port_controller_set X2 = {2, X1};
|
||||
|
||||
void port_write(unsigned char* buffer, unsigned idx, unsigned ctrl, short x)
|
||||
{
|
||||
switch(idx) {
|
||||
case 0:
|
||||
switch(ctrl) {
|
||||
case 0: if(x) buffer[0] |= 1; else buffer[0] &= ~1; break;
|
||||
};
|
||||
break;
|
||||
case 1:
|
||||
switch(256 * cstyle + ctrl) {
|
||||
case 0: if(x) buffer[0] |= 2; else buffer[0] &= ~2; break;
|
||||
case 1: if(x) buffer[0] |= 4; else buffer[0] &= ~4; break;
|
||||
case 2: if(x) buffer[0] |= 8; else buffer[0] &= ~8; break;
|
||||
case 3: if(x) buffer[0] |= 16; else buffer[0] &= ~16; break;
|
||||
case 4: if(x) buffer[0] |= 32; else buffer[0] &= ~32; break;
|
||||
case 5: if(x) buffer[0] |= 64; else buffer[0] &= ~64; break;
|
||||
case 6: if(x) buffer[0] |= 128; else buffer[0] &= ~128; break;
|
||||
|
||||
case 258: if(x) buffer[0] |= 128; else buffer[0] &= ~128; break;
|
||||
case 259: if(x) buffer[0] |= 64; else buffer[0] &= ~64; break;
|
||||
case 260: if(x) buffer[0] |= 8; else buffer[0] &= ~8; break;
|
||||
case 261: if(x) buffer[0] |= 16; else buffer[0] &= ~16; break;
|
||||
case 262: if(x) buffer[0] |= 2; else buffer[0] &= ~2; break;
|
||||
case 263: if(x) buffer[0] |= 4; else buffer[0] &= ~4; break;
|
||||
case 264: if(x) buffer[0] |= 32; else buffer[0] &= ~32; break;
|
||||
|
||||
case 512: if(x) buffer[0] |= 32; else buffer[0] &= ~32; break;
|
||||
case 514: if(x) buffer[0] |= 128; else buffer[0] &= ~128; break;
|
||||
case 515: if(x) buffer[0] |= 64; else buffer[0] &= ~64; break;
|
||||
case 516: if(x) buffer[0] |= 4; else buffer[0] &= ~4; break;
|
||||
case 517: if(x) buffer[0] |= 2; else buffer[0] &= ~2; break;
|
||||
case 518: if(x) buffer[0] |= 8; else buffer[0] &= ~8; break;
|
||||
case 519: if(x) buffer[0] |= 16; else buffer[0] &= ~16; break;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
short port_read(const unsigned char* buffer, unsigned idx, unsigned ctrl)
|
||||
{
|
||||
switch(idx) {
|
||||
case 0:
|
||||
switch(ctrl) {
|
||||
case 0: return (buffer[0] & 1) ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
switch(256 * cstyle + ctrl) {
|
||||
case 0: return (buffer[0] & 2) ? 1 : 0;
|
||||
case 1: return (buffer[0] & 4) ? 1 : 0;
|
||||
case 2: return (buffer[0] & 8) ? 1 : 0;
|
||||
case 3: return (buffer[0] & 16) ? 1 : 0;
|
||||
case 4: return (buffer[0] & 32) ? 1 : 0;
|
||||
case 5: return (buffer[0] & 64) ? 1 : 0;
|
||||
case 6: return (buffer[0] & 128) ? 1 : 0;
|
||||
|
||||
case 258: return (buffer[0] & 128) ? 1 : 0;
|
||||
case 259: return (buffer[0] & 64) ? 1 : 0;
|
||||
case 260: return (buffer[0] & 8) ? 1 : 0;
|
||||
case 261: return (buffer[0] & 16) ? 1 : 0;
|
||||
case 262: return (buffer[0] & 2) ? 1 : 0;
|
||||
case 263: return (buffer[0] & 4) ? 1 : 0;
|
||||
case 264: return (buffer[0] & 32) ? 1 : 0;
|
||||
|
||||
case 512: return (buffer[0] & 32) ? 1 : 0;
|
||||
case 514: return (buffer[0] & 128) ? 1 : 0;
|
||||
case 515: return (buffer[0] & 64) ? 1 : 0;
|
||||
case 516: return (buffer[0] & 4) ? 1 : 0;
|
||||
case 517: return (buffer[0] & 2) ? 1 : 0;
|
||||
case 518: return (buffer[0] & 8) ? 1 : 0;
|
||||
case 519: return (buffer[0] & 16) ? 1 : 0;
|
||||
};
|
||||
break;
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
void port_display(const unsigned char* buffer, unsigned idx, char* buf)
|
||||
{
|
||||
size_t ptr = 0;
|
||||
short tmp;
|
||||
switch(idx) {
|
||||
case 0:
|
||||
buf[ptr++] = (buffer[0] & 1) ? 'F' : '-';
|
||||
break;
|
||||
case 1:
|
||||
buf[ptr++] = (buffer[0] & 2) ? 'L' : '-';
|
||||
buf[ptr++] = (buffer[0] & 4) ? 'R' : '-';
|
||||
buf[ptr++] = (buffer[0] & 8) ? 'A' : '-';
|
||||
buf[ptr++] = (buffer[0] & 16) ? 'D' : '-';
|
||||
buf[ptr++] = (buffer[0] & 32) ? 'J' : '-';
|
||||
buf[ptr++] = (buffer[0] & 64) ? 'S' : '-';
|
||||
buf[ptr++] = (buffer[0] & 128) ? 's' : '-';
|
||||
break;
|
||||
};
|
||||
buf[ptr] = '\0';
|
||||
};
|
||||
size_t port_serialize(const unsigned char* buffer, char* textbuf)
|
||||
{
|
||||
size_t ptr = 0;
|
||||
short tmp;
|
||||
textbuf[ptr++] = (buffer[0] & 1) ? 'F' : '.';
|
||||
textbuf[ptr++] = '|';
|
||||
textbuf[ptr++] = (buffer[0] & 2) ? 'L' : '.';
|
||||
textbuf[ptr++] = (buffer[0] & 4) ? 'R' : '.';
|
||||
textbuf[ptr++] = (buffer[0] & 8) ? 'A' : '.';
|
||||
textbuf[ptr++] = (buffer[0] & 16) ? 'D' : '.';
|
||||
textbuf[ptr++] = (buffer[0] & 32) ? 'J' : '.';
|
||||
textbuf[ptr++] = (buffer[0] & 64) ? 'S' : '.';
|
||||
textbuf[ptr++] = (buffer[0] & 128) ? 's' : '.';
|
||||
textbuf[ptr] = '\0';
|
||||
return ptr;
|
||||
};
|
||||
size_t port_deserialize(unsigned char* buffer, const char* textbuf)
|
||||
{
|
||||
memset(buffer, 0, 2);
|
||||
size_t ptr = 0;
|
||||
short tmp;
|
||||
if(read_button_value(textbuf, ptr)) buffer[0] |= 1;
|
||||
skip_rest_of_field(textbuf, ptr, true);
|
||||
if(read_button_value(textbuf, ptr)) buffer[0] |= 2;
|
||||
if(read_button_value(textbuf, ptr)) buffer[0] |= 4;
|
||||
if(read_button_value(textbuf, ptr)) buffer[0] |= 8;
|
||||
if(read_button_value(textbuf, ptr)) buffer[0] |= 16;
|
||||
if(read_button_value(textbuf, ptr)) buffer[0] |= 32;
|
||||
if(read_button_value(textbuf, ptr)) buffer[0] |= 64;
|
||||
if(read_button_value(textbuf, ptr)) buffer[0] |= 128;
|
||||
skip_rest_of_field(textbuf, ptr, false);
|
||||
};
|
||||
int port_legal(unsigned c)
|
||||
{
|
||||
if(c == 0) return true;
|
||||
return false;
|
||||
};
|
||||
unsigned port_used_indices(unsigned c)
|
||||
{
|
||||
if(c == 0) return 1;
|
||||
if(c == 1) return 9;
|
||||
return 0;
|
||||
};
|
||||
|
||||
struct _psystem : public port_type
|
||||
{
|
||||
_psystem() : port_type("system", "system", 1,1)
|
||||
{
|
||||
write = port_write;
|
||||
read = port_read;
|
||||
display = port_display;
|
||||
serialize = port_serialize;
|
||||
deserialize = port_deserialize;
|
||||
legal = port_legal;
|
||||
used_indices = port_used_indices;
|
||||
controller_info = &X2;
|
||||
}
|
||||
} psystem;
|
||||
|
||||
port_type* port_types[] = {&psystem, NULL};
|
||||
|
||||
port_index_triple t(unsigned p, unsigned c, unsigned i, bool nl)
|
||||
{
|
||||
port_index_triple x;
|
||||
x.valid = true;
|
||||
x.port = p;
|
||||
x.controller = c;
|
||||
x.control = i;
|
||||
return x;
|
||||
}
|
||||
|
||||
struct core_setting_group sky_settings;
|
||||
|
||||
unsigned world_compat[2] = {0, UINT_MAX};
|
||||
struct core_region_params world_region_params = {
|
||||
"world", "World", 0, 0, false, {656250, 18227}, world_compat
|
||||
};
|
||||
struct core_region world_region(world_region_params);
|
||||
struct core_region* regions[] = {&world_region, NULL};
|
||||
|
||||
struct core_romimage_info_params skyzip_params = {
|
||||
"rom", "skyroads.zip", 1, 1, 0
|
||||
};
|
||||
struct core_romimage_info skyzip(skyzip_params);
|
||||
struct core_romimage_info* images[] = {&skyzip, NULL};
|
||||
|
||||
extern struct core_core sky_core;
|
||||
|
||||
struct core_core_params sky_core_params = {
|
||||
[]() -> std::string { return "Sky"; },
|
||||
[](core_region& region) -> bool { return (®ion == &world_region); },
|
||||
[]() -> std::pair<uint32_t, uint32_t> { return std::make_pair(656250, 18227); },
|
||||
[]() -> std::pair<uint32_t, uint32_t> { return std::make_pair(48000, 1); },
|
||||
[]() -> std::pair<uint32_t, uint32_t> { return std::make_pair(0, 0); },
|
||||
[]() -> std::map<std::string, std::vector<char>> {
|
||||
std::map<std::string, std::vector<char>> r;
|
||||
std::vector<char> sram;
|
||||
sram.resize(32);
|
||||
memcpy(&sram[0], _gstate.sram, 32);
|
||||
r["sram"] = sram;
|
||||
return r;
|
||||
},
|
||||
[](std::map<std::string, std::vector<char>>& sram) -> void {
|
||||
if(sram.count("sram") && sram["sram"].size() == 32)
|
||||
memcpy(_gstate.sram, &sram["sram"][0], 32);
|
||||
else
|
||||
memset(_gstate.sram, 0, 32);
|
||||
},
|
||||
[](std::vector<char>& out) -> void {
|
||||
auto wram = _gstate.as_ram();
|
||||
out.resize(wram.second);
|
||||
memcpy(&out[0], wram.first, wram.second);
|
||||
},
|
||||
[](const char* in, size_t insize) -> void {
|
||||
auto wram = _gstate.as_ram();
|
||||
if(insize != wram.second)
|
||||
throw std::runtime_error("Save is of wrong size");
|
||||
memcpy(wram.first, in, wram.second);
|
||||
handle_loadstate(_gstate);
|
||||
},
|
||||
[]() -> core_region& { return world_region; },
|
||||
[]() -> void {},
|
||||
[]() -> void {},
|
||||
[](uint32_t w, uint32_t h) -> std::pair<uint32_t, uint32_t> {
|
||||
return std::make_pair(FB_WIDTH / w, FB_HEIGHT / h);
|
||||
},
|
||||
[]() -> void { sky_core.hide(); },
|
||||
[]() -> void {},
|
||||
[]() -> void {
|
||||
static unsigned count[4];
|
||||
static unsigned tcount[4] = {5, 7, 8, 25};
|
||||
uint16_t x = 0;
|
||||
for(unsigned i = 0; i < 7; i++)
|
||||
if(ecore_callbacks->get_input(0, 1, iindexes[cstyle][i]))
|
||||
x |= (1 << i);
|
||||
pflag = true;
|
||||
simulate_frame(_gstate, x);
|
||||
uint32_t* fb = indirect_flag ? fadeffect_buffer : sky::framebuffer;
|
||||
framebuffer_info inf;
|
||||
inf.type = &_pixel_format_rgb32;
|
||||
inf.mem = const_cast<char*>(reinterpret_cast<const char*>(fb));
|
||||
inf.physwidth = FB_WIDTH;
|
||||
inf.physheight = FB_HEIGHT;
|
||||
inf.physstride = 4 * FB_WIDTH;
|
||||
inf.width = FB_WIDTH;
|
||||
inf.height = FB_HEIGHT;
|
||||
inf.stride = 4 * FB_WIDTH;
|
||||
inf.offset_x = 0;
|
||||
inf.offset_y = 0;
|
||||
|
||||
framebuffer_raw ls(inf);
|
||||
ecore_callbacks->output_frame(ls, 656250, 18227);
|
||||
ecore_callbacks->timer_tick(18227, 656250);
|
||||
size_t samples = 1333;
|
||||
size_t extrasample = 0;
|
||||
for(unsigned i = 0; i < 4; i++) {
|
||||
count[i]++;
|
||||
if(count[i] == tcount[i]) {
|
||||
count[i] = 0;
|
||||
extrasample = extrasample ? 0 : 1;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
samples += extrasample;
|
||||
int16_t sbuf[2668];
|
||||
fetch_sfx(_gstate, sbuf, samples);
|
||||
audioapi_submit_buffer(sbuf, samples, true, 48000);
|
||||
},
|
||||
[]() -> void {},
|
||||
[]() -> bool { return pflag; },
|
||||
[](bool _pflag) -> void { pflag = _pflag; },
|
||||
[](long delay, bool hard) -> void {},
|
||||
port_types,
|
||||
[]() -> framebuffer_raw& {
|
||||
static framebuffer_raw x(cover_fbinfo);
|
||||
return x;
|
||||
},
|
||||
[]() -> std::string { return "sky"; }
|
||||
};
|
||||
struct core_core sky_core(sky_core_params);
|
||||
|
||||
void controller_magic()
|
||||
{
|
||||
if(magic_flags & 1) {
|
||||
X8.cclass = "gamepad";
|
||||
X8.button_count = 9;
|
||||
cstyle = 1;
|
||||
} else if(magic_flags & 2) {
|
||||
X8.cclass = "gb";
|
||||
X8.button_count = 8;
|
||||
cstyle = 2;
|
||||
} else if(magic_flags & 4) {
|
||||
X8.cclass = "gba";
|
||||
X8.button_count = 8;
|
||||
cstyle = 2;
|
||||
} else {
|
||||
cstyle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct core_type_params skytype_params = {
|
||||
"sky", "Sky", 3522, 0,
|
||||
[](core_romimage* images, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
|
||||
uint64_t rtc_subsec) -> int {
|
||||
controller_magic();
|
||||
const unsigned char* _filename = images[0].data;
|
||||
size_t size = images[0].size;
|
||||
std::string filename(_filename, _filename + size);
|
||||
try {
|
||||
load_rom(filename);
|
||||
} catch(std::exception& e) {
|
||||
messages << e.what();
|
||||
return -1;
|
||||
}
|
||||
rom_boot_vector(_gstate);
|
||||
return 0;
|
||||
},
|
||||
[](std::map<std::string, std::string>& settings) -> controller_set
|
||||
{
|
||||
controller_magic();
|
||||
controller_set r;
|
||||
r.ports.push_back(&psystem);
|
||||
r.portindex.indices.push_back(t(0, 0, 0, false));
|
||||
for(unsigned i = 0; i < 9; i++)
|
||||
r.portindex.indices.push_back(t(0, 1, i, true));
|
||||
r.portindex.logical_map.push_back(std::make_pair(0, 1));
|
||||
r.portindex.pcid_map.push_back(std::make_pair(0, 1));
|
||||
return r;
|
||||
},
|
||||
"sky",
|
||||
NULL,
|
||||
regions,
|
||||
images,
|
||||
&sky_settings,
|
||||
&sky_core,
|
||||
[]() -> std::pair<uint64_t, uint64_t> { return std::make_pair(0, 0); },
|
||||
[]() -> std::list<core_vma_info> {
|
||||
std::list<core_vma_info> r;
|
||||
|
||||
core_vma_info ram;
|
||||
ram.name = "RAM";
|
||||
ram.backing_ram = _gstate.as_ram().first;
|
||||
ram.size = _gstate.as_ram().second;
|
||||
ram.base = 0;
|
||||
ram.readonly = false;
|
||||
ram.endian = 0;
|
||||
ram.iospace_rw = NULL;
|
||||
r.push_back(ram);
|
||||
|
||||
return r;
|
||||
},
|
||||
[]() -> std::set<std::string> {
|
||||
std::set<std::string> r;
|
||||
r.insert("sram");
|
||||
return r;
|
||||
}
|
||||
};
|
||||
struct core_type skytype(skytype_params);
|
||||
core_sysregion X24("sky", skytype, world_region);
|
||||
}
|
121
src/emulation/sky/sound.cpp
Normal file
121
src/emulation/sky/sound.cpp
Normal file
|
@ -0,0 +1,121 @@
|
|||
#include "sound.hpp"
|
||||
#include "romimage.hpp"
|
||||
#include "util.hpp"
|
||||
#include "state.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include "library/zip.hpp"
|
||||
#include "library/minmax.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
sound::sound()
|
||||
{
|
||||
snds = NULL;
|
||||
rate = 128;
|
||||
pointer = 0;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
sound::sound(struct sounds& _snds, uint8_t _rate, uint32_t ptr, uint32_t len)
|
||||
{
|
||||
snds = &_snds;
|
||||
rate = _rate;
|
||||
pointer = ptr;
|
||||
length = len;
|
||||
}
|
||||
|
||||
sounds::sounds()
|
||||
{
|
||||
}
|
||||
|
||||
sounds::sounds(const std::vector<char>& snd, size_t samples)
|
||||
{
|
||||
sounddata = snd;
|
||||
sfx.resize(samples);
|
||||
if(snd.size() < 2 * samples + 2)
|
||||
(stringfmt() << "Sound pointer table incomplete").throwex();
|
||||
for(unsigned i = 0; i < samples; i++) {
|
||||
size_t sptr = combine(snd[2 * i + 0], snd[2 * i + 1]);
|
||||
size_t eptr = combine(snd[2 * i + 2], snd[2 * i + 3]);
|
||||
if(sptr >= snd.size())
|
||||
(stringfmt() << "Sound " << i << " points outside file").throwex();
|
||||
if(eptr > snd.size())
|
||||
(stringfmt() << "Sound " << i << " extends past the end of file").throwex();
|
||||
if(eptr <= sptr)
|
||||
(stringfmt() << "Sound " << i << " size invalid (must be >0)").throwex();
|
||||
uint8_t rate = snd[sptr];
|
||||
sfx[i] = sound(*this, rate, sptr + 1, eptr - sptr - 1);
|
||||
}
|
||||
}
|
||||
|
||||
active_sfx_dma::active_sfx_dma()
|
||||
{
|
||||
//End of transfer.
|
||||
left = 0;
|
||||
pointer = 0;
|
||||
subsample = 0;
|
||||
mdr = 128;
|
||||
rate = 128;
|
||||
}
|
||||
|
||||
void active_sfx_dma::reset(const struct sound& snd)
|
||||
{
|
||||
rate = snd.get_rate();
|
||||
left = 48000ULL * (256 - rate) * snd.get_length();
|
||||
subsample = 0;
|
||||
pointer = snd.get_pointer();
|
||||
mdr = access(snd.get_sounds(), pointer++);
|
||||
}
|
||||
|
||||
void active_sfx_dma::fetch(struct sounds& snds, int16_t* buffer, size_t samples)
|
||||
{
|
||||
while(left > 0 && samples > 0) {
|
||||
*(buffer++) = 256 * ((int16_t)mdr - 128);
|
||||
*(buffer++) = 256 * ((int16_t)mdr - 128);
|
||||
subsample += 1000000;
|
||||
while(subsample > 48000ULL * (256 - rate)) {
|
||||
mdr = snds.access(pointer++);
|
||||
subsample -= 48000ULL * (256 - rate);
|
||||
}
|
||||
left -= 1000000;
|
||||
samples--;
|
||||
}
|
||||
//Fill the rest with silence.
|
||||
for(size_t i = 0; i < samples; i++) {
|
||||
*(buffer++) = 0;
|
||||
*(buffer++) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void fetch_sfx(gstate& s, int16_t* buffer, size_t samples)
|
||||
{
|
||||
static std::vector<std::pair<int16_t, int16_t>> buf;
|
||||
if(buf.size() < samples)
|
||||
buf.resize(samples);
|
||||
s.dma.fetch(soundfx, buffer, samples);
|
||||
try {
|
||||
mplayer.decode(&buf[0], samples);
|
||||
} catch(...) {
|
||||
}
|
||||
for(size_t i = 0; i < samples; i++) {
|
||||
buffer[2 * i + 0] = max(min((int32_t)buffer[2 * i + 0] + buf[i].first, 32767), -32768);
|
||||
buffer[2 * i + 1] = max(min((int32_t)buffer[2 * i + 1] + buf[i].second, 32767), -32768);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sound_noise_maker::sound_noise_maker(const sounds& _snds, struct active_sfx_dma& _dma)
|
||||
: snds(_snds), dma(_dma)
|
||||
{
|
||||
}
|
||||
|
||||
sound_noise_maker::~sound_noise_maker() {}
|
||||
void sound_noise_maker::operator()(int sound, bool hipri)
|
||||
{
|
||||
if(!hipri && dma.busy())
|
||||
return;
|
||||
dma.reset(snds[sound]);
|
||||
}
|
||||
|
||||
sound_noise_maker gsfx(soundfx, _gstate.dma);
|
||||
}
|
80
src/emulation/sky/sound.hpp
Normal file
80
src/emulation/sky/sound.hpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
#ifndef _skycore__sound__hpp__included__
|
||||
#define _skycore__sound__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include "physics.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
const int sound_explode = 0; //Ship explodes.
|
||||
const int sound_bounce = 1; //Ship bounces from floor.
|
||||
const int sound_blow = 2; //Ship takes a blow (not fatal).
|
||||
const int sound_beep = 3; //O2/fuel exhausted.
|
||||
const int sound_suppiles = 4; //Suppiles received.
|
||||
|
||||
struct sounds;
|
||||
|
||||
struct sound
|
||||
{
|
||||
sound();
|
||||
sound(struct sounds& _snds, uint8_t _rate, uint32_t ptr, uint32_t len);
|
||||
const sounds& get_sounds() const { return *snds; }
|
||||
uint8_t get_rate() const { return rate; }
|
||||
uint32_t get_pointer() const { return pointer; }
|
||||
uint32_t get_length() const { return length; }
|
||||
private:
|
||||
sounds* snds;
|
||||
uint8_t rate;
|
||||
uint32_t pointer;
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
struct sounds
|
||||
{
|
||||
sounds();
|
||||
sounds(const std::vector<char>& snd, size_t samples);
|
||||
const sound& operator[](size_t idx) const { return (idx < sfx.size()) ? sfx[idx] : dummy; }
|
||||
uint8_t access(size_t idx) const { return (idx < sounddata.size()) ? sounddata[idx] : 0x80; }
|
||||
private:
|
||||
std::vector<char> sounddata;
|
||||
std::vector<sound> sfx;
|
||||
sound dummy;
|
||||
};
|
||||
|
||||
struct gstate;
|
||||
void fetch_sfx(gstate& s, int16_t* buffer, size_t samples); //Stereo!
|
||||
|
||||
struct active_sfx_dma
|
||||
{
|
||||
active_sfx_dma();
|
||||
void reset(const struct sound& snd);
|
||||
void fetch(struct sounds& snds, int16_t* buffer, size_t samples); //Stereo!
|
||||
bool busy() { return (left > 0); }
|
||||
private:
|
||||
uint8_t access(const struct sounds& snds, uint32_t addr) { snds.access(addr); }
|
||||
int64_t left;
|
||||
uint32_t pointer;
|
||||
uint32_t subsample;
|
||||
uint32_t padA;
|
||||
uint16_t padB;
|
||||
uint8_t mdr;
|
||||
uint8_t rate;
|
||||
};
|
||||
|
||||
struct sound_noise_maker : public noise_maker
|
||||
{
|
||||
sound_noise_maker(const sounds& _snds, struct active_sfx_dma& _dma);
|
||||
~sound_noise_maker();
|
||||
void operator()(int sound, bool hipri = true);
|
||||
private:
|
||||
const sounds& snds;
|
||||
active_sfx_dma& dma;
|
||||
};
|
||||
|
||||
extern sound_noise_maker gsfx;
|
||||
}
|
||||
#endif
|
47
src/emulation/sky/state.cpp
Normal file
47
src/emulation/sky/state.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include "state.hpp"
|
||||
#include "romimage.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
const char* statenames[] = {
|
||||
"MENU_FADEIN", "MENU", "MENU_FADEOUT", "LOAD_LEVEL", "LEVEL_FADEIN", "LEVEL_PLAY", "LEVEL_COMPLETE",
|
||||
"LEVEL_FADEOUT", "LOAD_MENU", "LEVEL_UNAVAIL", "DEMO_UNAVAIL", "LEVEL_FADEOUT_RETRY"
|
||||
};
|
||||
|
||||
void gstate::level_init(uint8_t _stage)
|
||||
{
|
||||
stage = _stage;
|
||||
p.level_init(curlevel);
|
||||
paused = 0;
|
||||
speedind = 0;
|
||||
fuelind = 0;
|
||||
o2ind = 0;
|
||||
distind = 0;
|
||||
lockind = 0;
|
||||
beep_phase = 0;
|
||||
}
|
||||
uint8_t gstate::simulate_frame(int lr, int ad, bool jump)
|
||||
{
|
||||
uint8_t dstatus = p.simulate_frame(curlevel, gsfx, lr, ad, jump);
|
||||
uint16_t lt = p.lpos >> 16;
|
||||
uint8_t ht = (p.hpos - 12160) / 5888;
|
||||
if(secret == 1 && p.is_set(physics::flag_landed) && ht <= 2 && lt >= 131 && lt <= 170)
|
||||
secret |= 0x80;
|
||||
else if(secret == 2 && p.is_set(physics::flag_landed) && ht == 3 && lt >= 58 && lt <= 62)
|
||||
secret |= 0x80;
|
||||
return dstatus;
|
||||
}
|
||||
void gstate::change_state(uint8_t newstate)
|
||||
{
|
||||
state = newstate;
|
||||
fadecount = 0;
|
||||
}
|
||||
|
||||
std::pair<uint8_t*, size_t> gstate::as_ram()
|
||||
{
|
||||
return std::make_pair(reinterpret_cast<uint8_t*>(this), sizeof(*this));
|
||||
}
|
||||
|
||||
gstate _gstate;
|
||||
music_player mplayer(_gstate.pcmpos);
|
||||
}
|
70
src/emulation/sky/state.hpp
Normal file
70
src/emulation/sky/state.hpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#ifndef _skycore__state__hpp__included__
|
||||
#define _skycore__state__hpp__included__
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include "physics.hpp"
|
||||
#include "music.hpp"
|
||||
#include "demo.hpp"
|
||||
#include "level.hpp"
|
||||
#include "sound.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
const uint8_t state_menu_fadein = 0; //Menu fading in.
|
||||
const uint8_t state_menu = 1; //In menu.
|
||||
const uint8_t state_menu_fadeout = 2; //Menu fading out.
|
||||
const uint8_t state_load_level = 3; //Level being loaded.
|
||||
const uint8_t state_level_fadein = 4; //Level fading in.
|
||||
const uint8_t state_level_play = 5; //Level being played.
|
||||
const uint8_t state_level_complete = 6; //Level completed.
|
||||
const uint8_t state_level_fadeout = 7; //Level fading out.
|
||||
const uint8_t state_load_menu = 8; //Menu being loaded.
|
||||
const uint8_t state_level_unavail = 9; //Level unavailable.
|
||||
const uint8_t state_demo_unavail = 10; //Demo unavailable.
|
||||
const uint8_t state_level_fadeout_retry = 11; //Level fading out for retry.
|
||||
const uint8_t state_load_level_nomus = 12; //Level being loaded, without reloading music.
|
||||
const uint8_t state_lockup = 13; //Game is locked up.
|
||||
|
||||
struct gstate
|
||||
{
|
||||
//DO NOT PUT POINTERS IN HERE!!!
|
||||
//Also, be careful not to do anything undefined if there is a bad value.
|
||||
demo curdemo;
|
||||
level curlevel;
|
||||
active_sfx_dma dma;
|
||||
physics p;
|
||||
uint64_t pcmpos; //PCM position in song.
|
||||
uint64_t frames_ran; //Number of frames run.
|
||||
uint32_t cursong; //Current song number.
|
||||
uint16_t waited; //Menu wait.
|
||||
uint8_t paused; //Paused flag.
|
||||
uint8_t speedind; //Indicated speed.
|
||||
uint8_t o2ind; //Indicated amount of oxygen.
|
||||
uint8_t fuelind; //Indicated amount of fuel.
|
||||
uint8_t distind; //Indicated distance.
|
||||
uint8_t lockind; //Lock indicator flag.
|
||||
uint8_t beep_phase; //Out of O2/Fuel flash phase.
|
||||
uint8_t state; //State of game.
|
||||
uint8_t fadecount; //Fade counter.
|
||||
uint8_t stage; //Current stage.
|
||||
uint8_t oldstage; //old stage (used in menu).
|
||||
uint8_t savestage; //Saved stage (used over demo).
|
||||
uint8_t demo_flag; //Set to 1 to load demo.
|
||||
uint8_t lastkeys; //Last key state.
|
||||
uint8_t secret; //Secret flag.
|
||||
uint8_t padB; //Padding.
|
||||
uint8_t padC; //Padding.
|
||||
uint8_t padD; //Padding.
|
||||
uint8_t sram[32]; //SRAM.
|
||||
void level_init(uint8_t _stage);
|
||||
uint8_t simulate_frame(int lr, int ad, bool jump);
|
||||
void change_state(uint8_t newstate);
|
||||
std::pair<uint8_t*, size_t> as_ram();
|
||||
};
|
||||
extern gstate _gstate;
|
||||
extern music_player mplayer;
|
||||
inline gstate& get_state() { return _gstate; }
|
||||
}
|
||||
|
||||
#endif
|
513
src/emulation/sky/tasdemos.cpp
Normal file
513
src/emulation/sky/tasdemos.cpp
Normal file
|
@ -0,0 +1,513 @@
|
|||
#include "tasdemos.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
const unsigned char tasdemos_data[8065] =
|
||||
{
|
||||
0x01, 0xde, 0x6a, 0x12, 0x51, 0xc9, 0x89, 0x26, 0xce, 0x98, 0x6c, 0xb2, 0x47, 0xe3, 0x99, 0xca,
|
||||
0x9e, 0xdc, 0x27, 0xef, 0xc3, 0x02, 0x0b, 0x75, 0xc5, 0xa3, 0x68, 0x5d, 0x39, 0xf9, 0x04, 0xfd,
|
||||
0xc9, 0x00, 0x00, 0x30, 0x00, 0x09, 0x17, 0x0a, 0x2b, 0x09, 0x0f, 0x1a, 0x1a, 0x08, 0x09, 0x09,
|
||||
0x09, 0x18, 0x12, 0x0a, 0x04, 0x09, 0x04, 0x18, 0x08, 0x08, 0x16, 0x1a, 0x01, 0x0a, 0x1e, 0x09,
|
||||
0x0b, 0x19, 0x20, 0x09, 0x02, 0x19, 0x09, 0x18, 0x01, 0x08, 0x07, 0x09, 0x03, 0x19, 0x09, 0x1a,
|
||||
0x18, 0x08, 0x2e, 0x09, 0x01, 0x68, 0xd5, 0x41, 0xf9, 0xaf, 0x17, 0x6b, 0x21, 0x51, 0x7d, 0x3b,
|
||||
0xf3, 0x36, 0x25, 0xb4, 0x78, 0x1b, 0xfc, 0x1c, 0x7b, 0x18, 0x1d, 0x76, 0x51, 0x9a, 0x26, 0xba,
|
||||
0xe3, 0xc5, 0x27, 0xde, 0xaf, 0x00, 0x00, 0x80, 0x00, 0x09, 0x26, 0x08, 0x13, 0x09, 0x0e, 0x1a,
|
||||
0x09, 0x08, 0x0e, 0x09, 0x0e, 0x19, 0x1d, 0x09, 0x0b, 0x19, 0x0a, 0x09, 0x01, 0x08, 0x10, 0x18,
|
||||
0x02, 0x08, 0x08, 0x09, 0x12, 0x1a, 0x03, 0x0a, 0x02, 0x19, 0x03, 0x09, 0x16, 0x0a, 0x03, 0x19,
|
||||
0x0a, 0x18, 0x02, 0x08, 0x06, 0x0a, 0x05, 0x09, 0x00, 0x0a, 0x12, 0x1a, 0x03, 0x08, 0x11, 0x09,
|
||||
0x04, 0x19, 0x12, 0x09, 0x0e, 0x18, 0x14, 0x09, 0x0b, 0x18, 0x00, 0x19, 0x23, 0x0a, 0x1a, 0x09,
|
||||
0x0b, 0x18, 0x18, 0x09, 0x01, 0x0a, 0x0c, 0x1a, 0x06, 0x09, 0x01, 0x08, 0x0f, 0x09, 0x06, 0x19,
|
||||
0x14, 0x09, 0x0d, 0x18, 0x04, 0x08, 0x00, 0x09, 0x06, 0x0a, 0x09, 0x09, 0x02, 0x19, 0x05, 0x18,
|
||||
0x12, 0x09, 0x0f, 0x1a, 0x07, 0x09, 0x0e, 0x19, 0x07, 0x09, 0x02, 0x0a, 0x09, 0x1a, 0x0b, 0x0a,
|
||||
0x00, 0x09, 0x1a, 0x19, 0x05, 0x09, 0x00, 0x05, 0x01, 0xe3, 0x44, 0xa5, 0xc5, 0x61, 0x93, 0x6f,
|
||||
0xf8, 0xa8, 0xe3, 0x66, 0x48, 0x82, 0xea, 0x06, 0xa5, 0x8e, 0x0f, 0xa2, 0xd7, 0x91, 0x58, 0x70,
|
||||
0xf2, 0x24, 0xa8, 0xb3, 0xf1, 0xdc, 0x6f, 0x97, 0xf0, 0x00, 0x00, 0x3c, 0x1e, 0x09, 0x0d, 0x19,
|
||||
0x28, 0x09, 0x0d, 0x19, 0x18, 0x09, 0x07, 0x19, 0x0a, 0x09, 0x01, 0x0a, 0x06, 0x09, 0x0a, 0x18,
|
||||
0x01, 0x08, 0x09, 0x09, 0x0f, 0x1a, 0x06, 0x09, 0x08, 0x08, 0x0a, 0x19, 0x10, 0x09, 0x01, 0x19,
|
||||
0x05, 0x1a, 0x0b, 0x09, 0x08, 0x08, 0x10, 0x18, 0x08, 0x08, 0x1f, 0x1a, 0x00, 0x19, 0x17, 0x09,
|
||||
0x0f, 0x19, 0x0b, 0x09, 0x14, 0x19, 0x0b, 0x09, 0x01, 0xf3, 0x0a, 0x2e, 0x1c, 0xfb, 0x45, 0x48,
|
||||
0x76, 0x71, 0x75, 0x83, 0x34, 0xff, 0x5f, 0x78, 0x08, 0x44, 0x5b, 0x92, 0xe7, 0xff, 0xc4, 0xdc,
|
||||
0xf8, 0xd9, 0xcf, 0x3d, 0xf3, 0x5e, 0x96, 0xe2, 0x30, 0x00, 0x00, 0x48, 0x4e, 0x09, 0x02, 0x08,
|
||||
0x15, 0x09, 0x0c, 0x1a, 0x0d, 0x0a, 0x04, 0x08, 0x11, 0x18, 0x1e, 0x09, 0x0d, 0x0a, 0x11, 0x09,
|
||||
0x08, 0x19, 0x19, 0x08, 0x08, 0x19, 0x0d, 0x09, 0x0e, 0x1a, 0x0e, 0x08, 0x0f, 0x18, 0x09, 0x08,
|
||||
0x0b, 0x1a, 0x07, 0x0a, 0x38, 0x09, 0x01, 0x19, 0x0a, 0x18, 0x00, 0x19, 0x15, 0x09, 0x1d, 0x1a,
|
||||
0x2d, 0x09, 0x06, 0x08, 0x00, 0x09, 0x0c, 0x19, 0x06, 0x09, 0x15, 0x19, 0x05, 0x09, 0x12, 0x18,
|
||||
0x03, 0x0a, 0x11, 0x09, 0x01, 0x87, 0xff, 0xbc, 0x7a, 0x79, 0x90, 0xf0, 0x30, 0xcc, 0x5a, 0xd4,
|
||||
0xa2, 0xea, 0xae, 0xeb, 0xe4, 0x75, 0x69, 0x5e, 0x1c, 0x4d, 0x46, 0xe3, 0x09, 0x24, 0xd6, 0xff,
|
||||
0x77, 0x6b, 0x31, 0xb4, 0x74, 0x00, 0x00, 0x74, 0x00, 0x09, 0x1f, 0x0a, 0x19, 0x1a, 0x06, 0x0a,
|
||||
0x0e, 0x09, 0x05, 0x08, 0x2b, 0x18, 0x06, 0x19, 0x01, 0x09, 0x06, 0x0a, 0x13, 0x1a, 0x06, 0x09,
|
||||
0x11, 0x19, 0x01, 0x09, 0x02, 0x0a, 0x06, 0x1a, 0x04, 0x08, 0x1a, 0x18, 0x01, 0x08, 0x0a, 0x18,
|
||||
0x09, 0x08, 0x2c, 0x09, 0x0b, 0x0a, 0x11, 0x1a, 0x05, 0x0a, 0x0a, 0x19, 0x00, 0x1a, 0x09, 0x0a,
|
||||
0x03, 0x09, 0x18, 0x18, 0x24, 0x09, 0x00, 0x08, 0x01, 0x09, 0x00, 0x08, 0x01, 0x09, 0x00, 0x08,
|
||||
0x1e, 0x09, 0x00, 0x08, 0x35, 0x09, 0x02, 0x19, 0x09, 0x1a, 0x07, 0x0a, 0x0a, 0x1a, 0x0d, 0x09,
|
||||
0x0e, 0x19, 0x08, 0x09, 0x11, 0x19, 0x04, 0x09, 0x0f, 0x19, 0x07, 0x09, 0x06, 0x19, 0x2b, 0x09,
|
||||
0x08, 0x08, 0x11, 0x18, 0x06, 0x08, 0x13, 0x09, 0x05, 0x19, 0x3b, 0x09, 0x01, 0xf0, 0xbb, 0xb6,
|
||||
0x28, 0xae, 0x78, 0x5b, 0x02, 0x3b, 0x0f, 0x97, 0x49, 0xe0, 0xfb, 0x8c, 0x20, 0xb2, 0x20, 0x6f,
|
||||
0xce, 0xab, 0x64, 0x57, 0x5d, 0xcb, 0x32, 0x0b, 0xa6, 0x5a, 0xdd, 0x1c, 0x6b, 0x00, 0x00, 0x2e,
|
||||
0x00, 0x09, 0x10, 0x0a, 0x10, 0x1a, 0x11, 0x0a, 0x38, 0x09, 0x05, 0x19, 0x19, 0x09, 0x10, 0x18,
|
||||
0x00, 0x08, 0x07, 0x0a, 0x0d, 0x09, 0x06, 0x19, 0x13, 0x09, 0x08, 0x0a, 0x07, 0x09, 0x0d, 0x19,
|
||||
0x16, 0x09, 0x11, 0x18, 0x02, 0x09, 0x0b, 0x1a, 0x0e, 0x09, 0x08, 0x08, 0x12, 0x09, 0x01, 0x05,
|
||||
0x3b, 0x08, 0x54, 0x70, 0x7f, 0x14, 0x66, 0x74, 0xc6, 0x8e, 0x52, 0x59, 0x0b, 0xf6, 0x64, 0xac,
|
||||
0x4b, 0x8a, 0x15, 0x5f, 0x8d, 0xd3, 0x9e, 0x38, 0x3e, 0x18, 0x0e, 0x71, 0x44, 0x04, 0x89, 0x00,
|
||||
0x00, 0x34, 0x00, 0x09, 0x0e, 0x08, 0x15, 0x18, 0x05, 0x0a, 0x07, 0x09, 0x2a, 0x19, 0x03, 0x09,
|
||||
0x02, 0x19, 0x08, 0x1a, 0x12, 0x09, 0x0d, 0x1a, 0x10, 0x08, 0x07, 0x09, 0x04, 0x19, 0x2e, 0x09,
|
||||
0x11, 0x19, 0x03, 0x09, 0x13, 0x19, 0x2f, 0x09, 0x01, 0x08, 0x10, 0x18, 0x07, 0x08, 0x1a, 0x19,
|
||||
0x0f, 0x09, 0x0e, 0x0a, 0x05, 0x09, 0x01, 0x92, 0x38, 0x72, 0xef, 0x83, 0x9a, 0x39, 0x89, 0xbf,
|
||||
0x7c, 0x01, 0xe8, 0x04, 0xa7, 0xf7, 0xb2, 0x3c, 0x14, 0xab, 0x54, 0x03, 0x13, 0xba, 0x94, 0x6d,
|
||||
0x5a, 0x67, 0x14, 0x07, 0xc6, 0x6b, 0x9e, 0x00, 0x00, 0x56, 0x00, 0x09, 0x03, 0x0a, 0x29, 0x09,
|
||||
0x0e, 0x18, 0x18, 0x0a, 0x1e, 0x09, 0x02, 0x0a, 0x0e, 0x1a, 0x07, 0x0a, 0x22, 0x09, 0x06, 0x19,
|
||||
0x19, 0x09, 0x10, 0x19, 0x0c, 0x09, 0x02, 0x19, 0x0a, 0x18, 0x1a, 0x09, 0x04, 0x08, 0x04, 0x09,
|
||||
0x05, 0x19, 0x0d, 0x09, 0x11, 0x19, 0x08, 0x09, 0x0b, 0x18, 0x11, 0x09, 0x05, 0x0a, 0x0d, 0x1a,
|
||||
0x07, 0x0a, 0x06, 0x1a, 0x0f, 0x09, 0x0c, 0x19, 0x06, 0x09, 0x1d, 0x08, 0x50, 0x09, 0x05, 0x19,
|
||||
0x0a, 0x09, 0x0f, 0x1a, 0x12, 0x09, 0x02, 0x19, 0x09, 0x18, 0x02, 0x09, 0x01, 0x0a, 0x3e, 0x09,
|
||||
0x01, 0x65, 0xa1, 0xa7, 0x73, 0x40, 0x61, 0x2a, 0x55, 0x82, 0x5a, 0x5c, 0xcb, 0xaa, 0x51, 0xbe,
|
||||
0x56, 0xc2, 0x54, 0xb2, 0x2a, 0x2e, 0x67, 0xb9, 0x96, 0x2f, 0xf5, 0xb0, 0xba, 0xa3, 0x1c, 0x22,
|
||||
0xbf, 0x00, 0x00, 0x34, 0x00, 0x09, 0x15, 0x0a, 0x37, 0x09, 0x20, 0x19, 0x17, 0x18, 0x11, 0x1a,
|
||||
0x07, 0x0a, 0x1d, 0x18, 0x0f, 0x0a, 0x07, 0x09, 0x0a, 0x0a, 0x0f, 0x1a, 0x0b, 0x0a, 0x17, 0x09,
|
||||
0x07, 0x08, 0x0e, 0x18, 0x12, 0x09, 0x0a, 0x19, 0x1a, 0x09, 0x11, 0x1a, 0x04, 0x0a, 0x06, 0x09,
|
||||
0x19, 0x19, 0x0e, 0x09, 0x07, 0x08, 0x1b, 0x09, 0x01, 0xa4, 0xdb, 0xa8, 0xc9, 0x92, 0xec, 0x97,
|
||||
0x1d, 0xbc, 0x95, 0xe6, 0x37, 0xa8, 0xef, 0x3c, 0x3f, 0x16, 0x46, 0xb4, 0xea, 0xcc, 0xd4, 0xa2,
|
||||
0xcf, 0xef, 0xfe, 0x5e, 0x46, 0x68, 0x13, 0x4e, 0x02, 0x00, 0x00, 0x4c, 0x00, 0x09, 0x2e, 0x0a,
|
||||
0x08, 0x09, 0x06, 0x19, 0x0d, 0x09, 0x25, 0x19, 0x12, 0x18, 0x06, 0x09, 0x10, 0x19, 0x09, 0x09,
|
||||
0x0b, 0x19, 0x0b, 0x0a, 0x07, 0x09, 0x09, 0x19, 0x14, 0x1a, 0x0c, 0x09, 0x06, 0x08, 0x06, 0x18,
|
||||
0x1b, 0x09, 0x03, 0x0a, 0x0c, 0x19, 0x0a, 0x09, 0x02, 0x0a, 0x10, 0x1a, 0x13, 0x18, 0x09, 0x08,
|
||||
0x0d, 0x19, 0x21, 0x09, 0x10, 0x19, 0x04, 0x09, 0x05, 0x0a, 0x0c, 0x1a, 0x0e, 0x0a, 0x11, 0x09,
|
||||
0x09, 0x19, 0x15, 0x08, 0x0b, 0x09, 0x00, 0x05, 0x01, 0xda, 0xa0, 0xc2, 0x11, 0xa8, 0x63, 0xa9,
|
||||
0x6c, 0x0c, 0x1c, 0x07, 0x88, 0xaa, 0x72, 0x89, 0xb0, 0x6b, 0x5a, 0x98, 0x9d, 0xa2, 0x38, 0x4d,
|
||||
0x8d, 0xb6, 0xd2, 0x5b, 0x33, 0x8f, 0xff, 0x98, 0xeb, 0x00, 0x00, 0x60, 0x15, 0x09, 0x1d, 0x19,
|
||||
0x0c, 0x09, 0x29, 0x19, 0x05, 0x09, 0x12, 0x19, 0x2a, 0x09, 0x23, 0x18, 0x0a, 0x09, 0x06, 0x19,
|
||||
0x01, 0x09, 0x32, 0x0a, 0x0a, 0x19, 0x34, 0x09, 0x21, 0x19, 0x11, 0x09, 0x0a, 0x0a, 0x06, 0x08,
|
||||
0x20, 0x09, 0x26, 0x19, 0x05, 0x09, 0x1e, 0x19, 0x18, 0x08, 0x05, 0x09, 0x1c, 0x1a, 0x3a, 0x09,
|
||||
0x20, 0x18, 0x06, 0x09, 0x01, 0x08, 0x2d, 0x09, 0x20, 0x1a, 0x03, 0x09, 0x24, 0x19, 0x23, 0x09,
|
||||
0x26, 0x19, 0x05, 0x09, 0x18, 0x18, 0x1c, 0x09, 0x21, 0x1a, 0x16, 0x09, 0x23, 0x19, 0x15, 0x09,
|
||||
0x26, 0x19, 0x10, 0x09, 0x18, 0x19, 0x06, 0x09, 0x1c, 0x08, 0x3f, 0x09, 0x01, 0x71, 0xb0, 0x5c,
|
||||
0x04, 0xff, 0x84, 0x39, 0x35, 0x3f, 0x68, 0xd8, 0x55, 0xa7, 0x59, 0x75, 0xa0, 0xf8, 0x53, 0x70,
|
||||
0x97, 0xf3, 0x1e, 0x99, 0x80, 0xf0, 0x0a, 0x4a, 0xc3, 0x17, 0x44, 0x87, 0xa7, 0x00, 0x00, 0x64,
|
||||
0x00, 0x09, 0x10, 0x0a, 0x0f, 0x1a, 0x00, 0x19, 0x03, 0x09, 0x17, 0x08, 0x2e, 0x09, 0x03, 0x19,
|
||||
0x4a, 0x09, 0x12, 0x18, 0x01, 0x08, 0x01, 0x09, 0x0a, 0x0a, 0x02, 0x09, 0x45, 0x19, 0x13, 0x1a,
|
||||
0x12, 0x18, 0x0c, 0x08, 0x2e, 0x09, 0x07, 0x19, 0x1e, 0x09, 0x0f, 0x19, 0x05, 0x08, 0x4d, 0x09,
|
||||
0x08, 0x0a, 0x1d, 0x09, 0x03, 0x19, 0x23, 0x09, 0x09, 0x19, 0x06, 0x09, 0x01, 0x0a, 0x12, 0x09,
|
||||
0x10, 0x18, 0x03, 0x09, 0x04, 0x0a, 0x33, 0x09, 0x07, 0x0a, 0x28, 0x09, 0x06, 0x0a, 0x28, 0x09,
|
||||
0x07, 0x0a, 0x40, 0x09, 0x1b, 0x18, 0x13, 0x08, 0x00, 0x0a, 0x15, 0x09, 0x03, 0x19, 0x06, 0x1a,
|
||||
0x11, 0x0a, 0x23, 0x09, 0x01, 0xdb, 0x48, 0xdd, 0xed, 0xa2, 0xb6, 0x1a, 0x8d, 0xc7, 0x66, 0xad,
|
||||
0x92, 0xc9, 0xa5, 0x4b, 0x40, 0xba, 0x50, 0x96, 0x0c, 0x2e, 0x87, 0xfa, 0x99, 0xdd, 0x45, 0x24,
|
||||
0x32, 0x67, 0x32, 0xfc, 0x1a, 0x00, 0x00, 0x48, 0x00, 0x09, 0x1a, 0x1a, 0x0d, 0x0a, 0x09, 0x1a,
|
||||
0x22, 0x09, 0x09, 0x08, 0x0f, 0x09, 0x0e, 0x18, 0x25, 0x09, 0x07, 0x19, 0x8a, 0x09, 0x09, 0x1a,
|
||||
0x0c, 0x0a, 0x24, 0x09, 0x10, 0x18, 0x02, 0x09, 0x0e, 0x19, 0x06, 0x08, 0x40, 0x19, 0x1a, 0x09,
|
||||
0x19, 0x19, 0x10, 0x0a, 0x0b, 0x1a, 0x00, 0x19, 0x0a, 0x18, 0x10, 0x19, 0x06, 0x1a, 0x1b, 0x09,
|
||||
0x0f, 0x19, 0x07, 0x09, 0x10, 0x18, 0x01, 0x09, 0x02, 0x0a, 0x13, 0x09, 0x13, 0x19, 0x07, 0x09,
|
||||
0x01, 0x78, 0x74, 0x87, 0xc8, 0x4b, 0xf4, 0xf4, 0x21, 0xb9, 0x2c, 0x5c, 0x99, 0xc5, 0xc6, 0x3b,
|
||||
0x0f, 0xd6, 0x97, 0xab, 0xa5, 0xf1, 0x9d, 0x6e, 0x90, 0x0c, 0x40, 0x84, 0xf1, 0x9b, 0xda, 0xd2,
|
||||
0xba, 0x00, 0x00, 0x9c, 0x00, 0x09, 0x14, 0x0a, 0x17, 0x08, 0x10, 0x0a, 0x0d, 0x08, 0x0b, 0x0a,
|
||||
0x0a, 0x08, 0x09, 0x0a, 0x08, 0x08, 0x08, 0x0a, 0x21, 0x08, 0x16, 0x0a, 0x16, 0x08, 0x39, 0x0a,
|
||||
0x39, 0x08, 0x0f, 0x0a, 0x01, 0x08, 0x0e, 0x19, 0x02, 0x18, 0x06, 0x08, 0x04, 0x0a, 0x0e, 0x19,
|
||||
0x00, 0x09, 0x13, 0x0a, 0x08, 0x19, 0x03, 0x09, 0x22, 0x0a, 0x09, 0x08, 0x07, 0x0a, 0x0e, 0x19,
|
||||
0x06, 0x0a, 0x39, 0x08, 0x27, 0x0a, 0x09, 0x19, 0x1b, 0x0a, 0x18, 0x08, 0x0e, 0x18, 0x0b, 0x08,
|
||||
0x0b, 0x19, 0x0b, 0x08, 0x0c, 0x19, 0x09, 0x08, 0x00, 0x0a, 0x10, 0x1a, 0x06, 0x0a, 0x10, 0x1a,
|
||||
0x0f, 0x0a, 0x35, 0x08, 0x06, 0x19, 0x0d, 0x08, 0x38, 0x0a, 0x05, 0x19, 0x05, 0x09, 0x05, 0x0a,
|
||||
0x39, 0x08, 0x28, 0x0a, 0x05, 0x08, 0x12, 0x18, 0x0f, 0x08, 0x33, 0x0a, 0x0d, 0x19, 0x0b, 0x0a,
|
||||
0x09, 0x08, 0x0f, 0x18, 0x1f, 0x08, 0x11, 0x0a, 0x08, 0x1a, 0x1e, 0x0a, 0x2b, 0x08, 0x0e, 0x19,
|
||||
0x12, 0x08, 0x22, 0x0a, 0x05, 0x08, 0x11, 0x09, 0x19, 0x08, 0x1d, 0x0a, 0x03, 0x08, 0x04, 0x09,
|
||||
0x01, 0xe9, 0x5c, 0x4b, 0xff, 0x19, 0x29, 0x6f, 0xdc, 0x5e, 0xb5, 0xaa, 0x17, 0x41, 0xaa, 0x35,
|
||||
0x62, 0x31, 0x3b, 0x99, 0x32, 0xf6, 0xb4, 0x65, 0x90, 0xf8, 0xac, 0x06, 0x4e, 0x04, 0x30, 0xdd,
|
||||
0x59, 0x00, 0x00, 0x5a, 0x00, 0x09, 0x14, 0x0a, 0x4b, 0x09, 0x11, 0x1a, 0x00, 0x19, 0x05, 0x09,
|
||||
0x12, 0x19, 0x06, 0x09, 0x14, 0x08, 0x31, 0x09, 0x10, 0x1a, 0x48, 0x09, 0x1d, 0x18, 0x0b, 0x0a,
|
||||
0x26, 0x09, 0x0d, 0x19, 0x31, 0x09, 0x10, 0x0a, 0x4c, 0x09, 0x19, 0x08, 0x0a, 0x19, 0x3f, 0x09,
|
||||
0x1c, 0x0a, 0x4a, 0x09, 0x0c, 0x19, 0x0d, 0x0a, 0x0c, 0x09, 0x11, 0x0a, 0x0d, 0x09, 0x0e, 0x19,
|
||||
0x0e, 0x09, 0x39, 0x19, 0x08, 0x09, 0x32, 0x08, 0x08, 0x09, 0x1d, 0x0a, 0x12, 0x09, 0x04, 0x19,
|
||||
0x16, 0x09, 0x03, 0x19, 0x37, 0x09, 0x0f, 0x19, 0x02, 0x09, 0x15, 0x08, 0x5f, 0x09, 0x01, 0x63,
|
||||
0x44, 0xd8, 0xdb, 0x02, 0x08, 0x18, 0x87, 0x66, 0xed, 0x5d, 0xa5, 0xa1, 0x08, 0x00, 0xc4, 0x01,
|
||||
0x7f, 0x5d, 0x26, 0xd9, 0xe2, 0x39, 0xe1, 0x97, 0x9a, 0x16, 0x7e, 0x92, 0x96, 0x34, 0x4a, 0x00,
|
||||
0x00, 0x7e, 0x00, 0x09, 0x14, 0x0a, 0x09, 0x09, 0x02, 0x19, 0x14, 0x09, 0x0f, 0x1a, 0x00, 0x0a,
|
||||
0x0d, 0x08, 0x09, 0x1a, 0x12, 0x09, 0x03, 0x08, 0x08, 0x18, 0x0b, 0x09, 0x01, 0x0a, 0x01, 0x09,
|
||||
0x01, 0x19, 0x09, 0x18, 0x05, 0x09, 0x0d, 0x19, 0x07, 0x09, 0x07, 0x19, 0x29, 0x0a, 0x12, 0x09,
|
||||
0x0d, 0x19, 0x10, 0x09, 0x08, 0x0a, 0x01, 0x09, 0x22, 0x18, 0x19, 0x09, 0x0e, 0x1a, 0x10, 0x09,
|
||||
0x0c, 0x0a, 0x0e, 0x09, 0x06, 0x18, 0x13, 0x09, 0x0b, 0x1a, 0x14, 0x09, 0x0f, 0x0a, 0x0d, 0x09,
|
||||
0x05, 0x19, 0x19, 0x09, 0x0a, 0x08, 0x09, 0x09, 0x09, 0x1a, 0x18, 0x09, 0x0f, 0x19, 0x07, 0x09,
|
||||
0x11, 0x19, 0x05, 0x09, 0x11, 0x19, 0x05, 0x09, 0x0e, 0x19, 0x14, 0x09, 0x0a, 0x19, 0x35, 0x09,
|
||||
0x0e, 0x19, 0x03, 0x09, 0x06, 0x08, 0x07, 0x18, 0x10, 0x08, 0x09, 0x09, 0x02, 0x19, 0x25, 0x09,
|
||||
0x01, 0x10, 0xbd, 0x37, 0x81, 0xab, 0xd0, 0xe6, 0xd6, 0x3f, 0xe7, 0x6b, 0x6f, 0xcf, 0x22, 0x6a,
|
||||
0xa9, 0x86, 0x1b, 0xdf, 0xd2, 0x7b, 0x61, 0xaf, 0xfa, 0xbb, 0x52, 0x17, 0xfa, 0x42, 0x73, 0x30,
|
||||
0xcd, 0x00, 0x00, 0x58, 0x56, 0x09, 0x0f, 0x19, 0x09, 0x09, 0x0f, 0x19, 0x09, 0x09, 0x08, 0x0a,
|
||||
0x1c, 0x09, 0x05, 0x19, 0x1a, 0x09, 0x05, 0x18, 0x0d, 0x08, 0x05, 0x09, 0x0c, 0x1a, 0x13, 0x09,
|
||||
0x0f, 0x19, 0x33, 0x09, 0x07, 0x19, 0x2a, 0x09, 0x05, 0x08, 0x0c, 0x09, 0x11, 0x19, 0x09, 0x09,
|
||||
0x14, 0x19, 0x0e, 0x09, 0x07, 0x0a, 0x2c, 0x09, 0x10, 0x0a, 0x15, 0x09, 0x0d, 0x18, 0x0a, 0x08,
|
||||
0x26, 0x09, 0x03, 0x0a, 0x06, 0x1a, 0x0c, 0x0a, 0x10, 0x09, 0x1a, 0x08, 0x3b, 0x09, 0x11, 0x1a,
|
||||
0x19, 0x19, 0x0b, 0x09, 0x11, 0x18, 0x0b, 0x09, 0x05, 0x0a, 0x7a, 0x09, 0x01, 0xf8, 0xc5, 0x71,
|
||||
0x92, 0x7b, 0x63, 0xaf, 0xdd, 0x7b, 0xca, 0x1a, 0xf4, 0xd3, 0xb1, 0xfe, 0x77, 0xd4, 0x95, 0x10,
|
||||
0xd4, 0x00, 0xdd, 0x70, 0xcd, 0x4e, 0x8b, 0xc9, 0xa1, 0x2a, 0x32, 0x2a, 0x6c, 0x00, 0x00, 0x50,
|
||||
0x00, 0x09, 0x08, 0x0a, 0x07, 0x09, 0x0c, 0x1a, 0x12, 0x08, 0x00, 0x09, 0x09, 0x19, 0x0d, 0x09,
|
||||
0x11, 0x19, 0x09, 0x09, 0x12, 0x19, 0x0d, 0x08, 0x20, 0x1a, 0x65, 0x09, 0x0c, 0x08, 0x12, 0x09,
|
||||
0x09, 0x08, 0x0e, 0x09, 0x0e, 0x18, 0x12, 0x09, 0x06, 0x0a, 0x6e, 0x09, 0x08, 0x19, 0x06, 0x09,
|
||||
0x08, 0x08, 0x94, 0x09, 0x08, 0x0a, 0x42, 0x09, 0x0e, 0x1a, 0x00, 0x19, 0x00, 0x09, 0x07, 0x0a,
|
||||
0x4e, 0x09, 0x01, 0x0a, 0x03, 0x09, 0x17, 0x19, 0x0a, 0x09, 0x10, 0x18, 0x06, 0x0a, 0x7c, 0x09,
|
||||
0x01, 0x70, 0x01, 0x0d, 0x8a, 0xbc, 0xf1, 0x36, 0x6b, 0x88, 0x76, 0x3b, 0x7c, 0x94, 0x4c, 0x52,
|
||||
0x1b, 0x20, 0x3f, 0x72, 0xe7, 0x24, 0xb3, 0x7a, 0x96, 0x5f, 0x09, 0xed, 0x7a, 0x20, 0x87, 0xe7,
|
||||
0xa6, 0x00, 0x00, 0x42, 0x09, 0x09, 0x0a, 0x19, 0x20, 0x09, 0x15, 0x18, 0x19, 0x0a, 0x14, 0x19,
|
||||
0x27, 0x0a, 0x56, 0x09, 0x23, 0x1a, 0x14, 0x19, 0x28, 0x09, 0x1a, 0x19, 0x0e, 0x09, 0x0f, 0x19,
|
||||
0x2b, 0x09, 0x1e, 0x18, 0x07, 0x09, 0x05, 0x08, 0x24, 0x09, 0x1c, 0x1a, 0x14, 0x09, 0x0e, 0x19,
|
||||
0x50, 0x09, 0x12, 0x19, 0x28, 0x09, 0x02, 0x19, 0x47, 0x09, 0x1e, 0x19, 0x05, 0x09, 0x05, 0x08,
|
||||
0x00, 0x09, 0x03, 0x19, 0x43, 0x09, 0x01, 0x07, 0x81, 0x39, 0x07, 0x7e, 0x57, 0x75, 0x0b, 0xda,
|
||||
0x51, 0x3b, 0x9c, 0x5e, 0xc6, 0x0c, 0x1f, 0x15, 0x0b, 0x68, 0x79, 0xc0, 0x92, 0x95, 0xe3, 0xcd,
|
||||
0xed, 0x21, 0x37, 0x63, 0xa6, 0x94, 0x7e, 0x00, 0x00, 0x76, 0xaf, 0x09, 0x04, 0x02, 0x01, 0x01,
|
||||
0x18, 0x02, 0x01, 0x01, 0x13, 0x00, 0x19, 0x04, 0x04, 0x08, 0x18, 0x09, 0x13, 0x0a, 0x0e, 0x09,
|
||||
0x0f, 0x08, 0x12, 0x09, 0x0b, 0x0a, 0x71, 0x09, 0x02, 0x0a, 0x04, 0x09, 0x00, 0x08, 0x04, 0x09,
|
||||
0x00, 0x0a, 0x22, 0x09, 0x00, 0x08, 0x04, 0x09, 0x00, 0x0a, 0x04, 0x09, 0x00, 0x08, 0x04, 0x09,
|
||||
0x00, 0x0a, 0x04, 0x09, 0x00, 0x08, 0x35, 0x09, 0x0a, 0x08, 0x10, 0x09, 0x08, 0x08, 0x09, 0x09,
|
||||
0x08, 0x0a, 0x09, 0x09, 0x06, 0x08, 0x21, 0x09, 0x0d, 0x0a, 0x05, 0x09, 0x0f, 0x0a, 0x07, 0x09,
|
||||
0x07, 0x08, 0x0d, 0x09, 0x07, 0x08, 0x35, 0x09, 0x07, 0x0a, 0x0e, 0x09, 0x10, 0x08, 0x1b, 0x09,
|
||||
0x03, 0x08, 0x04, 0x09, 0x03, 0x0a, 0x40, 0x09, 0x03, 0x08, 0x04, 0x09, 0x03, 0x0a, 0xd8, 0x09,
|
||||
0x01, 0x1d, 0x87, 0x1d, 0x92, 0x61, 0x27, 0xa8, 0x0f, 0xd3, 0xa1, 0xfe, 0x0c, 0x12, 0x73, 0xa5,
|
||||
0xba, 0x36, 0x90, 0x9c, 0xd3, 0x2a, 0xf0, 0x6e, 0xdb, 0x84, 0xe5, 0xf3, 0x8d, 0xf9, 0x8a, 0xe8,
|
||||
0xda, 0x00, 0x00, 0x46, 0x00, 0x09, 0x04, 0x08, 0x2c, 0x09, 0x0a, 0x19, 0x0c, 0x09, 0x09, 0x1a,
|
||||
0x1e, 0x08, 0x33, 0x09, 0x01, 0x19, 0x06, 0x18, 0x0f, 0x08, 0x62, 0x09, 0x0a, 0x19, 0x0d, 0x1a,
|
||||
0x0b, 0x18, 0x0e, 0x09, 0x06, 0x0a, 0x3d, 0x09, 0x0d, 0x1a, 0x0b, 0x09, 0x14, 0x18, 0x04, 0x0a,
|
||||
0x3e, 0x09, 0x10, 0x19, 0x12, 0x09, 0x09, 0x19, 0x3d, 0x09, 0x0f, 0x19, 0x0d, 0x09, 0x11, 0x19,
|
||||
0x17, 0x09, 0x04, 0x19, 0x44, 0x09, 0x1a, 0x19, 0x11, 0x09, 0x01, 0x50, 0xfd, 0xe3, 0x86, 0x49,
|
||||
0xbc, 0x96, 0xd9, 0xed, 0x1a, 0x81, 0x77, 0xa2, 0xc3, 0xb0, 0xac, 0xbe, 0x0e, 0xad, 0xcb, 0x3d,
|
||||
0x4e, 0x1a, 0xbb, 0x96, 0xab, 0xb3, 0x19, 0x49, 0x38, 0x7d, 0x99, 0x00, 0x00, 0x74, 0x00, 0x09,
|
||||
0x07, 0x0a, 0x08, 0x09, 0x0e, 0x1a, 0x10, 0x08, 0x10, 0x09, 0x02, 0x19, 0x14, 0x09, 0x11, 0x19,
|
||||
0x10, 0x09, 0x1b, 0x08, 0x04, 0x0a, 0x0f, 0x1a, 0x0b, 0x19, 0x15, 0x09, 0x08, 0x19, 0x0f, 0x09,
|
||||
0x12, 0x19, 0x16, 0x09, 0x02, 0x19, 0x15, 0x09, 0x00, 0x08, 0x2b, 0x09, 0x09, 0x19, 0x0e, 0x09,
|
||||
0x04, 0x19, 0x14, 0x09, 0x0c, 0x19, 0x0a, 0x09, 0x09, 0x1a, 0x12, 0x09, 0x0f, 0x18, 0x0b, 0x09,
|
||||
0x04, 0x19, 0x10, 0x09, 0x17, 0x19, 0x14, 0x09, 0x0f, 0x19, 0x06, 0x09, 0x0a, 0x19, 0x46, 0x09,
|
||||
0x06, 0x1a, 0x13, 0x18, 0x0f, 0x0a, 0x08, 0x1a, 0x12, 0x18, 0x41, 0x09, 0x07, 0x19, 0x0a, 0x09,
|
||||
0x0c, 0x19, 0x08, 0x09, 0x03, 0x0a, 0x25, 0x19, 0x36, 0x09, 0x05, 0x19, 0x32, 0x09, 0x06, 0x19,
|
||||
0x10, 0x09, 0x01, 0xc2, 0xc3, 0x5f, 0x25, 0xc5, 0x93, 0x21, 0x94, 0x06, 0x50, 0x39, 0xd8, 0xbb,
|
||||
0x22, 0xa9, 0xc3, 0xc6, 0x56, 0xa9, 0xf4, 0xbe, 0x83, 0x73, 0xff, 0x4f, 0x5d, 0xfe, 0x64, 0x61,
|
||||
0x3b, 0x97, 0xca, 0x00, 0x00, 0x78, 0x00, 0x09, 0x0d, 0x0a, 0x2b, 0x09, 0x03, 0x19, 0x16, 0x09,
|
||||
0x11, 0x1a, 0x00, 0x19, 0x06, 0x09, 0x06, 0x08, 0x0c, 0x18, 0x25, 0x09, 0x08, 0x18, 0x1f, 0x09,
|
||||
0x0b, 0x19, 0x15, 0x09, 0x03, 0x0a, 0x12, 0x09, 0x0a, 0x1a, 0x48, 0x09, 0x0a, 0x18, 0x08, 0x09,
|
||||
0x05, 0x0a, 0x29, 0x09, 0x10, 0x1a, 0x07, 0x0a, 0x38, 0x09, 0x0f, 0x18, 0x00, 0x08, 0x0c, 0x0a,
|
||||
0x1d, 0x09, 0x03, 0x19, 0x04, 0x18, 0x19, 0x0a, 0x19, 0x09, 0x07, 0x0a, 0x17, 0x09, 0x09, 0x19,
|
||||
0x1b, 0x09, 0x04, 0x08, 0x42, 0x09, 0x00, 0x0a, 0x00, 0x08, 0x0a, 0x09, 0x04, 0x0a, 0x37, 0x09,
|
||||
0x06, 0x19, 0x1a, 0x09, 0x19, 0x19, 0x1c, 0x09, 0x06, 0x1a, 0x23, 0x18, 0x1a, 0x09, 0x05, 0x19,
|
||||
0x1a, 0x09, 0x07, 0x19, 0x42, 0x09, 0x07, 0x19, 0x77, 0x09, 0x07, 0x19, 0x98, 0x09, 0x01, 0xab,
|
||||
0x77, 0xec, 0x80, 0x5d, 0x6a, 0x88, 0xb0, 0x6a, 0x86, 0xf8, 0x4e, 0x7d, 0xe1, 0x46, 0xf3, 0x4f,
|
||||
0x88, 0x3f, 0x33, 0x59, 0x09, 0x96, 0xa4, 0xcc, 0x11, 0xad, 0x34, 0x73, 0x9c, 0x90, 0xda, 0x00,
|
||||
0x00, 0x5a, 0x1a, 0x09, 0x02, 0x19, 0x17, 0x09, 0x0c, 0x18, 0x17, 0x08, 0x0d, 0x09, 0x0f, 0x1a,
|
||||
0x03, 0x0a, 0x06, 0x09, 0x0e, 0x19, 0x01, 0x1a, 0x09, 0x0a, 0x07, 0x09, 0x07, 0x0a, 0x03, 0x09,
|
||||
0x0c, 0x19, 0x05, 0x09, 0x02, 0x08, 0x0b, 0x09, 0x0f, 0x19, 0x09, 0x09, 0x02, 0x19, 0x0c, 0x18,
|
||||
0x01, 0x19, 0x11, 0x09, 0x0d, 0x18, 0x09, 0x09, 0x0a, 0x1a, 0x0f, 0x0a, 0x08, 0x1a, 0x05, 0x0a,
|
||||
0x02, 0x09, 0x05, 0x0a, 0x15, 0x09, 0x01, 0x08, 0x21, 0x18, 0x0d, 0x09, 0x24, 0x1a, 0x0a, 0x09,
|
||||
0x13, 0x19, 0x04, 0x09, 0x11, 0x19, 0x05, 0x09, 0x0a, 0x19, 0x0d, 0x09, 0x01, 0xb5, 0x84, 0x9a,
|
||||
0x7a, 0x5e, 0x32, 0xba, 0x2e, 0x02, 0x39, 0x7b, 0x56, 0x67, 0x3b, 0x62, 0x01, 0xca, 0x67, 0xc0,
|
||||
0x84, 0xaa, 0xb5, 0x92, 0xff, 0xc1, 0xc9, 0x84, 0x11, 0xea, 0xc3, 0x5a, 0xa9, 0x00, 0x00, 0x94,
|
||||
0x00, 0x09, 0x1c, 0x0a, 0x10, 0x09, 0x11, 0x19, 0x0e, 0x09, 0x11, 0x18, 0x09, 0x09, 0x12, 0x19,
|
||||
0x00, 0x09, 0x04, 0x0a, 0x11, 0x1a, 0x0a, 0x09, 0x0c, 0x18, 0x13, 0x09, 0x13, 0x19, 0x05, 0x09,
|
||||
0x11, 0x18, 0x06, 0x09, 0x00, 0x0a, 0x13, 0x1a, 0x0b, 0x19, 0x0a, 0x09, 0x0f, 0x18, 0x00, 0x08,
|
||||
0x09, 0x09, 0x0a, 0x19, 0x0c, 0x09, 0x06, 0x19, 0x0e, 0x09, 0x00, 0x0a, 0x09, 0x1a, 0x0b, 0x09,
|
||||
0x0d, 0x19, 0x0a, 0x09, 0x23, 0x19, 0x05, 0x09, 0x0a, 0x19, 0x19, 0x09, 0x07, 0x19, 0x0f, 0x09,
|
||||
0x02, 0x19, 0x12, 0x09, 0x1c, 0x08, 0x01, 0x0a, 0x09, 0x1a, 0x10, 0x0a, 0x08, 0x09, 0x07, 0x19,
|
||||
0x15, 0x09, 0x0d, 0x19, 0x03, 0x09, 0x06, 0x19, 0x0d, 0x09, 0x08, 0x0a, 0x11, 0x09, 0x0f, 0x18,
|
||||
0x00, 0x19, 0x08, 0x09, 0x13, 0x18, 0x00, 0x09, 0x12, 0x1a, 0x05, 0x0a, 0x0c, 0x1a, 0x0a, 0x09,
|
||||
0x0f, 0x19, 0x00, 0x09, 0x20, 0x08, 0x00, 0x09, 0x04, 0x08, 0x0f, 0x09, 0x09, 0x19, 0x1a, 0x09,
|
||||
0x18, 0x0a, 0x0e, 0x09, 0x01, 0x23, 0x76, 0xeb, 0x7a, 0x19, 0x6e, 0x75, 0xd0, 0xca, 0xde, 0x7e,
|
||||
0xfb, 0xa2, 0x0c, 0xf6, 0xb8, 0x9e, 0xea, 0x78, 0x9a, 0xb2, 0xb8, 0x55, 0x43, 0xa1, 0x9f, 0xe7,
|
||||
0xc2, 0xfc, 0xad, 0x10, 0x2a, 0x00, 0x00, 0x54, 0x74, 0x09, 0x06, 0x19, 0x3e, 0x09, 0x05, 0x19,
|
||||
0x2a, 0x09, 0x08, 0x19, 0x6c, 0x09, 0x06, 0x19, 0x3a, 0x09, 0x07, 0x19, 0x02, 0x09, 0x04, 0x19,
|
||||
0x20, 0x09, 0x04, 0x19, 0x2c, 0x09, 0x16, 0x0a, 0x62, 0x09, 0x25, 0x08, 0x08, 0x09, 0x26, 0x0a,
|
||||
0x25, 0x09, 0x1b, 0x08, 0x06, 0x18, 0x11, 0x09, 0x03, 0x0a, 0x1b, 0x09, 0x08, 0x0a, 0x3f, 0x09,
|
||||
0x03, 0x19, 0x0c, 0x09, 0x03, 0x19, 0x0c, 0x09, 0x03, 0x19, 0x0d, 0x09, 0x03, 0x19, 0x28, 0x09,
|
||||
0x05, 0x19, 0x3a, 0x09, 0x05, 0x19, 0x17, 0x09, 0x04, 0x19, 0x4e, 0x09, 0x01, 0xe8, 0xdb, 0xbc,
|
||||
0x58, 0x6b, 0x95, 0x16, 0x81, 0x87, 0x74, 0xcf, 0x7c, 0xe2, 0x71, 0xdb, 0x8b, 0xeb, 0x74, 0xaf,
|
||||
0xbb, 0x19, 0x29, 0xe4, 0xca, 0xd8, 0xc2, 0x0d, 0x25, 0xef, 0x1e, 0x9c, 0xfa, 0x00, 0x00, 0xae,
|
||||
0x6b, 0x09, 0x14, 0x0a, 0x2d, 0x09, 0x02, 0x19, 0x0d, 0x18, 0x12, 0x08, 0x02, 0x09, 0x01, 0x0a,
|
||||
0x00, 0x09, 0x03, 0x19, 0x0b, 0x1a, 0x04, 0x0a, 0x02, 0x09, 0x00, 0x0a, 0x0b, 0x1a, 0x02, 0x09,
|
||||
0x00, 0x0a, 0x00, 0x09, 0x02, 0x19, 0x0e, 0x18, 0x12, 0x08, 0x03, 0x0a, 0x00, 0x09, 0x03, 0x19,
|
||||
0x0c, 0x1a, 0x03, 0x0a, 0x01, 0x09, 0x01, 0x0a, 0x0b, 0x1a, 0x04, 0x09, 0x02, 0x19, 0x0d, 0x18,
|
||||
0x13, 0x08, 0x03, 0x0a, 0x00, 0x09, 0x03, 0x19, 0x0d, 0x1a, 0x01, 0x0a, 0x01, 0x09, 0x02, 0x0a,
|
||||
0x06, 0x1a, 0x09, 0x09, 0x02, 0x19, 0x0e, 0x18, 0x0f, 0x08, 0x06, 0x0a, 0x00, 0x09, 0x02, 0x19,
|
||||
0x0d, 0x1a, 0x01, 0x0a, 0x03, 0x09, 0x01, 0x0a, 0x02, 0x1a, 0x0d, 0x09, 0x02, 0x19, 0x0d, 0x18,
|
||||
0x11, 0x08, 0x05, 0x0a, 0x00, 0x09, 0x03, 0x19, 0x0c, 0x1a, 0x02, 0x0a, 0x01, 0x09, 0x02, 0x0a,
|
||||
0x0c, 0x1a, 0x03, 0x09, 0x03, 0x19, 0x0e, 0x18, 0x11, 0x08, 0x04, 0x0a, 0x00, 0x09, 0x02, 0x19,
|
||||
0x0c, 0x1a, 0x01, 0x0a, 0x04, 0x09, 0x01, 0x0a, 0x07, 0x1a, 0x33, 0x09, 0x11, 0x08, 0x11, 0x09,
|
||||
0x17, 0x08, 0x25, 0x09, 0x2b, 0x0a, 0x1c, 0x09, 0x00, 0x0a, 0x14, 0x08, 0x84, 0x09, 0x01, 0xbd,
|
||||
0xa2, 0x63, 0xa7, 0xa2, 0xaf, 0x15, 0x01, 0xf7, 0xbd, 0xaf, 0x4e, 0xef, 0x00, 0x11, 0x1f, 0x99,
|
||||
0x77, 0x91, 0xbf, 0xd2, 0x29, 0x6e, 0x9b, 0xcb, 0x4e, 0xb0, 0x87, 0x2b, 0xf6, 0x68, 0x62, 0x00,
|
||||
0x00, 0xc8, 0x45, 0x09, 0x04, 0x08, 0x04, 0x09, 0x10, 0x18, 0x09, 0x08, 0x0a, 0x09, 0x06, 0x1a,
|
||||
0x0b, 0x0a, 0x03, 0x09, 0x02, 0x0a, 0x01, 0x06, 0x00, 0x05, 0x14, 0x15, 0x02, 0x05, 0x10, 0x16,
|
||||
0x02, 0x05, 0x03, 0x04, 0x0c, 0x05, 0x0a, 0x15, 0x05, 0x05, 0x07, 0x06, 0x0f, 0x15, 0x02, 0x05,
|
||||
0x0a, 0x04, 0x10, 0x15, 0x05, 0x05, 0x0d, 0x15, 0x10, 0x05, 0x00, 0x04, 0x04, 0x05, 0x00, 0x06,
|
||||
0x04, 0x05, 0x00, 0x04, 0x04, 0x05, 0x00, 0x06, 0x02, 0x05, 0x08, 0x04, 0x10, 0x15, 0x0b, 0x14,
|
||||
0x0f, 0x16, 0x0a, 0x14, 0x06, 0x05, 0x0b, 0x14, 0x10, 0x05, 0x18, 0x16, 0x29, 0x14, 0x16, 0x06,
|
||||
0x03, 0x05, 0x0d, 0x06, 0x09, 0x16, 0x0b, 0x04, 0x08, 0x14, 0x02, 0x04, 0x0d, 0x05, 0x04, 0x15,
|
||||
0x11, 0x05, 0x11, 0x04, 0x07, 0x05, 0x1d, 0x09, 0x02, 0x0a, 0x03, 0x19, 0x01, 0x18, 0x3f, 0x19,
|
||||
0x00, 0x09, 0x0a, 0x08, 0x10, 0x09, 0x18, 0x0a, 0x3d, 0x09, 0x05, 0x19, 0x17, 0x09, 0x05, 0x19,
|
||||
0x7d, 0x09, 0x07, 0x19, 0x0a, 0x09, 0x13, 0x0a, 0x56, 0x09, 0x03, 0x19, 0x05, 0x18, 0x0a, 0x08,
|
||||
0x26, 0x09, 0x07, 0x08, 0x43, 0x09, 0x09, 0x19, 0x02, 0x09, 0x07, 0x0a, 0x01, 0x09, 0x00, 0x08,
|
||||
0x04, 0x09, 0x00, 0x0a, 0x04, 0x09, 0x00, 0x08, 0x04, 0x09, 0x00, 0x0a, 0x04, 0x09, 0x00, 0x08,
|
||||
0x04, 0x09, 0x04, 0x0a, 0x44, 0x09, 0x18, 0x19, 0x13, 0x09, 0x01, 0x80, 0x8f, 0x0e, 0x04, 0xe4,
|
||||
0xb5, 0x8b, 0x4b, 0x5e, 0x7c, 0x92, 0xdc, 0x7c, 0xb2, 0x3a, 0x0b, 0x45, 0x9b, 0x4c, 0x07, 0x2b,
|
||||
0xd6, 0x8d, 0x27, 0x26, 0xa1, 0xa1, 0x61, 0x72, 0x39, 0x3c, 0x9f, 0x00, 0x00, 0x86, 0x00, 0x09,
|
||||
0x0c, 0x08, 0x07, 0x09, 0x0f, 0x18, 0x0b, 0x19, 0x03, 0x09, 0x02, 0x08, 0x00, 0x09, 0x0f, 0x1a,
|
||||
0x12, 0x09, 0x0a, 0x1a, 0x02, 0x18, 0x04, 0x08, 0x0e, 0x18, 0x01, 0x08, 0x05, 0x09, 0x0b, 0x19,
|
||||
0x07, 0x09, 0x0b, 0x19, 0x04, 0x09, 0x0a, 0x19, 0x0a, 0x09, 0x06, 0x19, 0x08, 0x09, 0x0a, 0x19,
|
||||
0x0d, 0x09, 0x0c, 0x19, 0x07, 0x09, 0x0c, 0x18, 0x0a, 0x09, 0x03, 0x19, 0x11, 0x09, 0x03, 0x19,
|
||||
0x08, 0x1a, 0x05, 0x09, 0x0e, 0x19, 0x06, 0x09, 0x0f, 0x19, 0x00, 0x09, 0x10, 0x1a, 0x01, 0x09,
|
||||
0x0f, 0x18, 0x10, 0x09, 0x0d, 0x19, 0x05, 0x09, 0x08, 0x19, 0x09, 0x09, 0x07, 0x19, 0x0e, 0x09,
|
||||
0x0a, 0x19, 0x0e, 0x09, 0x0b, 0x19, 0x08, 0x09, 0x0f, 0x19, 0x09, 0x09, 0x08, 0x19, 0x06, 0x09,
|
||||
0x08, 0x0a, 0x0b, 0x09, 0x0a, 0x19, 0x0a, 0x09, 0x0e, 0x19, 0x27, 0x09, 0x00, 0x0a, 0x25, 0x09,
|
||||
0x0c, 0x18, 0x93, 0x09, 0x01, 0x42, 0xea, 0x18, 0x4a, 0x33, 0xd9, 0x22, 0x20, 0x3d, 0x99, 0xfd,
|
||||
0x82, 0x11, 0x9d, 0xa0, 0xb7, 0x3e, 0xe7, 0x9b, 0xa7, 0x87, 0xd8, 0xf9, 0x74, 0x29, 0x5f, 0xd8,
|
||||
0x61, 0xa8, 0xa3, 0x81, 0x17, 0x00, 0x00, 0x98, 0x2b, 0x09, 0x36, 0x19, 0x12, 0x1a, 0x25, 0x19,
|
||||
0x23, 0x18, 0x42, 0x19, 0x08, 0x09, 0x0d, 0x19, 0x08, 0x09, 0x11, 0x1a, 0x06, 0x09, 0x01, 0x19,
|
||||
0x0d, 0x18, 0x11, 0x08, 0x02, 0x09, 0x10, 0x0a, 0x10, 0x18, 0x06, 0x0a, 0x1a, 0x09, 0x02, 0x19,
|
||||
0x04, 0x1a, 0x00, 0x19, 0x06, 0x09, 0x21, 0x19, 0x07, 0x09, 0x13, 0x1a, 0x02, 0x09, 0x01, 0x08,
|
||||
0x01, 0x09, 0x17, 0x19, 0x0f, 0x09, 0x36, 0x19, 0x03, 0x09, 0x0e, 0x1a, 0x06, 0x09, 0x25, 0x18,
|
||||
0x13, 0x1a, 0x21, 0x19, 0x13, 0x1a, 0x2d, 0x18, 0x21, 0x1a, 0x15, 0x09, 0x14, 0x18, 0x03, 0x09,
|
||||
0x10, 0x19, 0x06, 0x09, 0x06, 0x0a, 0x12, 0x19, 0x04, 0x09, 0x07, 0x18, 0x14, 0x09, 0x02, 0x0a,
|
||||
0x02, 0x09, 0x0d, 0x19, 0x07, 0x09, 0x11, 0x1a, 0x04, 0x09, 0x0b, 0x19, 0x09, 0x09, 0x0f, 0x1a,
|
||||
0x01, 0x19, 0x01, 0x0a, 0x00, 0x09, 0x1f, 0x19, 0x07, 0x09, 0x06, 0x08, 0x0b, 0x09, 0x09, 0x08,
|
||||
0x0c, 0x09, 0x0a, 0x19, 0x1c, 0x09, 0x23, 0x05, 0x02, 0x15, 0x03, 0x16, 0x19, 0x04, 0x05, 0x05,
|
||||
0x01, 0x5c, 0x04, 0x43, 0x8e, 0x64, 0xcf, 0xd5, 0x34, 0xd1, 0x17, 0x05, 0x45, 0x59, 0x90, 0xb5,
|
||||
0xea, 0x93, 0x51, 0x13, 0x33, 0x18, 0xe3, 0x6a, 0x06, 0xea, 0xac, 0x7e, 0x2a, 0xe4, 0x36, 0x45,
|
||||
0xdd, 0x00, 0x00, 0x46, 0x00, 0x09, 0x4d, 0x0a, 0x17, 0x09, 0x0f, 0x18, 0x0a, 0x09, 0x0f, 0x1a,
|
||||
0x0c, 0x09, 0x01, 0x19, 0x0d, 0x18, 0x01, 0x0a, 0x00, 0x08, 0x01, 0x09, 0x02, 0x19, 0x0f, 0x1a,
|
||||
0x0f, 0x08, 0x06, 0x09, 0x12, 0x18, 0x03, 0x19, 0x08, 0x18, 0x10, 0x19, 0x08, 0x08, 0x19, 0x09,
|
||||
0x11, 0x19, 0x0a, 0x09, 0x10, 0x1a, 0x03, 0x09, 0x02, 0x0a, 0x20, 0x09, 0x07, 0x19, 0x07, 0x09,
|
||||
0x11, 0x19, 0x09, 0x09, 0x11, 0x19, 0x15, 0x08, 0x7a, 0x09, 0x01, 0x79, 0x6a, 0xb2, 0x22, 0xa0,
|
||||
0xd2, 0xf4, 0x74, 0x29, 0x79, 0x37, 0xc6, 0xcf, 0x70, 0x8f, 0xbe, 0xad, 0x57, 0x28, 0x41, 0x65,
|
||||
0xfb, 0x12, 0x02, 0xe1, 0x7f, 0xcc, 0x45, 0xc8, 0xa4, 0x65, 0xd4, 0x00, 0x00, 0x6e, 0x00, 0x09,
|
||||
0x08, 0x0a, 0x0f, 0x09, 0x0c, 0x1a, 0x07, 0x09, 0x0e, 0x1a, 0x0a, 0x09, 0x11, 0x18, 0x09, 0x08,
|
||||
0x00, 0x09, 0x00, 0x08, 0x06, 0x09, 0x11, 0x18, 0x0e, 0x0a, 0x06, 0x09, 0x06, 0x19, 0x08, 0x09,
|
||||
0x02, 0x19, 0x0d, 0x09, 0x12, 0x08, 0x14, 0x19, 0x06, 0x1a, 0x12, 0x0a, 0x00, 0x09, 0x0b, 0x19,
|
||||
0x0b, 0x09, 0x12, 0x19, 0x0b, 0x08, 0x07, 0x09, 0x02, 0x19, 0x09, 0x09, 0x11, 0x08, 0x08, 0x1a,
|
||||
0x16, 0x08, 0x1f, 0x09, 0x04, 0x1a, 0x0e, 0x0a, 0x01, 0x09, 0x0d, 0x19, 0x09, 0x09, 0x06, 0x19,
|
||||
0x10, 0x09, 0x10, 0x18, 0x0f, 0x09, 0x16, 0x0a, 0x08, 0x09, 0x02, 0x19, 0x26, 0x09, 0x1f, 0x08,
|
||||
0x16, 0x09, 0x12, 0x1a, 0x03, 0x0a, 0x4d, 0x09, 0x00, 0x19, 0x2e, 0x09, 0x01, 0x97, 0xad, 0x9a,
|
||||
0x9b, 0x08, 0xd9, 0x9b, 0xe3, 0x1d, 0xc5, 0x2d, 0xe0, 0x4e, 0x0a, 0xb3, 0xae, 0xb3, 0xac, 0xd9,
|
||||
0x76, 0x88, 0x41, 0xdd, 0xb4, 0x87, 0x26, 0x7e, 0xff, 0x0e, 0xc5, 0xf0, 0x85, 0x00, 0x00, 0x7e,
|
||||
0x00, 0x09, 0x15, 0x0a, 0x12, 0x09, 0x01, 0x19, 0x15, 0x09, 0x10, 0x19, 0x0a, 0x08, 0x11, 0x09,
|
||||
0x0f, 0x19, 0x08, 0x09, 0x05, 0x08, 0x06, 0x09, 0x01, 0x19, 0x27, 0x09, 0x01, 0x19, 0x1b, 0x09,
|
||||
0x03, 0x19, 0x13, 0x09, 0x05, 0x19, 0x11, 0x09, 0x03, 0x0a, 0x09, 0x09, 0x04, 0x19, 0x0b, 0x09,
|
||||
0x09, 0x08, 0x02, 0x09, 0x0b, 0x08, 0x09, 0x19, 0x00, 0x09, 0x01, 0x08, 0x02, 0x09, 0x02, 0x19,
|
||||
0x14, 0x09, 0x13, 0x1a, 0x03, 0x09, 0x05, 0x08, 0x17, 0x09, 0x02, 0x08, 0x06, 0x0a, 0x0e, 0x1a,
|
||||
0x02, 0x08, 0x0d, 0x18, 0x08, 0x08, 0x07, 0x09, 0x06, 0x08, 0x05, 0x0a, 0x0d, 0x1a, 0x16, 0x18,
|
||||
0x09, 0x1a, 0x08, 0x08, 0x01, 0x09, 0x04, 0x0a, 0x00, 0x09, 0x03, 0x19, 0x08, 0x09, 0x08, 0x19,
|
||||
0x09, 0x09, 0x29, 0x08, 0x05, 0x18, 0x00, 0x19, 0x12, 0x1a, 0x08, 0x0a, 0x17, 0x09, 0x01, 0x80,
|
||||
0x45, 0x34, 0x57, 0x6b, 0x83, 0xfb, 0x6b, 0x07, 0x7d, 0xfb, 0x3e, 0xa4, 0x11, 0x16, 0x74, 0xee,
|
||||
0x8a, 0xcf, 0x13, 0x81, 0x83, 0xab, 0x02, 0xcf, 0x22, 0x87, 0xbd, 0x7a, 0x22, 0xba, 0xcf, 0x00,
|
||||
0x00, 0x48, 0x1d, 0x09, 0x03, 0x19, 0x20, 0x09, 0x0e, 0x18, 0x02, 0x08, 0x06, 0x09, 0x10, 0x19,
|
||||
0x04, 0x09, 0x0f, 0x1a, 0x0b, 0x08, 0x10, 0x09, 0x03, 0x19, 0x6c, 0x09, 0x03, 0x19, 0x09, 0x09,
|
||||
0x0b, 0x18, 0x03, 0x09, 0x04, 0x19, 0x12, 0x09, 0x0b, 0x19, 0x04, 0x09, 0x01, 0x08, 0x01, 0x19,
|
||||
0x0d, 0x1a, 0x01, 0x09, 0x02, 0x11, 0x0f, 0x19, 0x02, 0x11, 0x11, 0x19, 0x01, 0x11, 0x09, 0x19,
|
||||
0x10, 0x09, 0x04, 0x19, 0x13, 0x09, 0x00, 0x08, 0x11, 0x09, 0x01, 0xa0, 0x75, 0xe5, 0x89, 0xe7,
|
||||
0x17, 0xc8, 0x47, 0x64, 0xdd, 0x35, 0xbc, 0xb0, 0x4e, 0xa4, 0x10, 0x4a, 0xde, 0xf3, 0x07, 0x64,
|
||||
0x61, 0xca, 0x7a, 0x27, 0xe0, 0x41, 0xab, 0x26, 0xc8, 0x7e, 0x22, 0x00, 0x00, 0x6c, 0x12, 0x09,
|
||||
0x09, 0x08, 0x04, 0x09, 0x05, 0x19, 0x0a, 0x09, 0x0d, 0x19, 0x06, 0x09, 0x01, 0x0a, 0x17, 0x09,
|
||||
0x00, 0x0a, 0x22, 0x09, 0x13, 0x1a, 0x02, 0x09, 0x05, 0x19, 0x11, 0x09, 0x05, 0x19, 0x02, 0x09,
|
||||
0x0f, 0x08, 0x02, 0x18, 0x12, 0x08, 0x03, 0x09, 0x03, 0x19, 0x0c, 0x09, 0x02, 0x19, 0x16, 0x09,
|
||||
0x0e, 0x0a, 0x03, 0x09, 0x02, 0x19, 0x12, 0x09, 0x02, 0x19, 0x16, 0x09, 0x17, 0x19, 0x0a, 0x09,
|
||||
0x07, 0x0a, 0x02, 0x09, 0x02, 0x0a, 0x04, 0x09, 0x14, 0x1a, 0x05, 0x09, 0x03, 0x08, 0x0d, 0x09,
|
||||
0x11, 0x18, 0x02, 0x08, 0x01, 0x09, 0x0e, 0x19, 0x07, 0x09, 0x0e, 0x1a, 0x02, 0x09, 0x03, 0x0a,
|
||||
0x22, 0x09, 0x10, 0x18, 0x0f, 0x09, 0x05, 0x08, 0x23, 0x09, 0x01, 0xa5, 0x6c, 0xc6, 0x79, 0x27,
|
||||
0x58, 0x55, 0x35, 0x5b, 0xcf, 0xf1, 0x8b, 0x60, 0x01, 0xa6, 0x38, 0xf8, 0x34, 0x83, 0xf5, 0x37,
|
||||
0xf0, 0xda, 0xd3, 0x92, 0xdc, 0x03, 0x40, 0xa6, 0xa8, 0x9f, 0xc8, 0x00, 0x00, 0x56, 0x1f, 0x09,
|
||||
0x00, 0x0a, 0x09, 0x1a, 0x08, 0x0a, 0x01, 0x09, 0x11, 0x19, 0x00, 0x09, 0x0d, 0x08, 0x04, 0x09,
|
||||
0x08, 0x18, 0x06, 0x09, 0x0a, 0x0a, 0x07, 0x09, 0x10, 0x19, 0x01, 0x09, 0x11, 0x19, 0x15, 0x1a,
|
||||
0x04, 0x19, 0x09, 0x09, 0x07, 0x18, 0x21, 0x09, 0x08, 0x1a, 0x00, 0x09, 0x03, 0x08, 0x06, 0x19,
|
||||
0x01, 0x09, 0x11, 0x08, 0x27, 0x09, 0x10, 0x1a, 0x0c, 0x09, 0x03, 0x19, 0x1e, 0x09, 0x0f, 0x18,
|
||||
0x07, 0x08, 0x08, 0x18, 0x09, 0x08, 0x03, 0x09, 0x10, 0x1a, 0x08, 0x09, 0x0f, 0x19, 0x07, 0x09,
|
||||
0x11, 0x08, 0x1c, 0x09, 0x01, 0x33, 0xbf, 0x71, 0xd7, 0xf3, 0xb4, 0x74, 0xf8, 0xde, 0xca, 0x73,
|
||||
0x65, 0xf7, 0x81, 0xe0, 0x3e, 0x57, 0x10, 0x91, 0x99, 0xb8, 0x50, 0x4f, 0x02, 0xc0, 0xcf, 0x17,
|
||||
0x8a, 0xad, 0x67, 0xda, 0xce, 0x00, 0x00, 0x6a, 0x17, 0x09, 0x01, 0x19, 0x15, 0x09, 0x0f, 0x19,
|
||||
0x0d, 0x09, 0x07, 0x19, 0x77, 0x09, 0x0d, 0x1a, 0x00, 0x09, 0x05, 0x0a, 0x11, 0x19, 0x05, 0x09,
|
||||
0x09, 0x19, 0x0e, 0x09, 0x03, 0x19, 0x11, 0x09, 0x0a, 0x08, 0x08, 0x18, 0x10, 0x08, 0x07, 0x09,
|
||||
0x02, 0x08, 0x03, 0x19, 0x06, 0x09, 0x00, 0x08, 0x34, 0x09, 0x03, 0x19, 0x0e, 0x09, 0x06, 0x19,
|
||||
0x09, 0x09, 0x05, 0x0a, 0x03, 0x09, 0x03, 0x08, 0x01, 0x09, 0x02, 0x0a, 0x02, 0x09, 0x02, 0x08,
|
||||
0x01, 0x09, 0x04, 0x0a, 0x17, 0x09, 0x05, 0x19, 0x0b, 0x09, 0x07, 0x0a, 0x0f, 0x1a, 0x0b, 0x0a,
|
||||
0x41, 0x09, 0x05, 0x19, 0x10, 0x09, 0x07, 0x19, 0x0a, 0x09, 0x10, 0x19, 0x08, 0x09, 0x04, 0x19,
|
||||
0x24, 0x09, 0x01, 0xde, 0xb2, 0xcf, 0x2f, 0x8e, 0xcf, 0x5c, 0x1d, 0xce, 0x78, 0x6a, 0x93, 0xbc,
|
||||
0x32, 0x14, 0x11, 0x7f, 0xb1, 0xa2, 0xce, 0xf2, 0x0b, 0x50, 0xe1, 0x59, 0xed, 0x58, 0x37, 0x49,
|
||||
0x2d, 0x8a, 0xe2, 0x00, 0x00, 0x44, 0x26, 0x09, 0x01, 0x19, 0x14, 0x09, 0x06, 0x1a, 0x11, 0x0a,
|
||||
0x16, 0x09, 0x0c, 0x19, 0x06, 0x09, 0x0b, 0x18, 0x01, 0x08, 0x09, 0x0a, 0x02, 0x1a, 0x12, 0x0a,
|
||||
0x37, 0x09, 0x02, 0x19, 0x0d, 0x09, 0x02, 0x11, 0x0f, 0x19, 0x11, 0x18, 0x29, 0x09, 0x05, 0x18,
|
||||
0x1e, 0x08, 0x05, 0x09, 0x10, 0x1a, 0x10, 0x0a, 0x28, 0x09, 0x10, 0x18, 0x0f, 0x08, 0x13, 0x09,
|
||||
0x11, 0x1a, 0x0a, 0x0a, 0x03, 0x09, 0x03, 0x08, 0x1f, 0x09, 0x01, 0x95, 0x30, 0x64, 0x64, 0x72,
|
||||
0x84, 0x53, 0x0b, 0x15, 0x8f, 0x75, 0x00, 0x7b, 0xf1, 0xd2, 0xf2, 0x4d, 0xa6, 0x72, 0x37, 0x34,
|
||||
0x2f, 0xa3, 0x7e, 0xcb, 0x72, 0x4f, 0xff, 0x60, 0x56, 0xe9, 0xb3, 0x00, 0x00, 0x64, 0x05, 0x09,
|
||||
0x0c, 0x1a, 0x01, 0x0a, 0x01, 0x09, 0x1e, 0x1a, 0x0f, 0x0a, 0x3c, 0x09, 0x03, 0x19, 0x0f, 0x09,
|
||||
0x01, 0x19, 0x18, 0x09, 0x02, 0x19, 0x1d, 0x09, 0x07, 0x08, 0x02, 0x09, 0x24, 0x08, 0x0e, 0x1a,
|
||||
0x0b, 0x0a, 0x06, 0x09, 0x0b, 0x18, 0x10, 0x1a, 0x1c, 0x08, 0x02, 0x19, 0x08, 0x18, 0x07, 0x0a,
|
||||
0x0f, 0x09, 0x0e, 0x1a, 0x09, 0x0a, 0x14, 0x09, 0x07, 0x1a, 0x1f, 0x08, 0x03, 0x09, 0x08, 0x19,
|
||||
0x13, 0x09, 0x0d, 0x1a, 0x05, 0x08, 0x17, 0x09, 0x01, 0x19, 0x14, 0x09, 0x02, 0x19, 0x0e, 0x09,
|
||||
0x07, 0x1a, 0x16, 0x08, 0x00, 0x09, 0x0f, 0x19, 0x05, 0x18, 0x0c, 0x0a, 0x10, 0x09, 0x00, 0x19,
|
||||
0x15, 0x09, 0x01, 0x62, 0xa4, 0x2b, 0x64, 0x8f, 0xc4, 0x8c, 0xd2, 0x7c, 0xa6, 0x71, 0xd0, 0x15,
|
||||
0xc0, 0x14, 0xe2, 0x5c, 0x07, 0x03, 0xf3, 0x8f, 0xa6, 0x97, 0xce, 0x9e, 0x4d, 0xc1, 0x44, 0x7c,
|
||||
0xec, 0x0c, 0xb9, 0x00, 0x00, 0x4c, 0x00, 0x09, 0x05, 0x0a, 0x04, 0x1a, 0x1a, 0x0a, 0x07, 0x09,
|
||||
0x01, 0x1a, 0x00, 0x16, 0x10, 0x1a, 0x0c, 0x08, 0x08, 0x09, 0x01, 0x19, 0x00, 0x11, 0x10, 0x19,
|
||||
0x0c, 0x0a, 0x14, 0x09, 0x0a, 0x18, 0x08, 0x09, 0x01, 0x08, 0x02, 0x09, 0x0a, 0x19, 0x1e, 0x09,
|
||||
0x00, 0x08, 0x06, 0x09, 0x09, 0x19, 0x23, 0x09, 0x0b, 0x1a, 0x03, 0x09, 0x07, 0x18, 0x19, 0x08,
|
||||
0x0b, 0x09, 0x01, 0x19, 0x13, 0x09, 0x09, 0x1a, 0x09, 0x0a, 0x00, 0x08, 0x10, 0x09, 0x01, 0x19,
|
||||
0x18, 0x09, 0x01, 0xfc, 0x2e, 0x46, 0xcf, 0x8d, 0xe9, 0xdd, 0xd4, 0x1a, 0xd6, 0xfc, 0xf4, 0x60,
|
||||
0x69, 0x83, 0x05, 0xbf, 0x89, 0x27, 0x40, 0x4c, 0xc8, 0x74, 0xc8, 0xed, 0x4e, 0x48, 0x5f, 0x5c,
|
||||
0xdb, 0xf7, 0xc5, 0x00, 0x00, 0x4a, 0x2a, 0x09, 0x02, 0x08, 0x1a, 0x09, 0x04, 0x1a, 0x00, 0x16,
|
||||
0x0b, 0x1a, 0x02, 0x0a, 0x11, 0x08, 0x14, 0x09, 0x0e, 0x1a, 0x05, 0x19, 0x19, 0x09, 0x11, 0x18,
|
||||
0x01, 0x09, 0x02, 0x0a, 0x0e, 0x19, 0x16, 0x09, 0x0b, 0x1a, 0x00, 0x19, 0x06, 0x09, 0x01, 0x08,
|
||||
0x03, 0x19, 0x15, 0x09, 0x11, 0x18, 0x13, 0x1a, 0x0e, 0x09, 0x10, 0x18, 0x04, 0x08, 0x01, 0x09,
|
||||
0x10, 0x1a, 0x04, 0x09, 0x07, 0x1a, 0x0b, 0x09, 0x01, 0x08, 0x11, 0x09, 0x02, 0x19, 0x1b, 0x09,
|
||||
0x01, 0x9e, 0x9c, 0x0f, 0x47, 0x3c, 0x0c, 0x0f, 0x15, 0xb8, 0xd1, 0x27, 0xe6, 0x54, 0xe0, 0x33,
|
||||
0x96, 0x7b, 0x73, 0x0e, 0x0b, 0x95, 0xe1, 0xf7, 0x83, 0x6b, 0xc3, 0x1c, 0x6c, 0xb4, 0x3e, 0xfa,
|
||||
0x26, 0x00, 0x00, 0x46, 0x07, 0x09, 0x03, 0x1a, 0x14, 0x09, 0x11, 0x1a, 0x02, 0x09, 0x11, 0x18,
|
||||
0x06, 0x09, 0x12, 0x18, 0x08, 0x09, 0x12, 0x1a, 0x02, 0x09, 0x01, 0x08, 0x10, 0x18, 0x01, 0x08,
|
||||
0x02, 0x09, 0x0b, 0x1a, 0x0b, 0x09, 0x09, 0x1a, 0x07, 0x09, 0x02, 0x08, 0x02, 0x09, 0x12, 0x18,
|
||||
0x00, 0x19, 0x02, 0x09, 0x0d, 0x18, 0x12, 0x1a, 0x0c, 0x0a, 0x31, 0x09, 0x09, 0x1a, 0x0d, 0x09,
|
||||
0x11, 0x19, 0x0b, 0x09, 0x12, 0x18, 0x03, 0x08, 0x23, 0x09, 0x01, 0xd6, 0x8f, 0xfd, 0x56, 0xf9,
|
||||
0x05, 0x67, 0x54, 0x1a, 0xb7, 0xf2, 0x8b, 0x14, 0x1c, 0x86, 0x99, 0x99, 0xb6, 0xb0, 0xf6, 0x58,
|
||||
0xa8, 0x7a, 0x48, 0x26, 0x4d, 0x30, 0x43, 0xe8, 0x5d, 0x62, 0xfd, 0x00, 0x00, 0x48, 0x2b, 0x09,
|
||||
0x05, 0x0a, 0x01, 0x1a, 0x14, 0x0a, 0x04, 0x09, 0x0d, 0x18, 0x09, 0x09, 0x07, 0x08, 0x07, 0x18,
|
||||
0x07, 0x08, 0x08, 0x09, 0x03, 0x19, 0x0d, 0x09, 0x02, 0x0a, 0x0b, 0x1a, 0x23, 0x09, 0x0c, 0x19,
|
||||
0x05, 0x18, 0x04, 0x19, 0x05, 0x18, 0x06, 0x08, 0x34, 0x09, 0x04, 0x1a, 0x02, 0x0a, 0x0e, 0x1a,
|
||||
0x20, 0x09, 0x07, 0x0a, 0x09, 0x09, 0x07, 0x0a, 0x0a, 0x09, 0x08, 0x0a, 0x05, 0x09, 0x02, 0x19,
|
||||
0x06, 0x09, 0x0b, 0x08, 0x12, 0x09, 0x01, 0x0c, 0x85, 0x6c, 0x94, 0x12, 0x2d, 0xb3, 0x09, 0xb8,
|
||||
0xfc, 0x00, 0xd5, 0x0a, 0xe7, 0x68, 0x2e, 0xa5, 0x73, 0x3f, 0x2c, 0x46, 0xc8, 0x87, 0x2b, 0x05,
|
||||
0x8b, 0x80, 0x06, 0xb6, 0x3f, 0xcc, 0x43, 0x00, 0x00, 0x72, 0x00, 0x09, 0x04, 0x08, 0x05, 0x18,
|
||||
0x17, 0x08, 0x0c, 0x09, 0x01, 0x18, 0x00, 0x14, 0x0c, 0x18, 0x17, 0x0a, 0x00, 0x09, 0x04, 0x0a,
|
||||
0x0d, 0x09, 0x01, 0x19, 0x0e, 0x18, 0x14, 0x09, 0x01, 0x19, 0x15, 0x09, 0x02, 0x19, 0x04, 0x1a,
|
||||
0x15, 0x0a, 0x33, 0x09, 0x02, 0x19, 0x0b, 0x09, 0x04, 0x19, 0x12, 0x09, 0x07, 0x19, 0x0c, 0x09,
|
||||
0x03, 0x19, 0x16, 0x09, 0x01, 0x19, 0x21, 0x09, 0x03, 0x19, 0x07, 0x09, 0x0b, 0x0a, 0x01, 0x19,
|
||||
0x09, 0x18, 0x05, 0x08, 0x1d, 0x19, 0x15, 0x09, 0x03, 0x1a, 0x10, 0x09, 0x09, 0x08, 0x06, 0x09,
|
||||
0x01, 0x19, 0x29, 0x09, 0x07, 0x08, 0x01, 0x09, 0x02, 0x19, 0x12, 0x09, 0x02, 0x19, 0x30, 0x09,
|
||||
0x07, 0x08, 0x02, 0x18, 0x00, 0x08, 0x1a, 0x09, 0x00, 0x19, 0x46, 0x09, 0x01, 0x5a, 0xe6, 0x2e,
|
||||
0xe2, 0x90, 0x50, 0x3d, 0x01, 0xe2, 0x17, 0x98, 0x86, 0x60, 0x55, 0x85, 0xec, 0x25, 0x8c, 0x32,
|
||||
0xd2, 0x1c, 0xe6, 0x0e, 0x29, 0xff, 0x99, 0x1b, 0x06, 0x4f, 0x13, 0xb1, 0x5a, 0x00, 0x00, 0x84,
|
||||
0x0a, 0x09, 0x0b, 0x08, 0x02, 0x09, 0x07, 0x19, 0x01, 0x09, 0x02, 0x08, 0x03, 0x19, 0x08, 0x1a,
|
||||
0x12, 0x0a, 0x10, 0x09, 0x02, 0x19, 0x08, 0x09, 0x06, 0x0a, 0x0c, 0x09, 0x07, 0x08, 0x05, 0x18,
|
||||
0x0c, 0x08, 0x13, 0x09, 0x07, 0x18, 0x07, 0x08, 0x0a, 0x09, 0x12, 0x1a, 0x04, 0x0a, 0x17, 0x09,
|
||||
0x03, 0x19, 0x0e, 0x09, 0x0d, 0x08, 0x07, 0x09, 0x0c, 0x0a, 0x05, 0x09, 0x05, 0x1a, 0x0e, 0x0a,
|
||||
0x02, 0x09, 0x02, 0x19, 0x15, 0x09, 0x0c, 0x19, 0x11, 0x09, 0x01, 0x08, 0x01, 0x09, 0x05, 0x08,
|
||||
0x02, 0x19, 0x08, 0x18, 0x0a, 0x09, 0x07, 0x19, 0x07, 0x09, 0x0c, 0x08, 0x11, 0x09, 0x04, 0x19,
|
||||
0x12, 0x09, 0x05, 0x19, 0x09, 0x09, 0x16, 0x1a, 0x0b, 0x19, 0x04, 0x09, 0x01, 0x08, 0x12, 0x09,
|
||||
0x0c, 0x18, 0x08, 0x09, 0x01, 0x0a, 0x08, 0x09, 0x03, 0x19, 0x13, 0x09, 0x12, 0x19, 0x07, 0x09,
|
||||
0x01, 0x19, 0x17, 0x09, 0x01, 0x95, 0x44, 0xe4, 0x43, 0x33, 0x1c, 0xac, 0xae, 0x01, 0xc8, 0x3d,
|
||||
0x52, 0x19, 0x0b, 0x40, 0x54, 0x6f, 0xd4, 0x50, 0x63, 0xfe, 0xbc, 0x00, 0x76, 0x38, 0x15, 0xd6,
|
||||
0xc2, 0xdf, 0x79, 0xef, 0x13, 0x00, 0x00, 0x7c, 0x00, 0x09, 0x13, 0x08, 0x02, 0x09, 0x01, 0x19,
|
||||
0x16, 0x09, 0x02, 0x18, 0x00, 0x14, 0x05, 0x18, 0x07, 0x08, 0x01, 0x1a, 0x00, 0x16, 0x0a, 0x1a,
|
||||
0x00, 0x0a, 0x04, 0x09, 0x07, 0x08, 0x00, 0x19, 0x00, 0x15, 0x05, 0x19, 0x0b, 0x09, 0x01, 0x1a,
|
||||
0x00, 0x16, 0x09, 0x1a, 0x09, 0x0a, 0x03, 0x09, 0x01, 0x19, 0x17, 0x09, 0x0f, 0x18, 0x03, 0x08,
|
||||
0x0c, 0x19, 0x0a, 0x09, 0x03, 0x19, 0x0f, 0x09, 0x07, 0x1a, 0x0c, 0x09, 0x00, 0x08, 0x24, 0x18,
|
||||
0x06, 0x08, 0x1b, 0x09, 0x01, 0x08, 0x04, 0x1a, 0x19, 0x09, 0x02, 0x19, 0x18, 0x09, 0x00, 0x19,
|
||||
0x03, 0x11, 0x01, 0x19, 0x0a, 0x09, 0x0d, 0x18, 0x08, 0x09, 0x05, 0x0a, 0x11, 0x1a, 0x04, 0x0a,
|
||||
0x18, 0x09, 0x01, 0x08, 0x02, 0x18, 0x14, 0x08, 0x16, 0x09, 0x01, 0x19, 0x10, 0x09, 0x07, 0x1a,
|
||||
0x18, 0x0a, 0x12, 0x09, 0x01, 0x10, 0x0d, 0x38, 0xaf, 0x4a, 0x93, 0x6e, 0xd2, 0x65, 0x2f, 0x1f,
|
||||
0xa4, 0xed, 0x4b, 0xe4, 0x9a, 0x1a, 0x7a, 0x3a, 0x4b, 0x3d, 0x73, 0x11, 0xdf, 0xbe, 0x9d, 0x37,
|
||||
0x0f, 0xd9, 0xb0, 0xa0, 0xb4, 0x00, 0x00, 0x58, 0x00, 0x09, 0x10, 0x0a, 0x0e, 0x09, 0x01, 0x19,
|
||||
0x15, 0x09, 0x02, 0x19, 0x06, 0x18, 0x0a, 0x0a, 0x0a, 0x19, 0x05, 0x09, 0x11, 0x1a, 0x04, 0x0a,
|
||||
0x01, 0x09, 0x0a, 0x18, 0x0d, 0x09, 0x02, 0x19, 0x0f, 0x1a, 0x0e, 0x18, 0x08, 0x1a, 0x02, 0x0a,
|
||||
0x09, 0x1a, 0x11, 0x0a, 0x04, 0x09, 0x06, 0x19, 0x0c, 0x09, 0x05, 0x0a, 0x13, 0x09, 0x02, 0x08,
|
||||
0x0d, 0x18, 0x06, 0x08, 0x02, 0x09, 0x0d, 0x19, 0x08, 0x09, 0x0f, 0x1a, 0x06, 0x09, 0x10, 0x18,
|
||||
0x09, 0x09, 0x02, 0x19, 0x0d, 0x18, 0x15, 0x1a, 0x01, 0x0a, 0x15, 0x09, 0x04, 0x19, 0x12, 0x09,
|
||||
0x01, 0x50, 0xcc, 0xb3, 0x5b, 0xe2, 0x8a, 0xfd, 0x51, 0xfe, 0x6d, 0xa4, 0x75, 0x1f, 0x55, 0x1f,
|
||||
0x4c, 0x14, 0x6b, 0x89, 0xa9, 0x29, 0x29, 0xf6, 0x51, 0x16, 0xc6, 0x02, 0xbd, 0x21, 0x91, 0x00,
|
||||
0xf9, 0x00, 0x00, 0x84, 0x00, 0x09, 0x44, 0x08, 0x0c, 0x09, 0x20, 0x0a, 0x27, 0x09, 0x07, 0x08,
|
||||
0x09, 0x09, 0x06, 0x0a, 0x0a, 0x09, 0x07, 0x0a, 0x0f, 0x09, 0x06, 0x08, 0x04, 0x09, 0x07, 0x08,
|
||||
0x0f, 0x09, 0x08, 0x0a, 0x20, 0x09, 0x0e, 0x0a, 0x2c, 0x09, 0x07, 0x08, 0x0e, 0x09, 0x07, 0x08,
|
||||
0x16, 0x09, 0x00, 0x0a, 0x04, 0x09, 0x06, 0x0a, 0x34, 0x09, 0x07, 0x08, 0x10, 0x09, 0x07, 0x08,
|
||||
0x1c, 0x09, 0x07, 0x08, 0x08, 0x09, 0x07, 0x0a, 0x08, 0x09, 0x07, 0x08, 0x0e, 0x09, 0x08, 0x08,
|
||||
0x2d, 0x09, 0x17, 0x0a, 0x05, 0x09, 0x02, 0x0a, 0x0e, 0x09, 0x18, 0x08, 0x02, 0x09, 0x00, 0x0a,
|
||||
0x05, 0x09, 0x10, 0x0a, 0x19, 0x09, 0x07, 0x08, 0x18, 0x09, 0x07, 0x0a, 0x07, 0x09, 0x07, 0x08,
|
||||
0x85, 0x09, 0x07, 0x1a, 0x02, 0x19, 0x42, 0x09, 0x06, 0x08, 0x4c, 0x09, 0x05, 0x0a, 0x1d, 0x09,
|
||||
0x05, 0x08, 0x36, 0x09, 0x0f, 0x0a, 0x1e, 0x09, 0x01, 0xf3, 0xf6, 0xc9, 0xf2, 0xb6, 0x95, 0xea,
|
||||
0x6c, 0xc7, 0xa1, 0x70, 0xeb, 0x43, 0xb3, 0x3a, 0xe7, 0xd3, 0x64, 0x15, 0xd0, 0x96, 0x0e, 0x96,
|
||||
0x47, 0xa4, 0xee, 0xfd, 0x04, 0x01, 0x4c, 0xe5, 0xba, 0x00, 0x00, 0x64, 0x19, 0x09, 0x0f, 0x19,
|
||||
0x01, 0x0a, 0x14, 0x1a, 0x00, 0x0a, 0x02, 0x09, 0x11, 0x18, 0x02, 0x09, 0x01, 0x15, 0x10, 0x19,
|
||||
0x02, 0x09, 0x02, 0x19, 0x12, 0x09, 0x14, 0x18, 0x10, 0x1a, 0x00, 0x19, 0x03, 0x09, 0x04, 0x19,
|
||||
0x0d, 0x09, 0x0b, 0x08, 0x01, 0x09, 0x09, 0x08, 0x08, 0x19, 0x09, 0x09, 0x23, 0x1a, 0x00, 0x0a,
|
||||
0x01, 0x09, 0x01, 0x08, 0x06, 0x09, 0x01, 0x19, 0x0b, 0x09, 0x12, 0x08, 0x2d, 0x09, 0x02, 0x0a,
|
||||
0x05, 0x1a, 0x08, 0x0a, 0x04, 0x09, 0x11, 0x19, 0x12, 0x18, 0x08, 0x08, 0x02, 0x09, 0x02, 0x19,
|
||||
0x08, 0x1a, 0x06, 0x09, 0x0d, 0x08, 0x07, 0x09, 0x13, 0x1a, 0x00, 0x19, 0x0c, 0x08, 0x12, 0x09,
|
||||
0x01, 0xc6, 0x5c, 0x2b, 0xd7, 0xcc, 0x8e, 0x41, 0x44, 0x5d, 0xdf, 0xc1, 0x8f, 0x12, 0xca, 0x78,
|
||||
0x0b, 0x05, 0x8d, 0x2a, 0x72, 0x1e, 0xea, 0xd6, 0xba, 0xc4, 0x48, 0x7a, 0xae, 0xd3, 0x4b, 0x19,
|
||||
0xe7, 0x00, 0x00, 0x4a, 0x02, 0x09, 0x05, 0x0a, 0x16, 0x1a, 0x0b, 0x19, 0x01, 0x09, 0x05, 0x08,
|
||||
0x0b, 0x09, 0x03, 0x19, 0x17, 0x09, 0x0e, 0x19, 0x0b, 0x09, 0x06, 0x19, 0x11, 0x09, 0x02, 0x19,
|
||||
0x0f, 0x18, 0x01, 0x09, 0x01, 0x0a, 0x00, 0x09, 0x03, 0x19, 0x14, 0x09, 0x02, 0x19, 0x14, 0x09,
|
||||
0x02, 0x19, 0x0a, 0x18, 0x08, 0x09, 0x0e, 0x0a, 0x0f, 0x19, 0x0e, 0x09, 0x01, 0x0a, 0x24, 0x09,
|
||||
0x0f, 0x1a, 0x06, 0x08, 0x0c, 0x09, 0x01, 0x19, 0x16, 0x09, 0x10, 0x08, 0x0a, 0x09, 0x01, 0x72,
|
||||
0xc6, 0x0b, 0x9e, 0xfd, 0xe8, 0xe8, 0x2e, 0x92, 0x84, 0xdd, 0xfb, 0x8d, 0xa8, 0x64, 0x84, 0xd2,
|
||||
0x2f, 0x62, 0x31, 0x53, 0xbf, 0x89, 0xce, 0x8d, 0xc5, 0x76, 0x43, 0xc6, 0x7b, 0x5a, 0x66, 0x00,
|
||||
0x00, 0x46, 0x00, 0x09, 0x06, 0x08, 0x22, 0x1a, 0x03, 0x18, 0x08, 0x08, 0x25, 0x19, 0x05, 0x09,
|
||||
0x03, 0x08, 0x05, 0x09, 0x04, 0x19, 0x23, 0x09, 0x18, 0x19, 0x1d, 0x09, 0x18, 0x18, 0x12, 0x09,
|
||||
0x00, 0x08, 0x12, 0x19, 0x25, 0x09, 0x04, 0x08, 0x02, 0x15, 0x0a, 0x16, 0x06, 0x0a, 0x13, 0x09,
|
||||
0x02, 0x0a, 0x04, 0x09, 0x0d, 0x18, 0x36, 0x09, 0x21, 0x1a, 0x0d, 0x08, 0x15, 0x19, 0x12, 0x09,
|
||||
0x16, 0x0a, 0x05, 0x09, 0x11, 0x19, 0x31, 0x09, 0x01, 0xe4, 0xb5, 0x9f, 0x25, 0xb6, 0x7a, 0x4e,
|
||||
0x37, 0x0f, 0x5d, 0x0a, 0x87, 0xee, 0xe9, 0x9c, 0x05, 0xef, 0x74, 0xea, 0xf8, 0xd8, 0x27, 0x03,
|
||||
0x87, 0xa7, 0xbd, 0xda, 0x02, 0x16, 0x3f, 0xbc, 0xc0, 0x00, 0x00, 0x66, 0x00, 0x09, 0x04, 0x08,
|
||||
0x0e, 0x18, 0x0d, 0x08, 0x0b, 0x18, 0x03, 0x08, 0x10, 0x09, 0x03, 0x0a, 0x12, 0x1a, 0x05, 0x0a,
|
||||
0x02, 0x1a, 0x0e, 0x0a, 0x10, 0x09, 0x01, 0x19, 0x0e, 0x09, 0x0e, 0x18, 0x01, 0x09, 0x02, 0x0a,
|
||||
0x00, 0x09, 0x05, 0x08, 0x04, 0x09, 0x0d, 0x18, 0x01, 0x09, 0x03, 0x19, 0x0b, 0x1a, 0x07, 0x0a,
|
||||
0x10, 0x19, 0x03, 0x09, 0x01, 0x19, 0x11, 0x09, 0x01, 0x19, 0x26, 0x09, 0x0f, 0x1a, 0x05, 0x09,
|
||||
0x08, 0x19, 0x15, 0x09, 0x0a, 0x18, 0x05, 0x08, 0x29, 0x09, 0x01, 0x19, 0x1b, 0x09, 0x04, 0x19,
|
||||
0x1a, 0x09, 0x0d, 0x1a, 0x0e, 0x09, 0x02, 0x18, 0x0d, 0x08, 0x0e, 0x09, 0x07, 0x1a, 0x11, 0x0a,
|
||||
0x1d, 0x09, 0x01, 0x4e, 0x11, 0xca, 0xcc, 0x1c, 0xd0, 0xbc, 0xfd, 0x36, 0x97, 0xd2, 0x85, 0x2e,
|
||||
0xad, 0x81, 0x07, 0x6b, 0x72, 0xca, 0xe1, 0xb1, 0x1e, 0x9f, 0x7e, 0x57, 0xb3, 0x43, 0x76, 0xf2,
|
||||
0xaf, 0x27, 0x78, 0x00, 0x00, 0x60, 0x00, 0x09, 0x13, 0x08, 0x20, 0x09, 0x02, 0x19, 0x16, 0x09,
|
||||
0x04, 0x14, 0x08, 0x18, 0x0c, 0x08, 0x0c, 0x09, 0x0b, 0x1a, 0x07, 0x09, 0x00, 0x08, 0x0e, 0x09,
|
||||
0x13, 0x1a, 0x14, 0x18, 0x04, 0x09, 0x0b, 0x19, 0x13, 0x09, 0x0c, 0x1a, 0x04, 0x09, 0x00, 0x08,
|
||||
0x52, 0x09, 0x05, 0x19, 0x0e, 0x09, 0x08, 0x19, 0x0c, 0x09, 0x11, 0x18, 0x07, 0x08, 0x0f, 0x1a,
|
||||
0x00, 0x09, 0x02, 0x08, 0x07, 0x09, 0x11, 0x1a, 0x13, 0x18, 0x00, 0x08, 0x01, 0x09, 0x00, 0x0a,
|
||||
0x07, 0x09, 0x0b, 0x19, 0x2a, 0x09, 0x05, 0x19, 0x12, 0x09, 0x12, 0x19, 0x05, 0x09, 0x10, 0x1a,
|
||||
0x0a, 0x09, 0x03, 0x08, 0x30, 0x09, 0x01, 0x99, 0x51, 0x74, 0xbe, 0xa6, 0xd1, 0xee, 0x36, 0x5d,
|
||||
0xec, 0xb1, 0x1f, 0xbd, 0x8b, 0xd2, 0x40, 0xf5, 0xf9, 0xa1, 0x89, 0x0b, 0xd9, 0xff, 0x82, 0x26,
|
||||
0x79, 0x56, 0xcc, 0x58, 0x91, 0x10, 0xb2, 0x00, 0x00, 0x6a, 0x38, 0x09, 0x24, 0x0a, 0x00, 0x09,
|
||||
0x06, 0x18, 0x13, 0x08, 0x0f, 0x09, 0x00, 0x0a, 0x0a, 0x09, 0x0d, 0x0a, 0x02, 0x09, 0x00, 0x08,
|
||||
0x04, 0x09, 0x01, 0x19, 0x05, 0x18, 0x00, 0x19, 0x0a, 0x09, 0x01, 0x19, 0x06, 0x09, 0x01, 0x0a,
|
||||
0x00, 0x09, 0x02, 0x19, 0x08, 0x09, 0x05, 0x0a, 0x04, 0x19, 0x03, 0x09, 0x05, 0x0a, 0x02, 0x09,
|
||||
0x02, 0x19, 0x1a, 0x09, 0x07, 0x08, 0x03, 0x09, 0x07, 0x08, 0x03, 0x09, 0x06, 0x08, 0x04, 0x09,
|
||||
0x06, 0x0a, 0x0a, 0x09, 0x07, 0x08, 0x21, 0x09, 0x04, 0x19, 0x03, 0x09, 0x06, 0x08, 0x19, 0x09,
|
||||
0x05, 0x0a, 0x0b, 0x09, 0x05, 0x08, 0x05, 0x09, 0x05, 0x0a, 0x0b, 0x09, 0x10, 0x0a, 0x30, 0x09,
|
||||
0x13, 0x08, 0x0b, 0x09, 0x01, 0x23, 0xab, 0x56, 0x5c, 0x52, 0x1d, 0xfd, 0x5f, 0x05, 0xc5, 0x6c,
|
||||
0x0c, 0xd3, 0x64, 0x19, 0x10, 0x92, 0x14, 0x8a, 0x01, 0x19, 0x64, 0x15, 0x32, 0xef, 0x5e, 0x36,
|
||||
0x64, 0x16, 0x40, 0x7f, 0x15, 0x00, 0x00, 0x66, 0x07, 0x09, 0x11, 0x1a, 0x06, 0x09, 0x12, 0x1a,
|
||||
0x03, 0x09, 0x02, 0x08, 0x03, 0x09, 0x0b, 0x18, 0x0e, 0x09, 0x01, 0x19, 0x0b, 0x18, 0x09, 0x0a,
|
||||
0x01, 0x09, 0x02, 0x19, 0x11, 0x09, 0x07, 0x19, 0x0b, 0x09, 0x04, 0x0a, 0x08, 0x1a, 0x0d, 0x09,
|
||||
0x12, 0x18, 0x13, 0x08, 0x14, 0x09, 0x0c, 0x1a, 0x06, 0x09, 0x03, 0x08, 0x17, 0x09, 0x03, 0x19,
|
||||
0x13, 0x09, 0x06, 0x18, 0x00, 0x19, 0x11, 0x09, 0x11, 0x1a, 0x02, 0x09, 0x01, 0x08, 0x0c, 0x09,
|
||||
0x01, 0x0a, 0x05, 0x1a, 0x00, 0x0a, 0x13, 0x09, 0x03, 0x08, 0x18, 0x09, 0x11, 0x18, 0x05, 0x09,
|
||||
0x02, 0x19, 0x0f, 0x09, 0x02, 0x0a, 0x0c, 0x1a, 0x1a, 0x18, 0x06, 0x08, 0x1f, 0x09, 0x01, 0xca,
|
||||
0xe5, 0xba, 0x14, 0xa4, 0x86, 0x58, 0x55, 0xd7, 0x91, 0xce, 0x47, 0x98, 0x52, 0x9c, 0xa2, 0x20,
|
||||
0x19, 0xc2, 0x49, 0xe4, 0xe9, 0x7a, 0x96, 0xa6, 0xe4, 0x00, 0x10, 0x6a, 0x8e, 0x09, 0x61, 0x00,
|
||||
0x00, 0x56, 0x00, 0x09, 0x0d, 0x08, 0x02, 0x09, 0x0a, 0x18, 0x0c, 0x09, 0x05, 0x19, 0x0b, 0x09,
|
||||
0x14, 0x19, 0x0a, 0x0a, 0x02, 0x09, 0x02, 0x19, 0x10, 0x09, 0x0c, 0x19, 0x06, 0x09, 0x03, 0x08,
|
||||
0x20, 0x09, 0x01, 0x19, 0x07, 0x1a, 0x0b, 0x09, 0x00, 0x08, 0x10, 0x09, 0x0b, 0x19, 0x0d, 0x09,
|
||||
0x13, 0x19, 0x3f, 0x09, 0x01, 0x19, 0x0c, 0x1a, 0x23, 0x09, 0x02, 0x19, 0x08, 0x09, 0x11, 0x19,
|
||||
0x0f, 0x08, 0x0f, 0x18, 0x0d, 0x08, 0x2c, 0x09, 0x03, 0x19, 0x14, 0x09, 0x0f, 0x0a, 0x01, 0x09,
|
||||
0x05, 0x19, 0x1e, 0x09, 0x01, 0x19, 0x2c, 0x09, 0x01, 0x90, 0x18, 0xe0, 0x06, 0x9a, 0x4d, 0x6f,
|
||||
0x04, 0x6c, 0xeb, 0xa6, 0x27, 0x92, 0xba, 0xb9, 0x41, 0x0f, 0xae, 0x40, 0x5a, 0xfd, 0xbd, 0x7d,
|
||||
0x9c, 0x48, 0xfe, 0xe6, 0xab, 0x67, 0x2b, 0x1a, 0x48, 0x00, 0x00, 0x58, 0x1e, 0x09, 0x02, 0x18,
|
||||
0x15, 0x09, 0x01, 0x19, 0x0d, 0x18, 0x08, 0x0a, 0x02, 0x19, 0x03, 0x18, 0x0d, 0x19, 0x01, 0x0a,
|
||||
0x03, 0x19, 0x24, 0x09, 0x03, 0x19, 0x15, 0x09, 0x0a, 0x0a, 0x02, 0x09, 0x10, 0x1a, 0x00, 0x0a,
|
||||
0x07, 0x08, 0x0a, 0x1a, 0x09, 0x09, 0x02, 0x19, 0x08, 0x09, 0x08, 0x0a, 0x2a, 0x19, 0x0a, 0x18,
|
||||
0x00, 0x19, 0x14, 0x09, 0x0e, 0x1a, 0x0c, 0x09, 0x04, 0x08, 0x13, 0x18, 0x03, 0x08, 0x0a, 0x09,
|
||||
0x0c, 0x08, 0x2c, 0x09, 0x01, 0x19, 0x0d, 0x09, 0x0d, 0x0a, 0x13, 0x09, 0x02, 0x19, 0x1b, 0x09,
|
||||
0x01, 0x19, 0x2b, 0x09, 0x01, 0xdf, 0x5d, 0x57, 0xf2, 0xf0, 0xe3, 0xfd, 0x93, 0x18, 0x2c, 0xd9,
|
||||
0x99, 0xed, 0x61, 0xed, 0x06, 0x2f, 0xa7, 0x4b, 0x5a, 0x25, 0x68, 0x76, 0x20, 0xe3, 0x18, 0x24,
|
||||
0x24, 0x55, 0x88, 0xe2, 0xb0, 0x00, 0x00, 0xaa, 0x00, 0x09, 0x14, 0x0a, 0x12, 0x09, 0x00, 0x0a,
|
||||
0x0f, 0x09, 0x00, 0x08, 0x0b, 0x09, 0x00, 0x0a, 0x0a, 0x09, 0x00, 0x08, 0x07, 0x09, 0x00, 0x0a,
|
||||
0x07, 0x09, 0x00, 0x08, 0x07, 0x09, 0x00, 0x0a, 0x05, 0x09, 0x00, 0x08, 0x05, 0x09, 0x00, 0x0a,
|
||||
0x05, 0x09, 0x00, 0x08, 0x05, 0x09, 0x00, 0x0a, 0x04, 0x09, 0x00, 0x08, 0x04, 0x09, 0x00, 0x0a,
|
||||
0x04, 0x09, 0x00, 0x08, 0x04, 0x09, 0x00, 0x0a, 0x04, 0x09, 0x00, 0x08, 0x04, 0x09, 0x00, 0x0a,
|
||||
0x04, 0x09, 0x00, 0x08, 0x04, 0x09, 0x00, 0x0a, 0x04, 0x09, 0x00, 0x08, 0x04, 0x09, 0x00, 0x0a,
|
||||
0x04, 0x09, 0x00, 0x08, 0x04, 0x09, 0x00, 0x0a, 0x04, 0x09, 0x00, 0x08, 0x04, 0x09, 0x00, 0x0a,
|
||||
0x04, 0x09, 0x00, 0x08, 0x04, 0x09, 0x00, 0x0a, 0x04, 0x09, 0x00, 0x08, 0x03, 0x09, 0x04, 0x0a,
|
||||
0x05, 0x09, 0x04, 0x19, 0x0e, 0x09, 0x1f, 0x19, 0x02, 0x09, 0x0d, 0x0a, 0x10, 0x09, 0x1c, 0x08,
|
||||
0x05, 0x09, 0x24, 0x19, 0x54, 0x09, 0x15, 0x11, 0x2e, 0x19, 0x1f, 0x09, 0x0d, 0x1a, 0x0f, 0x0a,
|
||||
0x05, 0x09, 0x09, 0x08, 0x08, 0x09, 0x01, 0x19, 0x09, 0x09, 0x05, 0x19, 0x0b, 0x18, 0x0c, 0x0a,
|
||||
0x37, 0x09, 0x01, 0x9b, 0x23, 0x5e, 0xc4, 0xdb, 0x44, 0xfe, 0x82, 0x31, 0xc6, 0x04, 0xf2, 0x5d,
|
||||
0x03, 0x25, 0xb1, 0x77, 0x79, 0x43, 0x68, 0x3f, 0x5a, 0x6f, 0xbf, 0x4e, 0x7d, 0xb6, 0x9e, 0x45,
|
||||
0x09, 0x4e, 0x98, 0x00, 0x00, 0x3c, 0x4b, 0x09, 0x02, 0x19, 0x22, 0x09, 0x10, 0x08, 0x04, 0x09,
|
||||
0x00, 0x0a, 0x1f, 0x1a, 0x08, 0x09, 0x14, 0x18, 0x26, 0x09, 0x0a, 0x19, 0x30, 0x09, 0x16, 0x1a,
|
||||
0x12, 0x09, 0x14, 0x18, 0x00, 0x19, 0x13, 0x09, 0x15, 0x1a, 0x13, 0x09, 0x0a, 0x18, 0x1e, 0x09,
|
||||
0x15, 0x1a, 0x12, 0x09, 0x0d, 0x19, 0x18, 0x09, 0x10, 0x18, 0x15, 0x09, 0x12, 0x1a, 0x1f, 0x0a,
|
||||
0x7c, 0x09, 0x01, 0x44, 0x39, 0xe8, 0x75, 0x1b, 0x7f, 0x71, 0x57, 0xa1, 0x4e, 0xd0, 0xc1, 0xeb,
|
||||
0x61, 0x0d, 0x83, 0xe3, 0x98, 0xe5, 0x7f, 0x1f, 0x72, 0x2f, 0xeb, 0x61, 0xf8, 0x67, 0x0b, 0x9f,
|
||||
0xd9, 0x81, 0x88, 0x00, 0x00, 0x6a, 0x00, 0x09, 0x06, 0x08, 0x04, 0x18, 0x16, 0x08, 0x0c, 0x09,
|
||||
0x01, 0x18, 0x00, 0x14, 0x04, 0x18, 0x06, 0x08, 0x19, 0x0a, 0x16, 0x09, 0x05, 0x18, 0x0e, 0x08,
|
||||
0x0d, 0x09, 0x04, 0x19, 0x12, 0x09, 0x0f, 0x1a, 0x0b, 0x0a, 0x33, 0x09, 0x03, 0x19, 0x13, 0x09,
|
||||
0x0b, 0x19, 0x17, 0x09, 0x05, 0x19, 0x15, 0x09, 0x00, 0x19, 0x22, 0x09, 0x08, 0x19, 0x09, 0x09,
|
||||
0x04, 0x0a, 0x0f, 0x18, 0x01, 0x08, 0x1b, 0x19, 0x0b, 0x09, 0x03, 0x08, 0x13, 0x09, 0x11, 0x1a,
|
||||
0x08, 0x08, 0x12, 0x19, 0x0f, 0x09, 0x03, 0x19, 0x07, 0x09, 0x12, 0x18, 0x0f, 0x19, 0x1a, 0x09,
|
||||
0x13, 0x0a, 0x0b, 0x1a, 0x02, 0x09, 0x02, 0x05, 0x00, 0x04, 0x10, 0x05, 0x00, 0x15, 0x47, 0x05,
|
||||
0x00
|
||||
};
|
||||
}
|
9
src/emulation/sky/tasdemos.hpp
Normal file
9
src/emulation/sky/tasdemos.hpp
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef _skycore__tasdemos__hpp__included__
|
||||
#define _skycore__tasdemos__hpp__included__
|
||||
|
||||
namespace sky
|
||||
{
|
||||
extern const unsigned char tasdemos_data[];
|
||||
}
|
||||
|
||||
#endif
|
95
src/emulation/sky/tile.cpp
Normal file
95
src/emulation/sky/tile.cpp
Normal file
|
@ -0,0 +1,95 @@
|
|||
#include "tile.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
uint16_t _floorheights[6] = {0, 12800, 15360, 17000, 20000, 25000 };
|
||||
|
||||
const uint8_t _floor_height[256] = {
|
||||
0, 1, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 5
|
||||
};
|
||||
|
||||
const uint8_t _tunnel_inner[38] = {
|
||||
16, 16, 16, 16, 15, 14, 13, 11,
|
||||
8, 7, 6, 5, 3, 3, 3, 3,
|
||||
3, 3, 2, 1, 0, 0, 0, 0,
|
||||
0, 0, 1, 2, 3, 3, 3, 3,
|
||||
3, 3, 5, 6, 7, 8
|
||||
};
|
||||
|
||||
const uint8_t _tunnel_outer[38] = {
|
||||
32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 31, 31, 31, 31, 31, 30, 30,
|
||||
30, 29, 29, 29, 28, 27, 26, 25,
|
||||
24, 22, 20, 18, 17, 14
|
||||
};
|
||||
|
||||
int tile::apparent_height() throw()
|
||||
{
|
||||
if((_tile & 0xE00) <= 0x400)
|
||||
return (_tile & 0xF00) >> 9;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
bool tile::is_colliding_floor(int16_t hchunk, int16_t vpos)
|
||||
{
|
||||
return has_lower_floor() && vpos > 7808 && vpos < 10240;
|
||||
}
|
||||
bool tile::is_colliding(int16_t hchunk, int16_t vpos)
|
||||
{
|
||||
if(hchunk <= 0)
|
||||
hchunk = 1 - hchunk;
|
||||
if(vpos <= 8576 || hchunk > 37)
|
||||
return false;
|
||||
//Glitched tiles
|
||||
if((_tile & 0xE00) >= 0x600)
|
||||
return true;
|
||||
//Tunnels.
|
||||
if((_tile & 0x100) != 0) {
|
||||
int16_t rvpos = vpos - 8704;
|
||||
if(rvpos >= 0 && rvpos < (128 * _tunnel_inner[hchunk]))
|
||||
return false;
|
||||
}
|
||||
//Upper limits.
|
||||
if((_tile & 0xE00) == 0x400 && vpos >= 15360)
|
||||
return false;
|
||||
if((_tile & 0xE00) == 0x200 && vpos >= 12800)
|
||||
return false;
|
||||
if((_tile & 0xF00) == 0 && vpos >= 10240)
|
||||
return false;
|
||||
//The bare turnnel special.
|
||||
if((_tile & 0xF00) == 0x100) {
|
||||
int16_t rvpos = vpos - 8704;
|
||||
if(rvpos >= 0 && rvpos >= (128 * _tunnel_outer[hchunk]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
int16_t tile::upper_level()
|
||||
{
|
||||
return _floorheights[_floor_height[_tile >> 8]];
|
||||
}
|
||||
unsigned tile::surface_type(int16_t vpos)
|
||||
{
|
||||
if(vpos == 10240)
|
||||
return lower_floor();
|
||||
else if(vpos == upper_level())
|
||||
return upper_floor();
|
||||
else
|
||||
return 16; //None.
|
||||
}
|
||||
bool tile::is_dangerous()
|
||||
{
|
||||
if((_tile & 0xF00) == 0)
|
||||
return ((_tile & 0xF) == 0x00 || (_tile & 0xF) == 0xC);
|
||||
if((_tile & 0xF00) == 0x100)
|
||||
return false;
|
||||
return ((_tile & 0xF0) == 0xC0);
|
||||
}
|
||||
bool tile::in_pipe(uint16_t hchunk, int16_t vpos)
|
||||
{
|
||||
if(hchunk > 23 || !is_tunnel())
|
||||
return false;
|
||||
return (vpos - 8704 < ((_tunnel_inner[hchunk] + _tunnel_outer[hchunk]) / 2) * 128);
|
||||
}
|
||||
}
|
36
src/emulation/sky/tile.hpp
Normal file
36
src/emulation/sky/tile.hpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifndef _skycore__tile__hpp__included__
|
||||
#define _skycore__tile__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace sky
|
||||
{
|
||||
struct tile
|
||||
{
|
||||
static const unsigned sticky = 2;
|
||||
static const unsigned slippery = 8;
|
||||
static const unsigned suppiles = 9;
|
||||
static const unsigned boost = 10;
|
||||
static const unsigned burning = 12;
|
||||
tile() { _tile = 0; }
|
||||
tile(uint16_t xtile) { _tile = xtile; }
|
||||
unsigned lower_floor() { return _tile & 0xF; }
|
||||
unsigned upper_floor() { return (_tile & 0xF0) >> 4; }
|
||||
bool is_tunnel() { return ((_tile & 0x100) != 0) && ((_tile & 0xE00) <= 0x400); }
|
||||
int apparent_height() throw();
|
||||
bool has_lower_floor() throw() { return ((_tile & 0xF) != 0); }
|
||||
bool is_colliding_floor(int16_t hchunk, int16_t vpos);
|
||||
bool is_colliding(int16_t hchunk, int16_t vpos);
|
||||
int16_t upper_level();
|
||||
unsigned surface_type(int16_t vpos);
|
||||
bool is_dangerous();
|
||||
bool is_block() { return ((_tile & 0xF00) != 0); }
|
||||
bool is_rblock() { return ((_tile & 0xE00) != 0); }
|
||||
bool is_blank() { return (_tile == 0); /* Not masked! */ }
|
||||
bool in_pipe(uint16_t hchunk, int16_t vpos);
|
||||
uint16_t rawtile() { return _tile; }
|
||||
private:
|
||||
uint16_t _tile;
|
||||
};
|
||||
}
|
||||
#endif
|
20
src/emulation/sky/util.cpp
Normal file
20
src/emulation/sky/util.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include "util.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
vector_input_stream::vector_input_stream(const std::vector<char>& _data, size_t _offset)
|
||||
: data(_data), offset(_offset)
|
||||
{
|
||||
}
|
||||
|
||||
vector_input_stream::~vector_input_stream()
|
||||
{
|
||||
}
|
||||
|
||||
int vector_input_stream::get()
|
||||
{
|
||||
if(offset < data.size())
|
||||
return (uint8_t)data[offset++];
|
||||
return -1;
|
||||
}
|
||||
}
|
56
src/emulation/sky/util.hpp
Normal file
56
src/emulation/sky/util.hpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef _skycore__util__hpp__included__
|
||||
#define _skycore__util__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "lzs.hpp"
|
||||
|
||||
namespace sky
|
||||
{
|
||||
inline uint8_t expand_color(uint8_t vgacolor)
|
||||
{
|
||||
vgacolor &= 0x3F;
|
||||
return (vgacolor << 2) | (vgacolor >> 4);
|
||||
}
|
||||
|
||||
inline uint8_t access_array(const std::vector<char>& data, size_t offset)
|
||||
{
|
||||
if(offset >= data.size())
|
||||
throw std::runtime_error("Attempt to access array outside bounds");
|
||||
return data[offset];
|
||||
}
|
||||
|
||||
inline uint16_t combine(uint8_t a, uint8_t b)
|
||||
{
|
||||
return ((uint16_t)b << 8) | (uint16_t)a;
|
||||
}
|
||||
|
||||
inline int sgn(int16_t v)
|
||||
{
|
||||
if(v < 0)
|
||||
return -1;
|
||||
if(v > 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int sgn(int32_t v)
|
||||
{
|
||||
if(v < 0)
|
||||
return -1;
|
||||
if(v > 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct vector_input_stream : public input_stream
|
||||
{
|
||||
vector_input_stream(const std::vector<char>& _data, size_t _offset);
|
||||
~vector_input_stream();
|
||||
int get();
|
||||
private:
|
||||
const std::vector<char>& data;
|
||||
size_t offset;
|
||||
};
|
||||
}
|
||||
#endif
|
|
@ -508,3 +508,4 @@ emucore_callbacks::~emucore_callbacks() throw()
|
|||
struct emucore_callbacks* ecore_callbacks;
|
||||
|
||||
bool new_core_flag = false;
|
||||
uint32_t magic_flags = 0;
|
Loading…
Add table
Reference in a new issue