diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e1aca79 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ + +SDL_CFLAGS = `sdl-config --cflags` +SDL_LIBS = `sdl-config --libs` +VORBIS_LIBS = -lvorbisidec +ZLIB_LIBS = -lz + +DEFINES = -DBYPASS_PROTECTION +#DEFINES = -DBYPASS_PROTECTION -DENABLE_PASSWORD_MENU -DNDEBUG + +CXXFLAGS += -Wall -Wuninitialized -Wshadow -Wundef -Wreorder -Wnon-virtual-dtor -Wno-multichar +CXXFLAGS += -MMD $(SDL_CFLAGS) -DUSE_ZLIB $(DEFINES) + +SRCS = collision.cpp cutscene.cpp file.cpp fs.cpp game.cpp graphics.cpp main.cpp menu.cpp \ + mixer.cpp mod_player.cpp ogg_player.cpp piege.cpp resource.cpp scaler.cpp seq_player.cpp \ + sfx_player.cpp staticres.cpp systemstub_sdl.cpp unpack.cpp util.cpp video.cpp + +OBJS = $(SRCS:.cpp=.o) +DEPS = $(SRCS:.cpp=.d) + +LIBS = $(SDL_LIBS) $(VORBIS_LIBS) $(ZLIB_LIBS) + +-include Makefile.local + +rs: $(OBJS) + $(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +clean: + rm -f *.o *.d + +-include $(DEPS) diff --git a/README b/README new file mode 100644 index 0000000..fd9629a --- /dev/null +++ b/README @@ -0,0 +1,110 @@ + +REminiscence README +Release version: 0.2.2 ($date) +------------------------------------------------------------------------------- + + +About: +------ + +REminiscence is a re-implementation of the engine used in the game Flashback +made by Delphine Software and released in 1992. More informations about the +game can be found at [1], [2] and [3]. + + +Compiling: +---------- + +Update the defines in the Makefile if needed. The SDL and zlib libraries are required. + + +Data Files: +----------- + +You will need the original files of the PC (DOS or CD) or Amiga release. +If you have a version distributed by SSI, you'll have to rename the files +and drop the 'ssi' suffix (ie. logosssi.cmd -> logos.cmd). + +To hear background music during polygonal cutscenes with the PC version, +you'll need to copy the .mod files of the Amiga version : + + mod.flashback-ascenseur + mod.flashback-ceinturea + mod.flashback-chute + mod.flashback-desintegr + mod.flashback-donneobjt + mod.flashback-fin + mod.flashback-fin2 + mod.flashback-game_over + mod.flashback-holocube + mod.flashback-introb + mod.flashback-jungle + mod.flashback-logo + mod.flashback-memoire + mod.flashback-missionca + mod.flashback-options1 + mod.flashback-options2 + mod.flashback-reunion + mod.flashback-taxi + mod.flashback-teleport2 + mod.flashback-teleporta + mod.flashback-voyage + +To hear voice during in-game dialogues, you'll need to copy the 'VOICE.VCE' +file from the SegaCD version to the DATA directory. + + +Running: +-------- + +By default, the engine will try to load the game data files from the 'DATA' +directory (as the original game did). The savestates are saved in the current +directory. These paths can be changed using command line switches : + + Usage: rs [OPTIONS]... + --datapath=PATH Path to data files (default 'DATA') + --savepath=PATH Path to save files (default '.') + +In-game hotkeys : + + Arrow Keys move Conrad + Enter use the current inventory object + Shift talk / use / run / shoot + Escape display the options + Backspace display the inventory + Alt Enter toggle windowed/fullscreen mode + Alt + and - change video scaler + Ctrl S save game state + Ctrl L load game state + Ctrl + and - change game state slot + Ctrl R toggle input keys record + Ctrl P toggle input keys replay + +Debug hotkeys : + + Ctrl F toggle fast mode + Ctrl I Conrad 'infinite' life + Ctrl B toggle display of updated dirty blocks + Ctrl M mirror mode (right - left swapped) + + +Credits: +-------- + +Delphine Software, obviously, for making another great game. +Yaz0r, Pixel and gawd for sharing information they gathered on the game. +Nicolas Bondoux for sound fixes. + + +Contact: +-------- + +Gregory Montoir, cyx@users.sourceforge.net + + +URLs: +----- + +[1] http://www.mobygames.com/game/flashback-the-quest-for-identity +[2] http://en.wikipedia.org/wiki/Flashback:_The_Quest_for_Identity +[3] http://ramal.free.fr/fb_en.htm diff --git a/collision.cpp b/collision.cpp new file mode 100644 index 0000000..ccd4a89 --- /dev/null +++ b/collision.cpp @@ -0,0 +1,522 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "game.h" +#include "resource.h" + + +void Game::col_prepareRoomState() { + memset(_col_activeCollisionSlots, 0xFF, sizeof(_col_activeCollisionSlots)); + _col_currentLeftRoom = _res._ctData[CT_LEFT_ROOM + _currentRoom]; + _col_currentRightRoom = _res._ctData[CT_RIGHT_ROOM + _currentRoom]; + for (int i = 0; i != _col_curPos; ++i) { + CollisionSlot *_di = _col_slotsTable[i]; + uint8_t room = _di->ct_pos / 64; + if (room == _currentRoom) { + _col_activeCollisionSlots[0x30 + (_di->ct_pos & 0x3F)] = i; + } else if (room == _col_currentLeftRoom) { + _col_activeCollisionSlots[0x00 + (_di->ct_pos & 0x3F)] = i; + } else if (room == _col_currentRightRoom) { + _col_activeCollisionSlots[0x60 + (_di->ct_pos & 0x3F)] = i; + } + } +#ifdef DEBUG_COLLISION + printf("---\n"); + for (int y = 0; y < 7; ++y) { + for (int x = 0; x < 16; ++x) { + printf("%d", _res._ctData[0x100 + _currentRoom * 0x70 + y * 16 + x]); + } + printf("\n"); + } +#endif +} + +void Game::col_clearState() { + _col_curPos = 0; + _col_curSlot = _col_slots; +} + +void Game::col_preparePiegeState(LivePGE *pge) { + debug(DBG_COL, "Game::col_preparePiegeState() pge_num=%d", pge - &_pgeLive[0]); + CollisionSlot *ct_slot1, *ct_slot2; + if (pge->init_PGE->unk1C == 0) { + pge->collision_slot = 0xFF; + return; + } + int i = 0; + ct_slot1 = 0; + for (int c = 0; c < pge->init_PGE->unk1C; ++c) { + ct_slot2 = _col_curSlot; + if (ct_slot2 + 1 > &_col_slots[255]) + return; + _col_curSlot = ct_slot2 + 1; + int16_t pos = col_getGridPos(pge, i); + if (pos < 0) { + if (ct_slot1 == 0) { + pge->collision_slot = 0xFF; + } else { + ct_slot1->index = 0xFFFF; + } + return; + } + ct_slot2->ct_pos = pos; + ct_slot2->live_pge = pge; + ct_slot2->index = 0xFFFF; + int16_t _ax = col_findSlot(pos); + if (_ax >= 0) { + ct_slot2->prev_slot = _col_slotsTable[_ax]; + _col_slotsTable[_ax] = ct_slot2; + if (ct_slot1 == 0) { + pge->collision_slot = _ax; + } else { + ct_slot1->index = _ax; + } + LivePGE *temp_pge = ct_slot2->live_pge; + if (temp_pge->flags & 0x80) { + _pge_liveTable2[temp_pge->index] = temp_pge; + temp_pge->flags |= 4; + } + if (ct_slot2->prev_slot) { + temp_pge = ct_slot2->prev_slot->live_pge; + if (temp_pge->flags & 0x80) { + _pge_liveTable2[temp_pge->index] = temp_pge; + temp_pge->flags |= 4; + } + } + } else { + ct_slot2->prev_slot = 0; + _col_slotsTable[_col_curPos] = ct_slot2; + if (ct_slot1 == 0) { + pge->collision_slot = _col_curPos; + } else { + ct_slot1->index = _col_curPos; + } + _col_curPos++; + } + ct_slot1 = ct_slot2; + i += 0x10; + } +} + +uint16_t Game::col_getGridPos(LivePGE *pge, int16_t dx) { + int16_t x = pge->pos_x + dx; + int16_t y = pge->pos_y; + + int8_t c = pge->room_location; + if (c < 0) return 0xFFFF; + + if (x < 0) { + c = _res._ctData[CT_LEFT_ROOM + c]; + if (c < 0) return 0xFFFF; + x += 256; + } else if (x >= 256) { + c = _res._ctData[CT_RIGHT_ROOM + c]; + if (c < 0) return 0xFFFF; + x -= 256; + } else if (y < 0) { + c = _res._ctData[CT_UP_ROOM + c]; + if (c < 0) return 0xFFFF; + y += 216; + } else if (y >= 216) { + c = _res._ctData[CT_DOWN_ROOM + c]; + if (c < 0) return 0xFFFF; + y -= 216; + } + + x = (x + 8) >> 4; + y = (y - 8) / 72; + if (x < 0 || x > 15 || y < 0 || y > 2) { + return 0xFFFF; + } else { + return y * 16 + x + c * 64; + } +} + +int16_t Game::col_findSlot(int16_t pos) { + for (uint16_t i = 0; i < _col_curPos; ++i) { + if (_col_slotsTable[i]->ct_pos == pos) + return i; + } + return -1; +} + +int16_t Game::col_getGridData(LivePGE *pge, int16_t dy, int16_t dx) { + if (_pge_currentPiegeFacingDir) { + dx = -dx; + } + const int16_t pge_grid_y = _col_currentPiegeGridPosY + dy; + const int16_t pge_grid_x = _col_currentPiegeGridPosX + dx; + const int8_t *room_ct_data; + int8_t next_room; + if (pge_grid_x < 0) { + room_ct_data = &_res._ctData[CT_LEFT_ROOM]; + next_room = room_ct_data[pge->room_location]; + if (next_room < 0) return 1; + room_ct_data += pge_grid_x + 16 + pge_grid_y * 16 + next_room * 0x70; + return (int16_t)room_ct_data[0x40]; + } else if (pge_grid_x >= 16) { + room_ct_data = &_res._ctData[CT_RIGHT_ROOM]; + next_room = room_ct_data[pge->room_location]; + if (next_room < 0) return 1; + room_ct_data += pge_grid_x - 16 + pge_grid_y * 16 + next_room * 0x70; + return (int16_t)room_ct_data[0x80]; + } else if (pge_grid_y < 1) { + room_ct_data = &_res._ctData[CT_UP_ROOM]; + next_room = room_ct_data[pge->room_location]; + if (next_room < 0) return 1; + room_ct_data += pge_grid_x + (pge_grid_y + 6) * 16 + next_room * 0x70; + return (int16_t)room_ct_data[0x100]; + } else if (pge_grid_y >= 7) { + room_ct_data = &_res._ctData[CT_DOWN_ROOM]; + next_room = room_ct_data[pge->room_location]; + if (next_room < 0) return 1; + room_ct_data += pge_grid_x + (pge_grid_y - 6) * 16 + next_room * 0x70; + return (int16_t)room_ct_data[0xC0]; + } else { + room_ct_data = &_res._ctData[0x100]; + room_ct_data += pge_grid_x + pge_grid_y * 16 + pge->room_location * 0x70; + return (int16_t)room_ct_data[0]; + } +} + +LivePGE *Game::col_findPiege(LivePGE *pge, uint16_t arg2) { + if (pge->collision_slot != 0xFF) { + CollisionSlot *slot = _col_slotsTable[pge->collision_slot]; + while (slot) { + if (slot->live_pge == pge) { + slot = slot->prev_slot; + } else { + if (arg2 == 0xFFFF || arg2 == slot->live_pge->init_PGE->object_type) { + return slot->live_pge; + } else { + slot = slot->prev_slot; + } + } + } + } + return 0; +} + +uint8_t Game::col_findCurrentCollidingObject(LivePGE *pge, uint8_t n1, uint8_t n2, uint8_t n3, LivePGE **pge_out) { + if (pge_out) { + *pge_out = pge; + } + if (pge->collision_slot != 0xFF) { + CollisionSlot *cs = _col_slotsTable[pge->collision_slot]; + while (cs) { + LivePGE *col_pge = cs->live_pge; + if (pge_out) { + *pge_out = col_pge; + } + if (col_pge->init_PGE->object_type == n1 || + col_pge->init_PGE->object_type == n2 || + col_pge->init_PGE->object_type == n3) { + return col_pge->init_PGE->colliding_icon_num; + } else { + cs = cs->prev_slot; + } + } + } + return 0; +} + +int16_t Game::col_detectHit(LivePGE *pge, int16_t arg2, int16_t arg4, col_Callback1 callback1, col_Callback2 callback2, int16_t argA, int16_t argC) { + debug(DBG_COL, "col_detectHit()"); + int16_t pos_dx, pos_dy, var8, varA; + int16_t collision_score = 0; + int8_t pge_room = pge->room_location; + if (pge_room < 0 || pge_room >= 0x40) { + return 0; + } + int16_t thr = pge->init_PGE->counter_values[0]; + if (thr > 0) { + pos_dx = -1; + pos_dy = -1; + } else { + pos_dx = 1; + pos_dy = 1; + thr = -thr; + } + if (_pge_currentPiegeFacingDir) { + pos_dx = -pos_dx; + } + int16_t grid_pos_x = (pge->pos_x + 8) >> 4; + int16_t grid_pos_y = (pge->pos_y / 72); + if (grid_pos_y >= 0 && grid_pos_y <= 2) { + grid_pos_y *= 16; + collision_score = 0; + var8 = 0; + varA = 0; + if (argA != 0) { + var8 = pos_dy; + grid_pos_x += pos_dx; + varA = 1; + } + while (varA <= thr) { + if (grid_pos_x < 0) { + pge_room = _res._ctData[CT_LEFT_ROOM + pge_room]; + if (pge_room < 0) break; + grid_pos_x += 16; + } + if (grid_pos_x >= 16) { + pge_room = _res._ctData[CT_RIGHT_ROOM + pge_room]; + if (pge_room < 0) break; + grid_pos_x -= 16; + } + int16_t slot = col_findSlot(grid_pos_y + grid_pos_x + pge_room * 64); + if (slot >= 0) { + CollisionSlot *cs = _col_slotsTable[slot]; + while (cs) { + collision_score += (this->*callback1)(cs->live_pge, pge, arg2, arg4); + cs = cs->prev_slot; + } + } + if ((this->*callback2)(pge, var8, varA, arg2) != 0) { + break; + } + grid_pos_x += pos_dx; + ++varA; + var8 += pos_dy; + } + } + if (argC == -1) { + return collision_score; + } else { + return 0; + } +} + +int Game::col_detectHitCallback1(LivePGE *pge, int16_t dy, int16_t unk1, int16_t unk2) { + if (col_getGridData(pge, 1, dy) != 0) { + return 1; + } else { + return 0; + } +} + +int Game::col_detectHitCallback6(LivePGE *pge, int16_t dy, int16_t unk1, int16_t unk2) { + return 0; +} + +int Game::col_detectHitCallback2(LivePGE *pge1, LivePGE *pge2, int16_t unk1, int16_t unk2) { + if (pge1 != pge2 && (pge1->flags & 4)) { + if (pge1->init_PGE->object_type == unk2) { + if ((pge1->flags & 1) == (pge2->flags & 1)) { + if (col_detectHitCallbackHelper(pge1, unk1) == 0) { + return 1; + } + } + } + } + return 0; +} + +int Game::col_detectHitCallback3(LivePGE *pge1, LivePGE *pge2, int16_t unk1, int16_t unk2) { + if (pge1 != pge2 && (pge1->flags & 4)) { + if (pge1->init_PGE->object_type == unk2) { + if ((pge1->flags & 1) != (pge2->flags & 1)) { + if (col_detectHitCallbackHelper(pge1, unk1) == 0) { + return 1; + } + } + } + } + return 0; +} + +int Game::col_detectHitCallback4(LivePGE *pge1, LivePGE *pge2, int16_t unk1, int16_t unk2) { + if (pge1 != pge2 && (pge1->flags & 4)) { + if (pge1->init_PGE->object_type == unk2) { + if ((pge1->flags & 1) != (pge2->flags & 1)) { + if (col_detectHitCallbackHelper(pge1, unk1) == 0) { + pge_updateGroup(pge2->index, pge1->index, unk1); + return 1; + } + } + } + } + return 0; +} + +int Game::col_detectHitCallback5(LivePGE *pge1, LivePGE *pge2, int16_t unk1, int16_t unk2) { + if (pge1 != pge2 && (pge1->flags & 4)) { + if (pge1->init_PGE->object_type == unk2) { + if ((pge1->flags & 1) == (pge2->flags & 1)) { + if (col_detectHitCallbackHelper(pge1, unk1) == 0) { + pge_updateGroup(pge2->index, pge1->index, unk1); + return 1; + } + } + } + } + return 0; +} + +int Game::col_detectHitCallbackHelper(LivePGE *pge, int16_t groupId) { + InitPGE *init_pge = pge->init_PGE; + assert(init_pge->obj_node_number < _res._numObjectNodes); + ObjectNode *on = _res._objectNodesMap[init_pge->obj_node_number]; + Object *obj = &on->objects[pge->first_obj_number]; + int i = pge->first_obj_number; + while (pge->obj_type == obj->type && on->last_obj_number > i) { + if (obj->opcode2 == 0x6B) { // pge_op_isInGroupSlice + if (obj->opcode_arg2 == 0) { + if (groupId == 1 || groupId == 2) return 0xFFFF; + } + if (obj->opcode_arg2 == 1) { + if (groupId == 3 || groupId == 4) return 0xFFFF; + } + } else if (obj->opcode2 == 0x22) { // pge_op_isInGroup + if (obj->opcode_arg2 == groupId) return 0xFFFF; + } + + if (obj->opcode1 == 0x6B) { // pge_op_isInGroupSlice + if (obj->opcode_arg1 == 0) { + if (groupId == 1 || groupId == 2) return 0xFFFF; + } + if (obj->opcode_arg1 == 1) { + if (groupId == 3 || groupId == 4) return 0xFFFF; + } + } else if (obj->opcode1 == 0x22) { // pge_op_isInGroup + if (obj->opcode_arg1 == groupId) return 0xFFFF; + } + ++obj; + ++i; + } + return 0; +} + +int Game::col_detectGunHitCallback1(LivePGE *pge, int16_t arg2, int16_t arg4, int16_t arg6) { + int16_t _ax = col_getGridData(pge, 1, arg2); + if (_ax != 0) { + if (!(_ax & 2) || (arg6 != 1)) { + return _ax; + } + } + return 0; +} + +int Game::col_detectGunHitCallback2(LivePGE *pge1, LivePGE *pge2, int16_t arg4, int16_t) { + if (pge1 != pge2 && (pge1->flags & 4)) { + if (pge1->init_PGE->object_type == 1 || pge1->init_PGE->object_type == 10) { + uint8_t id; + if ((pge1->flags & 1) != (pge2->flags & 1)) { + id = 4; + if (arg4 == 0) { + id = 3; + } + } else { + id = 2; + if (arg4 == 0) { + id = 1; + } + } + if (col_detectHitCallbackHelper(pge1, id) != 0) { + pge_updateGroup(pge2->index, pge1->index, id); + return 1; + } + } + } + return 0; +} + +int Game::col_detectGunHitCallback3(LivePGE *pge1, LivePGE *pge2, int16_t arg4, int16_t) { + if (pge1 != pge2 && (pge1->flags & 4)) { + if (pge1->init_PGE->object_type == 1 || pge1->init_PGE->object_type == 12 || pge1->init_PGE->object_type == 10) { + uint8_t id; + if ((pge1->flags & 1) != (pge2->flags & 1)) { + id = 4; + if (arg4 == 0) { + id = 3; + } + } else { + id = 2; + if (arg4 == 0) { + id = 1; + } + } + if (col_detectHitCallbackHelper(pge1, id) != 0) { + pge_updateGroup(pge2->index, pge1->index, id); + return 1; + } + + } + } + return 0; +} + +int Game::col_detectGunHit(LivePGE *pge, int16_t arg2, int16_t arg4, col_Callback1 callback1, col_Callback2 callback2, int16_t argA, int16_t argC) { + int8_t pge_room = pge->room_location; + if (pge_room < 0 || pge_room >= 0x40) return 0; + int16_t thr, pos_dx, pos_dy; + if (argC == -1) { + thr = pge->init_PGE->counter_values[0]; + } else { + thr = pge->init_PGE->counter_values[3]; + } + if (thr > 0) { + pos_dx = -1; + pos_dy = -1; + } else { + pos_dx = 1; + pos_dy = 1; + thr = -thr; + } + if (_pge_currentPiegeFacingDir) { + pos_dx = -pos_dx; + } + int16_t grid_pos_x = (pge->pos_x + 8) >> 4; + int16_t grid_pos_y = (pge->pos_y - 8) / 72; + if (grid_pos_y >= 0 && grid_pos_y <= 2) { + grid_pos_y *= 16; + int16_t var8 = 0; + int16_t varA = 0; + if (argA != 0) { + var8 = pos_dy; + grid_pos_x += pos_dx; + varA = 1; + } + while (varA <= thr) { + if (grid_pos_x < 0) { + pge_room = _res._ctData[CT_LEFT_ROOM + pge_room]; + if (pge_room < 0) return 0; + grid_pos_x += 0x10; + } + if (grid_pos_x >= 0x10) { + pge_room = _res._ctData[CT_RIGHT_ROOM + pge_room]; + if (pge_room < 0) return 0; + grid_pos_x -= 0x10; + } + int16_t slot = col_findSlot(pge_room * 64 + grid_pos_x + grid_pos_y); + if (slot >= 0) { + CollisionSlot *cs = _col_slotsTable[slot]; + while (cs) { + int r = (this->*callback1)(cs->live_pge, pge, arg2, arg4); + if (r != 0) return r; + cs = cs->prev_slot; + } + } + if ((this->*callback2)(pge, var8, varA, arg2) != 0) { + break; + } + grid_pos_x += pos_dx; + ++varA; + var8 += pos_dy; + } + } + return 0; +} diff --git a/cutscene.cpp b/cutscene.cpp new file mode 100644 index 0000000..c9677c4 --- /dev/null +++ b/cutscene.cpp @@ -0,0 +1,1031 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "resource.h" +#include "systemstub.h" +#include "video.h" +#include "cutscene.h" + + +Cutscene::Cutscene(Resource *res, SystemStub *stub, Video *vid) + : _res(res), _stub(stub), _vid(vid) { + memset(_palBuf, 0, sizeof(_palBuf)); +} + +void Cutscene::sync() { + // XXX input handling + if (!(_stub->_pi.dbgMask & PlayerInput::DF_FASTMODE)) { + int32_t delay = _stub->getTimeStamp() - _tstamp; + int32_t pause = _frameDelay * TIMER_SLICE - delay; + if (pause > 0) { + _stub->sleep(pause); + } + } + _tstamp = _stub->getTimeStamp(); +} + +void Cutscene::copyPalette(const uint8_t *pal, uint16_t num) { + uint8_t *dst = (uint8_t *)_palBuf; + if (num != 0) { + dst += 0x20; + } + memcpy(dst, pal, 0x20); + _newPal = true; +} + +void Cutscene::updatePalette() { + if (_newPal) { + const uint8_t *p = _palBuf; + for (int i = 0; i < 32; ++i) { + uint16_t color = READ_BE_UINT16(p); p += 2; + uint8_t t = (color == 0) ? 0 : 3; + Color c; + c.r = ((color & 0xF00) >> 6) | t; + c.g = ((color & 0x0F0) >> 2) | t; + c.b = ((color & 0x00F) << 2) | t; + _stub->setPaletteEntry(0xC0 + i, &c); + } + _newPal = false; + } +} + +void Cutscene::setPalette() { + sync(); + updatePalette(); + SWAP(_page0, _page1); + _stub->copyRect(0, 0, Video::GAMESCREEN_W, Video::GAMESCREEN_H, _page0, 256); + _stub->updateScreen(0); +} + +void Cutscene::initRotationData(uint16_t a, uint16_t b, uint16_t c) { + int16_t n1 = _sinTable[a]; + int16_t n2 = _cosTable[a]; + int16_t n3 = _sinTable[c]; + int16_t n4 = _cosTable[c]; + int16_t n5 = _sinTable[b]; + int16_t n6 = _cosTable[b]; + _rotData[0] = ((n2 * n6) >> 8) - ((((n4 * n1) >> 8) * n5) >> 8); + _rotData[1] = ((n1 * n6) >> 8) + ((((n4 * n2) >> 8) * n5) >> 8); + _rotData[2] = ( n3 * n1) >> 8; + _rotData[3] = (-n3 * n2) >> 8; +} + +uint16_t Cutscene::findTextSeparators(const uint8_t *p) { + uint8_t *q = _textSep; + uint16_t ret = 0; + uint16_t pos = 0; + for (; *p != 0xA; ++p) { + if (*p == 0x7C) { + *q++ = pos; + if (pos > ret) { + ret = pos; + } + pos = 0; + } else { + ++pos; + } + } + *q++ = pos; + if (pos > ret) { + ret = pos; + } + *q++ = 0; + return ret; +} + +void Cutscene::drawText(int16_t x, int16_t y, const uint8_t *p, uint16_t color, uint8_t *page, uint8_t n) { + debug(DBG_CUT, "Cutscene::drawText(x=%d, y=%d, c=%d)", x, y, color); + uint16_t last_sep = 0; + if (n != 0) { + last_sep = findTextSeparators(p); + if (n != 2) { + last_sep = 30; + } + } + const uint8_t *sep = _textSep; + y += 50; + x += 8; + int16_t yy = y; + int16_t xx = x; + if (n != 0) { + xx += ((last_sep - *sep++) & 0xFE) * 4; + } + for (; *p != 0xA; ++p) { + if (*p == 0x7C) { + yy += 8; + xx = x; + if (n != 0) { + xx += ((last_sep - *sep++) & 0xFE) * 4; + } + } else if (*p == 0x20) { + xx += 8; + } else { + uint8_t *dst_char = page + 256 * yy + xx; + const uint8_t *src = _res->_fnt + (*p - 32) * 32; + for (int h = 0; h < 8; ++h) { + for (int w = 0; w < 4; ++w) { + uint8_t c1 = (*src & 0xF0) >> 4; + uint8_t c2 = (*src & 0x0F) >> 0; + ++src; + if (c1 != 0) { + *dst_char = (c1 == 0xF) ? color : (0xE0 + c1); + } + ++dst_char; + if (c2 != 0) { + *dst_char = (c2 == 0xF) ? color : (0xE0 + c2); + } + ++dst_char; + } + dst_char += 256 - 8; + } + xx += 8; + } + } +} + +void Cutscene::swapLayers() { + if (_clearScreen == 0) { + memcpy(_page1, _pageC, Video::GAMESCREEN_W * Video::GAMESCREEN_H); + } else { + memset(_page1, 0xC0, Video::GAMESCREEN_W * Video::GAMESCREEN_H); + } +} + +void Cutscene::drawCreditsText() { + if (_creditsSequence) { + if (_textUnk2 != 0) { + if (_varText == 0) { + _textUnk2 = 0; + } else { + return; + } + } + if (_creditsTextCounter <= 0) { // XXX + uint8_t code = *_textCurPtr; + if (code == 0xFF) { + _textBuf[0] = 0xA; +// _cut_status = 0; + } else if (code == 0xFE) { + ++_textCurPtr; + code = *_textCurPtr++; + _creditsTextCounter = code; + } else if (code == 1) { + ++_textCurPtr; + _creditsTextPosX = *_textCurPtr++; + _creditsTextPosY = *_textCurPtr++; + } else if (code == 0) { + _textCurBuf = _textBuf; + _textBuf[0] = 0xA; + ++_textCurPtr; + if (_varText != 0) { + _textUnk2 = 0xFF; + } + } else { + *_textCurBuf++ = code; + _textCurBuf = _textCurBuf; + *_textCurBuf = 0xA; + ++_textCurPtr; + } + } else { + _creditsTextCounter -= 10; // XXX adjust + } + drawText((_creditsTextPosX - 1) * 8, _creditsTextPosY * 8, _textBuf, 0xEF, _page1, 0); + } +} + +void Cutscene::drawProtectionShape(uint8_t shapeNum, int16_t zoom) { + debug(DBG_CUT, "Cutscene::drawProtectionShape() shapeNum = %d", shapeNum); + _shape_ix = 64; + _shape_iy = 64; + _shape_count = 0; + + int16_t x = 0; + int16_t y = 0; + zoom += 512; + initRotationData(0, 180, 90); + + const uint8_t *shapeOffsetTable = _protectionShapeData + READ_BE_UINT16(_protectionShapeData + 0x02); + const uint8_t *shapeDataTable = _protectionShapeData + READ_BE_UINT16(_protectionShapeData + 0x0E); + const uint8_t *verticesOffsetTable = _protectionShapeData + READ_BE_UINT16(_protectionShapeData + 0x0A); + const uint8_t *verticesDataTable = _protectionShapeData + READ_BE_UINT16(_protectionShapeData + 0x12); + + ++shapeNum; + const uint8_t *shapeData = shapeDataTable + READ_BE_UINT16(shapeOffsetTable + (shapeNum & 0x7FF) * 2); + uint16_t primitiveCount = READ_BE_UINT16(shapeData); shapeData += 2; + + while (primitiveCount--) { + uint16_t verticesOffset = READ_BE_UINT16(shapeData); shapeData += 2; + const uint8_t *p = verticesDataTable + READ_BE_UINT16(verticesOffsetTable + (verticesOffset & 0x3FFF) * 2); + int16_t dx = 0; + int16_t dy = 0; + if (verticesOffset & 0x8000) { + dx = READ_BE_UINT16(shapeData); shapeData += 2; + dy = READ_BE_UINT16(shapeData); shapeData += 2; + } + _hasAlphaColor = (verticesOffset & 0x4000) != 0; + _primitiveColor = 0xC0 + *shapeData++; + drawShapeScaleRotate(p, zoom, dx, dy, x, y, 0, 0); + ++_shape_count; + } +} + +void Cutscene::op_markCurPos() { + debug(DBG_CUT, "Cutscene::op_markCurPos()"); + _cmdPtrBak = _cmdPtr; + drawCreditsText(); + _frameDelay = 5; + setPalette(); + swapLayers(); + _varText = 0; +} + +void Cutscene::op_refreshScreen() { + debug(DBG_CUT, "Cutscene::op_refreshScreen()"); + _clearScreen = fetchNextCmdByte(); + if (_clearScreen != 0) { + swapLayers(); + _varText = 0; + } +} + +void Cutscene::op_waitForSync() { + debug(DBG_CUT, "Cutscene::op_waitForSync()"); + if (_creditsSequence) { + uint16_t n = fetchNextCmdByte() * 2; + do { + _varText = 0xFF; + _frameDelay = 3; + if (_textBuf == _textCurBuf) { + _creditsTextCounter = 20; + } + memcpy(_page1, _page0, Video::GAMESCREEN_W * Video::GAMESCREEN_H); + drawCreditsText(); + setPalette(); + } while (--n); + swapLayers(); + _varText = 0; + } else { + _frameDelay = fetchNextCmdByte() * 4; + sync(); // XXX handle input + } +} + +void Cutscene::drawShape(const uint8_t *data, int16_t x, int16_t y) { + debug(DBG_CUT, "Cutscene::drawShape()"); + _gfx._layer = _page1; + uint8_t numVertices = *data++; + if (numVertices & 0x80) { + Point pt; + pt.x = READ_BE_UINT16(data) + x; data += 2; + pt.y = READ_BE_UINT16(data) + y; data += 2; + uint16_t rx = READ_BE_UINT16(data); data += 2; + uint16_t ry = READ_BE_UINT16(data); data += 2; + _gfx.drawEllipse(_primitiveColor, _hasAlphaColor, &pt, rx, ry); + } else if (numVertices == 0) { + Point pt; + pt.x = READ_BE_UINT16(data) + x; data += 2; + pt.y = READ_BE_UINT16(data) + y; data += 2; + _gfx.drawPoint(_primitiveColor, &pt); + } else { + Point *pt = _vertices; + int16_t ix = READ_BE_UINT16(data); data += 2; + int16_t iy = READ_BE_UINT16(data); data += 2; + pt->x = ix + x; + pt->y = iy + y; + ++pt; + int16_t n = numVertices - 1; + ++numVertices; + for (; n >= 0; --n) { + int16_t dx = (int8_t)*data++; + int16_t dy = (int8_t)*data++; + if (dy == 0 && n != 0 && *(data + 1) == 0) { + ix += dx; + --numVertices; + } else { + ix += dx; + iy += dy; + pt->x = ix + x; + pt->y = iy + y; + ++pt; + } + } + _gfx.drawPolygon(_primitiveColor, _hasAlphaColor, _vertices, numVertices); + } +} + +void Cutscene::op_drawShape() { + debug(DBG_CUT, "Cutscene::op_drawShape()"); + + int16_t x = 0; + int16_t y = 0; + uint16_t shapeOffset = fetchNextCmdWord(); + if (shapeOffset & 0x8000) { + x = fetchNextCmdWord(); + y = fetchNextCmdWord(); + } + + const uint8_t *shapeOffsetTable = _polPtr + READ_BE_UINT16(_polPtr + 0x02); + const uint8_t *shapeDataTable = _polPtr + READ_BE_UINT16(_polPtr + 0x0E); + const uint8_t *verticesOffsetTable = _polPtr + READ_BE_UINT16(_polPtr + 0x0A); + const uint8_t *verticesDataTable = _polPtr + READ_BE_UINT16(_polPtr + 0x12); + + const uint8_t *shapeData = shapeDataTable + READ_BE_UINT16(shapeOffsetTable + (shapeOffset & 0x7FF) * 2); + uint16_t primitiveCount = READ_BE_UINT16(shapeData); shapeData += 2; + + while (primitiveCount--) { + uint16_t verticesOffset = READ_BE_UINT16(shapeData); shapeData += 2; + const uint8_t *primitiveVertices = verticesDataTable + READ_BE_UINT16(verticesOffsetTable + (verticesOffset & 0x3FFF) * 2); + int16_t dx = 0; + int16_t dy = 0; + if (verticesOffset & 0x8000) { + dx = READ_BE_UINT16(shapeData); shapeData += 2; + dy = READ_BE_UINT16(shapeData); shapeData += 2; + } + _hasAlphaColor = (verticesOffset & 0x4000) != 0; + uint8_t color = *shapeData++; + if (_clearScreen == 0) { + color += 0x10; + } + _primitiveColor = 0xC0 + color; + drawShape(primitiveVertices, x + dx, y + dy); + } + if (_clearScreen != 0) { + memcpy(_pageC, _page1, Video::GAMESCREEN_W * Video::GAMESCREEN_H); + } +} + +void Cutscene::op_setPalette() { + debug(DBG_CUT, "Cutscene::op_setPalette()"); + uint8_t num = fetchNextCmdByte(); + uint8_t palNum = fetchNextCmdByte(); + uint16_t off = READ_BE_UINT16(_polPtr + 6); + const uint8_t *p = _polPtr + off + num * 32; + copyPalette(p, palNum ^ 1); + if (_creditsSequence) { + _palBuf[0x20] = 0x0F; + _palBuf[0x21] = 0xFF; + } +} + +void Cutscene::op_drawStringAtBottom() { + debug(DBG_CUT, "Cutscene::op_drawStringAtBottom()"); + uint16_t strId = fetchNextCmdWord(); + if (!_creditsSequence) { + memset(_pageC + 179 * 256, 0xC0, 45 * 256); + memset(_page1 + 179 * 256, 0xC0, 45 * 256); + memset(_page0 + 179 * 256, 0xC0, 45 * 256); + if (strId != 0xFFFF) { + const uint8_t *str = _res->getCineString(strId); + if (str) { + drawText(0, 129, str, 0xEF, _page1, 1); + drawText(0, 129, str, 0xEF, _pageC, 1); + } + } + } +} + +void Cutscene::op_nop() { + debug(DBG_CUT, "Cutscene::op_nop()"); +} + +void Cutscene::op_skip3() { + debug(DBG_CUT, "Cutscene::op_skip3()"); + _cmdPtr += 3; +} + +void Cutscene::op_refreshAll() { + debug(DBG_CUT, "Cutscene::op_refreshAll()"); + _frameDelay = 5; + setPalette(); + swapLayers(); + _varText = 0xFF; + op_handleKeys(); +} + +void Cutscene::drawShapeScale(const uint8_t *data, int16_t zoom, int16_t b, int16_t c, int16_t d, int16_t e, int16_t f, int16_t g) { + debug(DBG_CUT, "Cutscene::drawShapeScale(%d, %d, %d, %d, %d, %d, %d)", zoom, b, c, d, e, f, g); + _gfx._layer = _page1; + uint8_t numVertices = *data++; + if (numVertices & 0x80) { + int16_t x, y; + Point *pt = _vertices; + Point pr[2]; + _shape_cur_x = b + READ_BE_UINT16(data); data += 2; + _shape_cur_y = c + READ_BE_UINT16(data); data += 2; + x = READ_BE_UINT16(data); data += 2; + y = READ_BE_UINT16(data); data += 2; + _shape_cur_x16 = 0; + _shape_cur_y16 = 0; + pr[0].x = 0; + pr[0].y = -y; + pr[1].x = -x; + pr[1].y = y; + if (_shape_count == 0) { + f -= ((((_shape_ix - _shape_ox) * zoom) * 128) + 0x8000) >> 16; + g -= ((((_shape_iy - _shape_oy) * zoom) * 128) + 0x8000) >> 16; + pt->x = f; + pt->y = g; + ++pt; + _shape_cur_x16 = f << 16; + _shape_cur_y16 = g << 16; + } else { + _shape_cur_x16 = _shape_prev_x16 + ((_shape_cur_x - _shape_prev_x) * zoom) * 128; + pt->x = (_shape_cur_x16 + 0x8000) >> 16; + _shape_cur_y16 = _shape_prev_y16 + ((_shape_cur_y - _shape_prev_y) * zoom) * 128; + pt->y = (_shape_cur_y16 + 0x8000) >> 16; + ++pt; + } + for (int i = 0; i < 2; ++i) { + _shape_cur_x += pr[i].x; + _shape_cur_x16 += pr[i].x * zoom * 128; + pt->x = (_shape_cur_x16 + 0x8000) >> 16; + _shape_cur_y += pr[i].y; + _shape_cur_y16 += pr[i].y * zoom * 128; + pt->y = (_shape_cur_y16 + 0x8000) >> 16; + ++pt; + } + _shape_prev_x = _shape_cur_x; + _shape_prev_y = _shape_cur_y; + _shape_prev_x16 = _shape_cur_x16; + _shape_prev_y16 = _shape_cur_y16; + Point po; + po.x = _vertices[0].x + d + _shape_ix; + po.y = _vertices[0].y + e + _shape_iy; + int16_t rx = _vertices[0].x - _vertices[2].x; + int16_t ry = _vertices[0].y - _vertices[1].y; + _gfx.drawEllipse(_primitiveColor, _hasAlphaColor, &po, rx, ry); + } else if (numVertices == 0) { + Point pt; + pt.x = _shape_cur_x = b + READ_BE_UINT16(data); data += 2; + pt.y = _shape_cur_y = c + READ_BE_UINT16(data); data += 2; + if (_shape_count == 0) { + f -= ((((_shape_ix - pt.x) * zoom) * 128) + 0x8000) >> 16; + g -= ((((_shape_iy - pt.y) * zoom) * 128) + 0x8000) >> 16; + pt.x = f + _shape_ix + d; + pt.y = g + _shape_iy + e; + _shape_cur_x16 = f << 16; + _shape_cur_y16 = g << 16; + } else { + _shape_cur_x16 = _shape_prev_x16 + ((pt.x - _shape_prev_x) * zoom) * 128; + _shape_cur_y16 = _shape_prev_y16 + ((pt.y - _shape_prev_y) * zoom) * 128; + pt.x = ((_shape_cur_x16 + 0x8000) >> 16) + _shape_ix + d; + pt.y = ((_shape_cur_y16 + 0x8000) >> 16) + _shape_iy + e; + } + _shape_prev_x = _shape_cur_x; + _shape_prev_y = _shape_cur_y; + _shape_prev_x16 = _shape_cur_x16; + _shape_prev_y16 = _shape_cur_y16; + _gfx.drawPoint(_primitiveColor, &pt); + } else { + Point *pt = _vertices; + int16_t ix, iy; + _shape_cur_x = ix = READ_BE_UINT16(data) + b; data += 2; + _shape_cur_y = iy = READ_BE_UINT16(data) + c; data += 2; + if (_shape_count == 0) { + f -= ((((_shape_ix - _shape_ox) * zoom) * 128) + 0x8000) >> 16; + g -= ((((_shape_iy - _shape_oy) * zoom) * 128) + 0x8000) >> 16; + pt->x = f + _shape_ix + d; + pt->y = g + _shape_iy + e; + ++pt; + _shape_cur_x16 = f << 16; + _shape_cur_y16 = g << 16; + } else { + _shape_cur_x16 = _shape_prev_x16 + ((_shape_cur_x - _shape_prev_x) * zoom) * 128; + _shape_cur_y16 = _shape_prev_y16 + ((_shape_cur_y - _shape_prev_y) * zoom) * 128; + pt->x = ix = ((_shape_cur_x16 + 0x8000) >> 16) + _shape_ix + d; + pt->y = iy = ((_shape_cur_y16 + 0x8000) >> 16) + _shape_iy + e; + ++pt; + } + int16_t n = numVertices - 1; + ++numVertices; + int16_t sx = 0; + for (; n >= 0; --n) { + ix = (int8_t)(*data++) + sx; + iy = (int8_t)(*data++); + if (iy == 0 && n != 0 && *(data + 1) == 0) { + sx = ix; + --numVertices; + } else { + sx = 0; + _shape_cur_x += ix; + _shape_cur_y += iy; + _shape_cur_x16 += ix * zoom * 128; + _shape_cur_y16 += iy * zoom * 128; + pt->x = ((_shape_cur_x16 + 0x8000) >> 16) + _shape_ix + d; + pt->y = ((_shape_cur_y16 + 0x8000) >> 16) + _shape_iy + e; + ++pt; + } + } + _shape_prev_x = _shape_cur_x; + _shape_prev_y = _shape_cur_y; + _shape_prev_x16 = _shape_cur_x16; + _shape_prev_y16 = _shape_cur_y16; + _gfx.drawPolygon(_primitiveColor, _hasAlphaColor, _vertices, numVertices); + } +} + +void Cutscene::op_drawShapeScale() { + debug(DBG_CUT, "Cutscene::op_drawShapeScale()"); + + _shape_count = 0; + + int16_t x = 0; + int16_t y = 0; + uint16_t shapeOffset = fetchNextCmdWord(); + if (shapeOffset & 0x8000) { + x = fetchNextCmdWord(); + y = fetchNextCmdWord(); + } + + uint16_t zoom = fetchNextCmdWord() + 512; + _shape_ix = fetchNextCmdByte(); + _shape_iy = fetchNextCmdByte(); + + const uint8_t *shapeOffsetTable = _polPtr + READ_BE_UINT16(_polPtr + 0x02); + const uint8_t *shapeDataTable = _polPtr + READ_BE_UINT16(_polPtr + 0x0E); + const uint8_t *verticesOffsetTable = _polPtr + READ_BE_UINT16(_polPtr + 0x0A); + const uint8_t *verticesDataTable = _polPtr + READ_BE_UINT16(_polPtr + 0x12); + + const uint8_t *shapeData = shapeDataTable + READ_BE_UINT16(shapeOffsetTable + (shapeOffset & 0x7FF) * 2); + uint16_t primitiveCount = READ_BE_UINT16(shapeData); shapeData += 2; + + if (primitiveCount != 0) { + uint16_t verticesOffset = READ_BE_UINT16(shapeData); + int16_t dx = 0; + int16_t dy = 0; + if (verticesOffset & 0x8000) { + dx = READ_BE_UINT16(shapeData + 2); + dy = READ_BE_UINT16(shapeData + 4); + } + const uint8_t *p = verticesDataTable + READ_BE_UINT16(verticesOffsetTable + (verticesOffset & 0x3FFF) * 2) + 1; + _shape_ox = READ_BE_UINT16(p) + dx; p += 2; + _shape_oy = READ_BE_UINT16(p) + dy; p += 2; + while (primitiveCount--) { + verticesOffset = READ_BE_UINT16(shapeData); shapeData += 2; + p = verticesDataTable + READ_BE_UINT16(verticesOffsetTable + (verticesOffset & 0x3FFF) * 2); + dx = 0; + dy = 0; + if (verticesOffset & 0x8000) { + dx = READ_BE_UINT16(shapeData); shapeData += 2; + dy = READ_BE_UINT16(shapeData); shapeData += 2; + } + _hasAlphaColor = (verticesOffset & 0x4000) != 0; + uint8_t color = *shapeData++; + if (_clearScreen == 0) { + color += 0x10; // 2nd pal buf + } + _primitiveColor = 0xC0 + color; + drawShapeScale(p, zoom, dx, dy, x, y, 0, 0); + ++_shape_count; + } + } +} + +void Cutscene::drawShapeScaleRotate(const uint8_t *data, int16_t zoom, int16_t b, int16_t c, int16_t d, int16_t e, int16_t f, int16_t g) { + debug(DBG_CUT, "Cutscene::drawShapeScaleRotate(%d, %d, %d, %d, %d, %d, %d)", zoom, b, c, d, e, f, g); + _gfx._layer = _page1; + uint8_t numVertices = *data++; + if (numVertices & 0x80) { + int16_t x, y, ix, iy; + Point pr[2]; + Point *pt = _vertices; + _shape_cur_x = ix = b + READ_BE_UINT16(data); data += 2; + _shape_cur_y = iy = c + READ_BE_UINT16(data); data += 2; + x = READ_BE_UINT16(data); data += 2; + y = READ_BE_UINT16(data); data += 2; + _shape_cur_x16 = _shape_ix - ix; + _shape_cur_y16 = _shape_iy - iy; + _shape_ox = _shape_cur_x = _shape_ix + ((_shape_cur_x16 * _rotData[0] + _shape_cur_y16 * _rotData[1]) >> 8); + _shape_oy = _shape_cur_y = _shape_iy + ((_shape_cur_x16 * _rotData[2] + _shape_cur_y16 * _rotData[3]) >> 8); + pr[0].x = 0; + pr[0].y = -y; + pr[1].x = -x; + pr[1].y = y; + if (_shape_count == 0) { + f -= ((_shape_ix - _shape_cur_x) * zoom * 128 + 0x8000) >> 16; + g -= ((_shape_iy - _shape_cur_y) * zoom * 128 + 0x8000) >> 16; + pt->x = f; + pt->y = g; + ++pt; + _shape_cur_x16 = f << 16; + _shape_cur_y16 = g << 16; + } else { + _shape_cur_x16 = _shape_prev_x16 + (_shape_cur_x - _shape_prev_x) * zoom * 128; + _shape_cur_y16 = _shape_prev_y16 + (_shape_cur_y - _shape_prev_y) * zoom * 128; + pt->x = (_shape_cur_x16 + 0x8000) >> 16; + pt->y = (_shape_cur_y16 + 0x8000) >> 16; + ++pt; + } + for (int i = 0; i < 2; ++i) { + _shape_cur_x += pr[i].x; + _shape_cur_x16 += pr[i].x * zoom * 128; + pt->x = (_shape_cur_x16 + 0x8000) >> 16; + _shape_cur_y += pr[i].y; + _shape_cur_y16 += pr[i].y * zoom * 128; + pt->y = (_shape_cur_y16 + 0x8000) >> 16; + ++pt; + } + _shape_prev_x = _shape_cur_x; + _shape_prev_y = _shape_cur_y; + _shape_prev_x16 = _shape_cur_x16; + _shape_prev_y16 = _shape_cur_y16; + Point po; + po.x = _vertices[0].x + d + _shape_ix; + po.y = _vertices[0].y + e + _shape_iy; + int16_t rx = _vertices[0].x - _vertices[2].x; + int16_t ry = _vertices[0].y - _vertices[1].y; + _gfx.drawEllipse(_primitiveColor, _hasAlphaColor, &po, rx, ry); + } else if (numVertices == 0) { + Point pt; + pt.x = b + READ_BE_UINT16(data); data += 2; + pt.y = c + READ_BE_UINT16(data); data += 2; + _shape_cur_x16 = _shape_ix - pt.x; + _shape_cur_y16 = _shape_iy - pt.y; + _shape_cur_x = _shape_ix + ((_rotData[0] * _shape_cur_x16 + _rotData[1] * _shape_cur_y16) >> 8); + _shape_cur_y = _shape_iy + ((_rotData[2] * _shape_cur_x16 + _rotData[3] * _shape_cur_y16) >> 8); + if (_shape_count != 0) { + _shape_cur_x16 = _shape_prev_x16 + (_shape_cur_x - _shape_prev_x) * zoom * 128; + pt.x = ((_shape_cur_x16 + 0x8000) >> 16) + _shape_ix + d; + _shape_cur_y16 = _shape_prev_y16 + (_shape_cur_y - _shape_prev_y) * zoom * 128; + pt.y = ((_shape_cur_y16 + 0x8000) >> 16) + _shape_iy + e; + } else { + f -= (((_shape_ix - _shape_cur_x) * zoom * 128) + 0x8000) >> 16; + g -= (((_shape_iy - _shape_cur_y) * zoom * 128) + 0x8000) >> 16; + _shape_cur_x16 = f << 16; + _shape_cur_y16 = g << 16; + pt.x = f + _shape_ix + d; + pt.y = g + _shape_iy + e; + } + _shape_prev_x = _shape_cur_x; + _shape_prev_y = _shape_cur_y; + _shape_prev_x16 = _shape_cur_x16; + _shape_prev_y16 = _shape_cur_y16; + _gfx.drawPoint(_primitiveColor, &pt); + } else { + int16_t x, y, a, shape_last_x, shape_last_y; + Point tempVertices[40]; + _shape_cur_x = b + READ_BE_UINT16(data); data += 2; + x = _shape_cur_x; + _shape_cur_y = c + READ_BE_UINT16(data); data += 2; + y = _shape_cur_y; + _shape_cur_x16 = _shape_ix - x; + _shape_cur_y16 = _shape_iy - y; + + a = _shape_ix + ((_rotData[0] * _shape_cur_x16 + _rotData[1] * _shape_cur_y16) >> 8); + if (_shape_count == 0) { + _shape_ox = a; + } + _shape_cur_x = shape_last_x = a; + a = _shape_iy + ((_rotData[2] * _shape_cur_x16 + _rotData[3] * _shape_cur_y16) >> 8); + if (_shape_count == 0) { + _shape_oy = a; + } + _shape_cur_y = shape_last_y = a; + + int16_t ix = x; + int16_t iy = y; + Point *pt2 = tempVertices; + int16_t sx = 0; + for (int16_t n = numVertices - 1; n >= 0; --n) { + x = (int8_t)(*data++) + sx; + y = (int8_t)(*data++); + if (y == 0 && n != 0 && *(data + 1) == 0) { + sx = x; + --numVertices; + } else { + ix += x; + iy += y; + sx = 0; + _shape_cur_x16 = _shape_ix - ix; + _shape_cur_y16 = _shape_iy - iy; + a = _shape_ix + ((_rotData[0] * _shape_cur_x16 + _rotData[1] * _shape_cur_y16) >> 8); + pt2->x = a - shape_last_x; + shape_last_x = a; + a = _shape_iy + ((_rotData[2] * _shape_cur_x16 + _rotData[3] * _shape_cur_y16) >> 8); + pt2->y = a - shape_last_y; + shape_last_y = a; + ++pt2; + } + } + Point *pt = _vertices; + if (_shape_count == 0) { + ix = _shape_ox; + iy = _shape_oy; + f -= (((_shape_ix - ix) * zoom * 128) + 0x8000) >> 16; + g -= (((_shape_iy - iy) * zoom * 128) + 0x8000) >> 16; + pt->x = f + _shape_ix + d; + pt->y = g + _shape_iy + e; + ++pt; + _shape_cur_x16 = f << 16; + _shape_cur_y16 = g << 16; + } else { + _shape_cur_x16 = _shape_prev_x16 + ((_shape_cur_x - _shape_prev_x) * zoom * 128); + pt->x = _shape_ix + d + ((_shape_cur_x16 + 0x8000) >> 16); + _shape_cur_y16 = _shape_prev_y16 + ((_shape_cur_y - _shape_prev_y) * zoom * 128); + pt->y = _shape_iy + e + ((_shape_cur_y16 + 0x8000) >> 16); + ++pt; + } + for (int i = 0; i < numVertices; ++i) { + _shape_cur_x += tempVertices[i].x; + _shape_cur_x16 += tempVertices[i].x * zoom * 128; + pt->x = d + _shape_ix + ((_shape_cur_x16 + 0x8000) >> 16); + _shape_cur_y += tempVertices[i].y; + _shape_cur_y16 += tempVertices[i].y * zoom * 128; + pt->y = e + _shape_iy + ((_shape_cur_y16 + 0x8000) >> 16); + ++pt; + } + _shape_prev_x = _shape_cur_x; + _shape_prev_y = _shape_cur_y; + _shape_prev_x16 = _shape_cur_x16; + _shape_prev_y16 = _shape_cur_y16; + _gfx.drawPolygon(_primitiveColor, _hasAlphaColor, _vertices, numVertices + 1); + } +} + +void Cutscene::op_drawShapeScaleRotate() { + debug(DBG_CUT, "Cutscene::op_drawShapeScaleRotate()"); + + _shape_count = 0; + + int16_t x = 0; + int16_t y = 0; + uint16_t shapeOffset = fetchNextCmdWord(); + if (shapeOffset & 0x8000) { + x = fetchNextCmdWord(); + y = fetchNextCmdWord(); + } + + uint16_t zoom = 512; + if (shapeOffset & 0x4000) { + zoom += fetchNextCmdWord(); + } + _shape_ix = fetchNextCmdByte(); + _shape_iy = fetchNextCmdByte(); + + uint16_t r1, r2, r3; + r1 = fetchNextCmdWord(); + r2 = 180; + if (shapeOffset & 0x2000) { + r2 = fetchNextCmdWord(); + } + r3 = 90; + if (shapeOffset & 0x1000) { + r3 = fetchNextCmdWord(); + } + initRotationData(r1, r2, r3); + + const uint8_t *shapeOffsetTable = _polPtr + READ_BE_UINT16(_polPtr + 0x02); + const uint8_t *shapeDataTable = _polPtr + READ_BE_UINT16(_polPtr + 0x0E); + const uint8_t *verticesOffsetTable = _polPtr + READ_BE_UINT16(_polPtr + 0x0A); + const uint8_t *verticesDataTable = _polPtr + READ_BE_UINT16(_polPtr + 0x12); + + const uint8_t *shapeData = shapeDataTable + READ_BE_UINT16(shapeOffsetTable + (shapeOffset & 0x7FF) * 2); + uint16_t primitiveCount = READ_BE_UINT16(shapeData); shapeData += 2; + + while (primitiveCount--) { + uint16_t verticesOffset = READ_BE_UINT16(shapeData); shapeData += 2; + const uint8_t *p = verticesDataTable + READ_BE_UINT16(verticesOffsetTable + (verticesOffset & 0x3FFF) * 2); + int16_t dx = 0; + int16_t dy = 0; + if (verticesOffset & 0x8000) { + dx = READ_BE_UINT16(shapeData); shapeData += 2; + dy = READ_BE_UINT16(shapeData); shapeData += 2; + } + _hasAlphaColor = (verticesOffset & 0x4000) != 0; + uint8_t color = *shapeData++; + if (_clearScreen == 0) { + color += 0x10; // 2nd pal buf + } + _primitiveColor = 0xC0 + color; + drawShapeScaleRotate(p, zoom, dx, dy, x, y, 0, 0); + ++_shape_count; + } +} + +void Cutscene::op_drawCreditsText() { + debug(DBG_CUT, "Cutscene::op_drawCreditsText()"); + _varText = 0xFF; + if (_textCurBuf == _textBuf) { + ++_creditsTextCounter; + } + memcpy(_page1, _page0, Video::GAMESCREEN_W * Video::GAMESCREEN_H); + _frameDelay = 10; + setPalette(); +} + +void Cutscene::op_drawStringAtPos() { + debug(DBG_CUT, "Cutscene::op_drawStringAtPos()"); + uint16_t strId = fetchNextCmdWord(); + if (strId != 0xFFFF) { + int16_t x = (int8_t)fetchNextCmdByte() * 8; + int16_t y = (int8_t)fetchNextCmdByte() * 8; + if (!_creditsSequence) { + const uint8_t *str = _res->getCineString(strId & 0xFFF); + if (str) { + uint8_t color = 0xD0 + (strId >> 0xC); + drawText(x, y, str, color, _page1, 2); + } + // workaround for buggy cutscene script + if (_id == 0x34 && (strId & 0xFFF) == 0x45) { + if ((_cmdPtr - _cmdPtrBak) == 0xA) { + _stub->copyRect(0, 0, Video::GAMESCREEN_W, Video::GAMESCREEN_H, _page1, 256); + _stub->updateScreen(0); + } else { + _stub->sleep(15); + } + } + } + } +} + +void Cutscene::op_handleKeys() { + debug(DBG_CUT, "Cutscene::op_handleKeys()"); + while (1) { + uint8_t key_mask = fetchNextCmdByte(); + if (key_mask == 0xFF) { + return; + } + bool b = true; + switch (key_mask) { + case 1: + b = (_stub->_pi.dirMask & PlayerInput::DIR_UP) != 0; + break; + case 2: + b = (_stub->_pi.dirMask & PlayerInput::DIR_DOWN) != 0; + break; + case 4: + b = (_stub->_pi.dirMask & PlayerInput::DIR_LEFT) != 0; + break; + case 8: + b = (_stub->_pi.dirMask & PlayerInput::DIR_RIGHT) != 0; + break; + case 0x80: + b = _stub->_pi.space || _stub->_pi.enter || _stub->_pi.shift; + break; + } + if (b) { + break; + } + _cmdPtr += 2; + } + _stub->_pi.dirMask = 0; + _stub->_pi.enter = false; + _stub->_pi.space = false; + _stub->_pi.shift = false; + int16_t n = fetchNextCmdWord(); + if (n < 0) { + n = -n - 1; + if (_varKey == 0) { + _stop = true; + return; + } + if (_varKey != n) { + _cmdPtr = _cmdPtrBak; + return; + } + _varKey = 0; + --n; + _cmdPtr = _res->_cmd; + n = READ_BE_UINT16(_cmdPtr + n * 2 + 2); + } + _cmdPtr = _cmdPtrBak = _res->_cmd + n + _startOffset; +} + +uint8_t Cutscene::fetchNextCmdByte() { + return *_cmdPtr++; +} + +uint16_t Cutscene::fetchNextCmdWord() { + uint16_t i = READ_BE_UINT16(_cmdPtr); + _cmdPtr += 2; + return i; +} + +void Cutscene::mainLoop(uint16_t offset) { + _frameDelay = 5; + _tstamp = _stub->getTimeStamp(); + + Color c; + c.r = c.g = c.b = 0; + for (int i = 0; i < 0x20; ++i) { + _stub->setPaletteEntry(0xC0 + i, &c); + } + _newPal = false; + _hasAlphaColor = false; + uint8_t *p = _res->_cmd; + if (offset != 0) { + offset = READ_BE_UINT16(p + (offset + 1) * 2); + } + _startOffset = (READ_BE_UINT16(p) + 1) * 2; + _varKey = 0; + _cmdPtr = _cmdPtrBak = p + _startOffset + offset; + _polPtr = _res->_pol; + debug(DBG_CUT, "_startOffset = %d offset = %d", _startOffset, offset); + + while (!_stub->_pi.quit && !_interrupted && !_stop) { + uint8_t op = fetchNextCmdByte(); + debug(DBG_CUT, "Cutscene::play() opcode = 0x%X (%d)", op, (op >> 2)); + if (op & 0x80) { + break; + } + op >>= 2; + if (op >= NUM_OPCODES) { + error("Invalid cutscene opcode = 0x%02X", op); + } + (this->*_opcodeTable[op])(); + _stub->processEvents(); + if (_stub->_pi.backspace) { + _stub->_pi.backspace = false; + _interrupted = true; + } + } +} + +void Cutscene::load(uint16_t cutName) { + assert(cutName != 0xFFFF); + const char *name = _namesTable[cutName & 0xFF]; + switch (_res->_type) { + case kResourceTypeAmiga: + if (strncmp(name, "INTRO", 5) == 0) { + name = "INTRO"; + } + _res->load(name, Resource::OT_CMP); + break; + case kResourceTypePC: + _res->load(name, Resource::OT_CMD); + _res->load(name, Resource::OT_POL); + _res->load_CINE(); + break; + } +} + +void Cutscene::prepare() { + _page0 = _vid->_frontLayer; + _page1 = _vid->_tempLayer; + _pageC = _vid->_tempLayer2; + _stub->_pi.dirMask = 0; + _stub->_pi.enter = false; + _stub->_pi.space = false; + _stub->_pi.shift = false; + _interrupted = false; + _stop = false; + _gfx.setClippingRect(8, 50, 240, 128); +} + +void Cutscene::startCredits() { + _textCurPtr = _creditsData; + _textBuf[0] = 0xA; + _textCurBuf = _textBuf; + _creditsSequence = true; +// _cut_status = 1; + _varText = 0; + _textUnk2 = 0; + _creditsTextCounter = 0; + _interrupted = false; + const uint16_t *cut_seq = _creditsCutSeq; + while (!_stub->_pi.quit && !_interrupted) { + uint16_t cut_id = *cut_seq++; + if (cut_id == 0xFFFF) { + break; + } + prepare(); + uint16_t cutName = _offsetsTable[cut_id * 2 + 0]; + uint16_t cutOff = _offsetsTable[cut_id * 2 + 1]; + load(cutName); + mainLoop(cutOff); + } + _creditsSequence = false; +} + +void Cutscene::play() { + if (_id != 0xFFFF) { + _textCurBuf = NULL; + debug(DBG_CUT, "Cutscene::play() _id=0x%X", _id); + _creditsSequence = false; + prepare(); + uint16_t cutName = _offsetsTable[_id * 2 + 0]; + uint16_t cutOff = _offsetsTable[_id * 2 + 1]; + if (cutName != 0xFFFF) { + load(cutName); + mainLoop(cutOff); + } + _vid->fullRefresh(); + if (_id != 0x3D) { + _id = 0xFFFF; + } + } +} diff --git a/cutscene.h b/cutscene.h new file mode 100644 index 0000000..4feea07 --- /dev/null +++ b/cutscene.h @@ -0,0 +1,134 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CUTSCENE_H__ +#define CUTSCENE_H__ + +#include "intern.h" +#include "graphics.h" + +struct Resource; +struct SystemStub; +struct Video; + +struct Cutscene { + typedef void (Cutscene::*OpcodeStub)(); + + enum { + NUM_OPCODES = 15, + TIMER_SLICE = 15 + }; + + static const OpcodeStub _opcodeTable[]; + static const char *_namesTable[]; + static const uint16_t _offsetsTable[]; + static const uint16_t _cosTable[]; + static const uint16_t _sinTable[]; + static const uint8_t _creditsData[]; + static const uint16_t _creditsCutSeq[]; + static const uint8_t _musicTable[]; + static const uint8_t _protectionShapeData[]; + + Graphics _gfx; + Resource *_res; + SystemStub *_stub; + Video *_vid; + + uint16_t _id; + uint16_t _deathCutsceneId; + bool _interrupted; + bool _stop; + uint8_t *_polPtr; + uint8_t *_cmdPtr; + uint8_t *_cmdPtrBak; + uint32_t _tstamp; + uint8_t _frameDelay; + bool _newPal; + uint8_t _palBuf[0x20 * 2]; + uint16_t _startOffset; + bool _creditsSequence; + uint32_t _rotData[4]; + uint8_t _primitiveColor; + uint8_t _clearScreen; + Point _vertices[0x80]; + bool _hasAlphaColor; + uint8_t _varText; + uint8_t _varKey; + int16_t _shape_ix; + int16_t _shape_iy; + int16_t _shape_ox; + int16_t _shape_oy; + int16_t _shape_cur_x; + int16_t _shape_cur_y; + int16_t _shape_prev_x; + int16_t _shape_prev_y; + uint16_t _shape_count; + uint32_t _shape_cur_x16; + uint32_t _shape_cur_y16; + uint32_t _shape_prev_x16; + uint32_t _shape_prev_y16; + uint8_t _textSep[0x14]; + uint8_t _textBuf[500]; + const uint8_t *_textCurPtr; + uint8_t *_textCurBuf; + uint8_t _textUnk2; + uint8_t _creditsTextPosX; + uint8_t _creditsTextPosY; + int16_t _creditsTextCounter; + uint8_t *_page0, *_page1, *_pageC; + + Cutscene(Resource *res, SystemStub *stub, Video *vid); + + void sync(); + void copyPalette(const uint8_t *pal, uint16_t num); + void updatePalette(); + void setPalette(); + void initRotationData(uint16_t a, uint16_t b, uint16_t c); + uint16_t findTextSeparators(const uint8_t *p); + void drawText(int16_t x, int16_t y, const uint8_t *p, uint16_t color, uint8_t *page, uint8_t n); + void swapLayers(); + void drawCreditsText(); + void drawProtectionShape(uint8_t shapeNum, int16_t zoom); + void drawShape(const uint8_t *data, int16_t x, int16_t y); + void drawShapeScale(const uint8_t *data, int16_t zoom, int16_t b, int16_t c, int16_t d, int16_t e, int16_t f, int16_t g); + void drawShapeScaleRotate(const uint8_t *data, int16_t zoom, int16_t b, int16_t c, int16_t d, int16_t e, int16_t f, int16_t g); + + void op_markCurPos(); + void op_refreshScreen(); + void op_waitForSync(); + void op_drawShape(); + void op_setPalette(); + void op_drawStringAtBottom(); + void op_nop(); + void op_skip3(); + void op_refreshAll(); + void op_drawShapeScale(); + void op_drawShapeScaleRotate(); + void op_drawCreditsText(); + void op_drawStringAtPos(); + void op_handleKeys(); + + uint8_t fetchNextCmdByte(); + uint16_t fetchNextCmdWord(); + void mainLoop(uint16_t offset); + void load(uint16_t cutName); + void prepare(); + void startCredits(); + void play(); +}; + +#endif // CUTSCENE_H__ diff --git a/file.cpp b/file.cpp new file mode 100644 index 0000000..aab81d3 --- /dev/null +++ b/file.cpp @@ -0,0 +1,260 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "fs.h" +#ifdef USE_ZLIB +#include "zlib.h" +#endif +#include "file.h" + + +struct File_impl { + bool _ioErr; + File_impl() : _ioErr(false) {} + virtual ~File_impl() {} + virtual bool open(const char *path, const char *mode) = 0; + virtual void close() = 0; + virtual uint32_t size() = 0; + virtual void seek(int32_t off) = 0; + virtual uint32_t read(void *ptr, uint32_t len) = 0; + virtual uint32_t write(void *ptr, uint32_t len) = 0; +}; + +struct stdFile : File_impl { + FILE *_fp; + stdFile() : _fp(0) {} + bool open(const char *path, const char *mode) { + _ioErr = false; + _fp = fopen(path, mode); + return (_fp != 0); + } + void close() { + if (_fp) { + fclose(_fp); + _fp = 0; + } + } + uint32_t size() { + uint32_t sz = 0; + if (_fp) { + int pos = ftell(_fp); + fseek(_fp, 0, SEEK_END); + sz = ftell(_fp); + fseek(_fp, pos, SEEK_SET); + } + return sz; + } + void seek(int32_t off) { + if (_fp) { + fseek(_fp, off, SEEK_SET); + } + } + uint32_t read(void *ptr, uint32_t len) { + if (_fp) { + uint32_t r = fread(ptr, 1, len, _fp); + if (r != len) { + _ioErr = true; + } + return r; + } + return 0; + } + uint32_t write(void *ptr, uint32_t len) { + if (_fp) { + uint32_t r = fwrite(ptr, 1, len, _fp); + if (r != len) { + _ioErr = true; + } + return r; + } + return 0; + } +}; + +#ifdef USE_ZLIB +struct zlibFile : File_impl { + gzFile _fp; + zlibFile() : _fp(0) {} + bool open(const char *path, const char *mode) { + _ioErr = false; + _fp = gzopen(path, mode); + return (_fp != 0); + } + void close() { + if (_fp) { + gzclose(_fp); + _fp = 0; + } + } + uint32_t size() { + uint32_t sz = 0; + if (_fp) { + int pos = gztell(_fp); + gzseek(_fp, 0, SEEK_END); + sz = gztell(_fp); + gzseek(_fp, pos, SEEK_SET); + } + return sz; + } + void seek(int32_t off) { + if (_fp) { + gzseek(_fp, off, SEEK_SET); + } + } + uint32_t read(void *ptr, uint32_t len) { + if (_fp) { + uint32_t r = gzread(_fp, ptr, len); + if (r != len) { + _ioErr = true; + } + return r; + } + return 0; + } + uint32_t write(void *ptr, uint32_t len) { + if (_fp) { + uint32_t r = gzwrite(_fp, ptr, len); + if (r != len) { + _ioErr = true; + } + return r; + } + return 0; + } +}; +#endif + + +File::File() + : _impl(0) { +} + +File::~File() { + if (_impl) { + _impl->close(); + delete _impl; + } +} + +bool File::open(const char *filename, const char *mode, FileSystem *fs) { + if (_impl) { + _impl->close(); + delete _impl; + _impl = 0; + } + assert(mode[0] != 'z'); + _impl = new stdFile; + char *path = fs->findPath(filename); + if (path) { + debug(DBG_FILE, "Open file name '%s' mode '%s' path '%s'", filename, mode, path); + bool ret = _impl->open(path, mode); + free(path); + return ret; + } + return false; +} + +bool File::open(const char *filename, const char *mode, const char *directory) { + if (_impl) { + _impl->close(); + delete _impl; + _impl = 0; + } +#ifdef USE_ZLIB + if (mode[0] == 'z') { + _impl = new zlibFile; + ++mode; + } +#endif + if (!_impl) { + _impl = new stdFile; + } + char path[512]; + snprintf(path, sizeof(path), "%s/%s", directory, filename); + debug(DBG_FILE, "Open file name '%s' mode '%s' path '%s'", filename, mode, path); + return _impl->open(path, mode); +} + +void File::close() { + if (_impl) { + _impl->close(); + } +} + +bool File::ioErr() const { + return _impl->_ioErr; +} + +uint32_t File::size() { + return _impl->size(); +} + +void File::seek(int32_t off) { + _impl->seek(off); +} + +uint32_t File::read(void *ptr, uint32_t len) { + return _impl->read(ptr, len); +} + +uint8_t File::readByte() { + uint8_t b; + read(&b, 1); + return b; +} + +uint16_t File::readUint16LE() { + uint8_t lo = readByte(); + uint8_t hi = readByte(); + return (hi << 8) | lo; +} + +uint32_t File::readUint32LE() { + uint16_t lo = readUint16LE(); + uint16_t hi = readUint16LE(); + return (hi << 16) | lo; +} + +uint16_t File::readUint16BE() { + uint8_t hi = readByte(); + uint8_t lo = readByte(); + return (hi << 8) | lo; +} + +uint32_t File::readUint32BE() { + uint16_t hi = readUint16BE(); + uint16_t lo = readUint16BE(); + return (hi << 16) | lo; +} + +uint32_t File::write(void *ptr, uint32_t len) { + return _impl->write(ptr, len); +} + +void File::writeByte(uint8_t b) { + write(&b, 1); +} + +void File::writeUint16BE(uint16_t n) { + writeByte(n >> 8); + writeByte(n & 0xFF); +} + +void File::writeUint32BE(uint32_t n) { + writeUint16BE(n >> 16); + writeUint16BE(n & 0xFFFF); +} diff --git a/file.h b/file.h new file mode 100644 index 0000000..9fd5335 --- /dev/null +++ b/file.h @@ -0,0 +1,50 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FILE_H__ +#define FILE_H__ + +#include "intern.h" + +struct File_impl; +struct FileSystem; + +struct File { + File(); + ~File(); + + File_impl *_impl; + + bool open(const char *filename, const char *mode, FileSystem *fs); + bool open(const char *filename, const char *mode, const char *directory); + void close(); + bool ioErr() const; + uint32_t size(); + void seek(int32_t off); + uint32_t read(void *ptr, uint32_t len); + uint8_t readByte(); + uint16_t readUint16LE(); + uint32_t readUint32LE(); + uint16_t readUint16BE(); + uint32_t readUint32BE(); + uint32_t write(void *ptr, uint32_t size); + void writeByte(uint8_t b); + void writeUint16BE(uint16_t n); + void writeUint32BE(uint32_t n); +}; + +#endif // FILE_H__ diff --git a/fs.cpp b/fs.cpp new file mode 100644 index 0000000..fbebbd5 --- /dev/null +++ b/fs.cpp @@ -0,0 +1,167 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#include +#endif +#include "fs.h" + +struct FileName { + char *name; + int dir; +}; + +struct FileSystem_impl { + + char **_dirsList; + int _dirsCount; + FileName *_filesList; + int _filesCount; + + FileSystem_impl() : + _dirsList(0), _dirsCount(0), _filesList(0), _filesCount(0) { + } + + ~FileSystem_impl() { + for (int i = 0; i < _dirsCount; ++i) { + free(_dirsList[i]); + } + free(_dirsList); + for (int i = 0; i < _filesCount; ++i) { + free(_filesList[i].name); + } + free(_filesList); + } + + void setRootDirectory(const char *dir) { + getPathListFromDirectory(dir); + debug(DBG_FILE, "Found %d files and %d directories", _filesCount, _dirsCount); + } + + char *findPath(const char *name) const { + for (int i = 0; i < _filesCount; ++i) { + if (strcasecmp(_filesList[i].name, name) == 0) { + const char *dir = _dirsList[_filesList[i].dir]; + const int len = strlen(dir) + 1 + strlen(_filesList[i].name) + 1; + char *p = (char *)malloc(len); + if (p) { + snprintf(p, len, "%s/%s", dir, _filesList[i].name); + } + return p; + } + } + return 0; + } + + void addPath(const char *dir, const char *name) { + int index = -1; + for (int i = 0; i < _dirsCount; ++i) { + if (strcmp(_dirsList[i], dir) == 0) { + index = i; + break; + } + } + if (index == -1) { + _dirsList = (char **)realloc(_dirsList, (_dirsCount + 1) * sizeof(char *)); + if (_dirsList) { + _dirsList[_dirsCount] = strdup(dir); + index = _dirsCount; + ++_dirsCount; + } + } + _filesList = (FileName *)realloc(_filesList, (_filesCount + 1) * sizeof(FileName)); + if (_filesList) { + _filesList[_filesCount].name = strdup(name); + _filesList[_filesCount].dir = index; + ++_filesCount; + } + } + + void getPathListFromDirectory(const char *dir); +}; + +#ifdef _WIN32 +void FileSystem_impl::getPathListFromDirectory(const char *dir) { + WIN32_FIND_DATA findData; + char searchPath[MAX_PATH]; + snprintf(searchPath, sizeof(searchPath), "%s/*", dir); + HANDLE h = FindFirstFile(searchPath, &findData); + if (h) { + do { + if (findData.cFileName[0] == '.') { + continue; + } + char filePath[MAX_PATH]; + snprintf(filePath, sizeof(filePath), "%s/%s", dir, findData.cFileName); + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + getPathListFromDirectory(filePath); + } else { + addPath(dir, findData.cFileName); + } + } while (FindNextFile(h, &findData)); + FindClose(h); + } +} +#else +void FileSystem_impl::getPathListFromDirectory(const char *dir) { + DIR *d = opendir(dir); + if (d) { + dirent *de; + while ((de = readdir(d)) != NULL) { + if (de->d_name[0] == '.') { + continue; + } + char filePath[512]; + snprintf(filePath, sizeof(filePath), "%s/%s", dir, de->d_name); + struct stat st; + if (stat(filePath, &st) == 0) { + if (S_ISDIR(st.st_mode)) { + getPathListFromDirectory(filePath); + } else { + addPath(dir, de->d_name); + } + } + } + closedir(d); + } +} +#endif + +FileSystem::FileSystem(const char *dataPath) { + _impl = new FileSystem_impl; + _impl->setRootDirectory(dataPath); +} + +FileSystem::~FileSystem() { + delete _impl; +} + +char *FileSystem::findPath(const char *filename) const { + return _impl->findPath(filename); +} + +bool FileSystem::exists(const char *filename) const { + char *path = findPath(filename); + if (path) { + free(path); + } + return path != 0; +} diff --git a/fs.h b/fs.h new file mode 100644 index 0000000..5a464d8 --- /dev/null +++ b/fs.h @@ -0,0 +1,36 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FS_H__ +#define FS_H__ + +#include "intern.h" + +struct FileSystem_impl; + +struct FileSystem { + FileSystem(const char *dataPath); + ~FileSystem(); + + FileSystem_impl *_impl; + + char *findPath(const char *filename) const; + bool exists(const char *filename) const; +}; + +#endif // FS_H__ + diff --git a/game.cpp b/game.cpp new file mode 100644 index 0000000..d9cd72d --- /dev/null +++ b/game.cpp @@ -0,0 +1,1805 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "file.h" +#include "fs.h" +#include "systemstub.h" +#include "unpack.h" +#include "game.h" +#include "seq_player.h" + + +Game::Game(SystemStub *stub, FileSystem *fs, const char *savePath, int level, ResourceType ver, Language lang) + : _cut(&_res, stub, &_vid), _menu(&_res, stub, &_vid), + _mix(fs, stub), _res(fs, ver, lang), _seq(stub, &_mix), _vid(&_res, stub), + _stub(stub), _fs(fs), _savePath(savePath) { + _stateSlot = 1; + _inp_demo = 0; + _inp_record = false; + _inp_replay = false; + _skillLevel = 1; + _currentLevel = level; +} + +void Game::run() { + _stub->init(g_caption, Video::GAMESCREEN_W, Video::GAMESCREEN_H); + + _randSeed = time(0); + + _res.load_TEXT(); + + switch (_res._type) { + case kResourceTypeAmiga: + _res.load("FONT8", Resource::OT_FNT, "SPR"); + break; + case kResourceTypePC: + _res.load("FB_TXT", Resource::OT_FNT); + _res._hasSeqData = _fs->exists("INTRO.SEQ"); + break; + } + +#ifndef BYPASS_PROTECTION + while (!handleProtectionScreen()); + if (_stub->_pi.quit) { + return; + } +#endif + + _mix.init(); + + playCutscene(0x40); + playCutscene(0x0D); + if (!_cut._interrupted && _res._type == kResourceTypePC) { + playCutscene(0x4A); + } + + switch (_res._type) { + case kResourceTypeAmiga: + _res.load("ICONE", Resource::OT_ICN, "SPR"); + _res.load("ICON", Resource::OT_ICN, "SPR"); + _res.load("PERSO", Resource::OT_SPM); + break; + case kResourceTypePC: + _res.load("GLOBAL", Resource::OT_ICN); + _res.load("GLOBAL", Resource::OT_SPC); + _res.load("PERSO", Resource::OT_SPR); + _res.load_SPR_OFF("PERSO", _res._spr1); + _res.load_FIB("GLOBAL"); + break; + } + + while (!_stub->_pi.quit) { + if (_res._type == kResourceTypePC) { + _mix.playMusic(1); + if (!_menu.handleTitleScreen(_skillLevel, _currentLevel)) { + break; + } + _mix.stopMusic(); + } + if (_currentLevel == 7) { + _vid.fadeOut(); + _vid.setTextPalette(); + playCutscene(0x3D); + } else { + _vid.setTextPalette(); + _vid.setPalette0xF(); + _stub->setOverscanColor(0xE0); + _vid._unkPalSlot1 = 0; + _vid._unkPalSlot2 = 0; + _score = 0; + loadLevelData(); + resetGameState(); + _endLoop = false; + while (!_stub->_pi.quit && !_endLoop) { + mainLoop(); + } + } + } + + _res.free_TEXT(); + + _mix.free(); + _stub->destroy(); +} + +void Game::resetGameState() { + _animBuffers._states[0] = _animBuffer0State; + _animBuffers._curPos[0] = 0xFF; + _animBuffers._states[1] = _animBuffer1State; + _animBuffers._curPos[1] = 0xFF; + _animBuffers._states[2] = _animBuffer2State; + _animBuffers._curPos[2] = 0xFF; + _animBuffers._states[3] = _animBuffer3State; + _animBuffers._curPos[3] = 0xFF; + _currentRoom = _res._pgeInit[0].init_room; + _cut._deathCutsceneId = 0xFFFF; + _pge_opTempVar2 = 0xFFFF; + _deathCutsceneCounter = 0; + _saveStateCompleted = false; + _loadMap = true; + pge_resetGroups(); + _blinkingConradCounter = 0; + _pge_processOBJ = false; + _pge_opTempVar1 = 0; + _textToDisplay = 0xFFFF; +} + +void Game::mainLoop() { + playCutscene(); + if (_cut._id == 0x3D) { + showFinalScore(); + _endLoop = true; + return; + } + if (_deathCutsceneCounter) { + --_deathCutsceneCounter; + if (_deathCutsceneCounter == 0) { + playCutscene(_cut._deathCutsceneId); + if (!handleContinueAbort()) { + playCutscene(0x41); + _endLoop = true; + } else { + if (_validSaveState) { + if (!loadGameState(0)) { + _endLoop = true; + } + } else { + loadLevelData(); + resetGameState(); + } + } + return; + } + } + memcpy(_vid._frontLayer, _vid._backLayer, Video::GAMESCREEN_W * Video::GAMESCREEN_H); + pge_getInput(); + pge_prepare(); + col_prepareRoomState(); + uint8_t oldLevel = _currentLevel; + for (uint16_t i = 0; i < _res._pgeNum; ++i) { + LivePGE *pge = _pge_liveTable2[i]; + if (pge) { + _col_currentPiegeGridPosY = (pge->pos_y / 36) & ~1; + _col_currentPiegeGridPosX = (pge->pos_x + 8) >> 4; + pge_process(pge); + } + } + if (oldLevel != _currentLevel) { + changeLevel(); + _pge_opTempVar1 = 0; + return; + } + if (_loadMap) { + if (_currentRoom == 0xFF) { + _cut._id = 6; + _deathCutsceneCounter = 1; + } else { + _currentRoom = _pgeLive[0].room_location; + loadLevelMap(); + _loadMap = false; + _vid.fullRefresh(); + } + } + prepareAnims(); + drawAnims(); + drawCurrentInventoryItem(); + drawLevelTexts(); + printLevelCode(); + if (_blinkingConradCounter != 0) { + --_blinkingConradCounter; + } + _vid.updateScreen(); + updateTiming(); + drawStoryTexts(); + if (_stub->_pi.backspace) { + _stub->_pi.backspace = false; + handleInventory(); + } + if (_stub->_pi.escape) { + _stub->_pi.escape = false; + if (handleConfigPanel()) { + _endLoop = true; + return; + } + } + inp_handleSpecialKeys(); +} + +void Game::updateTiming() { + static uint32_t tstamp = 0; + int32_t delay = _stub->getTimeStamp() - tstamp; + int32_t pause = (_stub->_pi.dbgMask & PlayerInput::DF_FASTMODE) ? 20 : 30; + pause -= delay; + if (pause > 0) { + _stub->sleep(pause); + } + tstamp = _stub->getTimeStamp(); +} + +void Game::playCutscene(int id) { + if (id != -1) { + _cut._id = id; + } + if (_cut._id != 0xFFFF) { + _mix.stopMusic(); + if (_res._hasSeqData) { + int num = 0; + switch (_cut._id) { + case 0x02: { + static const uint8_t tab[] = { 1, 2, 1, 3, 3, 4, 4 }; + num = tab[_currentLevel]; + } + break; + case 0x05: { + static const uint8_t tab[] = { 1, 2, 3, 5, 5, 4, 4 }; + num = tab[_currentLevel]; + } + break; + case 0x0A: { + static const uint8_t tab[] = { 1, 2, 2, 2, 2, 2, 2 }; + num = tab[_currentLevel]; + } + break; + case 0x10: { + static const uint8_t tab[] = { 1, 1, 1, 2, 2, 3, 3 }; + num = tab[_currentLevel]; + } + break; + case 0x3C: { + static const uint8_t tab[] = { 1, 1, 1, 1, 1, 2, 2 }; + num = tab[_currentLevel]; + } + break; + case 0x40: + return; + case 0x4A: + return; + } + if (SeqPlayer::_namesTable[_cut._id]) { + char name[16]; + snprintf(name, sizeof(name), "%s.SEQ", SeqPlayer::_namesTable[_cut._id]); + char *p = strchr(name, '0'); + if (p) { + *p += num; + } + if (playCutsceneSeq(name)) { + if (_cut._id == 0x3D) { + playCutsceneSeq("CREDITS.SEQ"); + _cut._interrupted = false; + } else { + _cut._id = 0xFFFF; + } + return; + } + } + } + if (_cut._id != 0x4A) { + _mix.playMusic(Cutscene::_musicTable[_cut._id]); + } + _cut.play(); + if (id == 0x3D) { + _cut.startCredits(); + } + if (_cut._interrupted || id != 0x0D) { + _mix.stopMusic(); + } + } +} + +bool Game::playCutsceneSeq(const char *name) { + File f; + if (f.open(name, "rb", _fs)) { + _seq.setBackBuffer(_res._memBuf); + _seq.play(&f); + _vid.fullRefresh(); + return true; + } + return false; +} + +void Game::inp_handleSpecialKeys() { + if (_stub->_pi.dbgMask & PlayerInput::DF_SETLIFE) { + _pgeLive[0].life = 0x7FFF; + } + if (_stub->_pi.load) { + loadGameState(_stateSlot); + _stub->_pi.load = false; + } + if (_stub->_pi.save) { + saveGameState(_stateSlot); + _stub->_pi.save = false; + } + if (_stub->_pi.stateSlot != 0) { + int8_t slot = _stateSlot + _stub->_pi.stateSlot; + if (slot >= 1 && slot < 100) { + _stateSlot = slot; + debug(DBG_INFO, "Current game state slot is %d", _stateSlot); + } + _stub->_pi.stateSlot = 0; + } + if (_stub->_pi.inpRecord || _stub->_pi.inpReplay) { + bool replay = false; + bool record = false; + char demoFile[20]; + makeGameDemoName(demoFile); + if (_inp_demo) { + _inp_demo->close(); + delete _inp_demo; + } + _inp_demo = new File; + if (_stub->_pi.inpRecord) { + if (_inp_record) { + debug(DBG_INFO, "Stop recording input keys"); + } else { + if (_inp_demo->open(demoFile, "zwb", _savePath)) { + debug(DBG_INFO, "Recording input keys"); + _inp_demo->writeUint32BE('FBDM'); + _inp_demo->writeUint16BE(0); + _inp_demo->writeUint32BE(_randSeed); + record = true; + } else { + warning("Unable to save demo file '%s'", demoFile); + } + } + } + if (_stub->_pi.inpReplay) { + if (_inp_replay) { + debug(DBG_INFO, "Stop replaying input keys"); + } else { + if (_inp_demo->open(demoFile, "zrb", _savePath)) { + debug(DBG_INFO, "Replaying input keys"); + _inp_demo->readUint32BE(); + _inp_demo->readUint16BE(); + _randSeed = _inp_demo->readUint32BE(); + replay = true; + } else { + warning("Unable to open demo file '%s'", demoFile); + } + } + } + _inp_record = record; + _inp_replay = replay; + _stub->_pi.inpReplay = false; + _stub->_pi.inpRecord = false; + } +} + +void Game::drawCurrentInventoryItem() { + uint16_t src = _pgeLive[0].current_inventory_PGE; + if (src != 0xFF) { + _currentIcon = _res._pgeInit[src].icon_num; + drawIcon(_currentIcon, 232, 8, 0xA); + } +} + +void Game::showFinalScore() { + playCutscene(0x49); + char buf[50]; + snprintf(buf, sizeof(buf), "SCORE %08u", _score); + _vid.drawString(buf, (256 - strlen(buf) * 8) / 2, 40, 0xE5); + strcpy(buf, _menu._passwords[7][_skillLevel]); + _vid.drawString(buf, (256 - strlen(buf) * 8) / 2, 16, 0xE7); + while (!_stub->_pi.quit) { + _stub->copyRect(0, 0, Video::GAMESCREEN_W, Video::GAMESCREEN_H, _vid._frontLayer, 256); + _stub->updateScreen(0); + _stub->processEvents(); + if (_stub->_pi.enter) { + _stub->_pi.enter = false; + break; + } + _stub->sleep(100); + } +} + +bool Game::handleConfigPanel() { + if (_res._type == kResourceTypeAmiga) { + return true; + } + const int x = 7; + const int y = 10; + const int w = 17; + const int h = 12; + + _vid._charShadowColor = 0xE2; + _vid._charFrontColor = 0xEE; + _vid._charTransparentColor = 0xFF; + + _vid.PC_drawChar(0x81, y, x); + for (int i = 1; i < w; ++i) { + _vid.PC_drawChar(0x85, y, x + i); + } + _vid.PC_drawChar(0x82, y, x + w); + for (int j = 1; j < h; ++j) { + _vid.PC_drawChar(0x86, y + j, x); + for (int i = 1; i < w; ++i) { + _vid._charTransparentColor = 0xE2; + _vid.PC_drawChar(0x20, y + j, x + i); + } + _vid._charTransparentColor = 0xFF; + _vid.PC_drawChar(0x87, y + j, x + w); + } + _vid.PC_drawChar(0x83, y + h, x); + for (int i = 1; i < w; ++i) { + _vid.PC_drawChar(0x88, y + h, x + i); + } + _vid.PC_drawChar(0x84, y + h, x + w); + + _menu._charVar3 = 0xE4; + _menu._charVar4 = 0xE5; + _menu._charVar1 = 0xE2; + _menu._charVar2 = 0xEE; + + _vid.fullRefresh(); + enum { MENU_ITEM_LOAD = 1, MENU_ITEM_SAVE = 2, MENU_ITEM_ABORT = 3 }; + uint8_t colors[] = { 2, 3, 3, 3 }; + int current = 0; + while (!_stub->_pi.quit) { + _menu.drawString(_res.getMenuString(LocaleData::LI_18_RESUME_GAME), y + 2, 9, colors[0]); + _menu.drawString(_res.getMenuString(LocaleData::LI_20_LOAD_GAME), y + 4, 9, colors[1]); + _menu.drawString(_res.getMenuString(LocaleData::LI_21_SAVE_GAME), y + 6, 9, colors[2]); + _menu.drawString(_res.getMenuString(LocaleData::LI_19_ABORT_GAME), y + 8, 9, colors[3]); + char buf[30]; + snprintf(buf, sizeof(buf), "%s : %d-%02d", _res.getMenuString(LocaleData::LI_22_SAVE_SLOT), _currentLevel + 1, _stateSlot); + _menu.drawString(buf, y + 10, 9, 1); + + _vid.updateScreen(); + _stub->sleep(80); + inp_update(); + + int prev = current; + if (_stub->_pi.dirMask & PlayerInput::DIR_UP) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_UP; + current = (current + 3) % 4; + } + if (_stub->_pi.dirMask & PlayerInput::DIR_DOWN) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_DOWN; + current = (current + 1) % 4; + } + if (_stub->_pi.dirMask & PlayerInput::DIR_LEFT) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_LEFT; + --_stateSlot; + if (_stateSlot < 1) { + _stateSlot = 1; + } + } + if (_stub->_pi.dirMask & PlayerInput::DIR_RIGHT) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_RIGHT; + ++_stateSlot; + if (_stateSlot > 99) { + _stateSlot = 99; + } + } + if (prev != current) { + SWAP(colors[prev], colors[current]); + } + if (_stub->_pi.enter) { + _stub->_pi.enter = false; + switch (current) { + case MENU_ITEM_LOAD: + _stub->_pi.load = true; + break; + case MENU_ITEM_SAVE: + _stub->_pi.save = true; + break; + } + break; + } + } + _vid.fullRefresh(); + return (current == MENU_ITEM_ABORT); +} + +bool Game::handleContinueAbort() { + playCutscene(0x48); + int timeout = 100; + int current_color = 0; + uint8_t colors[] = { 0xE4, 0xE5 }; + uint8_t color_inc = 0xFF; + Color col; + _stub->getPaletteEntry(0xE4, &col); + memcpy(_vid._tempLayer, _vid._frontLayer, Video::GAMESCREEN_W * Video::GAMESCREEN_H); + while (timeout >= 0 && !_stub->_pi.quit) { + const char *str; + str = _res.getMenuString(LocaleData::LI_01_CONTINUE_OR_ABORT); + _vid.drawString(str, (256 - strlen(str) * 8) / 2, 64, 0xE3); + str = _res.getMenuString(LocaleData::LI_02_TIME); + char buf[50]; + snprintf(buf, sizeof(buf), "%s : %d", str, timeout / 10); + _vid.drawString(buf, 96, 88, 0xE3); + str = _res.getMenuString(LocaleData::LI_03_CONTINUE); + _vid.drawString(str, (256 - strlen(str) * 8) / 2, 104, colors[0]); + str = _res.getMenuString(LocaleData::LI_04_ABORT); + _vid.drawString(str, (256 - strlen(str) * 8) / 2, 112, colors[1]); + snprintf(buf, sizeof(buf), "SCORE %08u", _score); + _vid.drawString(buf, 64, 154, 0xE3); + if (_stub->_pi.dirMask & PlayerInput::DIR_UP) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_UP; + if (current_color > 0) { + SWAP(colors[current_color], colors[current_color - 1]); + --current_color; + } + } + if (_stub->_pi.dirMask & PlayerInput::DIR_DOWN) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_DOWN; + if (current_color < 1) { + SWAP(colors[current_color], colors[current_color + 1]); + ++current_color; + } + } + if (_stub->_pi.enter) { + _stub->_pi.enter = false; + return (current_color == 0); + } + _stub->copyRect(0, 0, Video::GAMESCREEN_W, Video::GAMESCREEN_H, _vid._frontLayer, 256); + _stub->updateScreen(0); + if (col.b >= 0x3D) { + color_inc = 0; + } + if (col.b < 2) { + color_inc = 0xFF; + } + if (color_inc == 0xFF) { + col.b += 2; + col.g += 2; + } else { + col.b -= 2; + col.g -= 2; + } + _stub->setPaletteEntry(0xE4, &col); + _stub->processEvents(); + _stub->sleep(100); + --timeout; + memcpy(_vid._frontLayer, _vid._tempLayer, Video::GAMESCREEN_W * Video::GAMESCREEN_H); + } + return false; +} + +bool Game::handleProtectionScreen() { + bool valid = true; + _cut.prepare(); + _cut.copyPalette(_protectionPal, 0); + _cut.updatePalette(); + _cut._gfx.setClippingRect(64, 48, 128, 128); + + _menu._charVar1 = 0xE0; + _menu._charVar2 = 0xEF; + _menu._charVar4 = 0xE5; + _menu._charVar5 = 0xE2; + + int shapeNum = getRandomNumber() % 30; + for (int16_t zoom = 2000; zoom != 0; zoom -= 100) { + _cut.drawProtectionShape(shapeNum, zoom); + _stub->copyRect(0, 0, Video::GAMESCREEN_W, Video::GAMESCREEN_H, _vid._tempLayer, 256); + _stub->updateScreen(0); + _stub->sleep(30); + } + int codeNum = getRandomNumber() % 5; + _cut.drawProtectionShape(shapeNum, 1); + _vid.setTextPalette(); + char codeText[7]; + int len = 0; + do { + codeText[len] = '\0'; + memcpy(_vid._frontLayer, _vid._tempLayer, Video::GAMESCREEN_W * Video::GAMESCREEN_H); + _menu.drawString("PROTECTION", 2, 11, 5); + char buf[20]; + snprintf(buf, sizeof(buf), "CODE %d : %s", codeNum + 1, codeText); + _menu.drawString(buf, 23, 8, 5); + _vid.updateScreen(); + _stub->sleep(50); + _stub->processEvents(); + char c = _stub->_pi.lastChar; + if (c != 0) { + _stub->_pi.lastChar = 0; + if (len < 6) { + if (c >= 'a' && c <= 'z') { + c &= ~0x20; + } + if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) { + codeText[len] = c; + ++len; + } + } + } + if (_stub->_pi.backspace) { + _stub->_pi.backspace = false; + if (len > 0) { + --len; + } + } + if (_stub->_pi.enter) { + _stub->_pi.enter = false; + if (len > 0) { + const uint8_t *p = _protectionCodeData + shapeNum * 0x1E + codeNum * 6; + for (int i = 0; i < len; ++i) { + uint8_t r = 0; + uint8_t ch = codeText[i]; + for (int b = 0; b < 8; ++b) { + if (ch & (1 << b)) { + r |= (1 << (7 - b)); + } + } + r ^= 0x55; + if (r != *p++) { + valid = false; + break; + } + } + break; + } + } + } while (!_stub->_pi.quit); + _vid.fadeOut(); + return valid; +} + +void Game::printLevelCode() { + if (_printLevelCodeCounter != 0) { + --_printLevelCodeCounter; + if (_printLevelCodeCounter != 0) { + char buf[32]; + snprintf(buf, sizeof(buf), "CODE: %s", _menu._passwords[_currentLevel][_skillLevel]); + _vid.drawString(buf, (Video::GAMESCREEN_W - strlen(buf) * 8) / 2, 16, 0xE7); + } + } +} + +void Game::printSaveStateCompleted() { + if (_saveStateCompleted) { + const char *str = _res.getMenuString(LocaleData::LI_05_COMPLETED); + _vid.drawString(str, (176 - strlen(str) * 8) / 2, 34, 0xE6); + } +} + +void Game::drawLevelTexts() { + LivePGE *pge = &_pgeLive[0]; + int8_t obj = col_findCurrentCollidingObject(pge, 3, 0xFF, 0xFF, &pge); + if (obj == 0) { + obj = col_findCurrentCollidingObject(pge, 0xFF, 5, 9, &pge); + } + if (obj > 0) { + _printLevelCodeCounter = 0; + if (_textToDisplay == 0xFFFF) { + uint8_t icon_num = obj - 1; + drawIcon(icon_num, 80, 8, 0xA); + uint8_t txt_num = pge->init_PGE->text_num; + const char *str = (const char *)_res._tbn + READ_LE_UINT16(_res._tbn + txt_num * 2); + _vid.drawString(str, (176 - strlen(str) * 8) / 2, 26, 0xE6); + if (icon_num == 2) { + printSaveStateCompleted(); + return; + } + } else { + _currentInventoryIconNum = obj - 1; + } + } + _saveStateCompleted = false; +} + +void Game::drawStoryTexts() { + if (_textToDisplay != 0xFFFF) { + uint16_t text_col_mask = 0xE8; + const uint8_t *str = _res.getGameString(_textToDisplay); + memcpy(_vid._tempLayer, _vid._frontLayer, Video::GAMESCREEN_W * Video::GAMESCREEN_H); + int textSpeechSegment = 0; + while (!_stub->_pi.quit) { + drawIcon(_currentInventoryIconNum, 80, 8, 0xA); + if (*str == 0xFF) { + text_col_mask = READ_LE_UINT16(str + 1); + str += 3; + } + int16_t text_y_pos = 26; + while (1) { + uint16_t len = getLineLength(str); + str = (const uint8_t *)_vid.drawString((const char *)str, (176 - len * 8) / 2, text_y_pos, text_col_mask); + text_y_pos += 8; + if (*str == 0 || *str == 0xB) { + break; + } + ++str; + } + MixerChunk chunk; + _res.load_VCE(_textToDisplay, textSpeechSegment++, &chunk.data, &chunk.len); + if (chunk.data) { + _mix.play(&chunk, 32000, Mixer::MAX_VOLUME); + } + _vid.updateScreen(); + while (!_stub->_pi.backspace && !_stub->_pi.quit) { + if (chunk.data && !_mix.isPlaying(&chunk)) { + break; + } + inp_update(); + _stub->sleep(80); + } + if (chunk.data) { + _mix.stopAll(); + free(chunk.data); + } + _stub->_pi.backspace = false; + if (*str == 0) { + break; + } + ++str; + memcpy(_vid._frontLayer, _vid._tempLayer, Video::GAMESCREEN_W * Video::GAMESCREEN_H); + } + _textToDisplay = 0xFFFF; + } +} + +void Game::prepareAnims() { + if (!(_currentRoom & 0x80) && _currentRoom < 0x40) { + int8_t pge_room; + LivePGE *pge = _pge_liveTable1[_currentRoom]; + while (pge) { + prepareAnimsHelper(pge, 0, 0); + pge = pge->next_PGE_in_room; + } + pge_room = _res._ctData[CT_UP_ROOM + _currentRoom]; + if (pge_room >= 0 && pge_room < 0x40) { + pge = _pge_liveTable1[pge_room]; + while (pge) { + if ((pge->init_PGE->object_type != 10 && pge->pos_y > 176) || (pge->init_PGE->object_type == 10 && pge->pos_y > 216)) { + prepareAnimsHelper(pge, 0, -216); + } + pge = pge->next_PGE_in_room; + } + } + pge_room = _res._ctData[CT_DOWN_ROOM + _currentRoom]; + if (pge_room >= 0 && pge_room < 0x40) { + pge = _pge_liveTable1[pge_room]; + while (pge) { + if (pge->pos_y < 48) { + prepareAnimsHelper(pge, 0, 216); + } + pge = pge->next_PGE_in_room; + } + } + pge_room = _res._ctData[CT_LEFT_ROOM + _currentRoom]; + if (pge_room >= 0 && pge_room < 0x40) { + pge = _pge_liveTable1[pge_room]; + while (pge) { + if (pge->pos_x > 224) { + prepareAnimsHelper(pge, -256, 0); + } + pge = pge->next_PGE_in_room; + } + } + pge_room = _res._ctData[CT_RIGHT_ROOM + _currentRoom]; + if (pge_room >= 0 && pge_room < 0x40) { + pge = _pge_liveTable1[pge_room]; + while (pge) { + if (pge->pos_x <= 32) { + prepareAnimsHelper(pge, 256, 0); + } + pge = pge->next_PGE_in_room; + } + } + } +} + +void Game::prepareAnimsHelper(LivePGE *pge, int16_t dx, int16_t dy) { + debug(DBG_GAME, "Game::prepareAnimsHelper() dx=0x%X dy=0x%X pge_num=%d pge->flags=0x%X pge->anim_number=0x%X", dx, dy, pge - &_pgeLive[0], pge->flags, pge->anim_number); + if (!(pge->flags & 8)) { + if (pge->index != 0 && loadMonsterSprites(pge) == 0) { + return; + } + assert(pge->anim_number < 1287); + const uint8_t *dataPtr = _res._sprData[pge->anim_number]; + if (dataPtr == 0) { + return; + } + const int8_t dw = (int8_t)dataPtr[0]; + const int8_t dh = (int8_t)dataPtr[1]; + uint8_t w = 0, h = 0; + switch (_res._type) { + case kResourceTypeAmiga: + w = ((dataPtr[2] >> 7) + 1) * 16; + h = dataPtr[2] & 0x7F; + break; + case kResourceTypePC: + w = dataPtr[2]; + h = dataPtr[3]; + dataPtr += 4; + break; + } + const int16_t ypos = dy + pge->pos_y - dh + 2; + int16_t xpos = dx + pge->pos_x - dw; + if (pge->flags & 2) { + xpos = dw + dx + pge->pos_x; + uint8_t _cl = w; + if (_cl & 0x40) { + _cl = h; + } else { + _cl &= 0x3F; + } + xpos -= _cl; + } + if (xpos <= -32 || xpos >= 256 || ypos < -48 || ypos >= 224) { + return; + } + xpos += 8; + if (pge == &_pgeLive[0]) { + _animBuffers.addState(1, xpos, ypos, dataPtr, pge, w, h); + } else if (pge->flags & 0x10) { + _animBuffers.addState(2, xpos, ypos, dataPtr, pge, w, h); + } else { + _animBuffers.addState(0, xpos, ypos, dataPtr, pge, w, h); + } + } else { + assert(pge->anim_number < _res._numSpc); + const uint8_t *dataPtr = _res._spc + READ_BE_UINT16(_res._spc + pge->anim_number * 2); + const int16_t xpos = dx + pge->pos_x + 8; + const int16_t ypos = dy + pge->pos_y + 2; + if (pge->init_PGE->object_type == 11) { + _animBuffers.addState(3, xpos, ypos, dataPtr, pge); + } else if (pge->flags & 0x10) { + _animBuffers.addState(2, xpos, ypos, dataPtr, pge); + } else { + _animBuffers.addState(0, xpos, ypos, dataPtr, pge); + } + } +} + +void Game::drawAnims() { + debug(DBG_GAME, "Game::drawAnims()"); + _eraseBackground = false; + drawAnimBuffer(2, _animBuffer2State); + drawAnimBuffer(1, _animBuffer1State); + drawAnimBuffer(0, _animBuffer0State); + _eraseBackground = true; + drawAnimBuffer(3, _animBuffer3State); +} + +void Game::drawAnimBuffer(uint8_t stateNum, AnimBufferState *state) { + debug(DBG_GAME, "Game::drawAnimBuffer() state=%d", stateNum); + assert(stateNum < 4); + _animBuffers._states[stateNum] = state; + uint8_t lastPos = _animBuffers._curPos[stateNum]; + if (lastPos != 0xFF) { + uint8_t numAnims = lastPos + 1; + state += lastPos; + _animBuffers._curPos[stateNum] = 0xFF; + do { + LivePGE *pge = state->pge; + if (!(pge->flags & 8)) { + if (stateNum == 1 && (_blinkingConradCounter & 1)) { + break; + } + switch (_res._type) { + case kResourceTypeAmiga: + _vid.AMIGA_decodeSpm(state->dataPtr, _res._memBuf); + drawCharacter(_res._memBuf, state->x, state->y, state->h, state->w, pge->flags); + break; + case kResourceTypePC: + if (!(state->dataPtr[-2] & 0x80)) { + decodeCharacterFrame(state->dataPtr, _res._memBuf); + drawCharacter(_res._memBuf, state->x, state->y, state->h, state->w, pge->flags); + } else { + drawCharacter(state->dataPtr, state->x, state->y, state->h, state->w, pge->flags); + } + break; + } + } else { + drawObject(state->dataPtr, state->x, state->y, pge->flags); + } + --state; + } while (--numAnims != 0); + } +} + +void Game::drawObject(const uint8_t *dataPtr, int16_t x, int16_t y, uint8_t flags) { + debug(DBG_GAME, "Game::drawObject() dataPtr[]=0x%X dx=%d dy=%d", dataPtr[0], (int8_t)dataPtr[1], (int8_t)dataPtr[2]); + assert(dataPtr[0] < 0x4A); + uint8_t slot = _res._rp[dataPtr[0]]; + uint8_t *data = _res.findBankData(slot); + if (data == 0) { + data = _res.loadBankData(slot); + } + int16_t posy = y - (int8_t)dataPtr[2]; + int16_t posx = x; + if (flags & 2) { + posx += (int8_t)dataPtr[1]; + } else { + posx -= (int8_t)dataPtr[1]; + } + int count = 0; + switch (_res._type) { + case kResourceTypeAmiga: + count = dataPtr[8]; + dataPtr += 9; + break; + case kResourceTypePC: + count = dataPtr[5]; + dataPtr += 6; + break; + } + for (int i = 0; i < count; ++i) { + drawObjectFrame(data, dataPtr, posx, posy, flags); + dataPtr += 4; + } +} + +void Game::drawObjectFrame(const uint8_t *bankDataPtr, const uint8_t *dataPtr, int16_t x, int16_t y, uint8_t flags) { + debug(DBG_GAME, "Game::drawObjectFrame(0x%X, %d, %d, 0x%X)", dataPtr, x, y, flags); + const uint8_t *src = bankDataPtr + dataPtr[0] * 32; + + int16_t sprite_y = y + dataPtr[2]; + int16_t sprite_x; + if (flags & 2) { + sprite_x = x - dataPtr[1] - (((dataPtr[3] & 0xC) + 4) * 2); + } else { + sprite_x = x + dataPtr[1]; + } + + uint8_t sprite_flags = dataPtr[3]; + if (flags & 2) { + sprite_flags ^= 0x10; + } + + uint8_t sprite_h = (((sprite_flags >> 0) & 3) + 1) * 8; + uint8_t sprite_w = (((sprite_flags >> 2) & 3) + 1) * 8; + + switch (_res._type) { + case kResourceTypeAmiga: + if (sprite_w == 24) { + // TODO: fix p24xN + return; + } + _vid.AMIGA_decodeSpc(src, sprite_w, sprite_h, _res._memBuf); + break; + case kResourceTypePC: + _vid.PC_decodeSpc(src, sprite_w, sprite_h, _res._memBuf); + break; + } + + src = _res._memBuf; + bool sprite_mirror_x = false; + int16_t sprite_clipped_w; + if (sprite_x >= 0) { + sprite_clipped_w = sprite_x + sprite_w; + if (sprite_clipped_w < 256) { + sprite_clipped_w = sprite_w; + } else { + sprite_clipped_w = 256 - sprite_x; + if (sprite_flags & 0x10) { + sprite_mirror_x = true; + src += sprite_w - 1; + } + } + } else { + sprite_clipped_w = sprite_x + sprite_w; + if (!(sprite_flags & 0x10)) { + src -= sprite_x; + sprite_x = 0; + } else { + sprite_mirror_x = true; + src += sprite_x + sprite_w - 1; + sprite_x = 0; + } + } + if (sprite_clipped_w <= 0) { + return; + } + + int16_t sprite_clipped_h; + if (sprite_y >= 0) { + sprite_clipped_h = 224 - sprite_h; + if (sprite_y < sprite_clipped_h) { + sprite_clipped_h = sprite_h; + } else { + sprite_clipped_h = 224 - sprite_y; + } + } else { + sprite_clipped_h = sprite_h + sprite_y; + src -= sprite_w * sprite_y; + sprite_y = 0; + } + if (sprite_clipped_h <= 0) { + return; + } + + if (!sprite_mirror_x && (sprite_flags & 0x10)) { + src += sprite_w - 1; + } + + uint32_t dst_offset = 256 * sprite_y + sprite_x; + uint8_t sprite_col_mask = (flags & 0x60) >> 1; + + if (_eraseBackground) { + if (!(sprite_flags & 0x10)) { + _vid.drawSpriteSub1(src, _vid._frontLayer + dst_offset, sprite_w, sprite_clipped_h, sprite_clipped_w, sprite_col_mask); + } else { + _vid.drawSpriteSub2(src, _vid._frontLayer + dst_offset, sprite_w, sprite_clipped_h, sprite_clipped_w, sprite_col_mask); + } + } else { + if (!(sprite_flags & 0x10)) { + _vid.drawSpriteSub3(src, _vid._frontLayer + dst_offset, sprite_w, sprite_clipped_h, sprite_clipped_w, sprite_col_mask); + } else { + _vid.drawSpriteSub4(src, _vid._frontLayer + dst_offset, sprite_w, sprite_clipped_h, sprite_clipped_w, sprite_col_mask); + } + } + _vid.markBlockAsDirty(sprite_x, sprite_y, sprite_clipped_w, sprite_clipped_h); +} + +void Game::decodeCharacterFrame(const uint8_t *dataPtr, uint8_t *dstPtr) { + int n = READ_BE_UINT16(dataPtr); dataPtr += 2; + uint16_t len = n * 2; + uint8_t *dst = dstPtr + 0x400; + while (n--) { + uint8_t c = *dataPtr++; + dst[0] = (c & 0xF0) >> 4; + dst[1] = (c & 0x0F) >> 0; + dst += 2; + } + dst = dstPtr; + const uint8_t *src = dstPtr + 0x400; + do { + uint8_t c1 = *src++; + if (c1 == 0xF) { + uint8_t c2 = *src++; + uint16_t c3 = *src++; + if (c2 == 0xF) { + c1 = *src++; + c2 = *src++; + c3 = (c3 << 4) | c1; + len -= 2; + } + memset(dst, c2, c3 + 4); + dst += c3 + 4; + len -= 3; + } else { + *dst++ = c1; + --len; + } + } while (len != 0); +} + +void Game::drawCharacter(const uint8_t *dataPtr, int16_t pos_x, int16_t pos_y, uint8_t a, uint8_t b, uint8_t flags) { + debug(DBG_GAME, "Game::drawCharacter(0x%X, %d, %d, 0x%X, 0x%X, 0x%X)", dataPtr, pos_x, pos_y, a, b, flags); + + bool var16 = false; // sprite_mirror_y + if (b & 0x40) { + b &= 0xBF; + SWAP(a, b); + var16 = true; + } + uint16_t sprite_h = a; + uint16_t sprite_w = b; + + const uint8_t *src = dataPtr; + bool var14 = false; + + int16_t sprite_clipped_w; + if (pos_x >= 0) { + if (pos_x + sprite_w < 256) { + sprite_clipped_w = sprite_w; + } else { + sprite_clipped_w = 256 - pos_x; + if (flags & 2) { + var14 = true; + if (var16) { + src += (sprite_w - 1) * sprite_h; + } else { + src += sprite_w - 1; + } + } + } + } else { + sprite_clipped_w = pos_x + sprite_w; + if (!(flags & 2)) { + if (var16) { + src -= sprite_h * pos_x; + pos_x = 0; + } else { + src -= pos_x; + pos_x = 0; + } + } else { + var14 = true; + if (var16) { + src += sprite_h * (pos_x + sprite_w - 1); + pos_x = 0; + } else { + src += pos_x + sprite_w - 1; + var14 = true; + pos_x = 0; + } + } + } + if (sprite_clipped_w <= 0) { + return; + } + + int16_t sprite_clipped_h; + if (pos_y >= 0) { + if (pos_y < 224 - sprite_h) { + sprite_clipped_h = sprite_h; + } else { + sprite_clipped_h = 224 - pos_y; + } + } else { + sprite_clipped_h = sprite_h + pos_y; + if (var16) { + src -= pos_y; + } else { + src -= sprite_w * pos_y; + } + pos_y = 0; + } + if (sprite_clipped_h <= 0) { + return; + } + + if (!var14 && (flags & 2)) { + if (var16) { + src += sprite_h * (sprite_w - 1); + } else { + src += sprite_w - 1; + } + } + + uint32_t dst_offset = 256 * pos_y + pos_x; + uint8_t sprite_col_mask = ((flags & 0x60) == 0x60) ? 0x50 : 0x40; + + debug(DBG_GAME, "dst_offset=0x%X src_offset=0x%X", dst_offset, src - dataPtr); + + if (!(flags & 2)) { + if (var16) { + _vid.drawSpriteSub5(src, _vid._frontLayer + dst_offset, sprite_h, sprite_clipped_h, sprite_clipped_w, sprite_col_mask); + } else { + _vid.drawSpriteSub3(src, _vid._frontLayer + dst_offset, sprite_w, sprite_clipped_h, sprite_clipped_w, sprite_col_mask); + } + } else { + if (var16) { + _vid.drawSpriteSub6(src, _vid._frontLayer + dst_offset, sprite_h, sprite_clipped_h, sprite_clipped_w, sprite_col_mask); + } else { + _vid.drawSpriteSub4(src, _vid._frontLayer + dst_offset, sprite_w, sprite_clipped_h, sprite_clipped_w, sprite_col_mask); + } + } + _vid.markBlockAsDirty(pos_x, pos_y, sprite_clipped_w, sprite_clipped_h); +} + +int Game::loadMonsterSprites(LivePGE *pge) { + debug(DBG_GAME, "Game::loadMonsterSprites()"); + InitPGE *init_pge = pge->init_PGE; + if (init_pge->obj_node_number != 0x49 && init_pge->object_type != 10) { + return 0xFFFF; + } + if (init_pge->obj_node_number == _curMonsterFrame) { + return 0xFFFF; + } + if (pge->room_location != _currentRoom) { + return 0; + } + + const uint8_t *mList = _monsterListLevels[_currentLevel]; + while (*mList != init_pge->obj_node_number) { + if (*mList == 0xFF) { // end of list + return 0; + } + mList += 2; + } + _curMonsterFrame = mList[0]; + if (_curMonsterNum != mList[1]) { + _curMonsterNum = mList[1]; + if (_res._type == kResourceTypeAmiga) { + _res.load(_monsterNames[1][_curMonsterNum], Resource::OT_SPM); + static const uint8_t tab[4] = { 0, 8, 0, 8 }; + const int offset = _vid._mapPalSlot2 * 16 + tab[_curMonsterNum]; + for (int i = 0; i < 8; ++i) { + _vid.setPaletteColorBE(0x50 + i, offset + i); + } + } else { + const char *name = _monsterNames[0][_curMonsterNum]; + _res.load(name, Resource::OT_SPRM); + _res.load_SPR_OFF(name, _res._sprm); + _vid.setPaletteSlotLE(5, _monsterPals[_curMonsterNum]); + } + } + return 0xFFFF; +} + +void Game::loadLevelMap() { + debug(DBG_GAME, "Game::loadLevelMap() room=%d", _currentRoom); + _currentIcon = 0xFF; + switch (_res._type) { + case kResourceTypeAmiga: + if (_currentLevel == 1) { + static const uint8_t tab[64] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 + }; + const int num = tab[_currentRoom]; + if (num != 0 && _res._levNum != num) { + char name[8]; + snprintf(name, sizeof(name), "level2_%d", num); + _res.load(name, Resource::OT_LEV); + _res._levNum = num; + } + } + _vid.AMIGA_decodeLev(_currentLevel, _currentRoom); + break; + case kResourceTypePC: + _vid.PC_decodeMap(_currentLevel, _currentRoom); + _vid.PC_setLevelPalettes(); + break; + } +} + +void Game::loadLevelData() { + _res.clearLevelRes(); + const Level *lvl = &_gameLevels[_currentLevel]; + switch (_res._type) { + case kResourceTypeAmiga: + if (_fs->exists("demo.lev")) { // demo data files + Cutscene::_namesTable[1] = "HOLOCUBE"; + Cutscene::_namesTable[4] = "CHUTE2"; + static const char *fname1 = "demo"; + static const char *fname2 = "demof"; + _res.load(fname1, Resource::OT_MBK); + _res.load(fname1, Resource::OT_CT); + _res.load(fname1, Resource::OT_PAL); + _res.load(fname1, Resource::OT_RPC); + _res.load(fname1, Resource::OT_SPC); + _res.load(fname1, Resource::OT_LEV); + _res.load(fname2, Resource::OT_PGE); + _res.load(fname1, Resource::OT_OBJ); + _res.load(fname1, Resource::OT_ANI); + _res.load(fname2, Resource::OT_TBN); + _res.load_SPL_demo(); + _res.load("level1", Resource::OT_SGD); + break; + } + { + const char *name = lvl->nameAmiga; + if (_currentLevel == 4) { + name = _gameLevels[3].nameAmiga; + } + _res.load(name, Resource::OT_MBK); + if (_currentLevel == 6) { + _res.load(_gameLevels[5].nameAmiga, Resource::OT_CT); + } else { + _res.load(name, Resource::OT_CT); + } + _res.load(name, Resource::OT_PAL); + _res.load(name, Resource::OT_RPC); + _res.load(name, Resource::OT_SPC); + if (_currentLevel == 1) { + _res.load("level2_1", Resource::OT_LEV); + _res._levNum = 1; + } else { + _res.load(name, Resource::OT_LEV); + } + } + _res.load(lvl->nameAmiga, Resource::OT_PGE); + _res.load(lvl->nameAmiga, Resource::OT_OBC); + _res.load(lvl->nameAmiga, Resource::OT_ANI); + _res.load(lvl->nameAmiga, Resource::OT_TBN); + { + char name[8]; + snprintf(name, sizeof(name), "level%d", lvl->sound); + _res.load(name, Resource::OT_SPL); + } + if (_currentLevel == 0) { + _res.load(lvl->nameAmiga, Resource::OT_SGD); + } + break; + case kResourceTypePC: + _res.load(lvl->name, Resource::OT_MBK); + _res.load(lvl->name, Resource::OT_CT); + _res.load(lvl->name, Resource::OT_PAL); + _res.load(lvl->name, Resource::OT_RP); + _res.load(lvl->name, Resource::OT_MAP); + _res.load(lvl->name2, Resource::OT_PGE); + _res.load(lvl->name2, Resource::OT_OBJ); + _res.load(lvl->name2, Resource::OT_ANI); + _res.load(lvl->name2, Resource::OT_TBN); + break; + } + + _cut._id = lvl->cutscene_id; + + _curMonsterNum = 0xFFFF; + _curMonsterFrame = 0; + + _res.clearBankData(); + _printLevelCodeCounter = 150; + + _col_slots2Cur = _col_slots2; + _col_slots2Next = 0; + + memset(_pge_liveTable2, 0, sizeof(_pge_liveTable2)); + memset(_pge_liveTable1, 0, sizeof(_pge_liveTable1)); + + _currentRoom = _res._pgeInit[0].init_room; + uint16_t n = _res._pgeNum; + while (n--) { + pge_loadForCurrentLevel(n); + } + + for (uint16_t i = 0; i < _res._pgeNum; ++i) { + if (_res._pgeInit[i].skill <= _skillLevel) { + LivePGE *pge = &_pgeLive[i]; + pge->next_PGE_in_room = _pge_liveTable1[pge->room_location]; + _pge_liveTable1[pge->room_location] = pge; + } + } + pge_resetGroups(); + _validSaveState = false; + + _mix.playMusic(Mixer::MUSIC_TRACK + lvl->track); +} + +void Game::drawIcon(uint8_t iconNum, int16_t x, int16_t y, uint8_t colMask) { + uint8_t buf[16 * 16]; + switch (_res._type) { + case kResourceTypeAmiga: + if (iconNum > 30) { + // inventory icons + switch (iconNum) { + case 76: // cursor + memset(buf, 0, 16 * 16); + for (int i = 0; i < 3; ++i) { + buf[i] = buf[15 * 16 + (15 - i)] = 1; + buf[i * 16] = buf[(15 - i) * 16 + 15] = 1; + } + break; + case 77: // up - icon.spr 4 + memset(buf, 0, 16 * 16); + _vid.AMIGA_decodeIcn(_res._icn, 35, buf); + break; + case 78: // down - icon.spr 5 + memset(buf, 0, 16 * 16); + _vid.AMIGA_decodeIcn(_res._icn, 36, buf); + break; + default: + memset(buf, 5, 16 * 16); + break; + } + } else { + _vid.AMIGA_decodeIcn(_res._icn, iconNum, buf); + } + break; + case kResourceTypePC: + _vid.PC_decodeIcn(_res._icn, iconNum, buf); + break; + } + _vid.drawSpriteSub1(buf, _vid._frontLayer + x + y * 256, 16, 16, 16, colMask << 4); + _vid.markBlockAsDirty(x, y, 16, 16); +} + +void Game::playSound(uint8_t sfxId, uint8_t softVol) { + if (sfxId < _res._numSfx) { + SoundFx *sfx = &_res._sfxList[sfxId]; + if (sfx->data) { + MixerChunk mc; + mc.data = sfx->data; + mc.len = sfx->len; + const int freq = _res._type == kResourceTypeAmiga ? 3546897 / 650 : 6000; + _mix.play(&mc, freq, Mixer::MAX_VOLUME >> softVol); + } + } else { + // in-game music + _mix.playMusic(sfxId); + } +} + +uint16_t Game::getRandomNumber() { + uint32_t n = _randSeed * 2; + if (_randSeed > n) { + n ^= 0x1D872B41; + } + _randSeed = n; + return n & 0xFFFF; +} + +void Game::changeLevel() { + _vid.fadeOut(); + loadLevelData(); + loadLevelMap(); + _vid.setPalette0xF(); + _vid.setTextPalette(); + _vid.fullRefresh(); +} + +uint16_t Game::getLineLength(const uint8_t *str) const { + uint16_t len = 0; + while (*str && *str != 0xB && *str != 0xA) { + ++str; + ++len; + } + return len; +} + +void Game::handleInventory() { + LivePGE *selected_pge = 0; + LivePGE *pge = &_pgeLive[0]; + if (pge->life > 0 && pge->current_inventory_PGE != 0xFF) { + playSound(66, 0); + InventoryItem items[24]; + int num_items = 0; + uint8_t inv_pge = pge->current_inventory_PGE; + while (inv_pge != 0xFF) { + items[num_items].icon_num = _res._pgeInit[inv_pge].icon_num; + items[num_items].init_pge = &_res._pgeInit[inv_pge]; + items[num_items].live_pge = &_pgeLive[inv_pge]; + inv_pge = _pgeLive[inv_pge].next_inventory_PGE; + ++num_items; + } + items[num_items].icon_num = 0xFF; + int current_item = 0; + int num_lines = (num_items - 1) / 4 + 1; + int current_line = 0; + bool display_score = false; + while (!_stub->_pi.backspace && !_stub->_pi.quit) { + // draw inventory background + int icon_h = 5; + int icon_y = 140; + int icon_num = 31; + do { + int icon_x = 56; + int icon_w = 9; + do { + drawIcon(icon_num, icon_x, icon_y, 0xF); + ++icon_num; + icon_x += 16; + } while (--icon_w); + icon_y += 16; + } while (--icon_h); + + if (!display_score) { + int icon_x_pos = 72; + for (int i = 0; i < 4; ++i) { + int item_it = current_line * 4 + i; + if (items[item_it].icon_num == 0xFF) { + break; + } + drawIcon(items[item_it].icon_num, icon_x_pos, 157, 0xA); + if (current_item == item_it) { + drawIcon(76, icon_x_pos, 157, 0xA); + selected_pge = items[item_it].live_pge; + uint8_t txt_num = items[item_it].init_pge->text_num; + const char *str = (const char *)_res._tbn + READ_LE_UINT16(_res._tbn + txt_num * 2); + _vid.drawString(str, (256 - strlen(str) * 8) / 2, 189, 0xED); + if (items[item_it].init_pge->init_flags & 4) { + char buf[10]; + snprintf(buf, sizeof(buf), "%d", selected_pge->life); + _vid.drawString(buf, (256 - strlen(buf) * 8) / 2, 197, 0xED); + } + } + icon_x_pos += 32; + } + if (current_line != 0) { + drawIcon(78, 120, 176, 0xA); // down arrow + } + if (current_line != num_lines - 1) { + drawIcon(77, 120, 143, 0xA); // up arrow + } + } else { + char buf[50]; + snprintf(buf, sizeof(buf), "SCORE %08u", _score); + _vid.drawString(buf, (114 - strlen(buf) * 8) / 2 + 72, 158, 0xE5); + snprintf(buf, sizeof(buf), "%s:%s", _res.getMenuString(LocaleData::LI_06_LEVEL), _res.getMenuString(LocaleData::LI_13_EASY + _skillLevel)); + _vid.drawString(buf, (114 - strlen(buf) * 8) / 2 + 72, 166, 0xE5); + } + + _vid.updateScreen(); + _stub->sleep(80); + inp_update(); + + if (_stub->_pi.dirMask & PlayerInput::DIR_UP) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_UP; + if (current_line < num_lines - 1) { + ++current_line; + current_item = current_line * 4; + } + } + if (_stub->_pi.dirMask & PlayerInput::DIR_DOWN) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_DOWN; + if (current_line > 0) { + --current_line; + current_item = current_line * 4; + } + } + if (_stub->_pi.dirMask & PlayerInput::DIR_LEFT) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_LEFT; + if (current_item > 0) { + int item_num = current_item % 4; + if (item_num > 0) { + --current_item; + } + } + } + if (_stub->_pi.dirMask & PlayerInput::DIR_RIGHT) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_RIGHT; + if (current_item < num_items - 1) { + int item_num = current_item % 4; + if (item_num < 3) { + ++current_item; + } + } + } + if (_stub->_pi.enter) { + _stub->_pi.enter = false; + display_score = !display_score; + } + } + _vid.fullRefresh(); + _stub->_pi.backspace = false; + if (selected_pge) { + pge_setCurrentInventoryObject(selected_pge); + } + playSound(66, 0); + } +} + +void Game::inp_update() { + if (_inp_replay && _inp_demo) { + uint8_t keymask = _inp_demo->readByte(); + if (_inp_demo->ioErr()) { + _inp_replay = false; + } else { + _stub->_pi.dirMask = keymask & 0xF; + _stub->_pi.enter = (keymask & 0x10) != 0; + _stub->_pi.space = (keymask & 0x20) != 0; + _stub->_pi.shift = (keymask & 0x40) != 0; + _stub->_pi.quit = (keymask & 0x80) != 0; + } + } + _stub->processEvents(); + if (_inp_record && _inp_demo) { + uint8_t keymask = _stub->_pi.dirMask; + if (_stub->_pi.enter) { + keymask |= 0x10; + } + if (_stub->_pi.space) { + keymask |= 0x20; + } + if (_stub->_pi.shift) { + keymask |= 0x40; + } + if (_stub->_pi.quit) { + keymask |= 0x80; + } + _inp_demo->writeByte(keymask); + if (_inp_demo->ioErr()) { + _inp_record = false; + } + } +} + +void Game::makeGameDemoName(char *buf) { + sprintf(buf, "rs-level%d.demo", _currentLevel + 1); +} + +void Game::makeGameStateName(uint8_t slot, char *buf) { + sprintf(buf, "rs-level%d-%02d.state", _currentLevel + 1, slot); +} + +bool Game::saveGameState(uint8_t slot) { + bool success = false; + char stateFile[20]; + makeGameStateName(slot, stateFile); + File f; + if (!f.open(stateFile, "zwb", _savePath)) { + warning("Unable to save state file '%s'", stateFile); + } else { + // header + f.writeUint32BE('FBSV'); + f.writeUint16BE(2); + char buf[32]; + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf), "level=%d room=%d", _currentLevel + 1, _currentRoom); + f.write(buf, sizeof(buf)); + // contents + saveState(&f); + if (f.ioErr()) { + warning("I/O error when saving game state"); + } else { + debug(DBG_INFO, "Saved state to slot %d", slot); + success = true; + } + } + return success; +} + +bool Game::loadGameState(uint8_t slot) { + bool success = false; + char stateFile[20]; + makeGameStateName(slot, stateFile); + File f; + if (!f.open(stateFile, "zrb", _savePath)) { + warning("Unable to open state file '%s'", stateFile); + } else { + uint32_t id = f.readUint32BE(); + if (id != 'FBSV') { + warning("Bad save state format"); + } else { + uint16_t ver = f.readUint16BE(); + if (ver != 2) { + warning("Invalid save state version"); + } else { + // header + char buf[32]; + f.read(buf, sizeof(buf)); + // contents + loadState(&f); + if (f.ioErr()) { + warning("I/O error when loading game state"); + } else { + debug(DBG_INFO, "Loaded state from slot %d", slot); + success = true; + } + } + } + } + return success; +} + +void Game::saveState(File *f) { + f->writeByte(_skillLevel); + f->writeUint32BE(_score); + if (_col_slots2Cur == 0) { + f->writeUint32BE(0xFFFFFFFF); + } else { + f->writeUint32BE(_col_slots2Cur - &_col_slots2[0]); + } + if (_col_slots2Next == 0) { + f->writeUint32BE(0xFFFFFFFF); + } else { + f->writeUint32BE(_col_slots2Next - &_col_slots2[0]); + } + for (int i = 0; i < _res._pgeNum; ++i) { + LivePGE *pge = &_pgeLive[i]; + f->writeUint16BE(pge->obj_type); + f->writeUint16BE(pge->pos_x); + f->writeUint16BE(pge->pos_y); + f->writeByte(pge->anim_seq); + f->writeByte(pge->room_location); + f->writeUint16BE(pge->life); + f->writeUint16BE(pge->counter_value); + f->writeByte(pge->collision_slot); + f->writeByte(pge->next_inventory_PGE); + f->writeByte(pge->current_inventory_PGE); + f->writeByte(pge->unkF); + f->writeUint16BE(pge->anim_number); + f->writeByte(pge->flags); + f->writeByte(pge->index); + f->writeUint16BE(pge->first_obj_number); + if (pge->next_PGE_in_room == 0) { + f->writeUint32BE(0xFFFFFFFF); + } else { + f->writeUint32BE(pge->next_PGE_in_room - &_pgeLive[0]); + } + if (pge->init_PGE == 0) { + f->writeUint32BE(0xFFFFFFFF); + } else { + f->writeUint32BE(pge->init_PGE - &_res._pgeInit[0]); + } + } + f->write(&_res._ctData[0x100], 0x1C00); + for (CollisionSlot2 *cs2 = &_col_slots2[0]; cs2 < _col_slots2Cur; ++cs2) { + if (cs2->next_slot == 0) { + f->writeUint32BE(0xFFFFFFFF); + } else { + f->writeUint32BE(cs2->next_slot - &_col_slots2[0]); + } + if (cs2->unk2 == 0) { + f->writeUint32BE(0xFFFFFFFF); + } else { + f->writeUint32BE(cs2->unk2 - &_res._ctData[0x100]); + } + f->writeByte(cs2->data_size); + f->write(cs2->data_buf, 0x10); + } +} + +void Game::loadState(File *f) { + uint16_t i; + uint32_t off; + _skillLevel = f->readByte(); + _score = f->readUint32BE(); + memset(_pge_liveTable2, 0, sizeof(_pge_liveTable2)); + memset(_pge_liveTable1, 0, sizeof(_pge_liveTable1)); + off = f->readUint32BE(); + if (off == 0xFFFFFFFF) { + _col_slots2Cur = 0; + } else { + _col_slots2Cur = &_col_slots2[0] + off; + } + off = f->readUint32BE(); + if (off == 0xFFFFFFFF) { + _col_slots2Next = 0; + } else { + _col_slots2Next = &_col_slots2[0] + off; + } + for (i = 0; i < _res._pgeNum; ++i) { + LivePGE *pge = &_pgeLive[i]; + pge->obj_type = f->readUint16BE(); + pge->pos_x = f->readUint16BE(); + pge->pos_y = f->readUint16BE(); + pge->anim_seq = f->readByte(); + pge->room_location = f->readByte(); + pge->life = f->readUint16BE(); + pge->counter_value = f->readUint16BE(); + pge->collision_slot = f->readByte(); + pge->next_inventory_PGE = f->readByte(); + pge->current_inventory_PGE = f->readByte(); + pge->unkF = f->readByte(); + pge->anim_number = f->readUint16BE(); + pge->flags = f->readByte(); + pge->index = f->readByte(); + pge->first_obj_number = f->readUint16BE(); + off = f->readUint32BE(); + if (off == 0xFFFFFFFF) { + pge->next_PGE_in_room = 0; + } else { + pge->next_PGE_in_room = &_pgeLive[0] + off; + } + off = f->readUint32BE(); + if (off == 0xFFFFFFFF) { + pge->init_PGE = 0; + } else { + pge->init_PGE = &_res._pgeInit[0] + off; + } + } + f->read(&_res._ctData[0x100], 0x1C00); + for (CollisionSlot2 *cs2 = &_col_slots2[0]; cs2 < _col_slots2Cur; ++cs2) { + off = f->readUint32BE(); + if (off == 0xFFFFFFFF) { + cs2->next_slot = 0; + } else { + cs2->next_slot = &_col_slots2[0] + off; + } + off = f->readUint32BE(); + if (off == 0xFFFFFFFF) { + cs2->unk2 = 0; + } else { + cs2->unk2 = &_res._ctData[0x100] + off; + } + cs2->data_size = f->readByte(); + f->read(cs2->data_buf, 0x10); + } + for (i = 0; i < _res._pgeNum; ++i) { + if (_res._pgeInit[i].skill <= _skillLevel) { + LivePGE *pge = &_pgeLive[i]; + if (pge->flags & 4) { + _pge_liveTable2[pge->index] = pge; + } + pge->next_PGE_in_room = _pge_liveTable1[pge->room_location]; + _pge_liveTable1[pge->room_location] = pge; + } + } + resetGameState(); +} + +void AnimBuffers::addState(uint8_t stateNum, int16_t x, int16_t y, const uint8_t *dataPtr, LivePGE *pge, uint8_t w, uint8_t h) { + debug(DBG_GAME, "AnimBuffers::addState() stateNum=%d x=%d y=%d dataPtr=0x%X pge=0x%X", stateNum, x, y, dataPtr, pge); + assert(stateNum < 4); + AnimBufferState *state = _states[stateNum]; + state->x = x; + state->y = y; + state->w = w; + state->h = h; + state->dataPtr = dataPtr; + state->pge = pge; + ++_curPos[stateNum]; + ++_states[stateNum]; +} diff --git a/game.h b/game.h new file mode 100644 index 0000000..d1c1e5f --- /dev/null +++ b/game.h @@ -0,0 +1,383 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GAME_H__ +#define GAME_H__ + +#include "intern.h" +#include "cutscene.h" +#include "menu.h" +#include "mixer.h" +#include "resource.h" +#include "seq_player.h" +#include "video.h" + +struct File; +struct FileSystem; +struct SystemStub; + +struct Game { + typedef int (Game::*pge_OpcodeProc)(ObjectOpcodeArgs *args); + typedef int (Game::*pge_ZOrderCallback)(LivePGE *, LivePGE *, uint8_t, uint8_t); + typedef int (Game::*col_Callback1)(LivePGE *, LivePGE *, int16_t, int16_t); + typedef int (Game::*col_Callback2)(LivePGE *, int16_t, int16_t, int16_t); + + enum { + CT_UP_ROOM = 0x00, + CT_DOWN_ROOM = 0x40, + CT_RIGHT_ROOM = 0x80, + CT_LEFT_ROOM = 0xC0 + }; + + static const Level _gameLevels[]; + static const uint16_t _scoreTable[]; + static const uint8_t _monsterListLevel1[]; + static const uint8_t _monsterListLevel2[]; + static const uint8_t _monsterListLevel3[]; + static const uint8_t _monsterListLevel4_1[]; + static const uint8_t _monsterListLevel4_2[]; + static const uint8_t _monsterListLevel5_1[]; + static const uint8_t _monsterListLevel5_2[]; + static const uint8_t *_monsterListLevels[]; + static const uint8_t _monsterPals[4][32]; + static const char *_monsterNames[2][4]; + static const pge_OpcodeProc _pge_opcodeTable[]; + static const uint8_t _pge_modKeysTable[]; + static const uint8_t _protectionCodeData[]; + static const uint8_t _protectionPal[]; + + Cutscene _cut; + Menu _menu; + Mixer _mix; + Resource _res; + SeqPlayer _seq; + Video _vid; + SystemStub *_stub; + FileSystem *_fs; + const char *_savePath; + + const uint8_t *_stringsTable; + const char **_textsTable; + uint8_t _currentLevel; + uint8_t _skillLevel; + uint32_t _score; + uint8_t _currentRoom; + uint8_t _currentIcon; + bool _loadMap; + uint8_t _printLevelCodeCounter; + uint32_t _randSeed; + uint16_t _currentInventoryIconNum; + uint16_t _curMonsterFrame; + uint16_t _curMonsterNum; + uint8_t _blinkingConradCounter; + uint16_t _textToDisplay; + bool _eraseBackground; + AnimBufferState _animBuffer0State[41]; + AnimBufferState _animBuffer1State[6]; // Conrad + AnimBufferState _animBuffer2State[42]; + AnimBufferState _animBuffer3State[12]; + AnimBuffers _animBuffers; + uint16_t _deathCutsceneCounter; + bool _saveStateCompleted; + bool _endLoop; + + Game(SystemStub *, FileSystem *, const char *savePath, int level, ResourceType ver, Language lang); + + void run(); + void resetGameState(); + void mainLoop(); + void updateTiming(); + void playCutscene(int id = -1); + bool playCutsceneSeq(const char *name); + void loadLevelMap(); + void loadLevelData(); + void drawIcon(uint8_t iconNum, int16_t x, int16_t y, uint8_t colMask); + void drawCurrentInventoryItem(); + void printLevelCode(); + void showFinalScore(); + bool handleConfigPanel(); + bool handleContinueAbort(); + bool handleProtectionScreen(); + void printSaveStateCompleted(); + void drawLevelTexts(); + void drawStoryTexts(); + void prepareAnims(); + void prepareAnimsHelper(LivePGE *pge, int16_t dx, int16_t dy); + void drawAnims(); + void drawAnimBuffer(uint8_t stateNum, AnimBufferState *state); + void drawObject(const uint8_t *dataPtr, int16_t x, int16_t y, uint8_t flags); + void drawObjectFrame(const uint8_t *bankDataPtr, const uint8_t *dataPtr, int16_t x, int16_t y, uint8_t flags); + void decodeCharacterFrame(const uint8_t *dataPtr, uint8_t *dstPtr); + void drawCharacter(const uint8_t *dataPtr, int16_t x, int16_t y, uint8_t a, uint8_t b, uint8_t flags); + int loadMonsterSprites(LivePGE *pge); + void playSound(uint8_t sfxId, uint8_t softVol); + uint16_t getRandomNumber(); + void changeLevel(); + uint16_t getLineLength(const uint8_t *str) const; + void handleInventory(); + + + // pieges + bool _pge_playAnimSound; + GroupPGE _pge_groups[256]; + GroupPGE *_pge_groupsTable[256]; + GroupPGE *_pge_nextFreeGroup; + LivePGE *_pge_liveTable2[256]; // active pieges list (index = pge number) + LivePGE *_pge_liveTable1[256]; // pieges list by room (index = room) + LivePGE _pgeLive[256]; + uint8_t _pge_currentPiegeRoom; + bool _pge_currentPiegeFacingDir; // (false == left) + bool _pge_processOBJ; + uint8_t _pge_inpKeysMask; + uint16_t _pge_opTempVar1; + uint16_t _pge_opTempVar2; + uint16_t _pge_compareVar1; + uint16_t _pge_compareVar2; + + void pge_resetGroups(); + void pge_removeFromGroup(uint8_t idx); + int pge_isInGroup(LivePGE *pge_dst, uint16_t group_id, uint16_t counter); + void pge_loadForCurrentLevel(uint16_t idx); + void pge_process(LivePGE *pge); + void pge_setupNextAnimFrame(LivePGE *pge, GroupPGE *le); + void pge_playAnimSound(LivePGE *pge, uint16_t arg2); + void pge_setupAnim(LivePGE *pge); + int pge_execute(LivePGE *live_pge, InitPGE *init_pge, const Object *obj); + void pge_prepare(); + void pge_setupDefaultAnim(LivePGE *pge); + uint16_t pge_processOBJ(LivePGE *pge); + void pge_setupOtherPieges(LivePGE *pge, InitPGE *init_pge); + void pge_addToCurrentRoomList(LivePGE *pge, uint8_t room); + void pge_getInput(); + int pge_op_isInpUp(ObjectOpcodeArgs *args); + int pge_op_isInpBackward(ObjectOpcodeArgs *args); + int pge_op_isInpDown(ObjectOpcodeArgs *args); + int pge_op_isInpForward(ObjectOpcodeArgs *args); + int pge_op_isInpUpMod(ObjectOpcodeArgs *args); + int pge_op_isInpBackwardMod(ObjectOpcodeArgs *args); + int pge_op_isInpDownMod(ObjectOpcodeArgs *args); + int pge_op_isInpForwardMod(ObjectOpcodeArgs *args); + int pge_op_isInpIdle(ObjectOpcodeArgs *args); + int pge_op_isInpNoMod(ObjectOpcodeArgs *args); + int pge_op_getCollision0u(ObjectOpcodeArgs *args); + int pge_op_getCollision00(ObjectOpcodeArgs *args); + int pge_op_getCollision0d(ObjectOpcodeArgs *args); + int pge_op_getCollision1u(ObjectOpcodeArgs *args); + int pge_op_getCollision10(ObjectOpcodeArgs *args); + int pge_op_getCollision1d(ObjectOpcodeArgs *args); + int pge_op_getCollision2u(ObjectOpcodeArgs *args); + int pge_op_getCollision20(ObjectOpcodeArgs *args); + int pge_op_getCollision2d(ObjectOpcodeArgs *args); + int pge_op_doesNotCollide0u(ObjectOpcodeArgs *args); + int pge_op_doesNotCollide00(ObjectOpcodeArgs *args); + int pge_op_doesNotCollide0d(ObjectOpcodeArgs *args); + int pge_op_doesNotCollide1u(ObjectOpcodeArgs *args); + int pge_op_doesNotCollide10(ObjectOpcodeArgs *args); + int pge_op_doesNotCollide1d(ObjectOpcodeArgs *args); + int pge_op_doesNotCollide2u(ObjectOpcodeArgs *args); + int pge_op_doesNotCollide20(ObjectOpcodeArgs *args); + int pge_op_doesNotCollide2d(ObjectOpcodeArgs *args); + int pge_op_collides0o0d(ObjectOpcodeArgs *args); + int pge_op_collides2o2d(ObjectOpcodeArgs *args); + int pge_op_collides0o0u(ObjectOpcodeArgs *args); + int pge_op_collides2o2u(ObjectOpcodeArgs *args); + int pge_op_collides2u2o(ObjectOpcodeArgs *args); + int pge_op_isInGroup(ObjectOpcodeArgs *args); + int pge_op_updateGroup0(ObjectOpcodeArgs *args); + int pge_op_updateGroup1(ObjectOpcodeArgs *args); + int pge_op_updateGroup2(ObjectOpcodeArgs *args); + int pge_op_updateGroup3(ObjectOpcodeArgs *args); + int pge_op_isPiegeDead(ObjectOpcodeArgs *args); + int pge_op_collides1u2o(ObjectOpcodeArgs *args); + int pge_op_collides1u1o(ObjectOpcodeArgs *args); + int pge_op_collides1o1u(ObjectOpcodeArgs *args); + int pge_o_unk0x2B(ObjectOpcodeArgs *args); + int pge_o_unk0x2C(ObjectOpcodeArgs *args); + int pge_o_unk0x2D(ObjectOpcodeArgs *args); + int pge_op_nop(ObjectOpcodeArgs *args); + int pge_op_pickupObject(ObjectOpcodeArgs *args); + int pge_op_addItemToInventory(ObjectOpcodeArgs *args); + int pge_op_copyPiege(ObjectOpcodeArgs *args); + int pge_op_canUseCurrentInventoryItem(ObjectOpcodeArgs *args); + int pge_op_removeItemFromInventory(ObjectOpcodeArgs *args); + int pge_o_unk0x34(ObjectOpcodeArgs *args); + int pge_op_isInpMod(ObjectOpcodeArgs *args); + int pge_op_setCollisionState1(ObjectOpcodeArgs *args); + int pge_op_setCollisionState0(ObjectOpcodeArgs *args); + int pge_op_isInGroup1(ObjectOpcodeArgs *args); + int pge_op_isInGroup2(ObjectOpcodeArgs *args); + int pge_op_isInGroup3(ObjectOpcodeArgs *args); + int pge_op_isInGroup4(ObjectOpcodeArgs *args); + int pge_o_unk0x3C(ObjectOpcodeArgs *args); + int pge_o_unk0x3D(ObjectOpcodeArgs *args); + int pge_op_setPiegeCounter(ObjectOpcodeArgs *args); + int pge_op_decPiegeCounter(ObjectOpcodeArgs *args); + int pge_o_unk0x40(ObjectOpcodeArgs *args); + int pge_op_wakeUpPiege(ObjectOpcodeArgs *args); + int pge_op_removePiege(ObjectOpcodeArgs *args); + int pge_op_removePiegeIfNotNear(ObjectOpcodeArgs *args); + int pge_op_loadPiegeCounter(ObjectOpcodeArgs *args); + int pge_o_unk0x45(ObjectOpcodeArgs *args); + int pge_o_unk0x46(ObjectOpcodeArgs *args); + int pge_o_unk0x47(ObjectOpcodeArgs *args); + int pge_o_unk0x48(ObjectOpcodeArgs *args); + int pge_o_unk0x49(ObjectOpcodeArgs *args); + int pge_o_unk0x4A(ObjectOpcodeArgs *args); + int pge_op_killPiege(ObjectOpcodeArgs *args); + int pge_op_isInCurrentRoom(ObjectOpcodeArgs *args); + int pge_op_isNotInCurrentRoom(ObjectOpcodeArgs *args); + int pge_op_scrollPosY(ObjectOpcodeArgs *args); + int pge_op_playDefaultDeathCutscene(ObjectOpcodeArgs *args); + int pge_o_unk0x50(ObjectOpcodeArgs *args); + int pge_o_unk0x52(ObjectOpcodeArgs *args); + int pge_o_unk0x53(ObjectOpcodeArgs *args); + int pge_op_isPiegeNear(ObjectOpcodeArgs *args); + int pge_op_setLife(ObjectOpcodeArgs *args); + int pge_op_incLife(ObjectOpcodeArgs *args); + int pge_op_setPiegeDefaultAnim(ObjectOpcodeArgs *args); + int pge_op_setLifeCounter(ObjectOpcodeArgs *args); + int pge_op_decLifeCounter(ObjectOpcodeArgs *args); + int pge_op_playCutscene(ObjectOpcodeArgs *args); + int pge_op_isTempVar2Set(ObjectOpcodeArgs *args); + int pge_op_playDeathCutscene(ObjectOpcodeArgs *args); + int pge_o_unk0x5D(ObjectOpcodeArgs *args); + int pge_o_unk0x5E(ObjectOpcodeArgs *args); + int pge_o_unk0x5F(ObjectOpcodeArgs *args); + int pge_op_findAndCopyPiege(ObjectOpcodeArgs *args); + int pge_op_isInRandomRange(ObjectOpcodeArgs *args); + int pge_o_unk0x62(ObjectOpcodeArgs *args); + int pge_o_unk0x63(ObjectOpcodeArgs *args); + int pge_o_unk0x64(ObjectOpcodeArgs *args); + int pge_op_addToCredits(ObjectOpcodeArgs *args); + int pge_op_subFromCredits(ObjectOpcodeArgs *args); + int pge_o_unk0x67(ObjectOpcodeArgs *args); + int pge_op_setCollisionState2(ObjectOpcodeArgs *args); + int pge_op_saveState(ObjectOpcodeArgs *args); + int pge_o_unk0x6A(ObjectOpcodeArgs *args); + int pge_op_isInGroupSlice(ObjectOpcodeArgs *args); + int pge_o_unk0x6C(ObjectOpcodeArgs *args); + int pge_op_isCollidingObject(ObjectOpcodeArgs *args); + int pge_o_unk0x6E(ObjectOpcodeArgs *args); + int pge_o_unk0x6F(ObjectOpcodeArgs *args); + int pge_o_unk0x70(ObjectOpcodeArgs *args); + int pge_o_unk0x71(ObjectOpcodeArgs *args); + int pge_o_unk0x72(ObjectOpcodeArgs *args); + int pge_o_unk0x73(ObjectOpcodeArgs *args); + int pge_op_collides4u(ObjectOpcodeArgs *args); + int pge_op_doesNotCollide4u(ObjectOpcodeArgs *args); + int pge_op_isBelowConrad(ObjectOpcodeArgs *args); + int pge_op_isAboveConrad(ObjectOpcodeArgs *args); + int pge_op_isNotFacingConrad(ObjectOpcodeArgs *args); + int pge_op_isFacingConrad(ObjectOpcodeArgs *args); + int pge_op_collides2u1u(ObjectOpcodeArgs *args); + int pge_op_displayText(ObjectOpcodeArgs *args); + int pge_o_unk0x7C(ObjectOpcodeArgs *args); + int pge_op_playSound(ObjectOpcodeArgs *args); + int pge_o_unk0x7E(ObjectOpcodeArgs *args); + int pge_o_unk0x7F(ObjectOpcodeArgs *args); + int pge_op_setPiegePosX(ObjectOpcodeArgs *args); + int pge_op_setPiegePosModX(ObjectOpcodeArgs *args); + int pge_op_changeRoom(ObjectOpcodeArgs *args); + int pge_op_hasInventoryItem(ObjectOpcodeArgs *args); + int pge_op_changeLevel(ObjectOpcodeArgs *args); + int pge_op_shakeScreen(ObjectOpcodeArgs *args); + int pge_o_unk0x86(ObjectOpcodeArgs *args); + int pge_op_playSoundGroup(ObjectOpcodeArgs *args); + int pge_op_adjustPos(ObjectOpcodeArgs *args); + int pge_op_setTempVar1(ObjectOpcodeArgs *args); + int pge_op_isTempVar1Set(ObjectOpcodeArgs *args); + int pge_setCurrentInventoryObject(LivePGE *pge); + void pge_updateInventory(LivePGE *pge1, LivePGE *pge2); + void pge_reorderInventory(LivePGE *pge); + LivePGE *pge_getInventoryItemBefore(LivePGE *pge, LivePGE *last_pge); + void pge_addToInventory(LivePGE *pge1, LivePGE *pge2, LivePGE *pge3); + int pge_updateCollisionState(LivePGE *pge, int16_t pge_dy, uint8_t var8); + int pge_ZOrder(LivePGE *pge, int16_t num, pge_ZOrderCallback compare, uint16_t unk); + void pge_updateGroup(uint8_t idx, uint8_t unk1, int16_t unk2); + void pge_removeFromInventory(LivePGE *pge1, LivePGE *pge2, LivePGE *pge3); + int pge_ZOrderByAnimY(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2); + int pge_ZOrderByAnimYIfType(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2); + int pge_ZOrderIfIndex(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2); + int pge_ZOrderByIndex(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2); + int pge_ZOrderByObj(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2); + int pge_ZOrderIfDifferentDirection(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2); + int pge_ZOrderIfSameDirection(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2); + int pge_ZOrderIfTypeAndSameDirection(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2); + int pge_ZOrderIfTypeAndDifferentDirection(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2); + int pge_ZOrderByNumber(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2); + + + // collision + CollisionSlot _col_slots[256]; + uint8_t _col_curPos; + CollisionSlot *_col_slotsTable[256]; + CollisionSlot *_col_curSlot; + CollisionSlot2 _col_slots2[256]; + CollisionSlot2 *_col_slots2Cur; + CollisionSlot2 *_col_slots2Next; + uint8_t _col_activeCollisionSlots[0x30 * 3]; // left, current, right + uint8_t _col_currentLeftRoom; + uint8_t _col_currentRightRoom; + int16_t _col_currentPiegeGridPosX; + int16_t _col_currentPiegeGridPosY; + + void col_prepareRoomState(); + void col_clearState(); + LivePGE *col_findPiege(LivePGE *pge, uint16_t arg2); + int16_t col_findSlot(int16_t pos); + void col_preparePiegeState(LivePGE *dst_pge); + uint16_t col_getGridPos(LivePGE *pge, int16_t dx); + int16_t col_getGridData(LivePGE *pge, int16_t dy, int16_t dx); + uint8_t col_findCurrentCollidingObject(LivePGE *pge, uint8_t n1, uint8_t n2, uint8_t n3, LivePGE **pge_out); + int16_t col_detectHit(LivePGE *pge, int16_t arg2, int16_t arg4, col_Callback1 callback1, col_Callback2 callback2, int16_t argA, int16_t argC); + int col_detectHitCallback2(LivePGE *pge1, LivePGE *pge2, int16_t unk1, int16_t unk2); + int col_detectHitCallback3(LivePGE *pge1, LivePGE *pge2, int16_t unk1, int16_t unk2); + int col_detectHitCallback4(LivePGE *pge1, LivePGE *pge2, int16_t unk1, int16_t unk2); + int col_detectHitCallback5(LivePGE *pge1, LivePGE *pge2, int16_t unk1, int16_t unk2); + int col_detectHitCallback1(LivePGE *pge, int16_t dy, int16_t unk1, int16_t unk2); + int col_detectHitCallback6(LivePGE *pge, int16_t dy, int16_t unk1, int16_t unk2); + int col_detectHitCallbackHelper(LivePGE *pge, int16_t unk1); + int col_detectGunHitCallback1(LivePGE *pge, int16_t arg2, int16_t arg4, int16_t arg6); + int col_detectGunHitCallback2(LivePGE *pge1, LivePGE *pge2, int16_t arg4, int16_t); + int col_detectGunHitCallback3(LivePGE *pge1, LivePGE *pge2, int16_t arg4, int16_t); + int col_detectGunHit(LivePGE *pge, int16_t arg2, int16_t arg4, col_Callback1 callback1, col_Callback2 callback2, int16_t argA, int16_t argC); + + + // input + uint8_t _inp_lastKeysHit; + uint8_t _inp_lastKeysHitLeftRight; + bool _inp_replay; + bool _inp_record; + File *_inp_demo; + + void inp_handleSpecialKeys(); + void inp_update(); + + + // save/load state + uint8_t _stateSlot; + bool _validSaveState; + + void makeGameDemoName(char *buf); + void makeGameStateName(uint8_t slot, char *buf); + bool saveGameState(uint8_t slot); + bool loadGameState(uint8_t slot); + void saveState(File *f); + void loadState(File *f); +}; + +#endif // GAME_H__ diff --git a/graphics.cpp b/graphics.cpp new file mode 100644 index 0000000..1da5a4d --- /dev/null +++ b/graphics.cpp @@ -0,0 +1,717 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "graphics.h" + + +void Graphics::setClippingRect(int16_t rx, int16_t ry, int16_t rw, int16_t rh) { + debug(DBG_VIDEO, "Graphics::setClippingRect(%d, %d, %d, %d)", rx, ry, rw, rh); + _crx = rx; + _cry = ry; + _crw = rw; + _crh = rh; +} + +void Graphics::drawPoint(uint8_t color, const Point *pt) { + debug(DBG_VIDEO, "Graphics::drawPoint() col=0x%X x=%d, y=%d", color, pt->x, pt->y); + if (pt->x >= 0 && pt->x < _crw && pt->y >= 0 && pt->y < _crh) { + *(_layer + (pt->y + _cry) * 256 + pt->x + _crx) = color; + } +} + +void Graphics::drawLine(uint8_t color, const Point *pt1, const Point *pt2) { + debug(DBG_VIDEO, "Graphics::drawLine()"); + int16_t dxincr1 = 1; + int16_t dyincr1 = 1; + int16_t dx = pt2->x - pt1->x; + if (dx < 0) { + dxincr1 = -1; + dx = -dx; + } + int16_t dy = pt2->y - pt1->y; + if (dy < 0) { + dyincr1 = -1; + dy = -dy; + } + int16_t dxincr2, dyincr2, delta1, delta2; + if (dx < dy) { + dxincr2 = 0; + dyincr2 = 1; + delta1 = dx; + delta2 = dy; + if (dyincr1 < 0) { + dyincr2 = -1; + } + } else { + dxincr2 = 1; + dyincr2 = 0; + delta1 = dy; + delta2 = dx; + if (dxincr1 < 0) { + dxincr2 = -1; + } + } + Point pt; + pt.x = pt1->x; + pt.y = pt1->y; + int16_t octincr1 = delta1 * 2 - delta2 * 2; + int16_t octincr2 = delta1 * 2; + int16_t oct = delta1 * 2 - delta2; + if (delta2 >= 0) { + drawPoint(color, &pt); + while (--delta2 >= 0) { + if (oct >= 0) { + pt.x += dxincr1; + pt.y += dyincr1; + oct += octincr1; + } else { + pt.x += dxincr2; + pt.y += dyincr2; + oct += octincr2; + } + drawPoint(color, &pt); + } + } +} + +void Graphics::addEllipseRadius(int16_t y, int16_t x1, int16_t x2) { + debug(DBG_VIDEO, "Graphics::addEllipseRadius()"); + if (y >= 0 && y <= _crh) { + y = (y - _areaPoints[0]) * 2; + if (x1 < 0) { + x1 = 0; + } + if (x2 >= _crw) { + x2 = _crw - 1; + } + _areaPoints[y + 1] = x1; + _areaPoints[y + 2] = x2; + } +} + +void Graphics::drawEllipse(uint8_t color, bool hasAlpha, const Point *pt, int16_t rx, int16_t ry) { + debug(DBG_VIDEO, "Graphics::drawEllipse()"); + bool flag = false; + int16_t y = pt->y - ry; + if (y < 0) { + y = 0; + } + if (y < _crh) { + if (pt->y + ry >= 0) { + _areaPoints[0] = y; + int32_t dy = 0; + int32_t rxsq = rx * rx; + int32_t rxsq2 = rx * rx * 2; + int32_t rxsq4 = rx * rx * 4; + int32_t rysq = ry * ry; + int32_t rysq2 = ry * ry * 2; + int32_t rysq4 = ry * ry * 4; + + int32_t dx = 0; + int32_t b = rx * ((rysq2 & 0xFFFF) + (rysq2 >> 16)); + int32_t a = 2 * b; + + int32_t ny1, ny2, nx1, nx2; + ny1 = ny2 = rysq4 / 2 - a + rxsq; + nx1 = nx2 = rxsq2 - b + rysq; + + while (ny2 < 0) { + int16_t x2 = pt->x + rx; + int16_t x1 = pt->x - rx; + int16_t by = pt->y + dy; + int16_t ty = pt->y - dy; + if (x1 != x2) { + addEllipseRadius(by, x1, x2); + if (ty < by) { + addEllipseRadius(ty, x1, x2); + } + } + dy += 1; + dx += rxsq4; + nx1 = dx; + if (nx2 < 0) { + nx2 += nx1 + rxsq2; + ny2 += nx1; + } else { + --rx; + a -= rysq4; + ny1 = a; + nx2 += nx1 + rxsq2 - ny1; + ny2 += nx1 + rysq2 - ny1; + } + } + + while (rx >= 0) { + bool flag2 = false; + int16_t x2 = pt->x + rx; + int16_t x1 = pt->x - rx; + int16_t by = pt->y + dy; + int16_t ty = pt->y - dy; + if (!flag && x1 != x2) { + flag2 = true; + addEllipseRadius(by, x1, x2); + if (ty < by) { + addEllipseRadius(ty, x1, x2); + } + } + if (flag2) { + flag = true; + } + --rx; + a -= rysq4; + nx1 = a; + if (ny2 < 0) { + ++dy; + flag = false; + dx += rxsq4; + ny2 += dx - nx1 + rysq2; + ny1 = dx - nx1 + rysq2; + } else { + ny2 += rysq2 - nx1; + ny1 = rysq2 - nx1; + } + } + if (flag) { + ++dy; + } + + while (dy <= ry) { + int16_t ty = pt->y - dy; + int16_t by = pt->y + dy; + if (ty < by) { + addEllipseRadius(ty, pt->x, pt->x); + } + addEllipseRadius(by, pt->x, pt->x); + ++dy; + } + y = pt->y + ry + 1; + if (y > _crh) { + y = _crh; + } + y = (y - _areaPoints[0]) * 2; + _areaPoints[y + 1] = -1; + fillArea(color, hasAlpha); + } + } +} + +void Graphics::fillArea(uint8_t color, bool hasAlpha) { + debug(DBG_VIDEO, "Graphics::fillArea()"); + int16_t *pts = _areaPoints; + uint8_t *dst = _layer + (_cry + *pts++) * 256 + _crx; + int16_t x1 = *pts++; + if (x1 >= 0) { + if (hasAlpha && color > 0xC7) { + do { + int16_t x2 = *pts++; + if (x2 < _crw && x2 >= x1) { + int len = x2 - x1 + 1; + for (int i = 0; i < len; ++i) { + *(dst + x1 + i) |= color & 8; // XXX 0x88 + } + } + dst += 256; + x1 = *pts++; + } while (x1 >= 0); + } else { + do { + int16_t x2 = *pts++; + if (x2 < _crw && x2 >= x1) { + int len = x2 - x1 + 1; + memset(dst + x1, color, len); + } + dst += 256; + x1 = *pts++; + } while (x1 >= 0); + } + } +} + +void Graphics::drawSegment(uint8_t color, bool hasAlpha, int16_t ys, const Point *pts, uint8_t numPts) { + debug(DBG_VIDEO, "Graphics::drawSegment()"); + int16_t xmin, xmax, ymin, ymax; + xmin = xmax = pts[0].x; + ymin = ymax = pts[0].y; + for (int i = 1; i < numPts; ++i) { + int16_t x = pts[i].x; + int16_t y = pts[i].y; + if ((xmin << 16) + ymin > (x << 16) + y) { + xmin = x; + ymin = y; + } + if ((xmax << 16) + ymax < (x << 16) + y) { + xmax = x; + ymax = y; + } + } + if (xmin < 0) { + xmin = 0; + } + if (xmax >= _crw) { + xmax = _crw - 1; + } + _areaPoints[0] = ys; + _areaPoints[1] = xmin; + _areaPoints[2] = xmax; + _areaPoints[3] = -1; + fillArea(color, hasAlpha); +} + +void Graphics::drawPolygonOutline(uint8_t color, const Point *pts, uint8_t numPts) { + debug(DBG_VIDEO, "Graphics::drawPolygonOutline()"); + assert(numPts >= 2); + int i; + for (i = 0; i < numPts - 1; ++i) { + drawLine(color, &pts[i], &pts[i + 1]); + } + drawLine(color, &pts[i], &pts[0]); +} + +static int32_t calcPolyStep1(int16_t dx, int16_t dy) { + debug(DBG_VIDEO, "Graphics::calcPolyStep1()"); + assert(dy != 0); + int32_t a = dx * 256; + if ((a >> 16) < dy) { + a = ((int16_t)(a / dy)) * 256; + } else { + a = ((a / 256) / dy) & 0xFFFF0000; + } + return a; +} + +static int32_t calcPolyStep2(int16_t dx, int16_t dy) { + debug(DBG_VIDEO, "Graphics::calcPolyStep2()"); + assert(dy != 0); + int32_t a = dx * 256; + if ((a >> 16) < dy) { + a = ((int16_t)(a / dy)) * 256; + } else { + a = ((a / 256) / dy) << 16; + } + return a; +} + +static void drawPolygonHelper1(int32_t &x, int16_t &y, int32_t &step, int16_t *&pts, int16_t *&start) { + bool first = true; + x = pts[0]; + y = pts[1]; + int16_t dy, dx; + do { + if (first) { + first = false; + } else { + x = *pts; + } + --pts; + dy = *pts - y; + --pts; + dx = *pts - x; + } while (dy <= 0 && start < pts); + x <<= 16; + if (dy > 0) { + step = calcPolyStep1(dx, dy); + } +} + +static void drawPolygonHelper2(int32_t &x, int16_t &y, int32_t &step, int16_t *&pts, int16_t *&start) { + bool first = true; + x = *start++; + y = *start++; + int16_t dy, dx; + do { + if (first) { + first = false; + } else { + x = *start; + start += 2; + } + dy = start[1] - y; + dx = start[0] - x; + } while (dy <= 0 && start < pts); + x <<= 16; + if (dy > 0) { + step = calcPolyStep2(dx, dy); + } +} + +void Graphics::drawPolygon(uint8_t color, bool hasAlpha, const Point *pts, uint8_t numPts) { + debug(DBG_VIDEO, "Graphics::drawPolygon()"); + assert(numPts * 4 < 0x100); + + int16_t *apts1 = &_areaPoints[0x100]; + int16_t *apts2 = &_areaPoints[0x100 + numPts * 2]; + + int16_t xmin, xmax, ymin, ymax; + xmin = xmax = pts[0].x; + ymin = ymax = pts[0].y; + + int16_t *spts = apts1; + *apts1++ = *apts2++ = pts[0].x; + *apts1++ = *apts2++ = pts[0].y; + + for (int p = 1; p < numPts; ++p) { + int16_t x = pts[p].x; + int16_t y = pts[p].y; + if (ymin > y) { + ymin = y; + spts = apts1; + } + if (ymax < y) { + ymax = y; + } + *apts1++ = *apts2++ = x; + *apts1++ = *apts2++ = y; + + if (xmin > x) { + xmin = x; + } + if (xmax < x) { + xmax = x; + } + } + int16_t *rpts = _areaPoints; + if (xmax < 0 || xmin >= _crw || ymax < 0 || ymin >= _crh) { + return; + } + if (numPts == 2) { + drawLine(color, &pts[0], &pts[1]); + return; + } + if (ymax == ymin) { + drawSegment(color, hasAlpha, ymax, pts, numPts); + return; + } + int16_t x, dx, y, dy; + int32_t a, b, d, f; + int32_t xstep1 = 0; + int32_t xstep2 = 0; + + apts1 = &spts[numPts * 2]; + xmax = _crw - 1; + ymax = _crh - 1; + int32_t l1 = 65536; + int32_t l2 = -65536; + if (ymin < 0) { + int16_t x0, y0; + do { + --apts1; + y0 = *apts1; + --apts1; + x0 = *apts1; + } while (y0 < 0); + x = apts1[2]; + y = apts1[3]; + dy = y0 - y; + dx = x0 - x; + xstep1 = (dy << 16) | dx; + assert(dy != 0); + a = y * dx / dy; + b = (x - a) << 16; + d = xstep1 = calcPolyStep1(dx, dy); + if (d < 0) { + d = -d; + } + if (d < l1) { + d = l2; + } + d /= 2; + b -= d; + + do { + x0 = *spts++; + y0 = *spts++; + } while (*(spts + 1) < 0); + dy = spts[1] - y0; + dx = spts[0] - x0; + xstep2 = (dy << 16) | dx; + assert(dy != 0); + a = y0 * dx / dy; + f = (x0 - a) << 16; + d = xstep2 = calcPolyStep2(dx, dy); + if (d < 0) { + d = -d; + } + if (d < l1) { + d = l1; + } + d /= 2; + f += d; + ymin = 0; + *rpts++ = 0; + goto gfx_startLine; + } + + *rpts++ = ymin; + +gfx_startNewLine: + drawPolygonHelper2(f, ymin, xstep2, apts1, spts); + if (spts >= apts1) { + b = apts1[0] << 16; + dy = apts1[1]; + if (dy <= ymax) goto gfx_endLine; + goto gfx_fillArea; + } + drawPolygonHelper1(b, ymin, xstep1, apts1, spts); + d = xstep1; + if (d < 0) { + if (d >= l2) { + d = l1; + } + d /= 2; + b += d; + } + d = xstep2; + if (d >= 0) { + if (d <= l1) { + d = l1; + } + d /= 2; + f += d; + } + d = b; + if (d < 0) { + d = 0; + } + x = f >> 16; + if (x > xmax) { + x = xmax; + } + *rpts++ = d >> 16; + *rpts++ = x; + ++ymin; + d = xstep1; + if (d >= 0) { + if (d <= l1) { + d = l1; + } + d /= 2; + } + b += d; + d = xstep2; + if (d < 0) { + if (d >= l2) { + d = l1; + } + d /= 2; + } + f += d; + +gfx_startLine: + while (1) { + dy = apts1[1]; + if (spts >= apts1) { + break; + } else if (dy > spts[1]) { + dy = spts[1]; + if (dy > ymax) { + goto gfx_drawPolygonEnd; + } + dy -= ymin; + if (dy > 0) { + --dy; + do { + a = b; + if (a < 0) { + a = 0; + } + x = f >> 16; + if (x > xmax) { + x = xmax; + } + *rpts++ = a >> 16; + *rpts++ = x; + b += xstep1; + f += xstep2; + --dy; + } while (dy >= 0); + } + drawPolygonHelper2(f, ymin, xstep2, apts1, spts); + d = xstep2; + if (d >= 0) { + if (d <= l1) { + d = l1; + } + d /= 2; + f += d; + } else { + d = b; + if (d < 0) { + d = 0; + } + x = f >> 16; + if (x > xmax) { + x = xmax; + } + *rpts++ = d >> 16; + *rpts++ = x; + ++ymin; + d = xstep2; + if (d >= l2) { + d = l1; + } + d /= 2; + f += d; + b += xstep1; + } + } else if (dy == spts[1]) { + if (dy > ymax) goto gfx_drawPolygonEnd; + dy -= ymin; + if (dy > 0) { + --dy; + do { + a = b; + if (a < 0) { + a = 0; + } + x = f >> 16; + if (x > xmax) { + x = xmax; + } + *rpts++ = a >> 16; + *rpts++ = x; + b += xstep1; + f += xstep2; + --dy; + } while (dy >= 0); + } + goto gfx_startNewLine; + } else if (dy > ymax) { + goto gfx_drawPolygonEnd; + } else { + dy -= ymin; + if (dy > 0) { + --dy; + do { + a = b; + if (a < 0) { + a = 0; + } + x = f >> 16; + if (x > xmax) { + x = xmax; + } + *rpts++ = a >> 16; + *rpts++ = x; + b += xstep1; + f += xstep2; + --dy; + } while (dy >= 0); + } + drawPolygonHelper1(b, ymin, xstep1, apts1, spts); + d = xstep1; + if (d < 0) { + if (d >= l2) { + d = l1; + } + d /= 2; + b += d; + } else { + d = b; + if (d < 0) { + d = 0; + } + x = f >> 16; + if (x > xmax) { + x = xmax; + } + *rpts++ = d >> 16; + *rpts++ = x; + ++ymin; + d = xstep1; + if (d <= l1) { + d = l1; + } + d /= 2; + b += d; + f += xstep2; + } + } + } + + if (dy > ymax) goto gfx_drawPolygonEnd; + dy -= ymin; + if (dy < 0) goto gfx_fillArea; + if (dy > 0) { + --dy; + do { + a = b; + if (a < 0) { + a = 0; + } + x = f >> 16; + if (x > xmax) { + x = xmax; + } + *rpts++ = a >> 16; + *rpts++ = x; + b += xstep1; + f += xstep2; + --dy; + } while (dy >= 0); + } + + b = f = (apts1[0] << 16) | apts1[1]; + +gfx_endLine: + d = xstep1; + if (d >= 0) { + if (d >= l1) { + d /= 2; + b -= d; + } + } + d = xstep2; + if (d < 0) { + d /= 2; + f -= d; + } + a = b; + if (a < 0) { + a = 0; + } + x = f >> 16; + if (x > xmax) { + x = xmax; + } + *rpts++ = a >> 16; + *rpts++ = x; + goto gfx_fillArea; + +gfx_drawPolygonEnd: + dy = ymax - ymin; + if (dy >= 0) { + do { + a = b; + if (a < 0) { + a = 0; + } + x = f >> 16; + if (x > xmax) { + x = xmax; + } + *rpts++ = a >> 16; + *rpts++ = x; + b += xstep1; + f += xstep2; + --dy; + } while (dy >= 0); + } + +gfx_fillArea: + *rpts++ = -1; + fillArea(color, hasAlpha); +} diff --git a/graphics.h b/graphics.h new file mode 100644 index 0000000..d28421b --- /dev/null +++ b/graphics.h @@ -0,0 +1,39 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GRAPHICS_H__ +#define GRAPHICS_H__ + +#include "intern.h" + +struct Graphics { + uint8_t *_layer; + int16_t _areaPoints[0x200]; + int16_t _crx, _cry, _crw, _crh; + + void setClippingRect(int16_t vx, int16_t vy, int16_t vw, int16_t vh); + void drawPoint(uint8_t color, const Point *pt); + void drawLine(uint8_t color, const Point *pt1, const Point *pt2); + void addEllipseRadius(int16_t y, int16_t x1, int16_t x2); + void drawEllipse(uint8_t color, bool hasAlpha, const Point *pt, int16_t rx, int16_t ry); + void fillArea(uint8_t color, bool hasAlpha); + void drawSegment(uint8_t color, bool hasAlpha, int16_t ys, const Point *pts, uint8_t numPts); + void drawPolygonOutline(uint8_t color, const Point *pts, uint8_t numPts); + void drawPolygon(uint8_t color, bool hasAlpha, const Point *pts, uint8_t numPts); +}; + +#endif // GRAPHICS_H__ diff --git a/intern.h b/intern.h new file mode 100644 index 0000000..6e9df9e --- /dev/null +++ b/intern.h @@ -0,0 +1,224 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef INTERN_H__ +#define INTERN_H__ + +#include +#include +#include +#include +#include + +#include "util.h" + +#define ABS(x) ((x)<0?-(x):(x)) +#define MAX(x,y) ((x)>(y)?(x):(y)) +#define MIN(x,y) ((x)<(y)?(x):(y)) +#ifndef ARRAYSIZE +#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) +#endif + + +inline void SWAP_UINT16(uint16_t *ptr) { + const uint8_t hi = *ptr >> 8; + const uint8_t lo = *ptr & 255; + *ptr = (lo << 8) | hi; +} + +inline uint16_t READ_BE_UINT16(const void *ptr) { + const uint8_t *b = (const uint8_t *)ptr; + return (b[0] << 8) | b[1]; +} + +inline uint32_t READ_BE_UINT32(const void *ptr) { + const uint8_t *b = (const uint8_t *)ptr; + return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; +} + +inline uint16_t READ_LE_UINT16(const void *ptr) { + const uint8_t *b = (const uint8_t *)ptr; + return (b[1] << 8) | b[0]; +} + +inline uint32_t READ_LE_UINT32(const void *ptr) { + const uint8_t *b = (const uint8_t *)ptr; + return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0]; +} + +template +inline void SWAP(T &a, T &b) { + T tmp = a; + a = b; + b = tmp; +} + +enum Language { + LANG_FR, + LANG_EN, + LANG_DE, + LANG_SP, + LANG_IT +}; + +enum ResourceType { + kResourceTypeAmiga, + kResourceTypePC +}; + +struct Color { + uint8_t r; + uint8_t g; + uint8_t b; +}; + +struct Point { + int16_t x; + int16_t y; +}; + +struct Level { + const char *name; + const char *name2; + const char *nameAmiga; + uint16_t cutscene_id; + uint8_t sound; + uint8_t track; +}; + +struct InitPGE { + uint16_t type; + int16_t pos_x; + int16_t pos_y; + uint16_t obj_node_number; + uint16_t life; + int16_t counter_values[4]; + uint8_t object_type; + uint8_t init_room; + uint8_t room_location; + uint8_t init_flags; + uint8_t colliding_icon_num; + uint8_t icon_num; + uint8_t object_id; + uint8_t skill; + uint8_t mirror_x; + uint8_t flags; + uint8_t unk1C; // collidable, collision_data_len + uint16_t text_num; +}; + +struct LivePGE { + uint16_t obj_type; + int16_t pos_x; + int16_t pos_y; + uint8_t anim_seq; + uint8_t room_location; + int16_t life; + int16_t counter_value; + uint8_t collision_slot; + uint8_t next_inventory_PGE; + uint8_t current_inventory_PGE; + uint8_t unkF; // unk_inventory_PGE + uint16_t anim_number; + uint8_t flags; + uint8_t index; + uint16_t first_obj_number; + LivePGE *next_PGE_in_room; + InitPGE *init_PGE; +}; + +struct GroupPGE { + GroupPGE *next_entry; + uint16_t index; + uint16_t group_id; +}; + +struct Object { + uint16_t type; + int8_t dx; + int8_t dy; + uint16_t init_obj_type; + uint8_t opcode2; + uint8_t opcode1; + uint8_t flags; + uint8_t opcode3; + uint16_t init_obj_number; + int16_t opcode_arg1; + int16_t opcode_arg2; + int16_t opcode_arg3; +}; + +struct ObjectNode { + uint16_t last_obj_number; + Object *objects; + uint16_t num_objects; +}; + +struct ObjectOpcodeArgs { + LivePGE *pge; // arg0 + int16_t a; // arg2 + int16_t b; // arg4 +}; + +struct AnimBufferState { + int16_t x, y; + uint8_t w, h; + const uint8_t *dataPtr; + LivePGE *pge; +}; + +struct AnimBuffers { + AnimBufferState *_states[4]; + uint8_t _curPos[4]; + + void addState(uint8_t stateNum, int16_t x, int16_t y, const uint8_t *dataPtr, LivePGE *pge, uint8_t w = 0, uint8_t h = 0); +}; + +struct CollisionSlot { + int16_t ct_pos; + CollisionSlot *prev_slot; + LivePGE *live_pge; + uint16_t index; +}; + +struct BankSlot { + uint16_t entryNum; + uint8_t *ptr; +}; + +struct CollisionSlot2 { + CollisionSlot2 *next_slot; + int8_t *unk2; + uint8_t data_size; + uint8_t data_buf[0x10]; // XXX check size +}; + +struct InventoryItem { + uint8_t icon_num; + InitPGE *init_pge; + LivePGE *live_pge; +}; + +struct SoundFx { + uint32_t offset; + uint16_t len; + uint8_t *data; +}; + +extern const char *g_caption; + +#endif // INTERN_H__ diff --git a/locale.cpp b/locale.cpp new file mode 100644 index 0000000..6ffbdc8 --- /dev/null +++ b/locale.cpp @@ -0,0 +1,49 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "locale.h" + + +Locale::Locale(Version ver) + : _ver(ver) { + switch (_ver) { + case LANG_FR: + _stringsTable = _stringsTableFR; + _textsTable = _textsTableFR; + break; + case LANG_EN: + _stringsTable = _stringsTableEN; + _textsTable = _textsTableEN; + break; + case LANG_DE: + _stringsTable = _stringsTableDE; + _textsTable = _textsTableDE; + break; + case LANG_SP: + _stringsTable = _stringsTableSP; + _textsTable = _textsTableSP; + break; + } +} + +const char *Locale::get(int id) const { + const char *text = 0; + if (id >= 0 && id < LI_NUM) { + text = _textsTable[id]; + } + return text; +} diff --git a/locale.h b/locale.h new file mode 100644 index 0000000..1e2823a --- /dev/null +++ b/locale.h @@ -0,0 +1,68 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LOCALE_H__ +#define LOCALE_H__ + +#include "intern.h" + +struct Locale { + enum Id { + LI_01_CONTINUE_OR_ABORT = 0, + LI_02_TIME, + LI_03_CONTINUE, + LI_04_ABORT, + LI_05_COMPLETED, + LI_06_LEVEL, + LI_07_START, + LI_08_SKILL, + LI_09_PASSWORD, + LI_10_INFO, + LI_11_QUIT, + LI_12_SKILL_LEVEL, + LI_13_EASY, + LI_14_NORMAL, + LI_15_EXPERT, + LI_16_ENTER_PASSWORD1, + LI_17_ENTER_PASSWORD2, + LI_18_RESUME_GAME, + LI_19_ABORT_GAME, + LI_20_LOAD_GAME, + LI_21_SAVE_GAME, + LI_22_SAVE_SLOT, + + LI_NUM + }; + + static const char *_textsTableFR[]; + static const char *_textsTableEN[]; + static const char *_textsTableDE[]; + static const char *_textsTableSP[]; + static const uint8_t _stringsTableFR[]; + static const uint8_t _stringsTableEN[]; + static const uint8_t _stringsTableDE[]; + static const uint8_t _stringsTableSP[]; + + Version _ver; + const char **_textsTable; + const uint8_t *_stringsTable; + + Locale(Version ver); + const char *get(int id) const; +}; + +#endif // LOCALE_H__ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..4dd1543 --- /dev/null +++ b/main.cpp @@ -0,0 +1,132 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include "file.h" +#include "fs.h" +#include "game.h" +#include "systemstub.h" + +static const char *USAGE = + "REminiscence - Flashback Interpreter\n" + "Usage: %s [OPTIONS]...\n" + " --datapath=PATH Path to data files (default 'DATA')\n" + " --savepath=PATH Path to save files (default '.')\n" + " --levelnum=NUM Starting level (default '0')"; + +static int detectVersion(FileSystem *fs) { + static const struct { + const char *filename; + int type; + const char *name; + } table[] = { + { "LEVEL1.MAP", kResourceTypePC, "PC" }, + { "LEVEL1.LEV", kResourceTypeAmiga, "Amiga" }, + { "DEMO.LEV", kResourceTypeAmiga, "Amiga" }, + { 0, -1 } + }; + for (int i = 0; table[i].filename; ++i) { + File f; + if (f.open(table[i].filename, "rb", fs)) { + debug(DBG_INFO, "Detected %s version", table[i].name); + return table[i].type; + } + } + return -1; +} + +static Language detectLanguage(FileSystem *fs) { + static const struct { + const char *filename; + Language language; + } table[] = { + // PC + { "ENGCINE.TXT", LANG_EN }, + { "FR_CINE.TXT", LANG_FR }, + { "GERCINE.TXT", LANG_DE }, + { "SPACINE.TXT", LANG_SP }, + { "ITACINE.TXT", LANG_IT }, + // Amiga + { "FRCINE.TXT", LANG_FR }, + { 0, LANG_EN } + }; + for (int i = 0; table[i].filename; ++i) { + File f; + if (f.open(table[i].filename, "rb", fs)) { + return table[i].language; + } + } + return LANG_EN; +} + +const char *g_caption = "REminiscence"; + +#undef main +int main(int argc, char *argv[]) { + const char *dataPath = "DATA"; + const char *savePath = "."; + int levelNum = 0; + if (argc == 2) { + // data path as the only command line argument + struct stat st; + if (stat(argv[1], &st) == 0 && S_ISDIR(st.st_mode)) { + dataPath = strdup(argv[1]); + } + } + while (1) { + static struct option options[] = { + { "datapath", required_argument, 0, 1 }, + { "savepath", required_argument, 0, 2 }, + { "levelnum", required_argument, 0, 3 }, + { 0, 0, 0, 0 } + }; + int index; + const int c = getopt_long(argc, argv, "", options, &index); + if (c == -1) { + break; + } + switch (c) { + case 1: + dataPath = strdup(optarg); + break; + case 2: + savePath = strdup(optarg); + break; + case 3: + levelNum = atoi(optarg); + break; + default: + printf(USAGE, argv[0]); + return 0; + } + } + g_debugMask = DBG_INFO; // DBG_CUT | DBG_VIDEO | DBG_RES | DBG_MENU | DBG_PGE | DBG_GAME | DBG_UNPACK | DBG_COL | DBG_MOD | DBG_SFX | DBG_FILE; + FileSystem fs(dataPath); + const int version = detectVersion(&fs); + if (version == -1) { + error("Unable to find data files, check that all required files are present"); + return -1; + } + Language language = detectLanguage(&fs); + SystemStub *stub = SystemStub_SDL_create(); + Game *g = new Game(stub, &fs, savePath, levelNum, (ResourceType)version, language); + g->run(); + delete g; + delete stub; + return 0; +} diff --git a/menu.cpp b/menu.cpp new file mode 100644 index 0000000..e9f8095 --- /dev/null +++ b/menu.cpp @@ -0,0 +1,407 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "game.h" +#include "resource.h" +#include "systemstub.h" +#include "video.h" +#include "menu.h" + + +Menu::Menu(Resource *res, SystemStub *stub, Video *vid) + : _res(res), _stub(stub), _vid(vid) { +} + +void Menu::drawString(const char *str, int16_t y, int16_t x, uint8_t color) { + debug(DBG_MENU, "Menu::drawString()"); + uint8_t v1b = _vid->_charFrontColor; + uint8_t v2b = _vid->_charTransparentColor; + uint8_t v3b = _vid->_charShadowColor; + switch (color) { + case 0: + _vid->_charFrontColor = _charVar1; + _vid->_charTransparentColor = _charVar2; + _vid->_charShadowColor = _charVar2; + break; + case 1: + _vid->_charFrontColor = _charVar2; + _vid->_charTransparentColor = _charVar1; + _vid->_charShadowColor = _charVar1; + break; + case 2: + _vid->_charFrontColor = _charVar3; + _vid->_charTransparentColor = 0xFF; + _vid->_charShadowColor = _charVar1; + break; + case 3: + _vid->_charFrontColor = _charVar4; + _vid->_charTransparentColor = 0xFF; + _vid->_charShadowColor = _charVar1; + break; + case 4: + _vid->_charFrontColor = _charVar2; + _vid->_charTransparentColor = 0xFF; + _vid->_charShadowColor = _charVar1; + break; + case 5: + _vid->_charFrontColor = _charVar2; + _vid->_charTransparentColor = 0xFF; + _vid->_charShadowColor = _charVar5; + break; + } + + drawString2(str, y, x); + + _vid->_charFrontColor = v1b; + _vid->_charTransparentColor = v2b; + _vid->_charShadowColor = v3b; +} + +void Menu::drawString2(const char *str, int16_t y, int16_t x) { + debug(DBG_MENU, "Menu::drawString2()"); + int len = 0; + while (*str) { + _vid->PC_drawChar((uint8_t)*str, y, x + len); + ++str; + ++len; + } + _vid->markBlockAsDirty(x * 8, y * 8, len * 8, 8); +} + +void Menu::loadPicture(const char *prefix) { + debug(DBG_MENU, "Menu::loadPicture('%s')", prefix); + _res->load_MAP_menu(prefix, _res->_memBuf); + for (int i = 0; i < 4; ++i) { + for (int y = 0; y < 224; ++y) { + for (int x = 0; x < 64; ++x) { + _vid->_frontLayer[i + x * 4 + 256 * y] = _res->_memBuf[0x3800 * i + x + 64 * y]; + } + } + } + _res->load_PAL_menu(prefix, _res->_memBuf); + _stub->setPalette(_res->_memBuf, 256); +} + +void Menu::handleInfoScreen() { + debug(DBG_MENU, "Menu::handleInfoScreen()"); + _vid->fadeOut(); + switch (_res->_lang) { + case LANG_FR: + loadPicture("instru_f"); + break; + case LANG_EN: + case LANG_DE: + case LANG_SP: + case LANG_IT: + loadPicture("instru_e"); + break; + } + _vid->fullRefresh(); + _vid->updateScreen(); + do { + _stub->sleep(EVENTS_DELAY); + _stub->processEvents(); + if (_stub->_pi.enter) { + _stub->_pi.enter = false; + break; + } + } while (!_stub->_pi.quit); +} + +void Menu::handleSkillScreen(uint8_t &new_skill) { + debug(DBG_MENU, "Menu::handleSkillScreen()"); + static const uint8_t option_colors[3][3] = { { 2, 3, 3 }, { 3, 2, 3}, { 3, 3, 2 } }; + _vid->fadeOut(); + loadPicture("menu3"); + _vid->fullRefresh(); + drawString(_res->getMenuString(LocaleData::LI_12_SKILL_LEVEL), 12, 4, 3); + int skill_level = new_skill; + do { + drawString(_res->getMenuString(LocaleData::LI_13_EASY), 15, 14, option_colors[skill_level][0]); + drawString(_res->getMenuString(LocaleData::LI_14_NORMAL), 17, 14, option_colors[skill_level][1]); + drawString(_res->getMenuString(LocaleData::LI_15_EXPERT), 19, 14, option_colors[skill_level][2]); + + _vid->updateScreen(); + _stub->sleep(EVENTS_DELAY); + _stub->processEvents(); + + if (_stub->_pi.dirMask & PlayerInput::DIR_UP) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_UP; + if (skill_level != 0) { + --skill_level; + } else { + skill_level = 2; + } + } + if (_stub->_pi.dirMask & PlayerInput::DIR_DOWN) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_DOWN; + if (skill_level != 2) { + ++skill_level; + } else { + skill_level = 0; + } + } + if (_stub->_pi.enter) { + _stub->_pi.enter = false; + new_skill = skill_level; + return; + } + } while (!_stub->_pi.quit); + new_skill = 1; +} + +bool Menu::handlePasswordScreen(uint8_t &new_skill, uint8_t &new_level) { + debug(DBG_MENU, "Menu::handlePasswordScreen()"); + _vid->fadeOut(); + _vid->_charShadowColor = _charVar1; + _vid->_charTransparentColor = 0xFF; + _vid->_charFrontColor = _charVar4; + _vid->fullRefresh(); + char password[7]; + int len = 0; + do { + loadPicture("menu2"); + drawString2(_res->getMenuString(LocaleData::LI_16_ENTER_PASSWORD1), 15, 3); + drawString2(_res->getMenuString(LocaleData::LI_17_ENTER_PASSWORD2), 17, 3); + + for (int i = 0; i < len; ++i) { + _vid->PC_drawChar((uint8_t)password[i], 21, i + 15); + } + _vid->PC_drawChar(0x20, 21, len + 15); + + _vid->markBlockAsDirty(15 * 8, 21 * 8, (len + 1) * 8, 8); + _vid->updateScreen(); + _stub->sleep(EVENTS_DELAY); + _stub->processEvents(); + char c = _stub->_pi.lastChar; + if (c != 0) { + _stub->_pi.lastChar = 0; + if (len < 6) { + if (c >= 'a' && c <= 'z') { + c &= ~0x20; + } + if ((c >= 'A' && c <= 'Z') || (c == 0x20)) { + password[len] = c; + ++len; + } + } + } + if (_stub->_pi.backspace) { + _stub->_pi.backspace = false; + if (len > 0) { + --len; + } + } + if (_stub->_pi.enter) { + _stub->_pi.enter = false; + password[len] = '\0'; + for (int level = 0; level < 8; ++level) { + for (int skill = 0; skill < 3; ++skill) { + if (strcmp(_passwords[level][skill], password) == 0) { + new_level = level; + new_skill = skill; + return true; + } + } + } + return false; + } + } while (!_stub->_pi.quit); + return false; +} + +bool Menu::handleLevelScreen(uint8_t &new_skill, uint8_t &new_level) { + debug(DBG_MENU, "Menu::handleLevelScreen()"); + _vid->fadeOut(); + loadPicture("menu2"); + _vid->fullRefresh(); + uint8_t currentSkill = new_skill; + uint8_t currentLevel = new_level; + do { + static const char *levelTitles[] = { + "Titan / The Jungle", + "Titan / New Washington", + "Titan / Death Tower Show", + "Earth / Surface", + "Earth / Paradise Club", + "Planet Morphs / Surface", + "Planet Morphs / Inner Core" + }; + for (int i = 0; i < 7; ++i) { + drawString(levelTitles[i], 7 + i * 2, 4, (currentLevel == i) ? 2 : 3); + } + _vid->markBlockAsDirty(4 * 8, 7 * 8, 192, 7 * 8); + + drawString(_res->getMenuString(LocaleData::LI_13_EASY), 23, 4, (currentSkill == 0) ? 2 : 3); + drawString(_res->getMenuString(LocaleData::LI_14_NORMAL), 23, 14, (currentSkill == 1) ? 2 : 3); + drawString(_res->getMenuString(LocaleData::LI_15_EXPERT), 23, 24, (currentSkill == 2) ? 2 : 3); + _vid->markBlockAsDirty(4 * 8, 23 * 8, 192, 8); + + _vid->updateScreen(); + _stub->sleep(EVENTS_DELAY); + _stub->processEvents(); + + if (_stub->_pi.dirMask & PlayerInput::DIR_UP) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_UP; + if (currentLevel != 0) { + --currentLevel; + } else { + currentLevel = 6; + } + } + if (_stub->_pi.dirMask & PlayerInput::DIR_DOWN) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_DOWN; + if (currentLevel != 6) { + ++currentLevel; + } else { + currentLevel = 0; + } + } + if (_stub->_pi.dirMask & PlayerInput::DIR_LEFT) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_LEFT; + if (currentSkill != 0) { + --currentSkill; + } else { + currentSkill = 2; + } + } + if (_stub->_pi.dirMask & PlayerInput::DIR_RIGHT) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_RIGHT; + if (currentSkill != 2) { + ++currentSkill; + } else { + currentSkill = 0; + } + } + if (_stub->_pi.enter) { + _stub->_pi.enter = false; + new_skill = currentSkill; + new_level = currentLevel; + return true; + } + } while (!_stub->_pi.quit); + return false; +} + +bool Menu::handleTitleScreen(uint8_t &new_skill, uint8_t &new_level) { + debug(DBG_MENU, "Menu::handleTitleScreen()"); + bool quit_loop = false; + int menu_entry = 0; + bool reinit_screen = true; + bool continue_game = true; + _charVar1 = 0; + _charVar2 = 0; + _charVar3 = 0; + _charVar4 = 0; + _charVar5 = 0; + static const struct { + int str; + int opt; + } menu_items[] = { + { LocaleData::LI_07_START, MENU_OPTION_ITEM_START }, +#ifdef ENABLE_PASSWORD_MENU + { LocaleData::LI_08_SKILL, MENU_OPTION_ITEM_SKILL }, + { LocaleData::LI_09_PASSWORD, MENU_OPTION_ITEM_PASSWORD }, +#else + { LocaleData::LI_06_LEVEL, MENU_OPTION_ITEM_LEVEL }, +#endif + { LocaleData::LI_10_INFO, MENU_OPTION_ITEM_INFO }, + { LocaleData::LI_11_QUIT, MENU_OPTION_ITEM_QUIT } + }; + static const int menu_items_count = ARRAYSIZE(menu_items); + while (!quit_loop) { + if (reinit_screen) { + _vid->fadeOut(); + loadPicture("menu1"); + _vid->fullRefresh(); + _charVar3 = 1; + _charVar4 = 2; + menu_entry = 0; + reinit_screen = false; + } + int selected_menu_entry = -1; + const int y_start = 26 - menu_items_count * 2; + for (int i = 0; i < menu_items_count; ++i) { + drawString(_res->getMenuString(menu_items[i].str), y_start + i * 2, 20, (i == menu_entry) ? 2 : 3); + } + + _vid->updateScreen(); + _stub->sleep(EVENTS_DELAY); + _stub->processEvents(); + + if (_stub->_pi.dirMask & PlayerInput::DIR_UP) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_UP; + if (menu_entry != 0) { + --menu_entry; + } else { + menu_entry = menu_items_count - 1; + } + } + if (_stub->_pi.dirMask & PlayerInput::DIR_DOWN) { + _stub->_pi.dirMask &= ~PlayerInput::DIR_DOWN; + if (menu_entry != menu_items_count - 1) { + ++menu_entry; + } else { + menu_entry = 0; + } + } + if (_stub->_pi.enter) { + _stub->_pi.enter = false; + selected_menu_entry = menu_entry; + } + + if (selected_menu_entry != -1) { + switch (menu_items[selected_menu_entry].opt) { + case MENU_OPTION_ITEM_START: + quit_loop = true; + break; + case MENU_OPTION_ITEM_SKILL: + handleSkillScreen(new_skill); + reinit_screen = true; + break; + case MENU_OPTION_ITEM_PASSWORD: + if (handlePasswordScreen(new_skill, new_level)) { + quit_loop = true; + } else { + reinit_screen = true; + } + break; + case MENU_OPTION_ITEM_LEVEL: + if (handleLevelScreen(new_skill, new_level)) { + quit_loop = true; + } else { + reinit_screen = true; + } + break; + case MENU_OPTION_ITEM_INFO: + handleInfoScreen(); + reinit_screen = true; + break; + case MENU_OPTION_ITEM_QUIT: + continue_game = false; + quit_loop = true; + break; + } + } + if (_stub->_pi.quit) { + continue_game = false; + quit_loop = true; + break; + } + } + return continue_game; +} diff --git a/menu.h b/menu.h new file mode 100644 index 0000000..f52f8ec --- /dev/null +++ b/menu.h @@ -0,0 +1,66 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef MENU_H__ +#define MENU_H__ + +#include "intern.h" + +struct Resource; +struct SystemStub; +struct Video; + +struct Menu { + enum { + MENU_OPTION_ITEM_START, + MENU_OPTION_ITEM_SKILL, + MENU_OPTION_ITEM_PASSWORD, + MENU_OPTION_ITEM_LEVEL, + MENU_OPTION_ITEM_INFO, + MENU_OPTION_ITEM_QUIT + }; + + enum { + EVENTS_DELAY = 80 + }; + + static const char *_passwords[8][3]; + + Resource *_res; + SystemStub *_stub; + Video *_vid; + + const char **_textOptions; + uint8_t _charVar1; + uint8_t _charVar2; + uint8_t _charVar3; + uint8_t _charVar4; + uint8_t _charVar5; + + Menu(Resource *res, SystemStub *stub, Video *vid); + + void drawString(const char *str, int16_t y, int16_t x, uint8_t color); + void drawString2(const char *str, int16_t y, int16_t x); + void loadPicture(const char *prefix); + void handleInfoScreen(); + void handleSkillScreen(uint8_t &new_skill); + bool handlePasswordScreen(uint8_t &new_skill, uint8_t &new_level); + bool handleLevelScreen(uint8_t &new_skill, uint8_t &new_level); + bool handleTitleScreen(uint8_t &new_skill, uint8_t &new_level); +}; + +#endif // MENU_H__ diff --git a/mixer.cpp b/mixer.cpp new file mode 100644 index 0000000..3380a0c --- /dev/null +++ b/mixer.cpp @@ -0,0 +1,183 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "mixer.h" +#include "systemstub.h" + + +Mixer::Mixer(FileSystem *fs, SystemStub *stub) + : _stub(stub), _musicType(MT_NONE), _mod(this, fs), _ogg(this, fs), _sfx(this) { + _musicTrack = -1; +} + +void Mixer::init() { + memset(_channels, 0, sizeof(_channels)); + _premixHook = 0; + _stub->startAudio(Mixer::mixCallback, this); +} + +void Mixer::free() { + setPremixHook(0, 0); + stopAll(); + _stub->stopAudio(); +} + +void Mixer::setPremixHook(PremixHook premixHook, void *userData) { + debug(DBG_SND, "Mixer::setPremixHook()"); + LockAudioStack las(_stub); + _premixHook = premixHook; + _premixHookData = userData; +} + +void Mixer::play(const MixerChunk *mc, uint16_t freq, uint8_t volume) { + debug(DBG_SND, "Mixer::play(%d, %d)", freq, volume); + LockAudioStack las(_stub); + MixerChannel *ch = 0; + for (int i = 0; i < NUM_CHANNELS; ++i) { + MixerChannel *cur = &_channels[i]; + if (cur->active) { + if (cur->chunk.data == mc->data) { + cur->chunkPos = 0; + return; + } + } else { + ch = cur; + break; + } + } + if (ch) { + ch->active = true; + ch->volume = volume; + ch->chunk = *mc; + ch->chunkPos = 0; + ch->chunkInc = (freq << FRAC_BITS) / _stub->getOutputSampleRate(); + } +} + +bool Mixer::isPlaying(const MixerChunk *mc) const { + debug(DBG_SND, "Mixer::isPlaying"); + LockAudioStack las(_stub); + for (int i = 0; i < NUM_CHANNELS; ++i) { + const MixerChannel *ch = &_channels[i]; + if (ch->active && ch->chunk.data == mc->data) { + return true; + } + } + return false; +} + +uint32_t Mixer::getSampleRate() const { + return _stub->getOutputSampleRate(); +} + +void Mixer::stopAll() { + debug(DBG_SND, "Mixer::stopAll()"); + LockAudioStack las(_stub); + for (uint8_t i = 0; i < NUM_CHANNELS; ++i) { + _channels[i].active = false; + } +} + +static bool isMusicSfx(int num) { + return (num >= 68 && num <= 75); +} + +void Mixer::playMusic(int num) { + debug(DBG_SND, "Mixer::playMusic(%d)", num); + if (num > MUSIC_TRACK && num != _musicTrack) { + if (_ogg.playTrack(num - MUSIC_TRACK)) { + _musicType = MT_OGG; + _musicTrack = num; + return; + } + } + if (num == 1) { // menu screen + if (_ogg.playTrack(2)) { + _musicType = MT_OGG; + _musicTrack = 2; + return; + } + } + if (isMusicSfx(num)) { // level action sequence + _sfx.play(num); + _musicType = MT_SFX; + } else { // cutscene + _mod.play(num); + _musicType = MT_MOD; + } +} + +void Mixer::stopMusic() { + debug(DBG_SND, "Mixer::stopMusic()"); + switch (_musicType) { + case MT_NONE: + break; + case MT_MOD: + _mod.stop(); + break; + case MT_OGG: + _ogg.stopTrack(); + _musicTrack = -1; + break; + case MT_SFX: + _sfx.stop(); + break; + } + _musicType = MT_NONE; + if (_musicTrack != -1) { + _ogg.resumeTrack(); + _musicType = MT_OGG; + } +} + +void Mixer::mix(int8_t *buf, int len) { + memset(buf, 0, len); + if (_premixHook) { + if (!_premixHook(_premixHookData, buf, len)) { + _premixHook = 0; + _premixHookData = 0; + } + } + for (uint8_t i = 0; i < NUM_CHANNELS; ++i) { + MixerChannel *ch = &_channels[i]; + if (ch->active) { + for (int pos = 0; pos < len; ++pos) { + if ((ch->chunkPos >> FRAC_BITS) >= (ch->chunk.len - 1)) { + ch->active = false; + break; + } + int out = resampleLinear(&ch->chunk, ch->chunkPos, ch->chunkInc, FRAC_BITS); + addclamp(buf[pos], out * ch->volume / Mixer::MAX_VOLUME); + ch->chunkPos += ch->chunkInc; + } + } + } +} + +void Mixer::addclamp(int8_t& a, int b) { + int add = a + b; + if (add < -128) { + add = -128; + } else if (add > 127) { + add = 127; + } + a = add; +} + +void Mixer::mixCallback(void *param, int8_t *buf, int len) { + ((Mixer *)param)->mix(buf, len); +} diff --git a/mixer.h b/mixer.h new file mode 100644 index 0000000..4a2397e --- /dev/null +++ b/mixer.h @@ -0,0 +1,108 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef MIXER_H__ +#define MIXER_H__ + +#include "intern.h" +#include "mod_player.h" +#include "ogg_player.h" +#include "sfx_player.h" + +struct MixerChunk { + uint8_t *data; + uint32_t len; + + MixerChunk() + : data(0), len(0) { + } + + int8_t getPCM(int offset) const { + if (offset < 0) { + offset = 0; + } else if (offset >= (int)len) { + offset = len - 1; + } + return (int8_t)data[offset]; + } +}; + +struct MixerChannel { + uint8_t active; + uint8_t volume; + MixerChunk chunk; + uint32_t chunkPos; + uint32_t chunkInc; +}; + +struct FileSystem; +struct SystemStub; + +struct Mixer { + typedef bool (*PremixHook)(void *userData, int8_t *buf, int len); + + enum MusicType { + MT_NONE, + MT_MOD, + MT_OGG, + MT_SFX, + }; + + enum { + MUSIC_TRACK = 1000, + NUM_CHANNELS = 4, + FRAC_BITS = 12, + MAX_VOLUME = 64 + }; + + FileSystem *_fs; + SystemStub *_stub; + MixerChannel _channels[NUM_CHANNELS]; + PremixHook _premixHook; + void *_premixHookData; + MusicType _musicType; + ModPlayer _mod; + OggPlayer _ogg; + SfxPlayer _sfx; + int _musicTrack; + + Mixer(FileSystem *fs, SystemStub *stub); + void init(); + void free(); + void setPremixHook(PremixHook premixHook, void *userData); + void play(const MixerChunk *mc, uint16_t freq, uint8_t volume); + bool isPlaying(const MixerChunk *mc) const; + uint32_t getSampleRate() const; + void stopAll(); + void playMusic(int num); + void stopMusic(); + void mix(int8_t *buf, int len); + + static void addclamp(int8_t &a, int b); + static void mixCallback(void *param, int8_t *buf, int len); +}; + +template +int resampleLinear(T *sample, int pos, int step, int fracBits) { + const int inputPos = pos >> fracBits; + const int inputFrac = pos & ((1 << fracBits) - 1); + int out = sample->getPCM(inputPos); + out += (sample->getPCM(inputPos + 1) - out) * inputFrac >> fracBits; + return out; +} + +#endif // MIXER_H__ diff --git a/mod_player.cpp b/mod_player.cpp new file mode 100644 index 0000000..3df55bf --- /dev/null +++ b/mod_player.cpp @@ -0,0 +1,522 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "file.h" +#include "mixer.h" +#include "mod_player.h" + + +ModPlayer::ModPlayer(Mixer *mixer, FileSystem *fs) + : _playing(false), _mix(mixer), _fs(fs) { + memset(&_modInfo, 0, sizeof(_modInfo)); +} + +uint16_t ModPlayer::findPeriod(uint16_t period, uint8_t fineTune) const { + for (int p = 0; p < 36; ++p) { + if (_periodTable[p] == period) { + return fineTune * 36 + p; + } + } + error("Invalid period=%d", period); + return 0; +} + +void ModPlayer::load(File *f) { + f->read(_modInfo.songName, 20); + _modInfo.songName[20] = 0; + debug(DBG_MOD, "songName = '%s'", _modInfo.songName); + + for (int s = 0; s < NUM_SAMPLES; ++s) { + SampleInfo *si = &_modInfo.samples[s]; + f->read(si->name, 22); + si->name[22] = 0; + si->len = f->readUint16BE() * 2; + si->fineTune = f->readByte(); + si->volume = f->readByte(); + si->repeatPos = f->readUint16BE() * 2; + si->repeatLen = f->readUint16BE() * 2; + si->data = 0; + assert(si->len == 0 || si->repeatPos + si->repeatLen <= si->len); + debug(DBG_MOD, "sample=%d name='%s' len=%d vol=%d", s, si->name, si->len, si->volume); + } + _modInfo.numPatterns = f->readByte(); + assert(_modInfo.numPatterns < NUM_PATTERNS); + f->readByte(); // 0x7F + f->read(_modInfo.patternOrderTable, NUM_PATTERNS); + f->readUint32BE(); // 'M.K.', Protracker, 4 channels + + uint16_t n = 0; + for (int i = 0; i < NUM_PATTERNS; ++i) { + if (_modInfo.patternOrderTable[i] != 0) { + n = MAX(n, _modInfo.patternOrderTable[i]); + } + } + debug(DBG_MOD, "numPatterns=%d",n + 1); + n = (n + 1) * 64 * 4 * 4; // 64 lines of 4 notes per channel + _modInfo.patternsTable = (uint8_t *)malloc(n); + assert(_modInfo.patternsTable); + f->read(_modInfo.patternsTable, n); + + for (int s = 0; s < NUM_SAMPLES; ++s) { + SampleInfo *si = &_modInfo.samples[s]; + if (si->len != 0) { + si->data = (int8_t *)malloc(si->len); + if (si->data) { + f->read(si->data, si->len); + } + } + } +} + +void ModPlayer::unload() { + if (_modInfo.songName[0]) { + free(_modInfo.patternsTable); + for (int s = 0; s < NUM_SAMPLES; ++s) { + free(_modInfo.samples[s].data); + } + memset(&_modInfo, 0, sizeof(_modInfo)); + } +} + +void ModPlayer::play(uint8_t num) { + if (!_playing && num < _modulesFilesCount) { + File f; + bool found = false; + for (uint8_t i = 0; i < ARRAYSIZE(_modulesFiles[num]); ++i) { + if (f.open(_modulesFiles[num][i], "rb", _fs)) { + found = true; + break; + } + } + if (!found) { + warning("Can't find music file %d", num); + } else { + load(&f); + _currentPatternOrder = 0; + _currentPatternPos = 0; + _currentTick = 0; + _patternDelay = 0; + _songSpeed = 6; + _songTempo = 125; + _patternLoopPos = 0; + _patternLoopCount = -1; + _samplesLeft = 0; + _songNum = num; + _introSongHack = false; + memset(_tracks, 0, sizeof(_tracks)); + _mix->setPremixHook(mixCallback, this); + _playing = true; + } + } +} + +void ModPlayer::stop() { + if (_playing) { + _mix->setPremixHook(0, 0); + _playing = false; + } + unload(); +} + +void ModPlayer::handleNote(int trackNum, uint32_t noteData) { + Track *tk = &_tracks[trackNum]; + uint16_t sampleNum = ((noteData >> 24) & 0xF0) | ((noteData >> 12) & 0xF); + uint16_t samplePeriod = (noteData >> 16) & 0xFFF; + uint16_t effectData = noteData & 0xFFF; + debug(DBG_MOD, "ModPlayer::handleNote(%d) p=%d/%d sampleNumber=0x%X samplePeriod=0x%X effectData=0x%X tk->period=%d", trackNum, _currentPatternPos, _currentPatternOrder, sampleNum, samplePeriod, effectData, tk->period); + if (sampleNum != 0) { + tk->sample = &_modInfo.samples[sampleNum - 1]; + tk->volume = tk->sample->volume; + tk->pos = 0; + } + if (samplePeriod != 0) { + tk->periodIndex = findPeriod(samplePeriod, tk->sample->fineTune); + if ((effectData >> 8) != 0x3 && (effectData >> 8) != 0x5) { + tk->period = _periodTable[tk->periodIndex]; + tk->freq = PAULA_FREQ / tk->period; + } else { + tk->portamento = _periodTable[tk->periodIndex]; + } + tk->vibratoAmp = 0; + tk->vibratoSpeed = 0; + tk->vibratoPos = 0; + } + tk->effectData = effectData; +} + +void ModPlayer::applyVolumeSlide(int trackNum, int amount) { + debug(DBG_MOD, "ModPlayer::applyVolumeSlide(%d, %d)", trackNum, amount); + Track *tk = &_tracks[trackNum]; + int vol = tk->volume + amount; + if (vol < 0) { + vol = 0; + } else if (vol > 64) { + vol = 64; + } + tk->volume = vol; +} + +void ModPlayer::applyVibrato(int trackNum) { + debug(DBG_MOD, "ModPlayer::applyVibrato(%d)", trackNum); + Track *tk = &_tracks[trackNum]; + int vib = tk->vibratoAmp * _sineWaveTable[tk->vibratoPos] / 128; + if (tk->period + vib != 0) { + tk->freq = PAULA_FREQ / (tk->period + vib); + } + tk->vibratoPos += tk->vibratoSpeed; + if (tk->vibratoPos >= 64) { + tk->vibratoPos = 0; + } +} + +void ModPlayer::applyPortamento(int trackNum) { + debug(DBG_MOD, "ModPlayer::applyPortamento(%d)", trackNum); + Track *tk = &_tracks[trackNum]; + if (tk->period < tk->portamento) { + tk->period = MIN(tk->period + tk->portamentoSpeed, tk->portamento); + } else if (tk->period > tk->portamento) { + tk->period = MAX(tk->period - tk->portamentoSpeed, tk->portamento); + } + if (tk->period != 0) { + tk->freq = PAULA_FREQ / tk->period; + } +} + +void ModPlayer::handleEffect(int trackNum, bool tick) { + Track *tk = &_tracks[trackNum]; + uint8_t effectNum = tk->effectData >> 8; + uint8_t effectXY = tk->effectData & 0xFF; + uint8_t effectX = effectXY >> 4; + uint8_t effectY = effectXY & 0xF; + debug(DBG_MOD, "ModPlayer::handleEffect(%d) effectNum=0x%X effectXY=0x%X", trackNum, effectNum, effectXY); + switch (effectNum) { + case 0x0: // arpeggio + if (tick && effectXY != 0) { + uint16_t period = tk->period; + switch (_currentTick & 3) { + case 1: + period = _periodTable[tk->periodIndex + effectX]; + break; + case 2: + period = _periodTable[tk->periodIndex + effectY]; + break; + } + tk->freq = PAULA_FREQ / period; + } + break; + case 0x1: // portamento up + if (tick) { + tk->period -= effectXY; + if (tk->period < 113) { // note B-3 + tk->period = 113; + } + tk->freq = PAULA_FREQ / tk->period; + } + break; + case 0x2: // portamento down + if (tick) { + tk->period += effectXY; + if (tk->period > 856) { // note C-1 + tk->period = 856; + } + tk->freq = PAULA_FREQ / tk->period; + } + break; + case 0x3: // tone portamento + if (!tick) { + if (effectXY != 0) { + tk->portamentoSpeed = effectXY; + } + } else { + applyPortamento(trackNum); + } + break; + case 0x4: // vibrato + if (!tick) { + if (effectX != 0) { + tk->vibratoSpeed = effectX; + } + if (effectY != 0) { + tk->vibratoAmp = effectY; + } + } else { + applyVibrato(trackNum); + } + break; + case 0x5: // tone portamento + volume slide + if (tick) { + applyPortamento(trackNum); + applyVolumeSlide(trackNum, effectX - effectY); + } + break; + case 0x6: // vibrato + volume slide + if (tick) { + applyVibrato(trackNum); + applyVolumeSlide(trackNum, effectX - effectY); + } + break; + case 0x9: // set sample offset + if (!tick) { + tk->pos = effectXY << (8 + FRAC_BITS); + } + break; + case 0xA: // volume slide + if (tick) { + applyVolumeSlide(trackNum, effectX - effectY); + } + break; + case 0xB: // position jump + if (!tick) { + _currentPatternOrder = effectXY; + _currentPatternPos = 0; + assert(_currentPatternOrder < _modInfo.numPatterns); + } + break; + case 0xC: // set volume + if (!tick) { + assert(effectXY <= 64); + tk->volume = effectXY; + } + break; + case 0xD: // pattern break + if (!tick) { + _currentPatternPos = effectX * 10 + effectY; + assert(_currentPatternPos < 64); + ++_currentPatternOrder; + debug(DBG_MOD, "_currentPatternPos = %d _currentPatternOrder = %d", _currentPatternPos, _currentPatternOrder); + } + break; + case 0xE: // extended effects + switch (effectX) { + case 0x0: // set filter, ignored + break; + case 0x1: // fineslide up + if (!tick) { + tk->period -= effectY; + if (tk->period < 113) { // B-3 note + tk->period = 113; + } + tk->freq = PAULA_FREQ / tk->period; + } + break; + case 0x2: // fineslide down + if (!tick) { + tk->period += effectY; + if (tk->period > 856) { // C-1 note + tk->period = 856; + } + tk->freq = PAULA_FREQ / tk->period; + } + break; + case 0x6: // loop pattern + if (!tick) { + if (effectY == 0) { + _patternLoopPos = _currentPatternPos | (_currentPatternOrder << 8); + debug(DBG_MOD, "_patternLoopPos=%d/%d", _currentPatternPos, _currentPatternOrder); + } else { + if (_patternLoopCount == -1) { + _patternLoopCount = effectY; + _currentPatternPos = _patternLoopPos & 0xFF; + _currentPatternOrder = _patternLoopPos >> 8; + } else { + --_patternLoopCount; + if (_patternLoopCount != 0) { + _currentPatternPos = _patternLoopPos & 0xFF; + _currentPatternOrder = _patternLoopPos >> 8; + } else { + _patternLoopCount = -1; + } + } + debug(DBG_MOD, "_patternLoopCount=%d", _patternLoopCount); + } + } + break; + case 0x9: // retrigger sample + if (tick) { + tk->retriggerCounter = effectY; + } else { + if (tk->retriggerCounter == 0) { + tk->pos = 0; + tk->retriggerCounter = effectY; + debug(DBG_MOD, "retrigger sample=%d _songSpeed=%d", effectY, _songSpeed); + } + --tk->retriggerCounter; + } + break; + case 0xA: // fine volume slide up + if (!tick) { + applyVolumeSlide(trackNum, effectY); + } + break; + case 0xB: // fine volume slide down + if (!tick) { + applyVolumeSlide(trackNum, -effectY); + } + break; + case 0xC: // cut sample + if (!tick) { + tk->cutCounter = effectY; + } else { + --tk->cutCounter; + if (tk->cutCounter == 0) { + tk->volume = 0; + } + } + case 0xD: // delay sample + if (!tick) { + tk->delayCounter = effectY; + } else { + if (tk->delayCounter != 0) { + --tk->delayCounter; + } + } + break; + case 0xE: // delay pattern + if (!tick) { + debug(DBG_MOD, "ModPlayer::handleEffect() _currentTick=%d delay pattern=%d", _currentTick, effectY); + _patternDelay = effectY; + } + break; + default: + warning("Unhandled extended effect 0x%X params=0x%X", effectX, effectY); + break; + } + break; + case 0xF: // set speed + if (!tick) { + if (effectXY < 0x20) { + _songSpeed = effectXY; + } else { + _songTempo = effectXY; + } + } + break; + default: + warning("Unhandled effect 0x%X params=0x%X", effectNum, effectXY); + break; + } +} + +void ModPlayer::handleTick() { + if (!_playing) { + return; + } +// if (_patternDelay != 0) { +// --_patternDelay; +// return; +// } + if (_currentTick == 0) { + debug(DBG_MOD, "_currentPatternOrder=%d _currentPatternPos=%d", _currentPatternOrder, _currentPatternPos); + uint8_t currentPattern = _modInfo.patternOrderTable[_currentPatternOrder]; + const uint8_t *p = _modInfo.patternsTable + (currentPattern * 64 + _currentPatternPos) * 16; + for (int i = 0; i < NUM_TRACKS; ++i) { + uint32_t noteData = READ_BE_UINT32(p); + handleNote(i, noteData); + p += 4; + } + ++_currentPatternPos; + if (_currentPatternPos == 64) { + ++_currentPatternOrder; + _currentPatternPos = 0; + debug(DBG_MOD, "ModPlayer::handleTick() _currentPatternOrder = %d/%d", _currentPatternOrder, _modInfo.numPatterns); + // On the amiga version, the introduction cutscene is shorter than the PC version ; + // so the music module doesn't synchronize at all with the PC datafiles, here we + // add a hack to let the music play longer + if (_songNum == 0 && _currentPatternOrder == 3 && !_introSongHack) { + _currentPatternOrder = 1; + _introSongHack = true; +// warning("Introduction module synchronization hack"); + } + } + } + for (int i = 0; i < NUM_TRACKS; ++i) { + handleEffect(i, (_currentTick != 0)); + } + ++_currentTick; + if (_currentTick == _songSpeed) { + _currentTick = 0; + } + if (_currentPatternOrder == _modInfo.numPatterns) { + debug(DBG_MOD, "ModPlayer::handleEffect() _currentPatternOrder == _modInfo.numPatterns"); + _playing = false; + } +} + +void ModPlayer::mixSamples(int8_t *buf, int samplesLen) { + for (int i = 0; i < NUM_TRACKS; ++i) { + Track *tk = &_tracks[i]; + if (tk->sample != 0 && tk->delayCounter == 0) { + int8_t *mixbuf = buf; + SampleInfo *si = tk->sample; + int len = si->len << FRAC_BITS; + int loopLen = si->repeatLen << FRAC_BITS; + int loopPos = si->repeatPos << FRAC_BITS; + int deltaPos = (tk->freq << FRAC_BITS) / _mix->getSampleRate(); + int curLen = samplesLen; + int pos = tk->pos; + while (curLen != 0) { + int count; + if (loopLen > (2 << FRAC_BITS)) { + if (pos >= loopPos + loopLen) { + pos -= loopLen; + } + count = MIN(curLen, (loopPos + loopLen - pos - 1) / deltaPos + 1); + curLen -= count; + } else { + if (pos >= len) { + count = 0; + } else { + count = MIN(curLen, (len - pos - 1) / deltaPos + 1); + } + curLen = 0; + } + while (count--) { + int out = resampleLinear(si, pos, deltaPos, FRAC_BITS); + Mixer::addclamp(*mixbuf++, out * tk->volume / 64); + pos += deltaPos; + } + } + tk->pos = pos; + } + } +} + +bool ModPlayer::mix(int8_t *buf, int len) { + if (_playing) { + memset(buf, 0, len); + const int samplesPerTick = _mix->getSampleRate() / (50 * _songTempo / 125); + while (len != 0) { + if (_samplesLeft == 0) { + handleTick(); + _samplesLeft = samplesPerTick; + } + int count = _samplesLeft; + if (count > len) { + count = len; + } + _samplesLeft -= count; + len -= count; + mixSamples(buf, count); + buf += count; + } + } + return _playing; +} + +bool ModPlayer::mixCallback(void *param, int8_t *buf, int len) { + return ((ModPlayer *)param)->mix(buf, len); +} diff --git a/mod_player.h b/mod_player.h new file mode 100644 index 0000000..4ae6683 --- /dev/null +++ b/mod_player.h @@ -0,0 +1,122 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef MOD_PLAYER_H__ +#define MOD_PLAYER_H__ + +#include "intern.h" + +struct File; +struct FileSystem; +struct Mixer; + +struct ModPlayer { + enum { + NUM_SAMPLES = 31, + NUM_TRACKS = 4, + NUM_PATTERNS = 128, + FRAC_BITS = 12, + PAULA_FREQ = 3546897 + }; + + struct SampleInfo { + char name[23]; + uint16_t len; + uint8_t fineTune; + uint8_t volume; + uint16_t repeatPos; + uint16_t repeatLen; + int8_t *data; + + int8_t getPCM(int offset) const { + if (offset < 0) { + offset = 0; + } else if (offset >= (int)len) { + offset = len - 1; + } + return data[offset]; + } + }; + + struct ModuleInfo { + char songName[21]; + SampleInfo samples[NUM_SAMPLES]; + uint8_t numPatterns; + uint8_t patternOrderTable[NUM_PATTERNS]; + uint8_t *patternsTable; + }; + + struct Track { + SampleInfo *sample; + uint8_t volume; + int pos; + int freq; + uint16_t period; + uint16_t periodIndex; + uint16_t effectData; + int vibratoSpeed; + int vibratoAmp; + int vibratoPos; + int portamento; + int portamentoSpeed; + int retriggerCounter; + int delayCounter; + int cutCounter; + }; + + static const int8_t _sineWaveTable[]; + static const uint16_t _periodTable[]; + static const char *_modulesFiles[][2]; + static const int _modulesFilesCount; + + ModuleInfo _modInfo; + uint8_t _currentPatternOrder; + uint8_t _currentPatternPos; + uint8_t _currentTick; + uint8_t _songSpeed; + uint8_t _songTempo; + int _patternDelay; + int _patternLoopPos; + int _patternLoopCount; + int _samplesLeft; + uint8_t _songNum; + bool _introSongHack; + bool _playing; + Track _tracks[NUM_TRACKS]; + Mixer *_mix; + FileSystem *_fs; + + ModPlayer(Mixer *mixer, FileSystem *fs); + + uint16_t findPeriod(uint16_t period, uint8_t fineTune) const; + void load(File *f); + void unload(); + void play(uint8_t num); + void stop(); + void handleNote(int trackNum, uint32_t noteData); + void handleTick(); + void applyVolumeSlide(int trackNum, int amount); + void applyVibrato(int trackNum); + void applyPortamento(int trackNum); + void handleEffect(int trackNum, bool tick); + void mixSamples(int8_t *buf, int len); + bool mix(int8_t *buf, int len); + + static bool mixCallback(void *param, int8_t *buf, int len); +}; + +#endif // MOD_PLAYER_H__ diff --git a/ogg_player.cpp b/ogg_player.cpp new file mode 100644 index 0000000..0daf5f7 --- /dev/null +++ b/ogg_player.cpp @@ -0,0 +1,214 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef USE_TREMOR +#include +#endif +#include "file.h" +#include "mixer.h" +#include "ogg_player.h" + +#ifdef USE_TREMOR +struct VorbisFile: File { + uint32_t offset; + + static size_t readHelper(void *ptr, size_t size, size_t nmemb, void *datasource) { + VorbisFile *vf = (VorbisFile *)datasource; + if (size != 0 && nmemb != 0) { + const int n = vf->read(ptr, size * nmemb); + if (n > 0) { + vf->offset += n; + return n / size; + } + } + return 0; + } + static int seekHelper(void *datasource, ogg_int64_t offset, int whence) { + VorbisFile *vf = (VorbisFile *)datasource; + switch (whence) { + case SEEK_SET: + vf->offset = offset; + break; + case SEEK_CUR: + vf->offset += offset; + break; + case SEEK_END: + vf->offset = vf->size() + offset; + break; + } + vf->seek(vf->offset); + return 0; + } + static int closeHelper(void *datasource) { + VorbisFile *vf = (VorbisFile *)datasource; + vf->close(); + delete vf; + return 0; + } + static long tellHelper(void *datasource) { + VorbisFile *vf = (VorbisFile *)datasource; + return vf->offset; + } +}; + +struct OggDecoder_impl { + OggDecoder_impl() + : _open(false), _readBuf(0), _readBufSize(0) { + } + ~OggDecoder_impl() { + free(_readBuf); + _readBuf = 0; + if (_open) { + ov_clear(&_ovf); + } + } + + bool load(VorbisFile *f, int mixerSampleRate) { + ov_callbacks ovcb; + ovcb.read_func = VorbisFile::readHelper; + ovcb.seek_func = VorbisFile::seekHelper; + ovcb.close_func = VorbisFile::closeHelper; + ovcb.tell_func = VorbisFile::tellHelper; + if (ov_open_callbacks(f, &_ovf, 0, 0, ovcb) < 0) { + warning("Invalid .ogg file"); + return false; + } + _open = true; + vorbis_info *vi = ov_info(&_ovf, -1); + if ((vi->channels != 1 && vi->channels != 2) || vi->rate != mixerSampleRate) { + warning("Unhandled ogg/pcm format ch %d rate %d", vi->channels, vi->rate); + return false; + } + _channels = vi->channels; + return true; + } + int read(int8_t *dst, int samples) { + int size = samples * _channels * sizeof(int16_t); + if (size > _readBufSize) { + _readBufSize = size; + free(_readBuf); + _readBuf = (int16_t *)malloc(_readBufSize); + if (!_readBuf) { + return 0; + } + } + int count = 0; + while (size > 0) { + const int len = ov_read(&_ovf, (char *)_readBuf, size, 0); + if (len < 0) { + // error in decoder + return 0; + } else if (len == 0) { + // loop + ov_raw_seek(&_ovf, 0); + continue; + } + switch (_channels) { + case 2: + assert((len & 1) == 0); + for (int i = 0; i < len / 2; i += 2) { + Mixer::addclamp(*dst++, ((_readBuf[i] + _readBuf[i + 1]) / 2) >> 8); + } + break; + case 1: + for (int i = 0; i < len / 2; ++i) { + Mixer::addclamp(*dst++, _readBuf[i] >> 8); + } + break; + } + size -= len; + count += len; + } + assert(size == 0); + return count; + } + + OggVorbis_File _ovf; + int _channels; + bool _open; + int16_t *_readBuf; + int _readBufSize; +}; +#endif + +OggPlayer::OggPlayer(Mixer *mixer, FileSystem *fs) + : _mix(mixer), _fs(fs), _impl(0) { +} + +OggPlayer::~OggPlayer() { +#ifdef USE_TREMOR + delete _impl; +#endif +} + +bool OggPlayer::playTrack(int num) { +#ifdef USE_TREMOR + stopTrack(); + char buf[16]; + snprintf(buf, sizeof(buf), "track%02d.ogg", num); + VorbisFile *vf = new VorbisFile; + if (vf->open(buf, "rb", _fs)) { + vf->offset = 0; + _impl = new OggDecoder_impl(); + if (_impl->load(vf, _mix->getSampleRate())) { + debug(DBG_INFO, "Playing '%s'", buf); + _mix->setPremixHook(mixCallback, this); + return true; + } + } + delete vf; +#endif + return false; +} + +void OggPlayer::stopTrack() { +#ifdef USE_TREMOR + _mix->setPremixHook(0, 0); + delete _impl; + _impl = 0; +#endif +} + +void OggPlayer::pauseTrack() { +#ifdef USE_TREMOR + if (_impl) { + _mix->setPremixHook(0, 0); + } +#endif +} + +void OggPlayer::resumeTrack() { +#ifdef USE_TREMOR + if (_impl) { + _mix->setPremixHook(mixCallback, this); + } +#endif +} + +bool OggPlayer::mix(int8_t *buf, int len) { +#ifdef USE_TREMOR + if (_impl) { + return _impl->read(buf, len) != 0; + } +#endif + return false; +} + +bool OggPlayer::mixCallback(void *param, int8_t *buf, int len) { + return ((OggPlayer *)param)->mix(buf, len); +} + diff --git a/ogg_player.h b/ogg_player.h new file mode 100644 index 0000000..9d11d7e --- /dev/null +++ b/ogg_player.h @@ -0,0 +1,45 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef OGG_PLAYER_H__ +#define OGG_PLAYER_H__ + +#include "intern.h" + +struct FileSystem; +struct Mixer; +struct OggDecoder_impl; + +struct OggPlayer { + OggPlayer(Mixer *mixer, FileSystem *fs); + ~OggPlayer(); + + bool playTrack(int num); + void stopTrack(); + void pauseTrack(); + void resumeTrack(); + bool isPlaying() const { return _impl != 0; } + bool mix(int8_t *buf, int len); + static bool mixCallback(void *param, int8_t *buf, int len); + + Mixer *_mix; + FileSystem *_fs; + OggDecoder_impl *_impl; +}; + +#endif // OGG_PLAYER_H__ + diff --git a/piege.cpp b/piege.cpp new file mode 100644 index 0000000..1ebe781 --- /dev/null +++ b/piege.cpp @@ -0,0 +1,2264 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "cutscene.h" +#include "resource.h" +#include "systemstub.h" +#include "game.h" + + +void Game::pge_resetGroups() { + memset(_pge_groupsTable, 0, sizeof(_pge_groupsTable)); + GroupPGE *le = &_pge_groups[0]; + _pge_nextFreeGroup = le; + int n = 0xFF; + while (n--) { + le->next_entry = le + 1; + le->index = 0; + le->group_id = 0; + ++le; + } + le->next_entry = 0; + le->index = 0; + le->group_id = 0; +} + +void Game::pge_removeFromGroup(uint8_t idx) { + GroupPGE *le = _pge_groupsTable[idx]; + if (le) { + _pge_groupsTable[idx] = 0; + GroupPGE *next = _pge_nextFreeGroup; + while (le) { + GroupPGE *cur = le->next_entry; + le->next_entry = next; + le->index = 0; + le->group_id = 0; + next = le; + le = cur; + } + _pge_nextFreeGroup = next; + } +} + +int Game::pge_isInGroup(LivePGE *pge_dst, uint16_t group_id, uint16_t counter) { + assert(counter >= 1 && counter <= 4); + uint16_t c = pge_dst->init_PGE->counter_values[counter - 1]; + GroupPGE *le = _pge_groupsTable[pge_dst->index]; + while (le) { + if (le->group_id == group_id && le->index == c) + return 1; + le = le->next_entry; + } + return 0; +} + +void Game::pge_loadForCurrentLevel(uint16_t idx) { + debug(DBG_PGE, "Game::pge_loadForCurrentLevel() idx=%d", idx); + + LivePGE *live_pge = &_pgeLive[idx]; + InitPGE *init_pge = &_res._pgeInit[idx]; + + live_pge->init_PGE = init_pge; + live_pge->obj_type = init_pge->type; + live_pge->pos_x = init_pge->pos_x; + live_pge->pos_y = init_pge->pos_y; + live_pge->anim_seq = 0; + live_pge->room_location = init_pge->init_room; + + live_pge->life = init_pge->life; + if (_skillLevel >= 2 && init_pge->object_type == 10) { + live_pge->life *= 2; + } + live_pge->counter_value = 0; + live_pge->collision_slot = 0xFF; + live_pge->next_inventory_PGE = 0xFF; + live_pge->current_inventory_PGE = 0xFF; + live_pge->unkF = 0xFF; + live_pge->anim_number = 0; + live_pge->index = idx; + live_pge->next_PGE_in_room = 0; + + uint16_t flags = 0; + if (init_pge->skill <= _skillLevel) { + if (init_pge->room_location != 0 || ((init_pge->flags & 4) && (_currentRoom == init_pge->init_room))) { + flags |= 4; + _pge_liveTable2[idx] = live_pge; + } + if (init_pge->mirror_x != 0) { + flags |= 1; + } + if (init_pge->init_flags & 8) { + flags |= 0x10; + } + flags |= (init_pge->init_flags & 3) << 5; + if (init_pge->flags & 2) { + flags |= 0x80; + } + live_pge->flags = flags; + assert(init_pge->obj_node_number < _res._numObjectNodes); + ObjectNode *on = _res._objectNodesMap[init_pge->obj_node_number]; + Object *obj = on->objects; + int i = 0; + while (obj->type != live_pge->obj_type) { + ++i; + ++obj; + } + assert(i < on->num_objects); + live_pge->first_obj_number = i; + pge_setupDefaultAnim(live_pge); + } +} + +void Game::pge_process(LivePGE *pge) { + debug(DBG_PGE, "Game::pge_process() pge_num=%d", pge - &_pgeLive[0]); + _pge_playAnimSound = true; + _pge_currentPiegeFacingDir = (pge->flags & 1) != 0; + _pge_currentPiegeRoom = pge->room_location; + GroupPGE *le = _pge_groupsTable[pge->index]; + if (le) { + pge_setupNextAnimFrame(pge, le); + } + const uint8_t *anim_data = _res.getAniData(pge->obj_type); + if (READ_LE_UINT16(anim_data) <= pge->anim_seq) { + InitPGE *init_pge = pge->init_PGE; + assert(init_pge->obj_node_number < _res._numObjectNodes); + ObjectNode *on = _res._objectNodesMap[init_pge->obj_node_number]; + Object *obj = &on->objects[pge->first_obj_number]; + while (1) { + if (obj->type != pge->obj_type) { + pge_removeFromGroup(pge->index); + return; + } + uint16_t _ax = pge_execute(pge, init_pge, obj); + if (_ax != 0) { + anim_data = _res.getAniData(pge->obj_type); + uint8_t snd = anim_data[2]; + if (snd) { + pge_playAnimSound(pge, snd); + } + pge_setupOtherPieges(pge, init_pge); + break; + } + ++obj; + } + } + pge_setupAnim(pge); + ++pge->anim_seq; + pge_removeFromGroup(pge->index); +} + +void Game::pge_setupNextAnimFrame(LivePGE *pge, GroupPGE *le) { + InitPGE *init_pge = pge->init_PGE; + assert(init_pge->obj_node_number < _res._numObjectNodes); + ObjectNode *on = _res._objectNodesMap[init_pge->obj_node_number]; + Object *obj = &on->objects[pge->first_obj_number]; + int i = pge->first_obj_number; + while (i < on->last_obj_number && pge->obj_type == obj->type) { + GroupPGE *next_le = le; + while (next_le) { + uint16_t groupId = next_le->group_id; + if (obj->opcode2 == 0x6B) { // pge_op_isInGroupSlice + if (obj->opcode_arg2 == 0) { + if (groupId == 1 || groupId == 2) goto set_anim; + } + if (obj->opcode_arg2 == 1) { + if (groupId == 3 || groupId == 4) goto set_anim; + } + } else if (groupId == obj->opcode_arg2) { + if (obj->opcode2 == 0x22 || obj->opcode2 == 0x6F) goto set_anim; + } + if (obj->opcode1 == 0x6B) { // pge_op_isInGroupSlice + if (obj->opcode_arg1 == 0) { + if (groupId == 1 || groupId == 2) goto set_anim; + } + if (obj->opcode_arg1 == 1) { + if (groupId == 3 || groupId == 4) goto set_anim; + } + } else if (groupId == obj->opcode_arg1) { + if (obj->opcode1 == 0x22 || obj->opcode1 == 0x6F) goto set_anim; + } + next_le = next_le->next_entry; + } + ++obj; + ++i; + } + return; + +set_anim: + const uint8_t *anim_data = _res.getAniData(pge->obj_type); + uint8_t _dh = READ_LE_UINT16(anim_data); + uint8_t _dl = pge->anim_seq; + const uint8_t *anim_frame = anim_data + 6 + _dl * 4; + while (_dh > _dl) { + if (READ_LE_UINT16(anim_frame) != 0xFFFF) { + if (_pge_currentPiegeFacingDir) { + pge->pos_x -= (int8_t)anim_frame[2]; + } else { + pge->pos_x += (int8_t)anim_frame[2]; + } + pge->pos_y += (int8_t)anim_frame[3]; + } + anim_frame += 4; + ++_dl; + } + pge->anim_seq = _dh; + _col_currentPiegeGridPosY = (pge->pos_y / 36) & ~1; + _col_currentPiegeGridPosX = (pge->pos_x + 8) >> 4; +} + +void Game::pge_playAnimSound(LivePGE *pge, uint16_t arg2) { + if ((pge->flags & 4) && _pge_playAnimSound) { + uint8_t sfxId = (arg2 & 0xFF) - 1; + if (_currentRoom == pge->room_location) { + playSound(sfxId, 0); + } else { + if (_res._ctData[CT_DOWN_ROOM + _currentRoom] == pge->room_location || + _res._ctData[CT_UP_ROOM + _currentRoom] == pge->room_location || + _res._ctData[CT_RIGHT_ROOM + _currentRoom] == pge->room_location || + _res._ctData[CT_LEFT_ROOM + _currentRoom] == pge->room_location) { + playSound(sfxId, 1); + } + } + } +} + +void Game::pge_setupAnim(LivePGE *pge) { + debug(DBG_PGE, "Game::pge_setupAnim() pgeNum=%d", pge - &_pgeLive[0]); + const uint8_t *anim_data = _res.getAniData(pge->obj_type); + if (READ_LE_UINT16(anim_data) < pge->anim_seq) { + pge->anim_seq = 0; + } + const uint8_t *anim_frame = anim_data + 6 + pge->anim_seq * 4; + if (READ_LE_UINT16(anim_frame) != 0xFFFF) { + uint16_t fl = READ_LE_UINT16(anim_frame); + if (pge->flags & 1) { + fl ^= 0x8000; + pge->pos_x -= (int8_t)anim_frame[2]; + } else { + pge->pos_x += (int8_t)anim_frame[2]; + } + pge->pos_y += (int8_t)anim_frame[3]; + pge->flags &= ~2; + if (fl & 0x8000) { + pge->flags |= 2; + } + pge->flags &= ~8; + if (READ_LE_UINT16(anim_data + 4) & 0xFFFF) { + pge->flags |= 8; + } + pge->anim_number = READ_LE_UINT16(anim_frame) & 0x7FFF; + } +} + +int Game::pge_execute(LivePGE *live_pge, InitPGE *init_pge, const Object *obj) { + debug(DBG_PGE, "Game::pge_execute() pge_num=%d op1=0x%X op2=0x%X op3=0x%X", live_pge - &_pgeLive[0], obj->opcode1, obj->opcode2, obj->opcode3); + pge_OpcodeProc op; + ObjectOpcodeArgs args; + if (obj->opcode1) { + args.pge = live_pge; + args.a = obj->opcode_arg1; + args.b = 0; + debug(DBG_PGE, "pge_execute op1=0x%X", obj->opcode1); + op = _pge_opcodeTable[obj->opcode1]; + if (!op) { + warning("Game::pge_execute() missing call to pge_opcode 0x%X", obj->opcode1); + return 0; + } + if (!((this->*op)(&args) & 0xFF)) + return 0; + } + if (obj->opcode2) { + args.pge = live_pge; + args.a = obj->opcode_arg2; + args.b = obj->opcode_arg1; + debug(DBG_PGE, "pge_execute op2=0x%X", obj->opcode2); + op = _pge_opcodeTable[obj->opcode2]; + if (!op) { + warning("Game::pge_execute() missing call to pge_opcode 0x%X", obj->opcode2); + return 0; + } + if (!((this->*op)(&args) & 0xFF)) + return 0; + } + if (obj->opcode3) { + args.pge = live_pge; + args.a = obj->opcode_arg3; + args.b = 0; + debug(DBG_PGE, "pge_execute op3=0x%X", obj->opcode3); + op = _pge_opcodeTable[obj->opcode3]; + if (op) { + (this->*op)(&args); + } else { + warning("Game::pge_execute() missing call to pge_opcode 0x%X", obj->opcode3); + } + } + live_pge->obj_type = obj->init_obj_type; + live_pge->first_obj_number = obj->init_obj_number; + live_pge->anim_seq = 0; + if (obj->flags & 0xF0) { + _score += _scoreTable[obj->flags >> 4]; + } + if (obj->flags & 1) { + live_pge->flags ^= 1; + } + if (obj->flags & 2) { + --live_pge->life; + if (init_pge->object_type == 1) { + _pge_processOBJ = true; + } else if (init_pge->object_type == 10) { + _score += 100; + } + } + if (obj->flags & 4) { + ++live_pge->life; + } + if (obj->flags & 8) { + live_pge->life = 0xFFFF; + } + + if (live_pge->flags & 1) { + live_pge->pos_x -= obj->dx; + } else { + live_pge->pos_x += obj->dx; + } + live_pge->pos_y += obj->dy; + + if (_pge_processOBJ) { + if (init_pge->object_type == 1) { + if (pge_processOBJ(live_pge) != 0) { + _blinkingConradCounter = 60; + _pge_processOBJ = false; + } + } + } + return 0xFFFF; +} + +void Game::pge_prepare() { + col_clearState(); + if (!(_currentRoom & 0x80)) { + LivePGE *pge = _pge_liveTable1[_currentRoom]; + while (pge) { + col_preparePiegeState(pge); + if (!(pge->flags & 4) && (pge->init_PGE->flags & 4)) { + _pge_liveTable2[pge->index] = pge; + pge->flags |= 4; + } + pge = pge->next_PGE_in_room; + } + } + for (uint16_t i = 0; i < _res._pgeNum; ++i) { + LivePGE *pge = _pge_liveTable2[i]; + if (pge && _currentRoom != pge->room_location) { + col_preparePiegeState(pge); + } + } +} + +void Game::pge_setupDefaultAnim(LivePGE *pge) { + const uint8_t *anim_data = _res.getAniData(pge->obj_type); + if (pge->anim_seq < READ_LE_UINT16(anim_data)) { + pge->anim_seq = 0; + } + const uint8_t *anim_frame = anim_data + 6 + pge->anim_seq * 4; + if (READ_LE_UINT16(anim_frame) != 0xFFFF) { + uint16_t f = READ_LE_UINT16(anim_data); + if (pge->flags & 1) { + f ^= 0x8000; + } + pge->flags &= ~2; + if (f & 0x8000) { + pge->flags |= 2; + } + pge->flags &= ~8; + if (READ_LE_UINT16(anim_data + 4) & 0xFFFF) { + pge->flags |= 8; + } + pge->anim_number = READ_LE_UINT16(anim_frame) & 0x7FFF; + debug(DBG_PGE, "Game::pge_setupDefaultAnim() pgeNum=%d pge->flags=0x%X pge->anim_number=0x%X pge->anim_seq=0x%X", pge - &_pgeLive[0], pge->flags, pge->anim_number, pge->anim_seq); + } +} + +uint16_t Game::pge_processOBJ(LivePGE *pge) { + InitPGE *init_pge = pge->init_PGE; + assert(init_pge->obj_node_number < _res._numObjectNodes); + ObjectNode *on = _res._objectNodesMap[init_pge->obj_node_number]; + Object *obj = &on->objects[pge->first_obj_number]; + int i = pge->first_obj_number; + while (i < on->last_obj_number && pge->obj_type == obj->type) { + if (obj->opcode2 == 0x6B) return 0xFFFF; + if (obj->opcode2 == 0x22 && obj->opcode_arg2 <= 4) return 0xFFFF; + + if (obj->opcode1 == 0x6B) return 0xFFFF; + if (obj->opcode1 == 0x22 && obj->opcode_arg1 <= 4) return 0xFFFF; + + ++obj; + ++i; + } + return 0; +} + +void Game::pge_setupOtherPieges(LivePGE *pge, InitPGE *init_pge) { + const int8_t *room_ct_data = 0; + if (pge->pos_x <= -10) { + pge->pos_x += 256; + room_ct_data = &_res._ctData[CT_LEFT_ROOM]; + } else if (pge->pos_x >= 256) { + pge->pos_x -= 256; + room_ct_data = &_res._ctData[CT_RIGHT_ROOM]; + } else if (pge->pos_y < 0) { + pge->pos_y += 216; + room_ct_data = &_res._ctData[CT_UP_ROOM]; + } else if (pge->pos_y >= 216) { + pge->pos_y -= 216; + room_ct_data = &_res._ctData[CT_DOWN_ROOM]; + } + if (room_ct_data) { + int8_t room = pge->room_location; + if (room >= 0) { + room = room_ct_data[room]; + pge->room_location = room; + } + if (init_pge->object_type == 1) { + _currentRoom = room; + col_prepareRoomState(); + _loadMap = true; + if (!(_currentRoom & 0x80) && _currentRoom < 0x40) { + LivePGE *pge_it = _pge_liveTable1[_currentRoom]; + while (pge_it) { + if (pge_it->init_PGE->flags & 4) { + _pge_liveTable2[pge_it->index] = pge_it; + pge_it->flags |= 4; + } + pge_it = pge_it->next_PGE_in_room; + } + room = _res._ctData[CT_UP_ROOM + _currentRoom]; + if (room >= 0 && room < 0x40) { + pge_it = _pge_liveTable1[room]; + while (pge_it) { + if (pge_it->init_PGE->object_type != 10 && pge_it->pos_y >= 48 && (pge_it->init_PGE->flags & 4)) { + _pge_liveTable2[pge_it->index] = pge_it; + pge_it->flags |= 4; + } + pge_it = pge_it->next_PGE_in_room; + } + } + room = _res._ctData[CT_DOWN_ROOM + _currentRoom]; + if (room >= 0 && room < 0x40) { + pge_it = _pge_liveTable1[room]; + while (pge_it) { + if (pge_it->init_PGE->object_type != 10 && pge_it->pos_y >= 176 && (pge_it->init_PGE->flags & 4)) { + _pge_liveTable2[pge_it->index] = pge_it; + pge_it->flags |= 4; + } + pge_it = pge_it->next_PGE_in_room; + } + } + } + } + } + pge_addToCurrentRoomList(pge, _pge_currentPiegeRoom); +} + +void Game::pge_addToCurrentRoomList(LivePGE *pge, uint8_t room) { + debug(DBG_PGE, "Game::pge_addToCurrentRoomList() pgeNum=%d room=%d", pge - &_pgeLive[0], room); + if (room != pge->room_location) { + LivePGE *cur_pge = _pge_liveTable1[room]; + LivePGE *prev_pge = 0; + while (cur_pge && cur_pge != pge) { + prev_pge = cur_pge; + cur_pge = cur_pge->next_PGE_in_room; + } + if (cur_pge) { + if (!prev_pge) { + _pge_liveTable1[room] = pge->next_PGE_in_room; + } else { + prev_pge->next_PGE_in_room = cur_pge->next_PGE_in_room; + } + LivePGE *temp = _pge_liveTable1[pge->room_location]; + pge->next_PGE_in_room = temp; + _pge_liveTable1[pge->room_location] = pge; + } + } +} + +void Game::pge_getInput() { + inp_update(); + _inp_lastKeysHit = _stub->_pi.dirMask; + if (_stub->_pi.mirrorMode && (_inp_lastKeysHit & 0xC)) { + _inp_lastKeysHit ^= 0xC; // invert left/right + } + if ((_inp_lastKeysHit & 0xC) && (_inp_lastKeysHit & 0x3)) { + const uint8_t mask = (_inp_lastKeysHit & 0xF0) | (_inp_lastKeysHitLeftRight & 0xF); + _pge_inpKeysMask = mask; + _inp_lastKeysHit = mask; + } else { + _pge_inpKeysMask = _inp_lastKeysHit; + _inp_lastKeysHitLeftRight = _inp_lastKeysHit; + } + if (_stub->_pi.enter) { + _pge_inpKeysMask |= 0x10; + } + if (_stub->_pi.space) { + _pge_inpKeysMask |= 0x20; + } + if (_stub->_pi.shift) { + _pge_inpKeysMask |= 0x40; + } +} + +int Game::pge_op_isInpUp(ObjectOpcodeArgs *args) { + if (1 == _pge_inpKeysMask) { + return 0xFFFF; + } else { + return 0; + } +} + +int Game::pge_op_isInpBackward(ObjectOpcodeArgs *args) { + uint8_t mask = 8; // right + if (_pge_currentPiegeFacingDir) { + mask = 4; // left + } + if (mask == _pge_inpKeysMask) { + return 0xFFFF; + } else { + return 0; + } +} + +int Game::pge_op_isInpDown(ObjectOpcodeArgs *args) { + if (2 == _pge_inpKeysMask) { + return 0xFFFF; + } else { + return 0; + } +} + +int Game::pge_op_isInpForward(ObjectOpcodeArgs *args) { + uint8_t mask = 4; + if (_pge_currentPiegeFacingDir) { + mask = 8; + } + if (mask == _pge_inpKeysMask) { + return 0xFFFF; + } else { + return 0; + } +} + +int Game::pge_op_isInpUpMod(ObjectOpcodeArgs *args) { + assert(args->a < 3); + uint8_t mask = _pge_modKeysTable[args->a] | 1; + if (mask == _pge_inpKeysMask) { + return 0xFFFF; + } else { + return 0; + } +} + +int Game::pge_op_isInpBackwardMod(ObjectOpcodeArgs *args) { + assert(args->a < 3); + uint8_t mask = _pge_modKeysTable[args->a]; + if (_pge_currentPiegeFacingDir) { + mask |= 4; + } else { + mask |= 8; + } + if (mask == _pge_inpKeysMask) { + return 0xFFFF; + } else { + return 0; + } +} + +int Game::pge_op_isInpDownMod(ObjectOpcodeArgs *args) { + assert(args->a < 3); + uint8_t mask = _pge_modKeysTable[args->a] | 2; + if (mask == _pge_inpKeysMask) { + return 0xFFFF; + } else { + return 0; + } +} + +int Game::pge_op_isInpForwardMod(ObjectOpcodeArgs *args) { + assert(args->a < 3); + uint8_t mask = _pge_modKeysTable[args->a]; + if (_pge_currentPiegeFacingDir) { + mask |= 8; + } else { + mask |= 4; + } + if (mask == _pge_inpKeysMask) { + return 0xFFFF; + } else { + return 0; + } +} + +int Game::pge_op_isInpIdle(ObjectOpcodeArgs *args) { + if (_pge_inpKeysMask == 0) { + return 0xFFFF; + } else { + return 0; + } +} + +int Game::pge_op_isInpNoMod(ObjectOpcodeArgs *args) { + assert(args->a < 3); + uint8_t mask = _pge_modKeysTable[args->a]; + if (((_pge_inpKeysMask & 0xF) | mask) == _pge_inpKeysMask) { + return 0xFFFF; + } else { + return 0; + } +} + +int Game::pge_op_getCollision0u(ObjectOpcodeArgs *args) { + return col_getGridData(args->pge, 0, -args->a); +} + +int Game::pge_op_getCollision00(ObjectOpcodeArgs *args) { + return col_getGridData(args->pge, 0, 0); +} + +int Game::pge_op_getCollision0d(ObjectOpcodeArgs *args) { + return col_getGridData(args->pge, 0, args->a); +} + +int Game::pge_op_getCollision1u(ObjectOpcodeArgs *args) { + return col_getGridData(args->pge, 1, -args->a); +} + +int Game::pge_op_getCollision10(ObjectOpcodeArgs *args) { + return col_getGridData(args->pge, 1, 0); +} + +int Game::pge_op_getCollision1d(ObjectOpcodeArgs *args) { + return col_getGridData(args->pge, 1, args->a); +} + +int Game::pge_op_getCollision2u(ObjectOpcodeArgs *args) { + return col_getGridData(args->pge, 2, -args->a); +} + +int Game::pge_op_getCollision20(ObjectOpcodeArgs *args) { + return col_getGridData(args->pge, 2, 0); +} + +int Game::pge_op_getCollision2d(ObjectOpcodeArgs *args) { + return col_getGridData(args->pge, 2, args->a); +} + +int Game::pge_op_doesNotCollide0u(ObjectOpcodeArgs *args) { + int16_t r = col_getGridData(args->pge, 0, -args->a); + if (r & 0xFFFF) { + return 0; + } else { + return 0xFFFF; + } +} + +int Game::pge_op_doesNotCollide00(ObjectOpcodeArgs *args) { + int16_t r = col_getGridData(args->pge, 0, 0); + if (r & 0xFFFF) { + return 0; + } else { + return 0xFFFF; + } +} + +int Game::pge_op_doesNotCollide0d(ObjectOpcodeArgs *args) { + int16_t r = col_getGridData(args->pge, 0, args->a); + if (r & 0xFFFF) { + return 0; + } else { + return 0xFFFF; + } +} + +int Game::pge_op_doesNotCollide1u(ObjectOpcodeArgs *args) { + int16_t r = col_getGridData(args->pge, 1, -args->a); + if (r & 0xFFFF) { + return 0; + } else { + return 0xFFFF; + } +} + +int Game::pge_op_doesNotCollide10(ObjectOpcodeArgs *args) { + int16_t r = col_getGridData(args->pge, 1, 0); + if (r & 0xFFFF) { + return 0; + } else { + return 0xFFFF; + } +} + +int Game::pge_op_doesNotCollide1d(ObjectOpcodeArgs *args) { + int16_t r = col_getGridData(args->pge, 1, args->a); + if (r & 0xFFFF) { + return 0; + } else { + return 0xFFFF; + } +} + +int Game::pge_op_doesNotCollide2u(ObjectOpcodeArgs *args) { + int16_t r = col_getGridData(args->pge, 2, -args->a); + if (r & 0xFFFF) { + return 0; + } else { + return 0xFFFF; + } +} + +int Game::pge_op_doesNotCollide20(ObjectOpcodeArgs *args) { + int16_t r = col_getGridData(args->pge, 2, 0); + if (r & 0xFFFF) { + return 0; + } else { + return 0xFFFF; + } +} + +int Game::pge_op_doesNotCollide2d(ObjectOpcodeArgs *args) { + int16_t r = col_getGridData(args->pge, 2, args->a); + if (r & 0xFFFF) { + return 0; + } else { + return 0xFFFF; + } +} + +int Game::pge_op_collides0o0d(ObjectOpcodeArgs *args) { + if (col_getGridData(args->pge, 0, args->a) & 0xFFFF) { + if (col_getGridData(args->pge, 0, args->a + 1) == 0) { + if (col_getGridData(args->pge, -1, args->a) == 0) { + return 0xFFFF; + } + } + } + return 0; +} + +int Game::pge_op_collides2o2d(ObjectOpcodeArgs *args) { + if (col_getGridData(args->pge, 2, args->a) & 0xFFFF) { + if (col_getGridData(args->pge, 2, args->a + 1) == 0) { + if (col_getGridData(args->pge, 1, args->a) == 0) { + return 0xFFFF; + } + } + } + return 0; +} + +int Game::pge_op_collides0o0u(ObjectOpcodeArgs *args) { + if (col_getGridData(args->pge, 0, args->a) & 0xFFFF) { + if (col_getGridData(args->pge, 0, args->a - 1) == 0) { + if (col_getGridData(args->pge, -1, args->a) == 0) { + return 0xFFFF; + } + } + } + return 0; +} + +int Game::pge_op_collides2o2u(ObjectOpcodeArgs *args) { + if (col_getGridData(args->pge, 2, args->a) & 0xFFFF) { + if (col_getGridData(args->pge, 2, args->a - 1) == 0) { + if (col_getGridData(args->pge, 1, args->a) == 0) { + return 0xFFFF; + } + } + } + return 0; +} + +int Game::pge_op_collides2u2o(ObjectOpcodeArgs *args) { + if (col_getGridData(args->pge, 2, args->a - 1) & 0xFFFF) { + if (col_getGridData(args->pge, 2, args->a) == 0) { + if (col_getGridData(args->pge, 1, args->a - 1) == 0) { + return 0xFFFF; + } + } + } + return 0; +} + +int Game::pge_op_isInGroup(ObjectOpcodeArgs *args) { + GroupPGE *le = _pge_groupsTable[args->pge->index]; + while (le) { + if (le->group_id == args->a) { + return 0xFFFF; + } + le = le->next_entry; + } + return 0; +} + +int Game::pge_op_updateGroup0(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + pge_updateGroup(pge->index, pge->init_PGE->counter_values[0], args->a); + return 0xFFFF; +} + +int Game::pge_op_updateGroup1(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + pge_updateGroup(pge->index, pge->init_PGE->counter_values[1], args->a); + return 0xFFFF; +} + +int Game::pge_op_updateGroup2(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + pge_updateGroup(pge->index, pge->init_PGE->counter_values[2], args->a); + return 0xFFFF; +} + +int Game::pge_op_updateGroup3(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + pge_updateGroup(pge->index, pge->init_PGE->counter_values[3], args->a); + return 0xFFFF; +} + +int Game::pge_op_isPiegeDead(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + if (pge->life <= 0) { + if (pge->init_PGE->object_type == 10) { + _score += 100; + } + return 1; + } + return 0; +} + +int Game::pge_op_collides1u2o(ObjectOpcodeArgs *args) { + if (col_getGridData(args->pge, 1, args->a - 1) & 0xFFFF) { + if (col_getGridData(args->pge, 2, args->a) == 0) { + return 0xFFFF; + } + } + return 0; +} + +int Game::pge_op_collides1u1o(ObjectOpcodeArgs *args) { + if (col_getGridData(args->pge, 1, args->a - 1) & 0xFFFF) { + if (col_getGridData(args->pge, 1, args->a) == 0) { + return 0xFFFF; + } + } + return 0; +} + +int Game::pge_op_collides1o1u(ObjectOpcodeArgs *args) { + if (col_getGridData(args->pge, 1, args->a - 1) == 0) { + if (col_getGridData(args->pge, 1, args->a) & 0xFFFF) { + return 0xFFFF; + } + } + return 0; +} + +int Game::pge_o_unk0x2B(ObjectOpcodeArgs *args) { + return pge_ZOrder(args->pge, args->a, &Game::pge_ZOrderIfTypeAndDifferentDirection, 0); +} + +int Game::pge_o_unk0x2C(ObjectOpcodeArgs *args) { + return pge_ZOrder(args->pge, args->a, &Game::pge_ZOrderIfTypeAndSameDirection, 0); +} + +int Game::pge_o_unk0x2D(ObjectOpcodeArgs *args) { + return pge_ZOrder(args->pge, args->a, &Game::pge_ZOrderByObj, 0) ^ 1; +} + +int Game::pge_op_nop(ObjectOpcodeArgs *args) { + return 1; +} + +int Game::pge_op_pickupObject(ObjectOpcodeArgs *args) { + LivePGE *pge = col_findPiege(args->pge, 3); + if (pge) { + pge_updateGroup(args->pge->index, pge->index, args->a); + return 0xFFFF; + } + return 0; +} + +int Game::pge_op_addItemToInventory(ObjectOpcodeArgs *args) { + pge_updateInventory(&_pgeLive[args->a], args->pge); + args->pge->room_location = 0xFF; + return 0xFFFF; +} + +int Game::pge_op_copyPiege(ObjectOpcodeArgs *args) { + LivePGE *src = &_pgeLive[args->a]; + LivePGE *dst = args->pge; + + dst->pos_x = src->pos_x; + dst->pos_y = src->pos_y; + dst->room_location = src->room_location; + + dst->flags &= 0xFE; + if (src->flags & 1) { + dst->flags |= 1; + } + pge_reorderInventory(args->pge); + return 0xFFFF; +} + +int Game::pge_op_removeItemFromInventory(ObjectOpcodeArgs *args) { + if (args->pge->current_inventory_PGE != 0xFF) { + pge_updateGroup(args->pge->index, args->pge->current_inventory_PGE, args->a); + } + return 1; +} + +int Game::pge_op_canUseCurrentInventoryItem(ObjectOpcodeArgs *args) { + LivePGE *pge = &_pgeLive[0]; + if (pge->current_inventory_PGE != 0xFF && _res._pgeInit[pge->current_inventory_PGE].object_id == args->a) { + return 1; + } + return 0; +} + +// useObject related +int Game::pge_o_unk0x34(ObjectOpcodeArgs *args) { + uint8_t mask = (_pge_inpKeysMask & 0xF) | _pge_modKeysTable[0]; + if (mask == _pge_inpKeysMask) { + if (col_getGridData(args->pge, 2, -args->a) == 0) { + return 0xFFFF; + } + } + return 0; +} + +int Game::pge_op_isInpMod(ObjectOpcodeArgs *args) { + assert(args->a < 3); + uint8_t mask = _pge_modKeysTable[args->a]; + if (mask == _pge_inpKeysMask) { + return 0xFFFF; + } else { + return 0; + } +} + +int Game::pge_op_setCollisionState1(ObjectOpcodeArgs *args) { + return pge_updateCollisionState(args->pge, args->a, 1); +} + +int Game::pge_op_setCollisionState0(ObjectOpcodeArgs *args) { + return pge_updateCollisionState(args->pge, args->a, 0); +} + +int Game::pge_op_isInGroup1(ObjectOpcodeArgs *args) { + return pge_isInGroup(args->pge, args->a, 1); +} + +int Game::pge_op_isInGroup2(ObjectOpcodeArgs *args) { + return pge_isInGroup(args->pge, args->a, 2); +} + +int Game::pge_op_isInGroup3(ObjectOpcodeArgs *args) { + return pge_isInGroup(args->pge, args->a, 3); +} + +int Game::pge_op_isInGroup4(ObjectOpcodeArgs *args) { + return pge_isInGroup(args->pge, args->a, 4); +} + +int Game::pge_o_unk0x3C(ObjectOpcodeArgs *args) { + return pge_ZOrder(args->pge, args->a, &Game::pge_ZOrderByAnimYIfType, args->b); +} + +int Game::pge_o_unk0x3D(ObjectOpcodeArgs *args) { + return pge_ZOrder(args->pge, args->a, &Game::pge_ZOrderByAnimY, 0); +} + +int Game::pge_op_setPiegeCounter(ObjectOpcodeArgs *args) { + args->pge->counter_value = args->a; + return 1; +} + +int Game::pge_op_decPiegeCounter(ObjectOpcodeArgs *args) { + args->pge->counter_value -= 1; + if (args->a == args->pge->counter_value) { + return 0xFFFF; + } else { + return 0; + } +} + +int Game::pge_o_unk0x40(ObjectOpcodeArgs *args) { + int8_t pge_room = args->pge->room_location; + if (pge_room < 0 || pge_room >= 0x40) return 0; + int col_area; + if (_currentRoom == pge_room) { + col_area = 1; + } else if (_col_currentLeftRoom == pge_room) { + col_area = 0; + } else if (_col_currentRightRoom == pge_room) { + col_area = 2; + } else { + return 0; + } + int16_t grid_pos_x = (args->pge->pos_x + 8) >> 4; + int16_t grid_pos_y = args->pge->pos_y / 72; + if (grid_pos_y >= 0 && grid_pos_y <= 2) { + grid_pos_y *= 16; + int16_t _cx = args->a; + if (_pge_currentPiegeFacingDir) { + _cx = -_cx; + } + int8_t _bl; + if (_cx >= 0) { + if (_cx > 0x10) { + _cx = 0x10; + } + int8_t *var2 = &_res._ctData[0x100] + pge_room * 0x70 + grid_pos_y * 2 + 0x10 + grid_pos_x; + uint8_t *var4 = _col_activeCollisionSlots + col_area * 0x30 + grid_pos_y + grid_pos_x; + int16_t var12 = grid_pos_x; + --_cx; + do { + --var12; + if (var12 < 0) { + --col_area; + if (col_area < 0) return 0; + pge_room = _res._ctData[CT_LEFT_ROOM + pge_room]; + if (pge_room < 0) return 0; + var12 = 15; + var2 = &_res._ctData[0x101] + pge_room * 0x70 + grid_pos_y * 2 + 15 + 0x10; + var4 = var4 - 31; + } + --var4; + _bl = *var4; + if (_bl >= 0) { + CollisionSlot *col_slot = _col_slotsTable[_bl]; + do { + if (args->pge != col_slot->live_pge && (col_slot->live_pge->flags & 4)) { + if (col_slot->live_pge->init_PGE->object_type == args->b) { + return 1; + } + } + col_slot = col_slot->prev_slot; + } while (col_slot); + } + --var2; + if (*var2 != 0) return 0; + --_cx; + } while (_cx >= 0); + } else { + _cx = -_cx; + if (_cx > 0x10) { + _cx = 0x10; + } + int8_t *var2 = &_res._ctData[0x101] + pge_room * 0x70 + grid_pos_y * 2 + 0x10 + grid_pos_x; + uint8_t *var4 = _col_activeCollisionSlots + 1 + col_area * 0x30 + grid_pos_y + grid_pos_x; + int16_t var12 = grid_pos_x; + --_cx; + do { + ++var12; + if (var12 == 0x10) { + ++col_area; + if (col_area > 2) return 0; + pge_room = _res._ctData[CT_RIGHT_ROOM + pge_room]; + if (pge_room < 0) return 0; + + var12 = 0; + var2 = &_res._ctData[0x101] + pge_room * 0x70 + grid_pos_y * 2 + 0x10; + var4 += 32; + } + var4++; + _bl = *var4; + if (_bl >= 0) { + CollisionSlot *col_slot = _col_slotsTable[_bl]; + do { + if (args->pge != col_slot->live_pge && (col_slot->live_pge->flags & 4)) { + if (col_slot->live_pge->init_PGE->object_type == args->b) { + return 1; + } + } + col_slot = col_slot->prev_slot; + } while (col_slot); + } + _bl = *var2; + ++var2; + if (_bl != 0) return 0; + --_cx; + } while (_cx >= 0); + } + } + return 0; +} + +int Game::pge_op_wakeUpPiege(ObjectOpcodeArgs *args) { + if (args->a <= 3) { + int16_t num = args->pge->init_PGE->counter_values[args->a]; + if (num >= 0) { + LivePGE *pge = &_pgeLive[num]; + pge->flags |= 4; + _pge_liveTable2[num] = pge; + } + } + return 1; +} + +int Game::pge_op_removePiege(ObjectOpcodeArgs *args) { + if (args->a <= 3) { + int16_t num = args->pge->init_PGE->counter_values[args->a]; + if (num >= 0) { + _pge_liveTable2[num] = 0; + _pgeLive[num].flags &= ~4; + } + } + return 1; +} + +int Game::pge_op_removePiegeIfNotNear(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + if (!(pge->init_PGE->flags & 4)) goto kill_pge; + if (_currentRoom & 0x80) goto skip_pge; + if (pge->room_location & 0x80) goto kill_pge; + if (pge->room_location > 0x3F) goto kill_pge; + if (pge->room_location == _currentRoom) goto skip_pge; + if (pge->room_location == _res._ctData[CT_UP_ROOM + _currentRoom]) goto skip_pge; + if (pge->room_location == _res._ctData[CT_DOWN_ROOM + _currentRoom]) goto skip_pge; + if (pge->room_location == _res._ctData[CT_RIGHT_ROOM + _currentRoom]) goto skip_pge; + if (pge->room_location == _res._ctData[CT_LEFT_ROOM + _currentRoom]) goto skip_pge; + +kill_pge: + pge->flags &= ~4; + pge->collision_slot = 0xFF; + _pge_liveTable2[pge->index] = 0; + +skip_pge: + _pge_playAnimSound = false; + return 1; +} + +int Game::pge_op_loadPiegeCounter(ObjectOpcodeArgs *args) { + args->pge->counter_value = args->pge->init_PGE->counter_values[args->a]; + return 1; +} + +int Game::pge_o_unk0x45(ObjectOpcodeArgs *args) { + return pge_ZOrder(args->pge, args->a, &Game::pge_ZOrderByNumber, 0); +} + +int Game::pge_o_unk0x46(ObjectOpcodeArgs *args) { + _pge_compareVar1 = 0; + pge_ZOrder(args->pge, args->a, &Game::pge_ZOrderIfDifferentDirection, 0); + return _pge_compareVar1; +} + +int Game::pge_o_unk0x47(ObjectOpcodeArgs *args) { + _pge_compareVar2 = 0; + pge_ZOrder(args->pge, args->a, &Game::pge_ZOrderIfSameDirection, 0); + return _pge_compareVar2; +} + +// used with Ian in level2 +int Game::pge_o_unk0x48(ObjectOpcodeArgs *args) { + LivePGE *pge = col_findPiege(&_pgeLive[0], args->pge->init_PGE->counter_values[0]); + if (pge && pge->life == args->pge->life) { + pge_updateGroup(args->pge->index, pge->index, args->a); + return 1; + } + return 0; +} + +int Game::pge_o_unk0x49(ObjectOpcodeArgs *args) { + return pge_ZOrder(&_pgeLive[0], args->a, &Game::pge_ZOrderIfIndex, args->pge->init_PGE->counter_values[0]); +} + +int Game::pge_o_unk0x4A(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + pge->room_location = 0xFE; + pge->flags &= ~4; + _pge_liveTable2[pge->index] = 0; + LivePGE *inv_pge = pge_getInventoryItemBefore(&_pgeLive[args->a], pge); + if (inv_pge == &_pgeLive[args->a]) { + if (pge->index != inv_pge->current_inventory_PGE) { + return 1; + } + } else { + if (pge->index != inv_pge->next_inventory_PGE) { + return 1; + } + } + pge_removeFromInventory(inv_pge, pge, &_pgeLive[args->a]); + return 1; +} + +int Game::pge_op_killPiege(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + pge->room_location = 0xFE; + pge->flags &= ~4; + _pge_liveTable2[pge->index] = 0; + if (pge->init_PGE->object_type == 10) { + _score += 200; + } + return 0xFFFF; +} + +int Game::pge_op_isInCurrentRoom(ObjectOpcodeArgs *args) { + return (args->pge->room_location == _currentRoom) ? 1 : 0; +} + +int Game::pge_op_isNotInCurrentRoom(ObjectOpcodeArgs *args) { + return (args->pge->room_location == _currentRoom) ? 0 : 1; +} + +int Game::pge_op_scrollPosY(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + args->pge->pos_y += args->a; + uint8_t pge_num = pge->current_inventory_PGE; + while (pge_num != 0xFF) { + pge = &_pgeLive[pge_num]; + pge->pos_y += args->a; + pge_num = pge->next_inventory_PGE; + } + return 1; +} + +int Game::pge_op_playDefaultDeathCutscene(ObjectOpcodeArgs *args) { + if (_deathCutsceneCounter == 0) { + _deathCutsceneCounter = args->a; + } + return 1; +} + +int Game::pge_o_unk0x50(ObjectOpcodeArgs *args) { + return pge_ZOrder(args->pge, args->a, &Game::pge_ZOrderByObj, 0); +} + +int Game::pge_o_unk0x52(ObjectOpcodeArgs *args) { + return col_detectHit(args->pge, args->a, args->b, &Game::col_detectHitCallback4, &Game::col_detectHitCallback1, 0, 0); +} + +int Game::pge_o_unk0x53(ObjectOpcodeArgs *args) { + return col_detectHit(args->pge, args->a, args->b, &Game::col_detectHitCallback5, &Game::col_detectHitCallback1, 0, 0); +} + +int Game::pge_op_isPiegeNear(ObjectOpcodeArgs *args) { + if (col_findPiege(&_pgeLive[0], args->a) != 0) { + return 1; + } + return 0; +} + +int Game::pge_op_setLife(ObjectOpcodeArgs *args) { + args->pge->life = args->a; + return 1; +} + +int Game::pge_op_incLife(ObjectOpcodeArgs *args) { + args->pge->life += args->a; + return 1; +} + +// level2, Ian +int Game::pge_op_setPiegeDefaultAnim(ObjectOpcodeArgs *args) { + assert(args->a >= 0 && args->a < 4); + int16_t r = args->pge->init_PGE->counter_values[args->a]; + args->pge->room_location = r; + if (r == 1) { + warning("setting _loadMap to true"); + _loadMap = true; + } + pge_setupDefaultAnim(args->pge); + return 1; +} + +int Game::pge_op_setLifeCounter(ObjectOpcodeArgs *args) { + _pgeLive[args->a].life = args->pge->init_PGE->counter_values[0]; + return 1; +} + +int Game::pge_op_decLifeCounter(ObjectOpcodeArgs *args) { + args->pge->life = _pgeLive[args->a].life - 1; + return 1; +} + +int Game::pge_op_playCutscene(ObjectOpcodeArgs *args) { + if (_deathCutsceneCounter == 0) { + _cut._id = args->a; + } + return 1; +} + +int Game::pge_op_isTempVar2Set(ObjectOpcodeArgs *args) { + if (_pge_opTempVar2 == args->a) { + return 1; + } + return 0; +} + +int Game::pge_op_playDeathCutscene(ObjectOpcodeArgs *args) { + if (_deathCutsceneCounter == 0) { + _deathCutsceneCounter = args->pge->init_PGE->counter_values[3] + 1; + _cut._deathCutsceneId = args->a; + } + return 1; +} + +int Game::pge_o_unk0x5D(ObjectOpcodeArgs *args) { + return col_detectHit(args->pge, args->a, args->b, &Game::col_detectHitCallback4, &Game::col_detectHitCallback6, 0, 0); +} + +int Game::pge_o_unk0x5E(ObjectOpcodeArgs *args) { + return col_detectHit(args->pge, args->a, args->b, &Game::col_detectHitCallback5, &Game::col_detectHitCallback6, 0, 0); +} + +int Game::pge_o_unk0x5F(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + + int8_t pge_room = pge->room_location; + if (pge_room < 0 || pge_room >= 0x40) return 0; + + int16_t dx; + int16_t _cx = pge->init_PGE->counter_values[0]; + if (_cx <= 0) { + dx = 1; + _cx = -_cx; + } else { + dx = -1; + } + if (_pge_currentPiegeFacingDir) { + dx = -dx; + } + int16_t grid_pos_x = (pge->pos_x + 8) >> 4; + int16_t grid_pos_y = 0; + do { + int16_t _ax = col_getGridData(pge, 1, -grid_pos_y); + if (_ax != 0) { + if (!(_ax & 2) || args->a != 1) { + pge->room_location = pge_room; + pge->pos_x = grid_pos_x * 16; + return 1; + } + } + if (grid_pos_x < 0) { + pge_room = _res._ctData[CT_LEFT_ROOM + pge_room]; + if (pge_room < 0 || pge_room >= 0x40) return 0; + grid_pos_x += 16; + } else if (grid_pos_x > 15) { + pge_room = _res._ctData[CT_RIGHT_ROOM + pge_room]; + if (pge_room < 0 || pge_room >= 0x40) return 0; + grid_pos_x -= 16; + } + grid_pos_x += dx; + ++grid_pos_y; + } while (grid_pos_y <= _cx); + return 0; +} + +int Game::pge_op_findAndCopyPiege(ObjectOpcodeArgs *args) { + GroupPGE *le = _pge_groupsTable[args->pge->index]; + while (le) { + if (le->group_id == args->a) { + args->a = le->index; + args->b = 0; + pge_op_copyPiege(args); + return 1; + } + le = le->next_entry; + } + return 0; +} + +int Game::pge_op_isInRandomRange(ObjectOpcodeArgs *args) { + uint16_t n = args->a; + if (n != 0) { + if ((getRandomNumber() % n) == 0) { + return 1; + } + } + return 0; +} + +int Game::pge_o_unk0x62(ObjectOpcodeArgs *args) { + return col_detectHit(args->pge, args->a, args->b, &Game::col_detectHitCallback3, &Game::col_detectHitCallback1, 0, -1); +} + +int Game::pge_o_unk0x63(ObjectOpcodeArgs *args) { + return col_detectHit(args->pge, args->a, args->b, &Game::col_detectHitCallback2, &Game::col_detectHitCallback1, 0, -1); +} + +int Game::pge_o_unk0x64(ObjectOpcodeArgs *args) { + return col_detectGunHit(args->pge, args->a, args->b, &Game::col_detectGunHitCallback3, &Game::col_detectGunHitCallback1, 1, -1); +} + +int Game::pge_op_addToCredits(ObjectOpcodeArgs *args) { + assert(args->a >= 0 && args->a < 3); + uint8_t pge = args->pge->init_PGE->counter_values[args->a]; + int16_t val = args->pge->init_PGE->counter_values[args->a + 1]; + _pgeLive[pge].life += val; + return 1; +} + +int Game::pge_op_subFromCredits(ObjectOpcodeArgs *args) { + assert(args->a >= 0 && args->a < 3); + uint8_t pge = args->pge->init_PGE->counter_values[args->a]; + int16_t val = args->pge->init_PGE->counter_values[args->a + 1]; + _pgeLive[pge].life -= val; + return 1; +} + +int Game::pge_o_unk0x67(ObjectOpcodeArgs *args) { + if (col_getGridData(args->pge, 1, -args->a) & 2) { + return 0xFFFF; + } + return 0; +} + +int Game::pge_op_setCollisionState2(ObjectOpcodeArgs *args) { + return pge_updateCollisionState(args->pge, args->a, 2); +} + +int Game::pge_op_saveState(ObjectOpcodeArgs *args) { + _saveStateCompleted = true; + _validSaveState = saveGameState(0); + return 0xFFFF; +} + +// useGun related +int Game::pge_o_unk0x6A(ObjectOpcodeArgs *args) { + LivePGE *_si = args->pge; + int8_t pge_room = _si->room_location; + if (pge_room < 0 || pge_room >= 0x40) return 0; + int8_t _bl; + int col_area = 0; + int8_t *ct_data; + if (_currentRoom == pge_room) { + col_area = 1; + } else if (_col_currentLeftRoom == pge_room) { + col_area = 0; + } else if (_col_currentRightRoom == pge_room) { + col_area = 2; + } else { + return 0; + } + int16_t grid_pos_x = (_si->pos_x + 8) >> 4; + int16_t grid_pos_y = (_si->pos_y / 72); + if (grid_pos_y >= 0 && grid_pos_y <= 2) { + grid_pos_y *= 16; + int16_t _cx = args->a; + if (_pge_currentPiegeFacingDir) { + _cx = -_cx; + } + if (_cx >= 0) { + if (_cx > 0x10) { + _cx = 0x10; + } + ct_data = &_res._ctData[0x100] + pge_room * 0x70 + grid_pos_y * 2 + 0x10 + grid_pos_x; + uint8_t *var4 = _col_activeCollisionSlots + col_area * 0x30 + grid_pos_y + grid_pos_x; + ++var4; + ++ct_data; + int16_t varA = grid_pos_x; + do { + --varA; + if (varA < 0) { + --col_area; + if (col_area < 0) return 0; + pge_room = _res._ctData[CT_LEFT_ROOM + pge_room]; + if (pge_room < 0) return 0; + varA = 0xF; + ct_data = &_res._ctData[0x101] + pge_room * 0x70 + grid_pos_y * 2 + 0x10 + varA; + var4 -= 0x1F; + } + --var4; + _bl = *var4; + if (_bl >= 0) { + CollisionSlot *collision_slot = _col_slotsTable[_bl]; + do { + _si = collision_slot->live_pge; + if (args->pge != _si && (_si->flags & 4) && _si->life >= 0) { + if (_si->init_PGE->object_type == 1 || _si->init_PGE->object_type == 10) { + return 1; + } + } + collision_slot = collision_slot->prev_slot; + } while (collision_slot); + } + --ct_data; + if (*ct_data != 0) return 0; + --_cx; + } while (_cx >= 0); + + } else { + _cx = -_cx; + if (_cx > 0x10) { + _cx = 0x10; + } + ct_data = &_res._ctData[0x101] + pge_room * 0x70 + grid_pos_y * 2 + 0x10 + grid_pos_x; + uint8_t *var4 = _col_activeCollisionSlots + 1 + col_area * 0x30 + grid_pos_y + grid_pos_x; + int16_t varA = grid_pos_x; + goto loc_0_15446; + do { + ++varA; + if (varA == 0x10) { + ++col_area; + if (col_area > 2) return 0; + pge_room = _res._ctData[CT_RIGHT_ROOM + pge_room]; + if (pge_room < 0) return 0; + varA = 0; + ct_data = &_res._ctData[0x100] + pge_room * 0x70 + grid_pos_y * 2 + 0x10 + varA; + var4 += 0x20; + } +loc_0_15446: + _bl = *var4; + ++var4; + if (_bl >= 0) { + CollisionSlot *collision_slot = _col_slotsTable[_bl]; + do { + _si = collision_slot->live_pge; + if (args->pge != _si && (_si->flags & 4) && _si->life >= 0) { + if (_si->init_PGE->object_type == 1 || _si->init_PGE->object_type == 10) { + return 1; + } + } + collision_slot = collision_slot->prev_slot; + } while (collision_slot); + } + _bl = *ct_data; + ++ct_data; + if (_bl != 0) return 0; + --_cx; + } while (_cx >= 0); + } + } + return 0; +} + +int Game::pge_op_isInGroupSlice(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + GroupPGE *le = _pge_groupsTable[pge->index]; + if (le) { + if (args->a == 0) { + do { + if (le->group_id == 1 || le->group_id == 2) { + return 1; + } + le = le->next_entry; + } while (le); + } else { + do { + if (le->group_id == 3 || le->group_id == 4) { + return 1; + } + le = le->next_entry; + } while (le); + } + } + return 0; +} + +int Game::pge_o_unk0x6C(ObjectOpcodeArgs *args) { + LivePGE *pge = col_findPiege(&_pgeLive[0], args->pge->init_PGE->counter_values[0]); + if (pge) { + if (pge->life <= args->pge->life) { + pge_updateGroup(args->pge->index, pge->index, args->a); + return 1; + } + } + return 0; +} + +int Game::pge_op_isCollidingObject(ObjectOpcodeArgs *args) { + uint8_t r = col_findCurrentCollidingObject(args->pge, 3, 0xFF, 0xFF, 0); + if (r == args->a) { + return 1; + } else { + return 0; + } +} + +// elevator +int Game::pge_o_unk0x6E(ObjectOpcodeArgs *args) { + GroupPGE *le = _pge_groupsTable[args->pge->index]; + while (le) { + if (args->a == le->group_id) { + pge_updateInventory(&_pgeLive[le->index], args->pge); + return 0xFFFF; + } + le = le->next_entry; + } + return 0; +} + + +int Game::pge_o_unk0x6F(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + GroupPGE *le = _pge_groupsTable[pge->index]; + while (le) { + if (args->a == le->group_id) { + pge_updateGroup(pge->index, le->index, 0xC); + return 1; + } + le = le->next_entry; + } + return 0; +} + +int Game::pge_o_unk0x70(ObjectOpcodeArgs *args) { + uint8_t pge_num = args->pge->current_inventory_PGE; + while (pge_num != 0xFF) { + pge_updateGroup(args->pge->index, _pgeLive[pge_num].index, args->a); + pge_num = _pgeLive[pge_num].next_inventory_PGE; + } + return 1; +} + +// elevator +int Game::pge_o_unk0x71(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + GroupPGE *le = _pge_groupsTable[pge->index]; + while (le) { + if (le->group_id == args->a) { + pge_reorderInventory(args->pge); + return 1; + } + le = le->next_entry; + } + return 0; +} + +int Game::pge_o_unk0x72(ObjectOpcodeArgs *args) { + int8_t *var4 = &_res._ctData[0x100] + args->pge->room_location * 0x70; + var4 += (((args->pge->pos_y / 36) & ~1) + args->a) * 16 + (args->pge->pos_x + 8) / 16; + + CollisionSlot2 *_di = _col_slots2Next; + int _cx = 0x100; + while (_di && _cx != 0) { + if (_di->unk2 != var4) { + _di = _di->next_slot; + --_cx; + } else { + memcpy(_di->unk2, _di->data_buf, _di->data_size + 1); + break; + } + } + return 0xFFFF; // XXX var4; +} + +int Game::pge_o_unk0x73(ObjectOpcodeArgs *args) { + LivePGE *pge = col_findPiege(args->pge, args->a); + if (pge != 0) { + pge_updateInventory(pge, args->pge); + return 0xFFFF; + } + return 0; +} + +int Game::pge_op_collides4u(ObjectOpcodeArgs *args) { + if (col_getGridData(args->pge, 4, -args->a) != 0) { + return 0xFFFF; + } + return 0; +} + +int Game::pge_op_doesNotCollide4u(ObjectOpcodeArgs *args) { + if (col_getGridData(args->pge, 4, -args->a) == 0) { + return 0xFFFF; + } + return 0; +} + +int Game::pge_op_isBelowConrad(ObjectOpcodeArgs *args) { + LivePGE *_si = args->pge; + LivePGE *pge_conrad = &_pgeLive[0]; + if (pge_conrad->room_location == _si->room_location) { + if ((pge_conrad->pos_y - 8) / 72 < _si->pos_y / 72) { + return 0xFFFF; + } + } else if (!(_si->room_location & 0x80) && _si->room_location < 0x40) { + if (pge_conrad->room_location == _res._ctData[CT_UP_ROOM + _si->room_location]) { + return 0xFFFF; + } + } + return 0; +} + +int Game::pge_op_isAboveConrad(ObjectOpcodeArgs *args) { + LivePGE *_si = args->pge; + LivePGE *pge_conrad = &_pgeLive[0]; + if (pge_conrad->room_location == _si->room_location) { + if ((pge_conrad->pos_y - 8) / 72 > _si->pos_y / 72) { + return 0xFFFF; + } + } else if (!(_si->room_location & 0x80) && _si->room_location < 0x40) { + if (pge_conrad->room_location == _res._ctData[CT_DOWN_ROOM + _si->room_location]) { + return 0xFFFF; + } + } + return 0; +} + +int Game::pge_op_isNotFacingConrad(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + LivePGE *pge_conrad = &_pgeLive[0]; + if (pge->pos_y / 72 == (pge_conrad->pos_y - 8) / 72) { // same grid cell + if (pge->room_location == pge_conrad->room_location) { + if (args->a == 0) { + if (_pge_currentPiegeFacingDir) { + if (pge->pos_x < pge_conrad->pos_x) { + return 0xFFFF; + } + } else { + if (pge->pos_x > pge_conrad->pos_x) { + return 0xFFFF; + } + } + } else { + int16_t dx; + if (_pge_currentPiegeFacingDir) { + dx = pge_conrad->pos_x - pge->pos_x; + } else { + dx = pge->pos_x - pge_conrad->pos_x; + } + if (dx > 0 && dx < args->a * 16) { + return 0xFFFF; + } + } + } else if (args->a == 0) { + if (!(pge->room_location & 0x80) && pge->room_location < 0x40) { + if (_pge_currentPiegeFacingDir) { + if (pge_conrad->room_location == _res._ctData[CT_RIGHT_ROOM + pge->room_location]) + return 0xFFFF; + } else { + if (pge_conrad->room_location == _res._ctData[CT_LEFT_ROOM + pge->room_location]) + return 0xFFFF; + } + } + } + } + return 0; +} + +int Game::pge_op_isFacingConrad(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + LivePGE *pge_conrad = &_pgeLive[0]; + if (pge->pos_y / 72 == (pge_conrad->pos_y - 8) / 72) { + if (pge->room_location == pge_conrad->room_location) { + if (args->a == 0) { + if (_pge_currentPiegeFacingDir) { + if (pge->pos_x > pge_conrad->pos_x) { + return 0xFFFF; + } + } else { + if (pge->pos_x <= pge_conrad->pos_x) { + return 0xFFFF; + } + } + } else { + int16_t dx; + if (_pge_currentPiegeFacingDir) { + dx = pge->pos_x - pge_conrad->pos_x; + } else { + dx = pge_conrad->pos_x - pge->pos_x; + } + if (dx > 0 && dx < args->a * 16) { + return 0xFFFF; + } + } + } else if (args->a == 0) { + if (!(pge->room_location & 0x80) && pge->room_location < 0x40) { + if (_pge_currentPiegeFacingDir) { + if (pge_conrad->room_location == _res._ctData[CT_LEFT_ROOM + pge->room_location]) + return 0xFFFF; + } else { + if (pge_conrad->room_location == _res._ctData[CT_RIGHT_ROOM + pge->room_location]) + return 0xFFFF; + } + } + + } + } + return 0; +} + +int Game::pge_op_collides2u1u(ObjectOpcodeArgs *args) { + if (col_getGridData(args->pge, 1, -args->a) == 0) { + if (col_getGridData(args->pge, 2, -(args->a + 1)) & 0xFFFF) { + return 0xFFFF; + } + } + return 0; +} + +int Game::pge_op_displayText(ObjectOpcodeArgs *args) { + _textToDisplay = args->a; + return 0xFFFF; +} + +int Game::pge_o_unk0x7C(ObjectOpcodeArgs *args) { + LivePGE *pge = col_findPiege(args->pge, 3); + if (pge == 0) { + pge = col_findPiege(args->pge, 5); + if (pge == 0) { + pge = col_findPiege(args->pge, 9); + if (pge == 0) { + pge = col_findPiege(args->pge, 0xFFFF); + } + } + } + if (pge != 0) { + pge_updateGroup(args->pge->index, pge->index, args->a); + } + return 0; +} + +int Game::pge_op_playSound(ObjectOpcodeArgs *args) { + uint8_t sfxId = args->a & 0xFF; + uint8_t softVol = args->a >> 8; + playSound(sfxId, softVol); + return 0xFFFF; +} + +int Game::pge_o_unk0x7E(ObjectOpcodeArgs *args) { + _pge_compareVar1 = 0; + pge_ZOrder(args->pge, args->a, &Game::pge_ZOrderByIndex, 0); + return _pge_compareVar1; +} + +int Game::pge_o_unk0x7F(ObjectOpcodeArgs *args) { + LivePGE *_si = args->pge; + uint8_t var4 = _si->collision_slot; + uint8_t var2 = _si->index; + while (var4 != 0xFF) { + CollisionSlot *slot = _col_slotsTable[var4]; + while (slot) { + if (slot->live_pge != args->pge) { + if (slot->live_pge->init_PGE->object_type == 3 && var2 != slot->live_pge->unkF) { + return 0; + } + } + if (slot->live_pge == args->pge) { + var4 = slot->index; + } + slot = slot->prev_slot; + } + } + return 0xFFFF; +} + +int Game::pge_op_setPiegePosX(ObjectOpcodeArgs *args) { + uint8_t pge_num = args->pge->unkF; + if (pge_num != 0xFF) { + args->pge->pos_x = _pgeLive[pge_num].pos_x; + } + return 0xFFFF; +} + +int Game::pge_op_setPiegePosModX(ObjectOpcodeArgs *args) { + uint8_t pge_num = args->pge->unkF; + if (pge_num != 0xFF) { + int16_t dx = _pgeLive[pge_num].pos_x % 256; + if (dx >= args->pge->pos_x) { + dx -= args->pge->pos_x; + } + args->pge->pos_x += dx; + } + return 0xFFFF; +} + +// taxi, level4 +int Game::pge_op_changeRoom(ObjectOpcodeArgs *args) { + InitPGE *init_pge_1 = args->pge->init_PGE; + assert(args->a >= 0 && args->a < 3); + int16_t _ax = init_pge_1->counter_values[args->a]; + int16_t _bx = init_pge_1->counter_values[args->a + 1]; + LivePGE *live_pge_1 = &_pgeLive[_bx]; + LivePGE *live_pge_2 = &_pgeLive[_ax]; + int8_t pge_room = live_pge_1->room_location; + if (pge_room >= 0 && pge_room < 0x40) { + int8_t _al = live_pge_2->room_location; + live_pge_2->pos_x = live_pge_1->pos_x; + live_pge_2->pos_y = live_pge_1->pos_y; + live_pge_2->room_location = live_pge_1->room_location; + pge_addToCurrentRoomList(live_pge_2, _al); + InitPGE *init_pge_2 = live_pge_2->init_PGE; + init_pge_1 = live_pge_1->init_PGE; + if (init_pge_2->obj_node_number == init_pge_1->obj_node_number) { + live_pge_2->flags &= 0xFE; + if (live_pge_1->flags & 1) { + live_pge_2->flags |= 1; + } + live_pge_2->obj_type = live_pge_1->obj_type; + live_pge_2->anim_seq = 0; + assert(init_pge_2->obj_node_number < _res._numObjectNodes); + ObjectNode *on = _res._objectNodesMap[init_pge_2->obj_node_number]; + Object *obj = on->objects; + int i = 0; + while (obj->type != live_pge_2->obj_type) { + ++i; + ++obj; + } + live_pge_2->first_obj_number = i; + } + if (init_pge_2->object_type == 1) { + if (_currentRoom != live_pge_2->room_location) { + _currentRoom = live_pge_2->room_location; + loadLevelMap(); + _vid.fullRefresh(); + } + } + pge_setupDefaultAnim(live_pge_2); + } + return 0xFFFF; +} + +// called for example before using gun, to check its presence +int Game::pge_op_hasInventoryItem(ObjectOpcodeArgs *args) { + LivePGE *pge = &_pgeLive[0]; + uint8_t _dl = pge->current_inventory_PGE; + while (_dl != 0xFF) { + pge = &_pgeLive[_dl]; + if (pge->init_PGE->object_id == args->a) { + return 0xFFFF; + } + _dl = pge->next_inventory_PGE; + } + return 0; +} + +int Game::pge_op_changeLevel(ObjectOpcodeArgs *args) { + _currentLevel = args->a - 1; + return _currentLevel; +} + +int Game::pge_op_shakeScreen(ObjectOpcodeArgs *args) { + _vid._shakeOffset = getRandomNumber() & 7; + return 0xFFFF; +} + +int Game::pge_o_unk0x86(ObjectOpcodeArgs *args) { + return col_detectGunHit(args->pge, args->a, args->b, &Game::col_detectGunHitCallback2, &Game::col_detectGunHitCallback1, 1, 0); +} + +int Game::pge_op_playSoundGroup(ObjectOpcodeArgs *args) { + assert(args->a < 4); + uint16_t c = args->pge->init_PGE->counter_values[args->a]; + uint8_t sfxId = c & 0xFF; + uint8_t softVol = c >> 8; + playSound(sfxId, softVol); + return 0xFFFF; +} + +int Game::pge_op_adjustPos(ObjectOpcodeArgs *args) { + LivePGE *pge = args->pge; + pge->pos_x &= 0xFFF0; + if (pge->pos_y != 70 && pge->pos_y != 142 && pge->pos_y != 214) { + pge->pos_y = ((pge->pos_y / 72) + 1) * 72 - 2; + } + return 0xFFFF; +} + +int Game::pge_op_setTempVar1(ObjectOpcodeArgs *args) { + _pge_opTempVar1 = args->a; + return 0xFFFF; +} + +int Game::pge_op_isTempVar1Set(ObjectOpcodeArgs *args) { + if (_pge_opTempVar1 != args->a) { + return 0; + } else { + return 0xFFFF; + } +} + +int Game::pge_setCurrentInventoryObject(LivePGE *pge) { + LivePGE *_bx = pge_getInventoryItemBefore(&_pgeLive[0], pge); + if (_bx == &_pgeLive[0]) { + if (_bx->current_inventory_PGE != pge->index) { + return 0; + } + } else { + if (_bx->next_inventory_PGE != pge->index) { + return 0; + } + } + pge_removeFromInventory(_bx, pge, &_pgeLive[0]); + pge_addToInventory(&_pgeLive[0], pge, &_pgeLive[0]); + return 0xFFFF; +} + +void Game::pge_updateInventory(LivePGE *pge1, LivePGE *pge2) { + if (pge2->unkF != 0xFF) { + pge_reorderInventory(pge2); + } + LivePGE *_ax = pge_getInventoryItemBefore(pge1, 0); + pge_addToInventory(_ax, pge2, pge1); +} + +void Game::pge_reorderInventory(LivePGE *pge) { + if (pge->unkF != 0xFF) { + LivePGE *_bx = &_pgeLive[pge->unkF]; + LivePGE *_di = pge_getInventoryItemBefore(_bx, pge); + if (_di == _bx) { + if (_di->current_inventory_PGE == pge->index) { + pge_removeFromInventory(_di, pge, _bx); + } + } else { + if (_di->next_inventory_PGE == pge->index) { + pge_removeFromInventory(_di, pge, _bx); + } + } + } +} + +LivePGE *Game::pge_getInventoryItemBefore(LivePGE *pge, LivePGE *last_pge) { + LivePGE *_di = pge; + uint8_t n = _di->current_inventory_PGE; + while (n != 0xFF) { + LivePGE *_si = &_pgeLive[n]; + if (_si == last_pge) { + break; + } else { + _di = _si; + n = _di->next_inventory_PGE; + } + } + return _di; +} + +void Game::pge_addToInventory(LivePGE *pge1, LivePGE *pge2, LivePGE *pge3) { + pge2->unkF = pge3->index; + if (pge1 == pge3) { + pge2->next_inventory_PGE = pge1->current_inventory_PGE; + pge1->current_inventory_PGE = pge2->index; + } else { + pge2->next_inventory_PGE = pge1->next_inventory_PGE; + pge1->next_inventory_PGE = pge2->index; + } +} + +int Game::pge_updateCollisionState(LivePGE *pge, int16_t pge_dy, uint8_t var8) { + uint8_t pge_unk1C = pge->init_PGE->unk1C; + if (!(pge->room_location & 0x80) && pge->room_location < 0x40) { + int8_t *grid_data = &_res._ctData[0x100] + 0x70 * pge->room_location; + int16_t pge_pos_y = ((pge->pos_y / 36) & ~1) + pge_dy; + int16_t pge_pos_x = (pge->pos_x + 8) >> 4; + + grid_data += pge_pos_x + pge_pos_y * 16; + + CollisionSlot2 *slot1 = _col_slots2Next; + int16_t i = 255; + pge_pos_x = i; + if (_pge_currentPiegeFacingDir) { + i = pge_unk1C - 1; + grid_data -= i; + } + while (slot1) { + if (slot1->unk2 == grid_data) { + slot1->data_size = pge_unk1C - 1; + assert(pge_unk1C < 0x70); + memset(grid_data, var8, pge_unk1C); + grid_data += pge_unk1C; + return 1; + } else { + ++i; + slot1 = slot1->next_slot; + if (--i == 0) { + break; + } + } + } + if (_col_slots2Cur < &_col_slots2[255]) { + slot1 = _col_slots2Cur; + slot1->unk2 = grid_data; + slot1->data_size = pge_unk1C - 1; + uint8_t *dst = &slot1->data_buf[0]; + int8_t *src = grid_data; + int n = pge_unk1C; + assert(n < 0x10); + while (n--) { + *dst++ = *src; + *src++ = var8; + } + ++_col_slots2Cur; + slot1->next_slot = _col_slots2Next; + _col_slots2Next = slot1; + } + } + return 1; +} + +int Game::pge_ZOrder(LivePGE *pge, int16_t num, pge_ZOrderCallback compare, uint16_t unk) { + uint8_t slot = pge->collision_slot; + while (slot != 0xFF) { + CollisionSlot *cs = _col_slotsTable[slot]; + if (cs == 0) { + return 0; + } + uint8_t slot_bak = slot; + slot = 0xFF; + while (cs != 0) { + if ((this->*compare)(cs->live_pge, pge, num, unk) != 0) { + return 1; + } + if (pge == cs->live_pge) { + slot = cs->index; + } + cs = cs->prev_slot; + if (slot == slot_bak) { + return 0; + } + } + } + return 0; +} + +void Game::pge_updateGroup(uint8_t idx, uint8_t unk1, int16_t unk2) { + debug(DBG_GAME, "Game::pge_updateGroup() idx=0x%X unk1=0x%X unk2=0x%X", idx, unk1, unk2); + LivePGE *pge = &_pgeLive[unk1]; + if (!(pge->flags & 4)) { + if (!(pge->init_PGE->flags & 1)) { + return; + } + pge->flags |= 4; + _pge_liveTable2[unk1] = pge; + } + if (unk2 <= 4) { + uint8_t pge_room = pge->room_location; + pge = &_pgeLive[idx]; + if (pge_room != pge->room_location) { + return; + } + if (unk1 == 0 && _blinkingConradCounter != 0) { + return; + } + // XXX + } + GroupPGE *le = _pge_nextFreeGroup; + if (le) { + // append to the list + _pge_nextFreeGroup = le->next_entry; + GroupPGE *_ax = _pge_groupsTable[unk1]; + _pge_groupsTable[unk1] = le; + le->next_entry = _ax; + le->index = idx; + le->group_id = unk2; + } +} + +void Game::pge_removeFromInventory(LivePGE *pge1, LivePGE *pge2, LivePGE *pge3) { + pge2->unkF = 0xFF; + if (pge3 == pge1) { + pge3->current_inventory_PGE = pge2->next_inventory_PGE; + pge2->next_inventory_PGE = 0xFF; + } else { + pge1->next_inventory_PGE = pge2->next_inventory_PGE; + pge2->next_inventory_PGE = 0xFF; + } +} + +int Game::pge_ZOrderByAnimY(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2) { + if (pge1 != pge2) { + if (_res.getAniData(pge1->obj_type)[3] == comp) { + return 1; + } + } + return 0; +} + +int Game::pge_ZOrderByAnimYIfType(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2) { + if (pge1->init_PGE->object_type == comp2) { + if (_res.getAniData(pge1->obj_type)[3] == comp) { + return 1; + } + } + return 0; +} + +int Game::pge_ZOrderIfIndex(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2) { + if (pge1->index != comp2) { + pge_updateGroup(pge2->index, pge1->index, comp); + return 1; + } + return 0; +} + +int Game::pge_ZOrderByIndex(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2) { + if (pge1 != pge2) { + pge_updateGroup(pge2->index, pge1->index, comp); + _pge_compareVar1 = 0xFFFF; + } + return 0; +} + +int Game::pge_ZOrderByObj(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2) { + if (comp == 10) { + if (pge1->init_PGE->object_type == comp && pge1->life >= 0) { + return 1; + } + } else { + if (pge1->init_PGE->object_type == comp) { + return 1; + } + } + return 0; +} + +int Game::pge_ZOrderIfDifferentDirection(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2) { + if (pge1 != pge2) { + if ((pge1->flags & 1) != (pge2->flags & 1)) { + _pge_compareVar1 = 1; + pge_updateGroup(pge2->index, pge1->index, comp); + if (pge2->index == 0) { + return 0xFFFF; + } + } + } + return 0; +} + +int Game::pge_ZOrderIfSameDirection(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2) { + if (pge1 != pge2) { + if ((pge1->flags & 1) == (pge2->flags & 1)) { + _pge_compareVar2 = 1; + pge_updateGroup(pge2->index, pge1->index, comp); + if (pge2->index == 0) { + return 0xFFFF; + } + } + } + return 0; +} + +int Game::pge_ZOrderIfTypeAndSameDirection(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2) { + if (pge1->init_PGE->object_type == comp) { + if ((pge1->flags & 1) == (pge2->flags & 1)) { + return 1; + } + } + return 0; +} + +int Game::pge_ZOrderIfTypeAndDifferentDirection(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2) { + if (pge1->init_PGE->object_type == comp) { + if ((pge1->flags & 1) != (pge2->flags & 1)) { + return 1; + } + } + return 0; +} + +int Game::pge_ZOrderByNumber(LivePGE *pge1, LivePGE *pge2, uint8_t comp, uint8_t comp2) { + return pge1 - pge2; +} diff --git a/resource.cpp b/resource.cpp new file mode 100644 index 0000000..3d60eed --- /dev/null +++ b/resource.cpp @@ -0,0 +1,1130 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "file.h" +#include "unpack.h" +#include "resource.h" + + +Resource::Resource(FileSystem *fs, ResourceType ver, Language lang) { + memset(this, 0, sizeof(Resource)); + _type = ver; + _lang = lang; + _fs = fs; + _memBuf = (uint8_t *)malloc(256 * 224); + if (!_memBuf) { + error("Unable to allocate temporary memory buffer"); + } + static const int kBankDataSize = 0x7000; + _bankData = (uint8_t *)malloc(kBankDataSize); + if (!_bankData) { + error("Unable to allocate bank data buffer"); + } + _bankDataTail = _bankData + kBankDataSize; + clearBankData(); +} + +Resource::~Resource() { + clearLevelRes(); + free(_fnt); + free(_icn); _icn = 0; + _icnLen = 0; + free(_tab); + free(_spc); + free(_spr1); + free(_memBuf); + free(_cmd); + free(_pol); + free(_cine_off); + free(_cine_txt); + for (int i = 0; i < _numSfx; ++i) { + free(_sfxList[i].data); + } + free(_sfxList); + free(_bankData); +} + +void Resource::clearLevelRes() { + free(_tbn); _tbn = 0; + free(_mbk); _mbk = 0; + free(_pal); _pal = 0; + free(_map); _map = 0; + free(_lev); _lev = 0; + _levNum = -1; + free(_sgd); _sgd = 0; + free(_ani); _ani = 0; + free_OBJ(); +} + +void Resource::load_FIB(const char *fileName) { + debug(DBG_RES, "Resource::load_FIB('%s')", fileName); + static const uint8_t fibonacciTable[] = { + 0xDE, 0xEB, 0xF3, 0xF8, 0xFB, 0xFD, 0xFE, 0xFF, + 0x00, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0D, 0x15 + }; + snprintf(_entryName, sizeof(_entryName), "%s.FIB", fileName); + File f; + if (f.open(_entryName, "rb", _fs)) { + _numSfx = f.readUint16LE(); + _sfxList = (SoundFx *)malloc(_numSfx * sizeof(SoundFx)); + if (!_sfxList) { + error("Unable to allocate SoundFx table"); + } + int i; + for (i = 0; i < _numSfx; ++i) { + SoundFx *sfx = &_sfxList[i]; + sfx->offset = f.readUint32LE(); + sfx->len = f.readUint16LE(); + sfx->data = 0; + } + for (i = 0; i < _numSfx; ++i) { + SoundFx *sfx = &_sfxList[i]; + if (sfx->len == 0) { + continue; + } + f.seek(sfx->offset); + uint8_t *data = (uint8_t *)malloc(sfx->len * 2); + if (!data) { + error("Unable to allocate SoundFx data buffer"); + } + sfx->data = data; + uint8_t c = f.readByte(); + *data++ = c; + *data++ = c; + uint16_t sz = sfx->len - 1; + while (sz--) { + uint8_t d = f.readByte(); + c += fibonacciTable[d >> 4]; + *data++ = c; + c += fibonacciTable[d & 15]; + *data++ = c; + } + sfx->len *= 2; + } + if (f.ioErr()) { + error("I/O error when reading '%s'", _entryName); + } + } else { + error("Can't open '%s'", _entryName); + } +} + +void Resource::load_SPL_demo() { + _numSfx = NUM_SFXS; + _sfxList = (SoundFx *)calloc(_numSfx, sizeof(SoundFx)); + if (!_sfxList) { + return; + } + for (int i = 0; _splNames[i] && i < NUM_SFXS; ++i) { + File f; + if (f.open(_splNames[i], "rb", _fs)) { + SoundFx *sfx = &_sfxList[i]; + const int size = f.size(); + sfx->data = (uint8_t *)malloc(size); + if (sfx->data) { + f.read(sfx->data, size); + sfx->offset = 0; + sfx->len = size; + } + } + } +} + +void Resource::load_MAP_menu(const char *fileName, uint8_t *dstPtr) { + debug(DBG_RES, "Resource::load_MAP_menu('%s')", fileName); + snprintf(_entryName, sizeof(_entryName), "%s.MAP", fileName); + File f; + if (f.open(_entryName, "rb", _fs)) { + if (f.size() != 0x3800 * 4) { + error("Wrong file size for '%s', %d", _entryName, f.size()); + } + f.read(dstPtr, 0x3800 * 4); + if (f.ioErr()) { + error("I/O error when reading '%s'", _entryName); + } + } else { + error("Can't open '%s'", _entryName); + } +} + +void Resource::load_PAL_menu(const char *fileName, uint8_t *dstPtr) { + debug(DBG_RES, "Resource::load_PAL_menu('%s')", fileName); + snprintf(_entryName, sizeof(_entryName), "%s.PAL", fileName); + File f; + if (f.open(_entryName, "rb", _fs)) { + if (f.size() != 768) { + error("Wrong file size for '%s', %d", _entryName, f.size()); + } + f.read(dstPtr, 768); + if (f.ioErr()) { + error("I/O error when reading '%s'", _entryName); + } + } else { + error("Can't open '%s'", _entryName); + } +} + +void Resource::load_SPR_OFF(const char *fileName, uint8_t *sprData) { + debug(DBG_RES, "Resource::load_SPR_OFF('%s')", fileName); + snprintf(_entryName, sizeof(_entryName), "%s.OFF", fileName); + File f; + if (f.open(_entryName, "rb", _fs)) { + int len = f.size(); + uint8_t *offData = (uint8_t *)malloc(len); + if (!offData) { + error("Unable to allocate sprite offsets"); + } + f.read(offData, len); + if (f.ioErr()) { + error("I/O error when reading '%s'", _entryName); + } + const uint8_t *p = offData; + uint16_t pos; + while ((pos = READ_LE_UINT16(p)) != 0xFFFF) { + assert(pos < NUM_SPRITES); + uint32_t off = READ_LE_UINT32(p + 2); + if (off == 0xFFFFFFFF) { + _sprData[pos] = 0; + } else { + _sprData[pos] = sprData + off; + } + p += 6; + } + free(offData); + } else { + error("Can't open '%s'", _entryName); + } +} + +void Resource::load_CINE() { + const char *baseName = 0; + switch (_lang) { + case LANG_FR: + baseName = "FR_CINE"; + break; + case LANG_EN: + baseName = "ENGCINE"; + break; + case LANG_DE: + baseName = "GERCINE"; + break; + case LANG_SP: + baseName = "SPACINE"; + break; + case LANG_IT: + baseName = "ITACINE"; + break; + } + debug(DBG_RES, "Resource::load_CINE('%s')", baseName); + if (_cine_off == 0) { + snprintf(_entryName, sizeof(_entryName), "%s.BIN", baseName); + File f; + if (f.open(_entryName, "rb", _fs)) { + int len = f.size(); + _cine_off = (uint8_t *)malloc(len); + if (!_cine_off) { + error("Unable to allocate cinematics offsets"); + } + f.read(_cine_off, len); + if (f.ioErr()) { + error("I/O error when reading '%s'", _entryName); + } + } else { + error("Can't open '%s'", _entryName); + } + } + if (_cine_txt == 0) { + snprintf(_entryName, sizeof(_entryName), "%s.TXT", baseName); + File f; + if (f.open(_entryName, "rb", _fs)) { + int len = f.size(); + _cine_txt = (uint8_t *)malloc(len); + if (!_cine_txt) { + error("Unable to allocate cinematics text data"); + } + f.read(_cine_txt, len); + if (f.ioErr()) { + error("I/O error when reading '%s'", _entryName); + } + } else { + error("Can't open '%s'", _entryName); + } + } +} + +void Resource::load_TEXT() { + File f; + // Load game strings + _stringsTable = 0; + if (f.open("STRINGS.TXT", "rb", _fs)) { + const int sz = f.size(); + _extStringsTable = (uint8_t *)malloc(sz); + if (_extStringsTable) { + f.read(_extStringsTable, sz); + _stringsTable = _extStringsTable; + } + f.close(); + } + if (!_stringsTable) { + switch (_lang) { + case LANG_FR: + _stringsTable = LocaleData::_stringsTableFR; + break; + case LANG_EN: + _stringsTable = LocaleData::_stringsTableEN; + break; + case LANG_DE: + _stringsTable = LocaleData::_stringsTableDE; + break; + case LANG_SP: + _stringsTable = LocaleData::_stringsTableSP; + break; + case LANG_IT: + _stringsTable = LocaleData::_stringsTableIT; + break; + } + } + // Load menu strings + _textsTable = 0; + if (f.open("MENUS.TXT", "rb", _fs)) { + const int offs = LocaleData::LI_NUM * sizeof(char *); + const int sz = f.size() + 1; + _extTextsTable = (char **)malloc(offs + sz); + if (_extTextsTable) { + char *textData = (char *)_extTextsTable + offs; + f.read(textData, sz); + textData[sz] = 0; + int textsCount = 0; + for (char *eol; (eol = strpbrk(textData, "\r\n")) != 0; ) { + *eol++ = 0; + if (*eol == '\r' || *eol == '\n') { + *eol++ = 0; + } + if (textsCount < LocaleData::LI_NUM && textData[0] != 0) { + _extTextsTable[textsCount] = textData; + ++textsCount; + } + textData = eol; + } + if (textsCount < LocaleData::LI_NUM && textData[0] != 0) { + _extTextsTable[textsCount] = textData; + ++textsCount; + } + if (textsCount < LocaleData::LI_NUM) { + free(_extTextsTable); + _extTextsTable = 0; + } else { + _textsTable = (const char **)_extTextsTable; + } + } + } + if (!_textsTable) { + switch (_lang) { + case LANG_FR: + _textsTable = LocaleData::_textsTableFR; + break; + case LANG_EN: + _textsTable = LocaleData::_textsTableEN; + break; + case LANG_DE: + _textsTable = LocaleData::_textsTableDE; + break; + case LANG_SP: + _textsTable = LocaleData::_textsTableSP; + break; + case LANG_IT: + _textsTable = LocaleData::_textsTableIT; + break; + } + } +} + +void Resource::free_TEXT() { + if (_extTextsTable) { + free(_extTextsTable); + _extTextsTable = 0; + } + _stringsTable = 0; + if (_extStringsTable) { + free(_extStringsTable); + _extStringsTable = 0; + } + _textsTable = 0; +} + +void Resource::load(const char *objName, int objType, const char *ext) { + debug(DBG_RES, "Resource::load('%s', %d)", objName, objType); + LoadStub loadStub = 0; + switch (objType) { + case OT_MBK: + snprintf(_entryName, sizeof(_entryName), "%s.MBK", objName); + loadStub = &Resource::load_MBK; + break; + case OT_PGE: + snprintf(_entryName, sizeof(_entryName), "%s.PGE", objName); + loadStub = &Resource::load_PGE; + break; + case OT_PAL: + snprintf(_entryName, sizeof(_entryName), "%s.PAL", objName); + loadStub = &Resource::load_PAL; + break; + case OT_CT: + snprintf(_entryName, sizeof(_entryName), "%s.CT", objName); + loadStub = &Resource::load_CT; + break; + case OT_MAP: + snprintf(_entryName, sizeof(_entryName), "%s.MAP", objName); + loadStub = &Resource::load_MAP; + break; + case OT_SPC: + snprintf(_entryName, sizeof(_entryName), "%s.SPC", objName); + loadStub = &Resource::load_SPC; + break; + case OT_RP: + snprintf(_entryName, sizeof(_entryName), "%s.RP", objName); + loadStub = &Resource::load_RP; + break; + case OT_RPC: + snprintf(_entryName, sizeof(_entryName), "%s.RPC", objName); + loadStub = &Resource::load_RP; + break; + case OT_SPR: + snprintf(_entryName, sizeof(_entryName), "%s.SPR", objName); + loadStub = &Resource::load_SPR; + break; + case OT_SPRM: + snprintf(_entryName, sizeof(_entryName), "%s.SPR", objName); + loadStub = &Resource::load_SPRM; + break; + case OT_ICN: + snprintf(_entryName, sizeof(_entryName), "%s.ICN", objName); + loadStub = &Resource::load_ICN; + break; + case OT_FNT: + snprintf(_entryName, sizeof(_entryName), "%s.FNT", objName); + loadStub = &Resource::load_FNT; + break; + case OT_OBJ: + snprintf(_entryName, sizeof(_entryName), "%s.OBJ", objName); + loadStub = &Resource::load_OBJ; + break; + case OT_ANI: + snprintf(_entryName, sizeof(_entryName), "%s.ANI", objName); + loadStub = &Resource::load_ANI; + break; + case OT_TBN: + snprintf(_entryName, sizeof(_entryName), "%s.TBN", objName); + loadStub = &Resource::load_TBN; + break; + case OT_CMD: + snprintf(_entryName, sizeof(_entryName), "%s.CMD", objName); + loadStub = &Resource::load_CMD; + break; + case OT_POL: + snprintf(_entryName, sizeof(_entryName), "%s.POL", objName); + loadStub = &Resource::load_POL; + break; + case OT_CMP: + snprintf(_entryName, sizeof(_entryName), "%s.CMP", objName); + loadStub = &Resource::load_CMP; + break; + case OT_OBC: + snprintf(_entryName, sizeof(_entryName), "%s.OBC", objName); + loadStub = &Resource::load_OBC; + break; + case OT_SPL: + snprintf(_entryName, sizeof(_entryName), "%s.SPL", objName); + loadStub = &Resource::load_SPL; + break; + case OT_LEV: + snprintf(_entryName, sizeof(_entryName), "%s.LEV", objName); + loadStub = &Resource::load_LEV; + break; + case OT_SGD: + snprintf(_entryName, sizeof(_entryName), "%s.SGD", objName); + loadStub = &Resource::load_SGD; + break; + case OT_SPM: + snprintf(_entryName, sizeof(_entryName), "%s.SPM", objName); + loadStub = &Resource::load_SPM; + break; + default: + error("Unimplemented Resource::load() type %d", objType); + break; + } + if (ext) { + snprintf(_entryName, sizeof(_entryName), "%s.%s", objName, ext); + } + File f; + if (f.open(_entryName, "rb", _fs)) { + assert(loadStub); + (this->*loadStub)(&f); + if (f.ioErr()) { + error("I/O error when reading '%s'", _entryName); + } + } else { + error("Can't open '%s'", _entryName); + } +} + +void Resource::load_CT(File *pf) { + debug(DBG_RES, "Resource::load_CT()"); + int len = pf->size(); + uint8_t *tmp = (uint8_t *)malloc(len); + if (!tmp) { + error("Unable to allocate CT buffer"); + } else { + pf->read(tmp, len); + if (!delphine_unpack((uint8_t *)_ctData, tmp, len)) { + error("Bad CRC for collision data"); + } + free(tmp); + } +} + +void Resource::load_FNT(File *f) { + debug(DBG_RES, "Resource::load_FNT()"); + int len = f->size(); + _fnt = (uint8_t *)malloc(len); + if (!_fnt) { + error("Unable to allocate FNT buffer"); + } else { + f->read(_fnt, len); + } +} + +void Resource::load_MBK(File *f) { + debug(DBG_RES, "Resource::load_MBK()"); + int len = f->size(); + _mbk = (uint8_t *)malloc(len); + if (!_mbk) { + error("Unable to allocate MBK buffer"); + } else { + f->read(_mbk, len); + } +} + +void Resource::load_ICN(File *f) { + debug(DBG_RES, "Resource::load_ICN()"); + int len = f->size(); + if (_icnLen == 0) { + _icn = (uint8_t *)malloc(len); + } else { + _icn = (uint8_t *)realloc(_icn, _icnLen + len); + } + if (!_icn) { + error("Unable to allocate ICN buffer"); + } else { + f->read(_icn + _icnLen, len); + } + _icnLen += len; +} + +void Resource::load_SPR(File *f) { + debug(DBG_RES, "Resource::load_SPR()"); + int len = f->size() - 12; + _spr1 = (uint8_t *)malloc(len); + if (!_spr1) { + error("Unable to allocate SPR1 buffer"); + } else { + f->seek(12); + f->read(_spr1, len); + } +} + +void Resource::load_SPRM(File *f) { + debug(DBG_RES, "Resource::load_SPRM()"); + const uint32_t len = f->size() - 12; + assert(len <= sizeof(_sprm)); + f->seek(12); + f->read(_sprm, len); +} + +void Resource::load_RP(File *f) { + debug(DBG_RES, "Resource::load_RP()"); + f->read(_rp, 0x4A); +} + +void Resource::load_SPC(File *f) { + debug(DBG_RES, "Resource::load_SPC()"); + int len = f->size(); + _spc = (uint8_t *)malloc(len); + if (!_spc) { + error("Unable to allocate SPC buffer"); + } else { + f->read(_spc, len); + _numSpc = READ_BE_UINT16(_spc) / 2; + } +} + +void Resource::load_PAL(File *f) { + debug(DBG_RES, "Resource::load_PAL()"); + int len = f->size(); + _pal = (uint8_t *)malloc(len); + if (!_pal) { + error("Unable to allocate PAL buffer"); + } else { + f->read(_pal, len); + } +} + +void Resource::load_MAP(File *f) { + debug(DBG_RES, "Resource::load_MAP()"); + int len = f->size(); + _map = (uint8_t *)malloc(len); + if (!_map) { + error("Unable to allocate MAP buffer"); + } else { + f->read(_map, len); + } +} + +void Resource::load_OBJ(File *f) { + debug(DBG_RES, "Resource::load_OBJ()"); + if (_type == kResourceTypeAmiga) { // demo has uncompressed objects data + const int size = f->size(); + uint8_t *buf = (uint8_t *)malloc(size); + if (!buf) { + error("Unable to allocate OBJ buffer"); + } else { + f->read(buf, size); + decodeOBJ(buf, size); + } + return; + } + _numObjectNodes = f->readUint16LE(); + assert(_numObjectNodes < 255); + uint32_t offsets[256]; + for (int i = 0; i < _numObjectNodes; ++i) { + offsets[i] = f->readUint32LE(); + } + offsets[_numObjectNodes] = f->size() - 2; + int numObjectsCount = 0; + uint16_t objectsCount[256]; + for (int i = 0; i < _numObjectNodes; ++i) { + int diff = offsets[i + 1] - offsets[i]; + if (diff != 0) { + objectsCount[numObjectsCount] = (diff - 2) / 0x12; + debug(DBG_RES, "i=%d objectsCount[numObjectsCount]=%d", i, objectsCount[numObjectsCount]); + ++numObjectsCount; + } + } + uint32_t prevOffset = 0; + ObjectNode *prevNode = 0; + int iObj = 0; + for (int i = 0; i < _numObjectNodes; ++i) { + if (prevOffset != offsets[i]) { + ObjectNode *on = (ObjectNode *)malloc(sizeof(ObjectNode)); + if (!on) { + error("Unable to allocate ObjectNode num=%d", i); + } + f->seek(offsets[i] + 2); + on->last_obj_number = f->readUint16LE(); + on->num_objects = objectsCount[iObj]; + debug(DBG_RES, "last=%d num=%d", on->last_obj_number, on->num_objects); + on->objects = (Object *)malloc(sizeof(Object) * on->num_objects); + for (int j = 0; j < on->num_objects; ++j) { + Object *obj = &on->objects[j]; + obj->type = f->readUint16LE(); + obj->dx = f->readByte(); + obj->dy = f->readByte(); + obj->init_obj_type = f->readUint16LE(); + obj->opcode2 = f->readByte(); + obj->opcode1 = f->readByte(); + obj->flags = f->readByte(); + obj->opcode3 = f->readByte(); + obj->init_obj_number = f->readUint16LE(); + obj->opcode_arg1 = f->readUint16LE(); + obj->opcode_arg2 = f->readUint16LE(); + obj->opcode_arg3 = f->readUint16LE(); + debug(DBG_RES, "obj_node=%d obj=%d op1=0x%X op2=0x%X op3=0x%X", i, j, obj->opcode2, obj->opcode1, obj->opcode3); + } + ++iObj; + prevOffset = offsets[i]; + prevNode = on; + } + _objectNodesMap[i] = prevNode; + } +} + +void Resource::free_OBJ() { + debug(DBG_RES, "Resource::free_OBJ()"); + ObjectNode *prevNode = 0; + for (int i = 0; i < _numObjectNodes; ++i) { + if (_objectNodesMap[i] != prevNode) { + ObjectNode *curNode = _objectNodesMap[i]; + free(curNode->objects); + free(curNode); + prevNode = curNode; + } + _objectNodesMap[i] = 0; + } +} + +void Resource::load_OBC(File *f) { + const int packedSize = f->readUint32BE(); + uint8_t *packedData = (uint8_t *)malloc(packedSize); + if (!packedData) { + error("Unable to allocate OBC temporary buffer 1"); + } + f->seek(packedSize); + const int unpackedSize = f->readUint32BE(); + uint8_t *tmp = (uint8_t *)malloc(unpackedSize); + if (!tmp) { + error("Unable to allocate OBC temporary buffer 2"); + } + f->seek(4); + f->read(packedData, packedSize); + if (!delphine_unpack(tmp, packedData, packedSize)) { + error("Bad CRC for compressed object data"); + } + free(packedData); + decodeOBJ(tmp, unpackedSize); + free(tmp); +} + +void Resource::decodeOBJ(const uint8_t *tmp, int size) { + uint32_t offsets[256]; + int tmpOffset = 0; + _numObjectNodes = 230; + for (int i = 0; i < _numObjectNodes; ++i) { + offsets[i] = READ_BE_UINT32(tmp + tmpOffset); tmpOffset += 4; + } + offsets[_numObjectNodes] = size; + int numObjectsCount = 0; + uint16_t objectsCount[256]; + for (int i = 0; i < _numObjectNodes; ++i) { + int diff = offsets[i + 1] - offsets[i]; + if (diff != 0) { + objectsCount[numObjectsCount] = (diff - 2) / 0x12; + ++numObjectsCount; + } + } + uint32_t prevOffset = 0; + ObjectNode *prevNode = 0; + int iObj = 0; + for (int i = 0; i < _numObjectNodes; ++i) { + if (prevOffset != offsets[i]) { + ObjectNode *on = (ObjectNode *)malloc(sizeof(ObjectNode)); + if (!on) { + error("Unable to allocate ObjectNode num=%d", i); + } + const uint8_t *objData = tmp + offsets[i]; + on->last_obj_number = READ_BE_UINT16(objData); objData += 2; + on->num_objects = objectsCount[iObj]; + on->objects = (Object *)malloc(sizeof(Object) * on->num_objects); + for (int j = 0; j < on->num_objects; ++j) { + Object *obj = &on->objects[j]; + obj->type = READ_BE_UINT16(objData); objData += 2; + obj->dx = *objData++; + obj->dy = *objData++; + obj->init_obj_type = READ_BE_UINT16(objData); objData += 2; + obj->opcode2 = *objData++; + obj->opcode1 = *objData++; + obj->flags = *objData++; + obj->opcode3 = *objData++; + obj->init_obj_number = READ_BE_UINT16(objData); objData += 2; + obj->opcode_arg1 = READ_BE_UINT16(objData); objData += 2; + obj->opcode_arg2 = READ_BE_UINT16(objData); objData += 2; + obj->opcode_arg3 = READ_BE_UINT16(objData); objData += 2; + debug(DBG_RES, "obj_node=%d obj=%d op1=0x%X op2=0x%X op3=0x%X", i, j, obj->opcode2, obj->opcode1, obj->opcode3); + } + ++iObj; + prevOffset = offsets[i]; + prevNode = on; + } + _objectNodesMap[i] = prevNode; + } +} + +void Resource::load_PGE(File *f) { + debug(DBG_RES, "Resource::load_PGE()"); + int len = f->size() - 2; + _pgeNum = f->readUint16LE(); + if (_type == kResourceTypeAmiga) { + SWAP_UINT16(&_pgeNum); + } + memset(_pgeInit, 0, sizeof(_pgeInit)); + debug(DBG_RES, "len=%d _pgeNum=%d", len, _pgeNum); + for (uint16_t i = 0; i < _pgeNum; ++i) { + InitPGE *pge = &_pgeInit[i]; + pge->type = f->readUint16LE(); + pge->pos_x = f->readUint16LE(); + pge->pos_y = f->readUint16LE(); + pge->obj_node_number = f->readUint16LE(); + pge->life = f->readUint16LE(); + for (int lc = 0; lc < 4; ++lc) { + pge->counter_values[lc] = f->readUint16LE(); + } + pge->object_type = f->readByte(); + pge->init_room = f->readByte(); + pge->room_location = f->readByte(); + pge->init_flags = f->readByte(); + pge->colliding_icon_num = f->readByte(); + pge->icon_num = f->readByte(); + pge->object_id = f->readByte(); + pge->skill = f->readByte(); + pge->mirror_x = f->readByte(); + pge->flags = f->readByte(); + pge->unk1C = f->readByte(); + f->readByte(); + pge->text_num = f->readUint16LE(); + } + if (_type == kResourceTypeAmiga) { + for (uint16_t i = 0; i < _pgeNum; ++i) { + InitPGE *pge = &_pgeInit[i]; + SWAP_UINT16((uint16_t *)&pge->type); + SWAP_UINT16((uint16_t *)&pge->pos_x); + SWAP_UINT16((uint16_t *)&pge->pos_y); + SWAP_UINT16((uint16_t *)&pge->obj_node_number); + SWAP_UINT16((uint16_t *)&pge->life); + for (int lc = 0; lc < 4; ++lc) { + SWAP_UINT16((uint16_t *)&pge->counter_values[lc]); + } + SWAP_UINT16((uint16_t *)&pge->text_num); + } + } +} + +void Resource::load_ANI(File *f) { + debug(DBG_RES, "Resource::load_ANI()"); + int size = f->size() - 2; + _ani = (uint8_t *)malloc(size); + if (!_ani) { + error("Unable to allocate ANI buffer"); + } else { + uint16_t count = f->readUint16LE(); + f->read(_ani, size); + if (_type == kResourceTypeAmiga) { + const uint8_t *end = _ani + size; + SWAP_UINT16(&count); + // byte-swap animation data + for (uint16_t i = 0; i < count; ++i) { + uint8_t *p = _ani + READ_BE_UINT16(_ani + 2 * i); + // byte-swap offset + SWAP(_ani[2 * i], _ani[2 * i + 1]); + if (p >= end) { + continue; + } + const int frames = READ_BE_UINT16(p); + if (p[0] != 0) { + // byte-swap only once + continue; + } + // byte-swap anim count + SWAP(p[0], p[1]); + debug(DBG_RES, "ani=%d frames=%d", i, frames); + for (int j = 0; j < frames; ++j) { + // byte-swap next frame + SWAP(p[6 + j * 4], p[6 + j * 4 + 1]); + } + } + } + } +} + +void Resource::load_TBN(File *f) { + debug(DBG_RES, "Resource::load_TBN()"); + int len = f->size(); + _tbn = (uint8_t *)malloc(len); + if (!_tbn) { + error("Unable to allocate TBN buffer"); + } else { + f->read(_tbn, len); + } + if (_type == kResourceTypeAmiga) { + const int firstOffset = READ_BE_UINT16(_tbn); + for (int i = 0; i < firstOffset; i += 2) { + // byte-swap offset + SWAP(_tbn[i], _tbn[i + 1]); + } + } +} + +void Resource::load_CMD(File *pf) { + debug(DBG_RES, "Resource::load_CMD()"); + free(_cmd); + int len = pf->size(); + _cmd = (uint8_t *)malloc(len); + if (!_cmd) { + error("Unable to allocate CMD buffer"); + } else { + pf->read(_cmd, len); + } +} + +void Resource::load_POL(File *pf) { + debug(DBG_RES, "Resource::load_POL()"); + free(_pol); + int len = pf->size(); + _pol = (uint8_t *)malloc(len); + if (!_pol) { + error("Unable to allocate POL buffer"); + } else { + pf->read(_pol, len); + } +} + +void Resource::load_CMP(File *pf) { + free(_pol); + free(_cmd); + int len = pf->size(); + uint8_t *tmp = (uint8_t *)malloc(len); + if (!tmp) { + error("Unable to allocate CMP buffer"); + } + pf->read(tmp, len); + struct { + int offset, packedSize, size; + } data[2]; + int offset = 0; + for (int i = 0; i < 2; ++i) { + int packedSize = READ_BE_UINT32(tmp + offset); offset += 4; + assert((packedSize & 1) == 0); + if (packedSize < 0) { + data[i].size = packedSize = -packedSize; + } else { + data[i].size = READ_BE_UINT32(tmp + offset + packedSize - 4); + } + data[i].offset = offset; + data[i].packedSize = packedSize; + offset += packedSize; + } + _pol = (uint8_t *)malloc(data[0].size); + if (!_pol) { + error("Unable to allocate POL buffer"); + } + if (data[0].packedSize == data[0].size) { + memcpy(_pol, tmp + data[0].offset, data[0].packedSize); + } else if (!delphine_unpack(_pol, tmp + data[0].offset, data[0].packedSize)) { + error("Bad CRC for cutscene polygon data"); + } + _cmd = (uint8_t *)malloc(data[1].size); + if (!_cmd) { + error("Unable to allocate CMD buffer"); + } + if (data[1].packedSize == data[1].size) { + memcpy(_cmd, tmp + data[1].offset, data[1].packedSize); + } else if (!delphine_unpack(_cmd, tmp + data[1].offset, data[1].packedSize)) { + error("Bad CRC for cutscene command data"); + } + free(tmp); +} + +void Resource::load_VCE(int num, int segment, uint8_t **buf, uint32_t *bufSize) { + *buf = 0; + int offset = _voicesOffsetsTable[num]; + if (offset != 0xFFFF) { + const uint16_t *p = _voicesOffsetsTable + offset / 2; + offset = (*p++) * 2048; + int count = *p++; + if (segment < count) { + File f; + if (f.open("VOICE.VCE", "rb", _fs)) { + int voiceSize = p[segment] * 2048 / 5; + uint8_t *voiceBuf = (uint8_t *)malloc(voiceSize); + if (voiceBuf) { + uint8_t *dst = voiceBuf; + offset += 0x2000; + for (int s = 0; s < count; ++s) { + int len = p[s] * 2048; + for (int i = 0; i < len / (0x2000 + 2048); ++i) { + if (s == segment) { + f.seek(offset); + int n = 2048; + while (n--) { + int v = f.readByte(); + if (v & 0x80) { + v = -(v & 0x7F); + } + *dst++ = (uint8_t)(v & 0xFF); + } + } + offset += 0x2000 + 2048; + } + if (s == segment) { + break; + } + } + *buf = voiceBuf; + *bufSize = voiceSize; + } + } + } + } +} + +void Resource::load_SPL(File *f) { + for (int i = 0; i < _numSfx; ++i) { + free(_sfxList[i].data); + } + free(_sfxList); + _numSfx = NUM_SFXS; + _sfxList = (SoundFx *)calloc(_numSfx, sizeof(SoundFx)); + if (!_sfxList) { + error("Unable to allocate SoundFx table"); + } + int offset = 0; + for (int i = 0; i < _numSfx; ++i) { + const int size = f->readUint16BE(); offset += 2; + if ((size & 0x8000) != 0) { + continue; + } + debug(DBG_RES, "sfx=%d size=%d", i, size); + assert(size != 0 && (size & 1) == 0); + if (i != 64) { + _sfxList[i].offset = offset; + _sfxList[i].len = size; + _sfxList[i].data = (uint8_t *)malloc(size); + assert(_sfxList[i].data); + f->read(_sfxList[i].data, size); + } else { + f->seek(offset + size); + } + offset += size; + } +} + +void Resource::load_LEV(File *f) { + const int len = f->size(); + _lev = (uint8_t *)malloc(len); + if (!_lev) { + error("Unable to allocate LEV buffer"); + } else { + f->read(_lev, len); + } +} + +void Resource::load_SGD(File *f) { + const int len = f->size(); + f->seek(len - 4); + int size = f->readUint32BE(); + f->seek(0); + uint8_t *tmp = (uint8_t *)malloc(len); + if (!tmp) { + error("Unable to allocate SGD temporary buffer"); + } + f->read(tmp, len); + _sgd = (uint8_t *)malloc(size); + if (!_sgd) { + error("Unable to allocate SGD buffer"); + } + if (!delphine_unpack(_sgd, tmp, len)) { + error("Bad CRC for SGD data"); + } + free(tmp); +} + +void Resource::load_SPM(File *f) { + static const int kPersoDatSize = 178647; + const int len = f->size(); + f->seek(len - 4); + const uint32_t size = f->readUint32BE(); + f->seek(0); + uint8_t *tmp = (uint8_t *)malloc(len); + if (!tmp) { + error("Unable to allocate SPM temporary buffer"); + } + f->read(tmp, len); + if (size == kPersoDatSize) { + _spr1 = (uint8_t *)malloc(size); + if (!_spr1) { + error("Unable to allocate SPR1 buffer"); + } + if (!delphine_unpack(_spr1, tmp, len)) { + error("Bad CRC for SPM data"); + } + } else { + assert(size <= sizeof(_sprm)); + if (!delphine_unpack(_sprm, tmp, len)) { + error("Bad CRC for SPM data"); + } + } + for (int i = 0; i < NUM_SPRITES; ++i) { + const uint32_t offset = _spmOffsetsTable[i]; + if (offset >= kPersoDatSize) { + _sprData[i] = _sprm + offset - kPersoDatSize; + } else { + _sprData[i] = _spr1 + offset; + } + } + free(tmp); +} + +void Resource::clearBankData() { + _bankBuffersCount = 0; + _bankDataHead = _bankData; +} + +int Resource::getBankDataSize(uint16_t num) { + int len = READ_BE_UINT16(_mbk + num * 6 + 4); + int size = 0; + switch (_type) { + case kResourceTypeAmiga: + if (len & 0x8000) { + len = -(int16_t)len; + } + size = len * 32; + break; + case kResourceTypePC: + size = (len & 0x7FFF) * 32; + break; + } + return size; +} + +uint8_t *Resource::findBankData(uint16_t num) { + for (int i = 0; i < _bankBuffersCount; ++i) { + if (_bankBuffers[i].entryNum == num) { + return _bankBuffers[i].ptr; + } + } + return 0; +} + +uint8_t *Resource::loadBankData(uint16_t num) { + const uint8_t *ptr = _mbk + num * 6; + int dataOffset = READ_BE_UINT32(ptr); + if (_type == kResourceTypePC) { + // first byte of the data buffer corresponds + // to the total count of entries + dataOffset &= 0xFFFF; + } + const int size = getBankDataSize(num); + const int avail = _bankDataTail - _bankDataHead; + if (avail < size) { + clearBankData(); + } + assert(_bankDataHead + size <= _bankDataTail); + assert(_bankBuffersCount < (int)ARRAYSIZE(_bankBuffers)); + _bankBuffers[_bankBuffersCount].entryNum = num; + _bankBuffers[_bankBuffersCount].ptr = _bankDataHead; + const uint8_t *data = _mbk + dataOffset; + if (READ_BE_UINT16(ptr + 4) & 0x8000) { + memcpy(_bankDataHead, data, size); + } else { + assert(dataOffset > 4); + assert(size == (int)READ_BE_UINT32(data - 4)); + if (!delphine_unpack(_bankDataHead, data, 0)) { + error("Bad CRC for bank data %d", num); + } + } + uint8_t *bankData = _bankDataHead; + _bankDataHead += size; + return bankData; +} + diff --git a/resource.h b/resource.h new file mode 100644 index 0000000..56406dc --- /dev/null +++ b/resource.h @@ -0,0 +1,214 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef RESOURCE_H__ +#define RESOURCE_H__ + +#include "intern.h" + +struct File; +struct FileSystem; + +struct LocaleData { + enum Id { + LI_01_CONTINUE_OR_ABORT = 0, + LI_02_TIME, + LI_03_CONTINUE, + LI_04_ABORT, + LI_05_COMPLETED, + LI_06_LEVEL, + LI_07_START, + LI_08_SKILL, + LI_09_PASSWORD, + LI_10_INFO, + LI_11_QUIT, + LI_12_SKILL_LEVEL, + LI_13_EASY, + LI_14_NORMAL, + LI_15_EXPERT, + LI_16_ENTER_PASSWORD1, + LI_17_ENTER_PASSWORD2, + LI_18_RESUME_GAME, + LI_19_ABORT_GAME, + LI_20_LOAD_GAME, + LI_21_SAVE_GAME, + LI_22_SAVE_SLOT, + + LI_NUM + }; + + static const char *_textsTableFR[]; + static const char *_textsTableEN[]; + static const char *_textsTableDE[]; + static const char *_textsTableSP[]; + static const char *_textsTableIT[]; + static const uint8_t _stringsTableFR[]; + static const uint8_t _stringsTableEN[]; + static const uint8_t _stringsTableDE[]; + static const uint8_t _stringsTableSP[]; + static const uint8_t _stringsTableIT[]; +}; + +struct Resource { + typedef void (Resource::*LoadStub)(File *); + + enum ObjectType { + OT_MBK, + OT_PGE, + OT_PAL, + OT_CT, + OT_MAP, + OT_SPC, + OT_RP, + OT_RPC, + OT_DEMO, + OT_ANI, + OT_OBJ, + OT_TBN, + OT_SPR, + OT_TAB, + OT_ICN, + OT_FNT, + OT_TXTBIN, + OT_CMD, + OT_POL, + OT_SPRM, + OT_OFF, + OT_CMP, + OT_OBC, + OT_SPL, + OT_LEV, + OT_SGD, + OT_SPM + }; + + enum { + NUM_SFXS = 66, + NUM_SPRITES = 1287 + }; + + static const uint16_t _voicesOffsetsTable[]; + static const uint32_t _spmOffsetsTable[]; + static const char *_splNames[]; + + FileSystem *_fs; + ResourceType _type; + Language _lang; + bool _hasSeqData; + char _entryName[32]; + uint8_t *_fnt; + uint8_t *_mbk; + uint8_t *_icn; + int _icnLen; + uint8_t *_tab; + uint8_t *_spc; // BE + uint16_t _numSpc; + uint8_t _rp[0x4A]; + uint8_t *_pal; // BE + uint8_t *_ani; + uint8_t *_tbn; + int8_t _ctData[0x1D00]; + uint8_t *_spr1; + uint8_t *_sprData[NUM_SPRITES]; // 0-0x22F + 0x28E-0x2E9 ... conrad, 0x22F-0x28D : junkie + uint8_t _sprm[0x10000]; + uint16_t _pgeNum; + InitPGE _pgeInit[256]; + uint8_t *_map; + uint8_t *_lev; + int _levNum; + uint8_t *_sgd; + uint16_t _numObjectNodes; + ObjectNode *_objectNodesMap[255]; + uint8_t *_memBuf; + SoundFx *_sfxList; + uint8_t _numSfx; + uint8_t *_cmd; + uint8_t *_pol; + uint8_t *_cine_off; + uint8_t *_cine_txt; + char **_extTextsTable; + const char **_textsTable; + uint8_t *_extStringsTable; + const uint8_t *_stringsTable; + uint8_t *_bankData; + uint8_t *_bankDataHead; + uint8_t *_bankDataTail; + BankSlot _bankBuffers[50]; + int _bankBuffersCount; + + Resource(FileSystem *fs, ResourceType type, Language lang); + ~Resource(); + + void clearLevelRes(); + void load_FIB(const char *fileName); + void load_SPL_demo(); + void load_MAP_menu(const char *fileName, uint8_t *dstPtr); + void load_PAL_menu(const char *fileName, uint8_t *dstPtr); + void load_SPR_OFF(const char *fileName, uint8_t *sprData); + void load_CINE(); + void load_TEXT(); + void free_TEXT(); + void load(const char *objName, int objType, const char *ext = 0); + void load_CT(File *pf); + void load_FNT(File *pf); + void load_MBK(File *pf); + void load_ICN(File *pf); + void load_SPR(File *pf); + void load_SPRM(File *pf); + void load_RP(File *pf); + void load_SPC(File *pf); + void load_PAL(File *pf); + void load_MAP(File *pf); + void load_OBJ(File *pf); + void free_OBJ(); + void load_OBC(File *pf); + void decodeOBJ(const uint8_t *, int); + void load_PGE(File *pf); + void load_ANI(File *pf); + void load_TBN(File *pf); + void load_CMD(File *pf); + void load_POL(File *pf); + void load_CMP(File *pf); + void load_VCE(int num, int segment, uint8_t **buf, uint32_t *bufSize); + void load_SPL(File *pf); + void load_LEV(File *pf); + void load_SGD(File *pf); + void load_SPM(File *f); + const uint8_t *getAniData(int num) const { + const int offset = READ_LE_UINT16(_ani + num * 2); + return _ani + offset; + } + const uint8_t *getGameString(int num) { + return _stringsTable + READ_LE_UINT16(_stringsTable + num * 2); + } + const uint8_t *getCineString(int num) { + if (_cine_off) { + const int offset = READ_BE_UINT16(_cine_off + num * 2); + return _cine_txt + offset; + } + return 0; + } + const char *getMenuString(int num) { + return (num >= 0 && num < LocaleData::LI_NUM) ? _textsTable[num] : ""; + } + void clearBankData(); + int getBankDataSize(uint16_t num); + uint8_t *findBankData(uint16_t num); + uint8_t *loadBankData(uint16_t num); +}; + +#endif // RESOURCE_H__ diff --git a/scaler.cpp b/scaler.cpp new file mode 100644 index 0000000..8edb46c --- /dev/null +++ b/scaler.cpp @@ -0,0 +1,192 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "scaler.h" + + +static void point1x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) { + dstPitch >>= 1; + while (h--) { + memcpy(dst, src, w * 2); + dst += dstPitch; + src += srcPitch; + } +} + +static void point2x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) { + dstPitch >>= 1; + const int dstPitch2 = dstPitch * 2; + while (h--) { + uint16_t *p = dst; + for (int i = 0; i < w; ++i, p += 2) { + const uint16_t c = *(src + i); + for (int j = 0; j < 2; ++j) { + *(p + j) = *(p + dstPitch + j) = c; + } + } + dst += dstPitch2; + src += srcPitch; + } +} + +static void point3x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) { + dstPitch >>= 1; + const int dstPitch2 = dstPitch * 2; + const int dstPitch3 = dstPitch * 3; + while (h--) { + uint16_t *p = dst; + for (int i = 0; i < w; ++i, p += 3) { + const uint16_t c = *(src + i); + for (int j = 0; j < 3; ++j) { + *(p + j) = *(p + dstPitch + j) = *(p + dstPitch2 + j) = c; + } + } + dst += dstPitch3; + src += srcPitch; + } +} + +static void point4x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) { + dstPitch >>= 1; + const int dstPitch2 = dstPitch * 2; + const int dstPitch3 = dstPitch * 3; + const int dstPitch4 = dstPitch * 4; + while (h--) { + uint16_t *p = dst; + for (int i = 0; i < w; ++i, p += 4) { + const uint16_t c = *(src + i); + for (int j = 0; j < 4; ++j) { + *(p + j) = *(p + dstPitch + j) = *(p + dstPitch2 + j) = *(p + dstPitch3 + j) = c; + } + } + dst += dstPitch4; + src += srcPitch; + } +} + +static void scale2x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) { + dstPitch >>= 1; + const int dstPitch2 = dstPitch * 2; + while (h--) { + uint16_t *p = dst; + uint16_t D = *(src - 1); + uint16_t E = *(src); + for (int i = 0; i < w; ++i, p += 2) { + uint16_t B = *(src + i - srcPitch); + uint16_t F = *(src + i + 1); + uint16_t H = *(src + i + srcPitch); + if (B != H && D != F) { + *(p) = D == B ? D : E; + *(p + 1) = B == F ? F : E; + *(p + dstPitch) = D == H ? D : E; + *(p + dstPitch + 1) = H == F ? F : E; + } else { + *(p) = E; + *(p + 1) = E; + *(p + dstPitch) = E; + *(p + dstPitch + 1) = E; + } + D = E; + E = F; + } + dst += dstPitch2; + src += srcPitch; + } +} + +static void scale3x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) { + dstPitch >>= 1; + const int dstPitch2 = dstPitch * 2; + const int dstPitch3 = dstPitch * 3; + while (h--) { + uint16_t *p = dst; + uint16_t A = *(src - srcPitch - 1); + uint16_t B = *(src - srcPitch); + uint16_t D = *(src - 1); + uint16_t E = *(src); + uint16_t G = *(src + srcPitch - 1); + uint16_t H = *(src + srcPitch); + for (int i = 0; i < w; ++i, p += 3) { + uint16_t C = *(src + i - srcPitch + 1); + uint16_t F = *(src + i + 1); + uint16_t I = *(src + i + srcPitch + 1); + if (B != H && D != F) { + *(p) = D == B ? D : E; + *(p + 1) = (D == B && E != C) || (B == F && E != A) ? B : E; + *(p + 2) = B == F ? F : E; + *(p + dstPitch) = (D == B && E != G) || (D == B && E != A) ? D : E; + *(p + dstPitch + 1) = E; + *(p + dstPitch + 2) = (B == F && E != I) || (H == F && E != C) ? F : E; + *(p + dstPitch2) = D == H ? D : E; + *(p + dstPitch2 + 1) = (D == H && E != I) || (H == F && E != G) ? H : E; + *(p + dstPitch2 + 2) = H == F ? F : E; + } else { + *(p) = E; + *(p + 1) = E; + *(p + 2) = E; + *(p + dstPitch) = E; + *(p + dstPitch + 1) = E; + *(p + dstPitch + 2) = E; + *(p + dstPitch2) = E; + *(p + dstPitch2 + 1) = E; + *(p + dstPitch2 + 2) = E; + } + A = B; + B = C; + D = E; + E = F; + G = H; + H = I; + } + dst += dstPitch3; + src += srcPitch; + } +} + +void scale4x(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h) { + static struct { + uint16_t *ptr; + int w, h, pitch; + int size; + } buf; + const int size = (w * 2 + 2) * (h * 2 + 2) * sizeof(uint16_t); + if (buf.size < size) { + free(buf.ptr); + buf.size = size; + buf.w = w * 2; + buf.h = h * 2; + buf.pitch = buf.w + 2; + buf.ptr = (uint16_t *)malloc(buf.size); + if (!buf.ptr) { + error("Unable to allocate scale4x intermediate buffer"); + } + } + scale2x(buf.ptr + buf.pitch + 1, buf.pitch * sizeof(uint16_t), src, srcPitch, w, h); + scale2x(dst, dstPitch, buf.ptr + buf.pitch + 1, buf.pitch, w * 2, h * 2); +} + +const Scaler _scalers[] = { + { "point1x", &point1x, 1 }, + { "point2x", &point2x, 2 }, + { "scale2x", &scale2x, 2 }, + { "point3x", &point3x, 3 }, + { "scale3x", &scale3x, 3 }, + { "point4x", &point4x, 4 }, + { "scale4x", &scale4x, 4 }, + { 0, 0, 0 } +}; + diff --git a/scaler.h b/scaler.h new file mode 100644 index 0000000..f6b4be2 --- /dev/null +++ b/scaler.h @@ -0,0 +1,44 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SCALER_H__ +#define SCALER_H__ + +#include "intern.h" + +typedef void (*ScaleProc)(uint16_t *dst, int dstPitch, const uint16_t *src, int srcPitch, int w, int h); + +enum { + SCALER_POINT_1X = 0, + SCALER_POINT_2X, + SCALER_SCALE_2X, + SCALER_POINT_3X, + SCALER_SCALE_3X, + SCALER_POINT_4X, + SCALER_SCALE_4X, + NUM_SCALERS = 7 +}; + +struct Scaler { + const char *name; + ScaleProc proc; + uint8_t factor; +}; + +extern const Scaler _scalers[]; + +#endif // SCALER_H__ diff --git a/seq_player.cpp b/seq_player.cpp new file mode 100644 index 0000000..77c6c10 --- /dev/null +++ b/seq_player.cpp @@ -0,0 +1,367 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "file.h" +#include "fs.h" +#include "mixer.h" +#include "seq_player.h" +#include "systemstub.h" + + +bool SeqDemuxer::open(File *f) { + _f = f; + _fileSize = _f->size(); + memset(_buffers, 0, sizeof(_buffers)); + _frameOffset = 0; + return readHeader(); +} + +void SeqDemuxer::close() { + _f = 0; + for (int i = 0; i < kBuffersCount; ++i) { + free(_buffers[i].data); + } +} + +bool SeqDemuxer::readHeader() { + for (int i = 0; i < 256; i += 4) { + if (_f->readUint32LE() != 0) { + return false; + } + } + for (int i = 0; i < kBuffersCount; ++i) { + const int size = _f->readUint16LE(); + if (size != 0) { + _buffers[i].size = 0; + _buffers[i].avail = size; + _buffers[i].data = (uint8_t *)malloc(size); + if (!_buffers[i].data) { + error("Unable to allocate %d bytes for SEQ buffer %d", size, i); + } + } + } + for (int i = 1; i <= 100; ++i) { + readFrameData(); + } + return true; +} + +bool SeqDemuxer::readFrameData() { + _frameOffset += kFrameSize; + if (_frameOffset >= _fileSize) { + return false; + } + _f->seek(_frameOffset); + _audioDataOffset = _f->readUint16LE(); + _audioDataSize = (_audioDataOffset != 0) ? kAudioBufferSize * 2 : 0; + _paletteDataOffset = _f->readUint16LE(); + _paletteDataSize = (_paletteDataOffset != 0) ? 768 : 0; + uint8_t num[4]; + for (int i = 0; i < 4; ++i) { + num[i] = _f->readByte(); + } + uint16_t offsets[4]; + for (int i = 0; i < 4; ++i) { + offsets[i] = _f->readUint16LE(); + } + for (int i = 0; i < 3; ++i) { + if (offsets[i] != 0) { + int e = i + 1; + while (e < 3 && offsets[e] == 0) { + ++e; + } + fillBuffer(num[i + 1], offsets[i], offsets[e] - offsets[i]); + } + } + if (num[0] != 255) { + assert(num[0] < kBuffersCount); + _videoData = num[0]; + } else { + _videoData = -1; + } + return !_f->ioErr(); +} + +void SeqDemuxer::fillBuffer(int num, int offset, int size) { + assert(num < kBuffersCount); + _f->seek(_frameOffset + offset); + assert(_buffers[num].size + size <= _buffers[num].avail); + _f->read(_buffers[num].data + _buffers[num].size, size); + _buffers[num].size += size; +} + +void SeqDemuxer::clearBuffer(int num) { + _buffers[num].size = 0; +} + +void SeqDemuxer::readPalette(uint8_t *dst) { + _f->seek(_frameOffset + _paletteDataOffset); + _f->read(dst, 256 * 3); +} + +void SeqDemuxer::readAudioS8(uint8_t *dst) { + _f->seek(_frameOffset + _audioDataOffset); + for (int i = 0; i < kAudioBufferSize; ++i) { + dst[i] = _f->readUint16BE() >> 8; + } +} + +struct BitStream { + BitStream(const uint8_t *src) + : _src(src) { + _bits = READ_LE_UINT16(_src); _src += 2; + _len = 16; + } + int getBits(int count) { + if (count > _len) { + _bits |= READ_LE_UINT16(_src) << _len; _src += 2; + _len += 16; + } + assert(count <= _len); + const int x = _bits & ((1 << count) - 1); + _bits >>= count; + _len -= count; + return x; + } + int getSignedBits(int count) { + const int32_t x = getBits(count); + return (x << (32 - count)) >> (32 - count); + } + + const uint8_t *_src; + int _len; + uint32_t _bits; +}; + +static const uint8_t *decodeSeqOp1Helper(const uint8_t *src, uint8_t *dst, int dstSize) { + int codes[64], count = 0; + BitStream bs(src); + for (int i = 0, sz = 0; i < 64 && sz < 64; ++i) { + codes[i] = bs.getSignedBits(4); + sz += ABS(codes[i]); + count += 4; + } + src += (count + 7) / 8; + for (int i = 0; i < 64 && dstSize > 0; ++i) { + int len = codes[i]; + if (len < 0) { + len = -len; + memset(dst, *src++, MIN(len, dstSize)); + } else { + memcpy(dst, src, MIN(len, dstSize)); + src += len; + } + dst += len; + dstSize -= len; + } + return src; +} + +static const uint8_t *decodeSeqOp1(uint8_t *dst, int pitch, const uint8_t *src) { + const int len = *src++; + if (len & 0x80) { + uint8_t buf[8 * 8]; + switch (len & 3) { + case 1: + src = decodeSeqOp1Helper(src, buf, sizeof(buf)); + for (int y = 0; y < 8; ++y) { + memcpy(dst, buf + y * 8, 8); + dst += pitch; + } + break; + case 2: + src = decodeSeqOp1Helper(src, buf, sizeof(buf)); + for (int i = 0; i < 8; i++) { + for (int y = 0; y < 8; ++y) { + dst[y * pitch] = buf[i * 8 + y]; + } + ++dst; + } + break; + } + } else { + static const uint8_t log2_16[] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 }; + BitStream bs(src + len); + assert(len <= 16); + const int bits = log2_16[len - 1] + 1; + for (int y = 0; y < 8; ++y) { + for (int x = 0; x < 8; ++x) { + dst[y * pitch + x] = src[bs.getBits(bits)]; + } + } + src += len + bits * 8; + } + return src; +} + +static const uint8_t *decodeSeqOp2(uint8_t *dst, int pitch, const uint8_t *src) { + for (int y = 0; y < 8; ++y) { + memcpy(dst + y * pitch, src, 8); + src += 8; + } + return src; +} + +static const uint8_t *decodeSeqOp3(uint8_t *dst, int pitch, const uint8_t *src) { + int pos; + do { + pos = *src++; + const int offset = ((pos >> 3) & 7) * pitch + (pos & 7); + dst[offset] = *src++; + } while ((pos & 0x80) == 0); + return src; +} + +SeqPlayer::SeqPlayer(SystemStub *stub, Mixer *mixer) + : _stub(stub), _buf(0), _mix(mixer) { + _soundQueuePreloadSize = 0; + _soundQueue = 0; +} + +SeqPlayer::~SeqPlayer() { +} + +void SeqPlayer::play(File *f) { + if (_demux.open(f)) { + Color pal[256]; + for (int i = 0; i < 256; ++i) { + _stub->getPaletteEntry(i, &pal[i]); + } + _mix->setPremixHook(mixCallback, this); + memset(_buf, 0, 256 * 224); + bool clearScreen = true; + while (true) { + const uint32_t nextFrameTimeStamp = _stub->getTimeStamp() + 1000 / 25; + _stub->processEvents(); + if (_stub->_pi.quit || _stub->_pi.backspace) { + _stub->_pi.backspace = false; + break; + } + if (!_demux.readFrameData()) { + break; + } + if (_demux._audioDataSize != 0) { + SoundBufferQueue *sbq = (SoundBufferQueue *)malloc(sizeof(SoundBufferQueue)); + if (sbq) { + sbq->data = (uint8_t *)malloc(SeqDemuxer::kAudioBufferSize); + if (sbq->data) { + _demux.readAudioS8(sbq->data); + sbq->size = SeqDemuxer::kAudioBufferSize; + sbq->read = 0; + sbq->next = 0; + } else { + free(sbq); + sbq = 0; + } + } + if (sbq) { + LockAudioStack las(_stub); + if (!_soundQueue) { + _soundQueue = sbq; + } else { + SoundBufferQueue *p = _soundQueue; + while (p->next) { + p = p->next; + } + p->next = sbq; + } + if (_soundQueuePreloadSize < kSoundPreloadSize) { + ++_soundQueuePreloadSize; + } + } + } + if (_demux._paletteDataSize != 0) { + uint8_t buf[256 * 3]; + _demux.readPalette(buf); + for (int i = 0; i < 256 * 3; ++i) { + buf[i] = (buf[i] << 2) | (buf[i] & 3); + } + _stub->setPalette(buf, 256); + } + if (_demux._videoData != -1) { + const int y0 = (224 - kVideoHeight) / 2; + const uint8_t *src = _demux._buffers[_demux._videoData].data; + _demux.clearBuffer(_demux._videoData); + BitStream bs(src); src += 128; + for (int y = 0; y < kVideoHeight; y += 8) { + for (int x = 0; x < kVideoWidth; x += 8) { + const int offset = (y0 + y) * 256 + x; + switch (bs.getBits(2)) { + case 1: + src = decodeSeqOp1(_buf + offset, 256, src); + break; + case 2: + src = decodeSeqOp2(_buf + offset, 256, src); + break; + case 3: + src = decodeSeqOp3(_buf + offset, 256, src); + break; + } + } + } + if (clearScreen) { + clearScreen = false; + _stub->copyRect(0, 0, kVideoWidth, 224, _buf, 256); + } else { + _stub->copyRect(0, y0, kVideoWidth, kVideoHeight, _buf, 256); + } + _stub->updateScreen(0); + } + const int diff = nextFrameTimeStamp - _stub->getTimeStamp(); + if (diff > 0) { + _stub->sleep(diff); + } + } + for (int i = 0; i < 256; ++i) { + _stub->setPaletteEntry(i, &pal[i]); + } + _mix->setPremixHook(0, 0); + _demux.close(); + // flush sound queue + LockAudioStack las(_stub); + while (_soundQueue) { + SoundBufferQueue *next = _soundQueue->next; + free(_soundQueue->data); + free(_soundQueue); + _soundQueue = next; + } + _soundQueuePreloadSize = 0; + } +} + +bool SeqPlayer::mix(int8_t *buf, int samples) { + if (_soundQueuePreloadSize < kSoundPreloadSize) { + return true; + } + while (_soundQueue && samples > 0) { + *buf++ = _soundQueue->data[_soundQueue->read]; + ++_soundQueue->read; + if (_soundQueue->read == _soundQueue->size) { + SoundBufferQueue *next = _soundQueue->next; + free(_soundQueue->data); + free(_soundQueue); + _soundQueue = next; + } + --samples; + } + return true; +} + +bool SeqPlayer::mixCallback(void *param, int8_t *buf, int len) { + return ((SeqPlayer *)param)->mix(buf, len); +} + diff --git a/seq_player.h b/seq_player.h new file mode 100644 index 0000000..2bd42bc --- /dev/null +++ b/seq_player.h @@ -0,0 +1,92 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SEQ_PLAYER_H__ +#define SEQ_PLAYER_H__ + +#include "intern.h" + +struct File; +struct SystemStub; +struct Mixer; + +struct SeqDemuxer { + enum { + kFrameSize = 6144, + kAudioBufferSize = 882, + kBuffersCount = 30 + }; + + bool open(File *f); + void close(); + + bool readHeader(); + bool readFrameData(); + void fillBuffer(int num, int offset, int size); + void clearBuffer(int num); + void readPalette(uint8_t *dst); + void readAudioS8(uint8_t *dst); + + int _frameOffset; + int _audioDataOffset; + int _audioDataSize; + int _paletteDataOffset; + int _paletteDataSize; + int _videoData; + struct { + int size; + int avail; + uint8_t *data; + } _buffers[kBuffersCount]; + int _fileSize; + File *_f; +}; + +struct SeqPlayer { + enum { + kVideoWidth = 256, + kVideoHeight = 128, + kSoundPreloadSize = 4 + }; + + static const char *_namesTable[]; + + struct SoundBufferQueue { + uint8_t *data; + int size; + int read; + SoundBufferQueue *next; + }; + + SeqPlayer(SystemStub *stub, Mixer *mixer); + ~SeqPlayer(); + + void setBackBuffer(uint8_t *buf) { _buf = buf; } + void play(File *f); + bool mix(int8_t *buf, int len); + static bool mixCallback(void *param, int8_t *buf, int len); + + SystemStub *_stub; + uint8_t *_buf; + Mixer *_mix; + SeqDemuxer _demux; + int _soundQueuePreloadSize; + SoundBufferQueue *_soundQueue; +}; + +#endif // SEQ_PLAYER_H__ + diff --git a/sfx_player.cpp b/sfx_player.cpp new file mode 100644 index 0000000..bee8a2b --- /dev/null +++ b/sfx_player.cpp @@ -0,0 +1,174 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "mixer.h" +#include "sfx_player.h" + + +SfxPlayer::SfxPlayer(Mixer *mixer) + : _mod(0), _playing(false), _mix(mixer) { +} + +void SfxPlayer::play(uint8_t num) { + debug(DBG_SFX, "SfxPlayer::play(%d)", num); + if (!_playing) { + if (num >= 68 && num <= 75) { + static const Module *modTable[] = { + &_module68, &_module68, &_module70, &_module70, + &_module72, &_module73, &_module74, &_module75 + }; + _mod = modTable[num - 68]; + _curOrder = 0; + _numOrders = READ_BE_UINT16(_mod->moduleData); + _orderDelay = 0; + _modData = _mod->moduleData + 0x22; + memset(_samples, 0, sizeof(_samples)); + _samplesLeft = 0; + _mix->setPremixHook(mixCallback, this); + _playing = true; + } + } +} + +void SfxPlayer::stop() { + if (_playing) { + _mix->setPremixHook(0, 0); + _playing = false; + } +} + +void SfxPlayer::playSample(int channel, const uint8_t *sampleData, uint16_t period) { + assert(channel < NUM_CHANNELS); + SampleInfo *si = &_samples[channel]; + si->len = READ_BE_UINT16(sampleData); sampleData += 2; + si->vol = READ_BE_UINT16(sampleData); sampleData += 2; + si->loopPos = READ_BE_UINT16(sampleData); sampleData += 2; + si->loopLen = READ_BE_UINT16(sampleData); sampleData += 2; + si->freq = PAULA_FREQ / period; + si->pos = 0; + si->data = sampleData; +} + +void SfxPlayer::handleTick() { + if (!_playing) { + return; + } + if (_orderDelay != 0) { + --_orderDelay; + // check for end of song + if (_orderDelay == 0 && _modData == 0) { + _playing = false; + } + } else { + _orderDelay = READ_BE_UINT16(_mod->moduleData + 2); + debug(DBG_SFX, "curOrder=%d/%d _orderDelay=%d\n", _curOrder, _numOrders, _orderDelay); + int16_t period = 0; + for (int ch = 0; ch < 3; ++ch) { + const uint8_t *sampleData = 0; + uint8_t b = *_modData++; + if (b != 0) { + --b; + assert(b < 5); + period = READ_BE_UINT16(_mod->moduleData + 4 + b * 2); + sampleData = _mod->sampleData[b]; + } + b = *_modData++; + if (b != 0) { + int16_t per = period + (b - 1); + if (per >= 0 && per < 40) { + per = _periodTable[per]; + } else if (per == -3) { + per = 0xA0; + } else { + per = 0x71; + } + playSample(ch, sampleData, per); + } + } + ++_curOrder; + if (_curOrder >= _numOrders) { + debug(DBG_SFX, "End of song"); + _orderDelay += 20; + _modData = 0; + } + } +} + +void SfxPlayer::mixSamples(int8_t *buf, int samplesLen) { + for (int i = 0; i < NUM_CHANNELS; ++i) { + SampleInfo *si = &_samples[i]; + if (si->data) { + int8_t *mixbuf = buf; + int len = si->len << FRAC_BITS; + int loopLen = si->loopLen << FRAC_BITS; + int loopPos = si->loopPos << FRAC_BITS; + int deltaPos = (si->freq << FRAC_BITS) / _mix->getSampleRate(); + int curLen = samplesLen; + int pos = si->pos; + while (curLen != 0) { + int count; + if (loopLen > (2 << FRAC_BITS)) { + assert(si->loopPos + si->loopLen <= si->len); + if (pos >= loopPos + loopLen) { + pos -= loopLen; + } + count = MIN(curLen, (loopPos + loopLen - pos - 1) / deltaPos + 1); + curLen -= count; + } else { + if (pos >= len) { + count = 0; + } else { + count = MIN(curLen, (len - pos - 1) / deltaPos + 1); + } + curLen = 0; + } + while (count--) { + int out = resampleLinear(si, pos, deltaPos, FRAC_BITS); + Mixer::addclamp(*mixbuf++, out * si->vol / 64); + pos += deltaPos; + } + } + si->pos = pos; + } + } +} + +bool SfxPlayer::mix(int8_t *buf, int len) { + if (_playing) { + memset(buf, 0, len); + const int samplesPerTick = _mix->getSampleRate() / 50; + while (len != 0) { + if (_samplesLeft == 0) { + handleTick(); + _samplesLeft = samplesPerTick; + } + int count = _samplesLeft; + if (count > len) { + count = len; + } + _samplesLeft -= count; + len -= count; + mixSamples(buf, count); + buf += count; + } + } + return _playing; +} + +bool SfxPlayer::mixCallback(void *param, int8_t *buf, int len) { + return ((SfxPlayer *)param)->mix(buf, len); +} diff --git a/sfx_player.h b/sfx_player.h new file mode 100644 index 0000000..588368f --- /dev/null +++ b/sfx_player.h @@ -0,0 +1,101 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SFX_PLAYER_H__ +#define SFX_PLAYER_H__ + +#include "intern.h" + +struct Mixer; + +struct SfxPlayer { + enum { + NUM_SAMPLES = 5, + NUM_CHANNELS = 3, + FRAC_BITS = 12, + PAULA_FREQ = 3546897 + }; + + struct Module { + const uint8_t *sampleData[NUM_SAMPLES]; + const uint8_t *moduleData; + }; + + struct SampleInfo { + uint16_t len; + uint16_t vol; + uint16_t loopPos; + uint16_t loopLen; + int freq; + int pos; + const uint8_t *data; + + int8_t getPCM(int offset) const { + if (offset < 0) { + offset = 0; + } else if (offset >= (int)len) { + offset = len - 1; + } + return (int8_t)data[offset]; + } + }; + + static const uint8_t _musicData68[]; + static const uint8_t _musicData70[]; + static const uint8_t _musicData72[]; + static const uint8_t _musicData73[]; + static const uint8_t _musicData74[]; + static const uint8_t _musicData75[]; + static const uint8_t _musicDataSample1[]; + static const uint8_t _musicDataSample2[]; // tick + static const uint8_t _musicDataSample3[]; // bell + static const uint8_t _musicDataSample4[]; + static const uint8_t _musicDataSample5[]; + static const uint8_t _musicDataSample6[]; + static const uint8_t _musicDataSample7[]; + static const uint8_t _musicDataSample8[]; + static const Module _module68; + static const Module _module70; + static const Module _module72; + static const Module _module73; + static const Module _module74; + static const Module _module75; + static const uint16_t _periodTable[]; + + const Module *_mod; + bool _playing; + int _samplesLeft; + uint16_t _curOrder; + uint16_t _numOrders; + uint16_t _orderDelay; + const uint8_t *_modData; + SampleInfo _samples[NUM_CHANNELS]; + Mixer *_mix; + + SfxPlayer(Mixer *mixer); + + void play(uint8_t num); + void stop(); + void playSample(int channel, const uint8_t *sampleData, uint16_t period); + void handleTick(); + bool mix(int8_t *buf, int len); + void mixSamples(int8_t *buf, int samplesLen); + + static bool mixCallback(void *param, int8_t *buf, int len); +}; + +#endif // SFX_PLAYER_H__ diff --git a/staticres.cpp b/staticres.cpp new file mode 100644 index 0000000..adfc41d --- /dev/null +++ b/staticres.cpp @@ -0,0 +1,3972 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "game.h" +#include "resource.h" + + +const Cutscene::OpcodeStub Cutscene::_opcodeTable[] = { + /* 0x00 */ + &Cutscene::op_markCurPos, + &Cutscene::op_refreshScreen, + &Cutscene::op_waitForSync, + &Cutscene::op_drawShape, + /* 0x04 */ + &Cutscene::op_setPalette, + &Cutscene::op_markCurPos, + &Cutscene::op_drawStringAtBottom, + &Cutscene::op_nop, + /* 0x08 */ + &Cutscene::op_skip3, + &Cutscene::op_refreshAll, + &Cutscene::op_drawShapeScale, + &Cutscene::op_drawShapeScaleRotate, + /* 0x0C */ + &Cutscene::op_drawCreditsText, + &Cutscene::op_drawStringAtPos, + &Cutscene::op_handleKeys +}; + +const char *Cutscene::_namesTable[] = { + "DEBUT", + "OBJET", + "CARTE", + "GEN", + "CHUTE", + "CODE", + "DESINTEG", + "INTRO1", + "STREM", + "HOLOSEQ", + "CARTEID", + "PONT", + "ASC", + "MAP", + "METRO", + "MISSIONS", + "GENMIS", + "MEMO", + "TAXI", + "ACCROCHE", + "VOYAGE", + "TELEPORT", + "LIFT", + "ESPIONS", + "LOG", + "FIN", + "GENEXP", + "LOGOS", + "OVER", + "SCORE", + "INTRO2" +}; + +const uint16_t Cutscene::_offsetsTable[] = { + 0x0000, 0x0000, 0x0001, 0x0003, 0x0001, 0x0004, 0xFFFF, 0x0000, 0x0001, 0x0002, + 0x0003, 0x0000, 0x0004, 0x0000, 0xFFFF, 0x0100, 0xFFFF, 0x0000, 0x0006, 0x0000, + 0x0001, 0x0001, 0xFFFF, 0x0000, 0xFFFF, 0x0200, 0x8007, 0x0000, 0x0003, 0x0001, + 0x0001, 0x000B, 0x0001, 0x0005, 0x0009, 0x0000, 0x0001, 0x0006, 0xFFFF, 0x0000, + 0x000B, 0x0000, 0x0001, 0x000A, 0xFFFF, 0x0001, 0xFFFF, 0x0002, 0xFFFF, 0x0000, + 0x000D, 0x0004, 0x000D, 0x0000, 0x000D, 0x0001, 0x000D, 0x0002, 0x000D, 0x0003, + 0xFFFF, 0x0000, 0xFFFF, 0x0001, 0x0001, 0x000C, 0x0001, 0x000D, 0x0001, 0x000E, + 0x0001, 0x000F, 0x0001, 0x0010, 0x000F, 0x0000, 0x000F, 0x0001, 0x000F, 0x0001, + 0x000F, 0x0003, 0x000F, 0x0002, 0x000F, 0x0004, 0x0001, 0x0008, 0x0001, 0x0007, + 0x000F, 0x0005, 0xFFFF, 0x0000, 0x0004, 0x0001, 0x0011, 0x0000, 0x0001, 0x0009, + 0x0012, 0x0000, 0xFFFF, 0x0000, 0x0014, 0x0000, 0x0015, 0x0000, 0x0016, 0x0000, + 0x0016, 0x0001, 0xFFFF, 0x0012, 0x0017, 0x0000, 0x0001, 0x0011, 0x0018, 0x0000, + 0x0001, 0x0013, 0x0019, 0x0000, 0x001A, 0x0000, 0x0019, 0x0001, 0x001B, 0x0000, + 0x001C, 0x0000, 0x000F, 0x0006, 0x000F, 0x0006, 0x000F, 0x0007, 0x000F, 0x0008, + 0x000F, 0x0009, 0x000F, 0x000A, 0x001D, 0x0000, 0x001B, 0x0001, 0x001E, 0x0000, + 0xFFFF, 0x0000 +}; + +const uint16_t Cutscene::_cosTable[] = { + 0x0100, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FE, 0x00FE, + 0x00FD, 0x00FC, 0x00FC, 0x00FB, 0x00FA, 0x00F9, 0x00F8, 0x00F7, + 0x00F6, 0x00F4, 0x00F3, 0x00F2, 0x00F0, 0x00EE, 0x00ED, 0x00EB, + 0x00E9, 0x00E8, 0x00E6, 0x00E4, 0x00E2, 0x00DF, 0x00DD, 0x00DB, + 0x00D9, 0x00D6, 0x00D4, 0x00D1, 0x00CF, 0x00CC, 0x00C9, 0x00C6, + 0x00C4, 0x00C1, 0x00BE, 0x00BB, 0x00B8, 0x00B5, 0x00B1, 0x00AE, + 0x00AB, 0x00A7, 0x00A4, 0x00A1, 0x009D, 0x009A, 0x0096, 0x0092, + 0x008F, 0x008B, 0x0087, 0x0083, 0x007F, 0x007C, 0x0078, 0x0074, + 0x0070, 0x006C, 0x0068, 0x0064, 0x005F, 0x005B, 0x0057, 0x0053, + 0x004F, 0x004A, 0x0046, 0x0042, 0x003D, 0x0039, 0x0035, 0x0030, + 0x002C, 0x0028, 0x0023, 0x001F, 0x001A, 0x0016, 0x0011, 0x000D, + 0x0008, 0x0004, 0x0000, 0xFFFC, 0xFFF8, 0xFFF3, 0xFFEF, 0xFFEA, + 0xFFE6, 0xFFE1, 0xFFDD, 0xFFD8, 0xFFD4, 0xFFD0, 0xFFCB, 0xFFC7, + 0xFFC3, 0xFFBE, 0xFFBA, 0xFFB6, 0xFFB1, 0xFFAD, 0xFFA9, 0xFFA5, + 0xFFA1, 0xFF9C, 0xFF98, 0xFF94, 0xFF90, 0xFF8C, 0xFF88, 0xFF84, + 0xFF80, 0xFF7D, 0xFF79, 0xFF75, 0xFF71, 0xFF6E, 0xFF6A, 0xFF66, + 0xFF63, 0xFF5F, 0xFF5C, 0xFF59, 0xFF55, 0xFF52, 0xFF4F, 0xFF4B, + 0xFF48, 0xFF45, 0xFF42, 0xFF3F, 0xFF3C, 0xFF3A, 0xFF37, 0xFF34, + 0xFF31, 0xFF2F, 0xFF2C, 0xFF2A, 0xFF27, 0xFF25, 0xFF23, 0xFF21, + 0xFF1E, 0xFF1C, 0xFF1A, 0xFF18, 0xFF17, 0xFF15, 0xFF13, 0xFF12, + 0xFF10, 0xFF0E, 0xFF0D, 0xFF0C, 0xFF0A, 0xFF09, 0xFF08, 0xFF07, + 0xFF06, 0xFF05, 0xFF04, 0xFF04, 0xFF03, 0xFF02, 0xFF02, 0xFF01, + 0xFF01, 0xFF01, 0xFF01, 0xFF01, 0xFF00, 0xFF01, 0xFF01, 0xFF01, + 0xFF01, 0xFF01, 0xFF02, 0xFF02, 0xFF03, 0xFF04, 0xFF04, 0xFF05, + 0xFF06, 0xFF07, 0xFF08, 0xFF09, 0xFF0A, 0xFF0C, 0xFF0D, 0xFF0E, + 0xFF10, 0xFF12, 0xFF13, 0xFF15, 0xFF17, 0xFF18, 0xFF1A, 0xFF1C, + 0xFF1E, 0xFF21, 0xFF23, 0xFF25, 0xFF27, 0xFF2A, 0xFF2C, 0xFF2F, + 0xFF31, 0xFF34, 0xFF37, 0xFF3A, 0xFF3C, 0xFF3F, 0xFF42, 0xFF45, + 0xFF48, 0xFF4B, 0xFF4F, 0xFF52, 0xFF55, 0xFF59, 0xFF5C, 0xFF5F, + 0xFF63, 0xFF66, 0xFF6A, 0xFF6E, 0xFF71, 0xFF75, 0xFF79, 0xFF7D, + 0xFF81, 0xFF84, 0xFF88, 0xFF8C, 0xFF90, 0xFF94, 0xFF98, 0xFF9C, + 0xFFA1, 0xFFA5, 0xFFA9, 0xFFAD, 0xFFB1, 0xFFB6, 0xFFBA, 0xFFBE, + 0xFFC3, 0xFFC7, 0xFFCB, 0xFFD0, 0xFFD4, 0xFFD8, 0xFFDD, 0xFFE1, + 0xFFE6, 0xFFEA, 0xFFEF, 0xFFF3, 0xFFF8, 0xFFFC, 0x0000, 0x0004, + 0x0008, 0x000D, 0x0011, 0x0016, 0x001A, 0x001F, 0x0023, 0x0028, + 0x002C, 0x0030, 0x0035, 0x0039, 0x003D, 0x0042, 0x0046, 0x004A, + 0x004F, 0x0053, 0x0057, 0x005B, 0x005F, 0x0064, 0x0068, 0x006C, + 0x0070, 0x0074, 0x0078, 0x007C, 0x0080, 0x0083, 0x0087, 0x008B, + 0x008F, 0x0092, 0x0096, 0x009A, 0x009D, 0x00A1, 0x00A4, 0x00A7, + 0x00AB, 0x00AE, 0x00B1, 0x00B5, 0x00B8, 0x00BB, 0x00BE, 0x00C1, + 0x00C4, 0x00C6, 0x00C9, 0x00CC, 0x00CF, 0x00D1, 0x00D4, 0x00D6, + 0x00D9, 0x00DB, 0x00DD, 0x00DF, 0x00E2, 0x00E4, 0x00E6, 0x00E8, + 0x00E9, 0x00EB, 0x00ED, 0x00EE, 0x00F0, 0x00F2, 0x00F3, 0x00F4, + 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FC, + 0x00FD, 0x00FE, 0x00FE, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF +}; + +const uint16_t Cutscene::_sinTable[] = { + 0x0000, 0x0004, 0x0008, 0x000D, 0x0011, 0x0016, 0x001A, 0x001F, + 0x0023, 0x0028, 0x002C, 0x0030, 0x0035, 0x0039, 0x003D, 0x0042, + 0x0046, 0x004A, 0x004F, 0x0053, 0x0057, 0x005B, 0x005F, 0x0064, + 0x0068, 0x006C, 0x0070, 0x0074, 0x0078, 0x007C, 0x007F, 0x0083, + 0x0087, 0x008B, 0x008F, 0x0092, 0x0096, 0x009A, 0x009D, 0x00A1, + 0x00A4, 0x00A7, 0x00AB, 0x00AE, 0x00B1, 0x00B5, 0x00B8, 0x00BB, + 0x00BE, 0x00C1, 0x00C4, 0x00C6, 0x00C9, 0x00CC, 0x00CF, 0x00D1, + 0x00D4, 0x00D6, 0x00D9, 0x00DB, 0x00DD, 0x00DF, 0x00E2, 0x00E4, + 0x00E6, 0x00E8, 0x00E9, 0x00EB, 0x00ED, 0x00EE, 0x00F0, 0x00F2, + 0x00F3, 0x00F4, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, + 0x00FC, 0x00FC, 0x00FD, 0x00FE, 0x00FE, 0x00FF, 0x00FF, 0x00FF, + 0x00FF, 0x00FF, 0x0100, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, + 0x00FE, 0x00FE, 0x00FD, 0x00FC, 0x00FC, 0x00FB, 0x00FA, 0x00F9, + 0x00F8, 0x00F7, 0x00F6, 0x00F4, 0x00F3, 0x00F2, 0x00F0, 0x00EE, + 0x00ED, 0x00EB, 0x00E9, 0x00E8, 0x00E6, 0x00E4, 0x00E2, 0x00DF, + 0x00DD, 0x00DB, 0x00D9, 0x00D6, 0x00D4, 0x00D1, 0x00CF, 0x00CC, + 0x00C9, 0x00C6, 0x00C4, 0x00C1, 0x00BE, 0x00BB, 0x00B8, 0x00B5, + 0x00B1, 0x00AE, 0x00AB, 0x00A7, 0x00A4, 0x00A1, 0x009D, 0x009A, + 0x0096, 0x0092, 0x008F, 0x008B, 0x0087, 0x0083, 0x007F, 0x007C, + 0x0078, 0x0074, 0x0070, 0x006C, 0x0068, 0x0064, 0x005F, 0x005B, + 0x0057, 0x0053, 0x004F, 0x004A, 0x0046, 0x0042, 0x003D, 0x0039, + 0x0035, 0x0030, 0x002C, 0x0028, 0x0023, 0x001F, 0x001A, 0x0016, + 0x0011, 0x000D, 0x0008, 0x0004, 0x0000, 0xFFFC, 0xFFF8, 0xFFF3, + 0xFFEF, 0xFFEA, 0xFFE6, 0xFFE1, 0xFFDD, 0xFFD8, 0xFFD4, 0xFFD0, + 0xFFCB, 0xFFC7, 0xFFC3, 0xFFBE, 0xFFBA, 0xFFB6, 0xFFB1, 0xFFAD, + 0xFFA9, 0xFFA5, 0xFFA1, 0xFF9C, 0xFF98, 0xFF94, 0xFF90, 0xFF8C, + 0xFF88, 0xFF84, 0xFF80, 0xFF7D, 0xFF79, 0xFF75, 0xFF71, 0xFF6E, + 0xFF6A, 0xFF66, 0xFF63, 0xFF5F, 0xFF5C, 0xFF59, 0xFF55, 0xFF52, + 0xFF4F, 0xFF4B, 0xFF48, 0xFF45, 0xFF42, 0xFF3F, 0xFF3C, 0xFF3A, + 0xFF37, 0xFF34, 0xFF31, 0xFF2F, 0xFF2C, 0xFF2A, 0xFF27, 0xFF25, + 0xFF23, 0xFF21, 0xFF1E, 0xFF1C, 0xFF1A, 0xFF18, 0xFF17, 0xFF15, + 0xFF13, 0xFF12, 0xFF10, 0xFF0E, 0xFF0D, 0xFF0C, 0xFF0A, 0xFF09, + 0xFF08, 0xFF07, 0xFF06, 0xFF05, 0xFF04, 0xFF04, 0xFF03, 0xFF02, + 0xFF02, 0xFF01, 0xFF01, 0xFF01, 0xFF01, 0xFF01, 0xFF00, 0xFF01, + 0xFF01, 0xFF01, 0xFF01, 0xFF01, 0xFF02, 0xFF02, 0xFF03, 0xFF04, + 0xFF04, 0xFF05, 0xFF06, 0xFF07, 0xFF08, 0xFF09, 0xFF0A, 0xFF0C, + 0xFF0D, 0xFF0E, 0xFF10, 0xFF12, 0xFF13, 0xFF15, 0xFF17, 0xFF18, + 0xFF1A, 0xFF1C, 0xFF1E, 0xFF21, 0xFF23, 0xFF25, 0xFF27, 0xFF2A, + 0xFF2C, 0xFF2F, 0xFF31, 0xFF34, 0xFF37, 0xFF3A, 0xFF3C, 0xFF3F, + 0xFF42, 0xFF45, 0xFF48, 0xFF4B, 0xFF4F, 0xFF52, 0xFF55, 0xFF59, + 0xFF5C, 0xFF5F, 0xFF63, 0xFF66, 0xFF6A, 0xFF6E, 0xFF71, 0xFF75, + 0xFF79, 0xFF7D, 0xFF81, 0xFF84, 0xFF88, 0xFF8C, 0xFF90, 0xFF94, + 0xFF98, 0xFF9C, 0xFFA1, 0xFFA5, 0xFFA9, 0xFFAD, 0xFFB1, 0xFFB6, + 0xFFBA, 0xFFBE, 0xFFC3, 0xFFC7, 0xFFCB, 0xFFD0, 0xFFD4, 0xFFD8, + 0xFFDD, 0xFFE1, 0xFFE6, 0xFFEA, 0xFFEF, 0xFFF3, 0xFFF8, 0xFFFC +}; + +const uint8_t Cutscene::_creditsData[] = { + 0xFE, 0x14, 0x00, 0x01, 0x00, 0x04, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x46, 0x6C, 0x61, 0x73, + 0x68, 0x42, 0x61, 0x63, 0x6B, 0x20, 0x54, 0x65, 0x61, 0x6D, 0x20, 0x69, 0x73, 0x2E, 0x2E, 0x2E, + 0xFE, 0x32, 0xFE, 0x14, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x05, 0x20, 0x20, 0x49, 0x6E, + 0x69, 0x74, 0x69, 0x61, 0x6C, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x50, 0x72, + 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x6D, 0x65, 0x72, 0x73, 0x3A, 0x7C, 0x7C, 0xFE, 0x1E, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x42, 0x65, 0x6E, 0x6F, 0x69, + 0x73, 0x74, 0x20, 0x41, 0x72, 0x6F, 0x6E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x68, 0x69, 0x6C, + 0x69, 0x70, 0x70, 0x65, 0x20, 0x43, 0x68, 0x61, 0x73, 0x74, 0x65, 0x6C, 0x20, 0x20, 0x20, 0x7C, + 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x50, 0x61, 0x75, 0x6C, 0x20, 0x43, 0x75, 0x69, 0x73, 0x73, 0x65, 0x74, 0x20, 0x20, + 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x46, 0x72, 0x65, 0x64, 0x65, 0x72, 0x69, 0x63, 0x20, 0x53, 0x61, 0x76, 0x6F, 0x69, 0x72, 0x20, + 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x50, 0xFE, 0x1E, 0x00, 0x01, 0x00, 0x05, 0x20, 0x20, 0x47, 0x72, + 0x61, 0x70, 0x68, 0x69, 0x63, 0x20, 0x41, 0x72, 0x74, 0x69, 0x73, 0x74, 0x73, 0x3A, 0x7C, 0x7C, + 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, + 0x61, 0x74, 0x72, 0x69, 0x63, 0x6B, 0x20, 0x44, 0x61, 0x68, 0x65, 0x72, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x54, 0x68, 0x69, 0x65, 0x72, 0x72, 0x79, 0x20, 0x4C, 0x65, 0x76, 0x61, 0x73, 0x74, 0x72, + 0x65, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x44, 0x65, 0x6E, 0x69, 0x73, 0x20, 0x4D, 0x65, 0x72, 0x63, 0x69, + 0x65, 0x72, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x69, 0x65, 0x72, 0x72, 0x79, 0x20, 0x50, 0x65, 0x72, + 0x72, 0x65, 0x61, 0x75, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x68, 0x72, 0x69, 0x73, 0x74, 0x69, 0x61, 0x6E, 0x20, 0x52, + 0x6F, 0x62, 0x65, 0x72, 0x74, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x61, 0x62, 0x72, 0x69, 0x63, 0x65, + 0x20, 0x56, 0x69, 0x73, 0x73, 0x65, 0x72, 0x6F, 0x74, 0x20, 0x20, 0x7C, 0xFE, 0x50, 0xFE, 0x1E, + 0x00, 0x01, 0x00, 0x07, 0x20, 0x20, 0x50, 0x43, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, + 0x20, 0x50, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x6D, 0x65, 0x72, 0x73, 0x3A, 0x7C, 0x7C, 0xFE, + 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x68, 0x69, + 0x6C, 0x69, 0x70, 0x70, 0x65, 0x20, 0x43, 0x68, 0x61, 0x73, 0x74, 0x65, 0x6C, 0x20, 0x20, 0x20, + 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x50, 0x61, 0x75, 0x6C, 0x20, 0x43, 0x75, 0x69, 0x73, 0x73, 0x65, 0x74, 0x20, + 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x54, 0x68, 0x69, 0x65, 0x72, 0x72, 0x79, 0x20, 0x47, 0x61, 0x65, 0x72, 0x74, 0x68, + 0x6E, 0x65, 0x72, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x6C, 0x61, 0x69, 0x6E, 0x20, 0x52, 0x61, 0x6D, 0x6F, + 0x6E, 0x64, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0xB4, 0xFE, 0x1E, 0x00, 0x01, 0x00, 0x05, 0x20, + 0x20, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x50, 0x43, 0x20, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x3A, 0x7C, 0x7C, 0xFE, 0x1E, 0x7C, 0x7C, 0xFE, 0x1E, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x69, + 0x65, 0x72, 0x72, 0x79, 0x20, 0x4C, 0x65, 0x76, 0x61, 0x73, 0x74, 0x72, 0x65, 0x20, 0x20, 0x7C, + 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x44, 0x65, 0x6E, 0x69, 0x73, 0x20, 0x4D, 0x65, 0x72, 0x63, 0x69, 0x65, 0x72, 0x20, 0x20, + 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x54, 0x68, 0x69, 0x65, 0x72, 0x72, 0x79, 0x20, 0x50, 0x65, 0x72, 0x72, 0x65, 0x61, 0x75, + 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x50, 0xFE, 0x1E, 0x00, 0x01, 0x00, 0x05, 0x20, 0x20, 0x53, 0x74, + 0x6F, 0x72, 0x79, 0x3A, 0x7C, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x75, 0x6C, 0x20, 0x43, 0x75, 0x69, + 0x73, 0x73, 0x65, 0x74, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x50, 0xFE, 0x1E, 0x00, 0x01, 0x00, 0x05, + 0x20, 0x20, 0x4C, 0x65, 0x76, 0x65, 0x6C, 0x20, 0x44, 0x65, 0x73, 0x69, 0x67, 0x6E, 0x3A, 0x7C, + 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x50, 0x61, 0x75, 0x6C, 0x20, 0x43, 0x75, 0x69, 0x73, 0x73, 0x65, 0x74, 0x20, + 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x50, 0x61, 0x74, 0x72, 0x69, 0x63, 0x6B, 0x20, 0x44, 0x61, 0x68, 0x65, 0x72, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x44, 0x65, 0x6E, 0x69, 0x73, 0x20, 0x4D, 0x65, 0x72, 0x63, + 0x69, 0x65, 0x72, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x72, 0x65, 0x64, 0x65, 0x72, 0x69, 0x63, 0x20, 0x53, 0x61, + 0x76, 0x6F, 0x69, 0x72, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x61, 0x62, 0x72, 0x69, 0x63, 0x65, 0x20, + 0x56, 0x69, 0x73, 0x73, 0x65, 0x72, 0x6F, 0x74, 0x20, 0x20, 0x7C, 0xFE, 0x50, 0xFE, 0x1E, 0x00, + 0x01, 0x00, 0x05, 0x20, 0x20, 0x4D, 0x75, 0x73, 0x69, 0x63, 0x3A, 0x7C, 0x7C, 0xFE, 0x1E, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4A, + 0x65, 0x61, 0x6E, 0x20, 0x42, 0x61, 0x75, 0x64, 0x6C, 0x6F, 0x74, 0x20, 0x20, 0x20, 0x7C, 0xFE, + 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x61, + 0x62, 0x72, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x73, 0x65, 0x72, 0x6F, 0x74, 0x20, 0x20, + 0x7C, 0xFE, 0x50, 0xFE, 0x1E, 0x00, 0x01, 0x00, 0x08, 0x20, 0x20, 0x53, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x66, 0x78, 0x3A, 0x7C, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x42, 0x65, 0x6E, 0x6F, 0x69, 0x73, 0x74, 0x20, 0x41, 0x72, 0x6F, + 0x6E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x68, 0x69, 0x6C, 0x69, 0x70, 0x70, 0x65, 0x20, 0x43, + 0x68, 0x61, 0x73, 0x74, 0x65, 0x6C, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x75, 0x6C, + 0x20, 0x43, 0x75, 0x69, 0x73, 0x73, 0x65, 0x74, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x61, 0x62, 0x72, 0x69, + 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x73, 0x65, 0x72, 0x6F, 0x74, 0x20, 0x20, 0x7C, 0xFE, 0x50, + 0xFE, 0x1E, 0x00, 0x01, 0x00, 0x06, 0x20, 0x20, 0x41, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x3A, 0x7C, + 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x42, 0x65, 0x6E, 0x6F, 0x69, 0x73, 0x74, 0x20, 0x41, 0x72, 0x6F, 0x6E, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x50, 0x61, 0x74, 0x72, 0x69, 0x63, 0x6B, 0x20, 0x44, 0x61, 0x68, 0x65, 0x72, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x69, 0x65, 0x72, 0x72, 0x79, 0x20, 0x4C, 0x65, 0x76, 0x61, + 0x73, 0x74, 0x72, 0x65, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x44, 0x65, 0x6E, 0x69, 0x73, 0x20, 0x4D, 0x65, + 0x72, 0x63, 0x69, 0x65, 0x72, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x69, 0x65, 0x72, 0x72, 0x79, 0x20, + 0x50, 0x65, 0x72, 0x72, 0x65, 0x61, 0x75, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x68, 0x72, 0x69, 0x73, 0x74, 0x69, 0x61, + 0x6E, 0x20, 0x52, 0x6F, 0x62, 0x65, 0x72, 0x74, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x61, 0x62, 0x72, + 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x73, 0x65, 0x72, 0x6F, 0x74, 0x20, 0x20, 0x7C, 0xFE, + 0x50, 0xFE, 0x1E, 0x00, 0x01, 0x00, 0x06, 0x20, 0x20, 0x53, 0x74, 0x75, 0x6E, 0x74, 0x6D, 0x61, + 0x6E, 0x3A, 0x7C, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x44, 0x65, 0x6E, 0x69, 0x73, 0x20, 0x4D, 0x65, 0x72, 0x63, 0x69, + 0x65, 0x72, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x50, 0xFE, 0x1E, 0x00, 0x01, 0x00, 0x06, 0x20, 0x20, + 0x56, 0x69, 0x64, 0x65, 0x6F, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x3A, + 0x7C, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x50, 0x61, 0x74, 0x72, 0x69, 0x63, 0x6B, 0x20, 0x44, 0x61, 0x68, 0x65, 0x72, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x54, 0x68, 0x69, 0x65, 0x72, 0x72, 0x79, 0x20, 0x50, 0x65, 0x72, 0x72, 0x65, + 0x61, 0x75, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x61, 0x62, 0x72, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, + 0x73, 0x65, 0x72, 0x6F, 0x74, 0x20, 0x20, 0x7C, 0xFE, 0x50, 0xFE, 0x1E, 0x00, 0x01, 0x00, 0x06, + 0x20, 0x20, 0x56, 0x69, 0x64, 0x65, 0x6F, 0x20, 0x43, 0x6F, 0x2D, 0x64, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x6F, 0x72, 0x73, 0x3A, 0x7C, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x69, 0x65, 0x72, 0x72, 0x79, 0x20, 0x4C, 0x65, + 0x76, 0x61, 0x73, 0x74, 0x72, 0x65, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x44, 0x65, 0x6E, 0x69, 0x73, 0x20, + 0x4D, 0x65, 0x72, 0x63, 0x69, 0x65, 0x72, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x68, 0x72, 0x69, 0x73, 0x74, 0x69, 0x61, + 0x6E, 0x20, 0x52, 0x6F, 0x62, 0x65, 0x72, 0x74, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x50, 0xFE, + 0x1E, 0x00, 0x01, 0x00, 0x06, 0x20, 0x20, 0x56, 0x69, 0x64, 0x65, 0x6F, 0x20, 0x73, 0x66, 0x78, + 0x3A, 0x7C, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x75, 0x6C, 0x20, 0x43, 0x75, 0x69, 0x73, 0x73, 0x65, + 0x74, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x69, 0x65, 0x72, 0x72, 0x79, 0x20, 0x50, 0x65, 0x72, 0x72, + 0x65, 0x61, 0x75, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x61, 0x62, 0x72, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, + 0x73, 0x73, 0x65, 0x72, 0x6F, 0x74, 0x20, 0x20, 0x7C, 0xFE, 0x50, 0xFE, 0x1E, 0x00, 0x01, 0x00, + 0x07, 0x20, 0x20, 0x54, 0x65, 0x73, 0x74, 0x65, 0x72, 0x73, 0x3A, 0x7C, 0x7C, 0xFE, 0x1E, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, + 0x68, 0x69, 0x6C, 0x20, 0x42, 0x72, 0x61, 0x64, 0x6C, 0x65, 0x79, 0x20, 0x20, 0x20, 0x7C, 0xFE, + 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x74, + 0x72, 0x69, 0x63, 0x69, 0x61, 0x20, 0x43, 0x75, 0x69, 0x73, 0x73, 0x65, 0x74, 0x20, 0x20, 0x20, + 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x53, 0x69, 0x6D, 0x6F, 0x6E, 0x20, 0x48, 0x61, 0x64, 0x6C, 0x69, 0x6E, 0x67, 0x74, + 0x6F, 0x6E, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x44, 0x61, 0x6E, 0x69, 0x65, 0x6C, 0x20, 0x4C, 0x6C, 0x65, 0x77, 0x65, 0x6C, + 0x6C, 0x79, 0x6E, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x4A, 0x65, 0x61, 0x6E, 0x2D, 0x50, 0x69, 0x65, 0x72, 0x72, 0x65, 0x20, 0x4C, 0x75, 0x63, 0x6B, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4D, 0x61, 0x72, 0x74, 0x69, 0x6E, 0x20, 0x53, 0x6D, + 0x69, 0x74, 0x68, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x50, 0xFE, 0x1E, 0x00, 0x01, 0x00, + 0x08, 0x20, 0x20, 0x4D, 0x61, 0x6E, 0x79, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x6B, 0x73, 0x20, 0x74, + 0x6F, 0x2E, 0x2E, 0x2E, 0x7C, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4C, 0x6F, 0x72, 0x69, 0x20, 0x43, 0x68, 0x72, 0x69, + 0x73, 0x74, 0x65, 0x6E, 0x73, 0x65, 0x6E, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x74, 0x72, 0x69, 0x63, 0x69, 0x61, 0x20, 0x43, 0x75, + 0x69, 0x73, 0x73, 0x65, 0x74, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x6E, 0x6E, 0x65, 0x2D, 0x4D, 0x61, 0x72, 0x69, 0x65, 0x20, + 0x4A, 0x6F, 0x61, 0x73, 0x73, 0x69, 0x6D, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4A, 0x65, 0x61, 0x6E, 0x2D, 0x50, 0x69, 0x65, 0x72, 0x72, + 0x65, 0x20, 0x4C, 0x75, 0x63, 0x6B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4D, + 0x61, 0x72, 0x63, 0x20, 0x4D, 0x69, 0x6E, 0x69, 0x65, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, + 0xFE, 0x50, 0xFE, 0x1E, 0x00, 0x01, 0x00, 0x05, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x20, 0x62, 0x79, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x50, 0x61, 0x75, 0x6C, 0x20, 0x43, 0x75, 0x69, 0x73, 0x73, 0x65, 0x74, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x50, 0xFE, 0x1E, 0x00, 0x01, 0x00, + 0x03, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x72, 0x6F, 0x64, 0x75, + 0x63, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7C, 0x7C, 0xFE, 0x1E, 0x20, 0x7C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x44, 0x65, 0x6C, + 0x70, 0x68, 0x69, 0x6E, 0x65, 0x20, 0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x55, 0x53, 0x20, 0x47, 0x4F, 0x4C, 0x44, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x1E, 0x20, 0x7C, 0x20, 0x7C, + 0x20, 0x7C, 0x20, 0x7C, 0x20, 0x7C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x28, 0x63, 0x29, 0x4D, 0x43, 0x4D, 0x58, 0x43, 0x49, 0x49, 0x49, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x50, 0xFE, 0xFF, 0x00, 0xFF +}; + +const uint16_t Cutscene::_creditsCutSeq[] = { + 0x00, 0x05, 0x2F, 0x32, 0x36, 0x3E, 0x30, 0x39, 0x3F, 0x14, 0x34, 0xFFFF +}; + +const uint8_t Cutscene::_musicTable[] = { + 0x10, 0x15, 0x15, 0xFF, 0x15, 0x19, 0x0F, 0xFF, 0x15, 0x04, 0x15, 0xFF, 0xFF, 0x00, 0x19, 0x15, + 0x15, 0x0D, 0x15, 0x0D, 0x18, 0x13, 0xFF, 0xFF, 0xFF, 0x14, 0x14, 0x14, 0x14, 0x14, 0xFF, 0xFF, + 0x13, 0x13, 0x13, 0x13, 0x15, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x13, 0x13, 0x11, 0xFF, 0x03, + 0x0E, 0x13, 0x12, 0xFF, 0x06, 0x07, 0x0A, 0x0A, 0x15, 0x05, 0x13, 0x02, 0x15, 0x09, 0x17, 0x08, + 0x0B, 0x0C, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xFF, 0xFF, 0xFF +}; + +const uint8_t Cutscene::_protectionShapeData[] = { + 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x06, 0xD4, 0x00, 0x00, 0x00, 0x92, + 0x00, 0x00, 0x08, 0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x28, 0x00, 0x54, 0x00, 0x8C, 0x00, 0xB2, + 0x00, 0xDE, 0x01, 0x21, 0x01, 0x54, 0x01, 0x7B, 0x01, 0x9D, 0x01, 0xC2, 0x01, 0xF0, 0x02, 0x2C, + 0x02, 0x66, 0x02, 0x9F, 0x02, 0xBF, 0x02, 0xF7, 0x03, 0x35, 0x03, 0x75, 0x03, 0xA4, 0x03, 0xFE, + 0x04, 0x3B, 0x04, 0x7B, 0x04, 0xB6, 0x04, 0xF8, 0x05, 0x3B, 0x05, 0x66, 0x05, 0x9E, 0x05, 0xD2, + 0x06, 0x10, 0x00, 0x00, 0x0F, 0xFF, 0x02, 0x22, 0x03, 0x33, 0x04, 0x44, 0x05, 0x55, 0x06, 0x66, + 0x07, 0x77, 0x08, 0x88, 0x09, 0x99, 0x0A, 0xAA, 0x0B, 0xBB, 0x0C, 0xCC, 0x0D, 0xDD, 0x0E, 0xEE, + 0x0F, 0xFF, 0x00, 0x00, 0x04, 0x05, 0x05, 0x05, 0x00, 0x00, 0x04, 0x44, 0x05, 0x55, 0x06, 0x66, + 0x07, 0x77, 0x08, 0x88, 0x09, 0x99, 0x0A, 0xAA, 0x0B, 0xBB, 0x0C, 0xCC, 0x0D, 0xDD, 0x0E, 0xEE, + 0x0F, 0xFF, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x00, + 0x03, 0x01, 0x00, 0x04, 0x02, 0x00, 0x05, 0x01, 0x00, 0x06, 0x02, 0x00, 0x07, 0x02, 0x00, 0x08, + 0x02, 0x00, 0x09, 0x01, 0x00, 0x0A, 0x02, 0x00, 0x0B, 0x02, 0x00, 0x0A, 0x00, 0x0C, 0x02, 0x00, + 0x0D, 0x01, 0x00, 0x0E, 0x02, 0x00, 0x0F, 0x01, 0x80, 0x0A, 0x00, 0x61, 0x00, 0x00, 0x02, 0x00, + 0x10, 0x01, 0x80, 0x02, 0xFF, 0xC9, 0xFF, 0xFF, 0x02, 0x80, 0x04, 0xFF, 0xB1, 0xFF, 0xFF, 0x02, + 0x00, 0x11, 0x01, 0x00, 0x12, 0x02, 0x00, 0x0E, 0x00, 0x00, 0x02, 0x80, 0x0D, 0x00, 0x00, 0x00, + 0x0E, 0x01, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x0E, 0x02, 0x00, 0x13, 0x01, 0x00, 0x14, 0x02, 0x00, + 0x15, 0x01, 0x00, 0x16, 0x02, 0x80, 0x0B, 0xFF, 0xEE, 0x00, 0x4C, 0x02, 0x00, 0x17, 0x01, 0x00, + 0x18, 0x01, 0x00, 0x19, 0x02, 0x00, 0x1A, 0x02, 0x00, 0x1B, 0x02, 0x00, 0x1C, 0x02, 0x00, 0x08, + 0x00, 0x00, 0x02, 0x00, 0x18, 0x01, 0x00, 0x19, 0x02, 0x80, 0x0D, 0x00, 0x00, 0x00, 0x46, 0x01, + 0x80, 0x0E, 0x00, 0x00, 0x00, 0x46, 0x02, 0x00, 0x1D, 0x01, 0x00, 0x1E, 0x02, 0x80, 0x0B, 0x00, + 0x08, 0x00, 0x4D, 0x02, 0x00, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x1F, 0x01, 0x00, 0x20, 0x02, 0x00, + 0x21, 0x02, 0x00, 0x22, 0x02, 0x00, 0x23, 0x01, 0x00, 0x24, 0x02, 0x00, 0x25, 0x01, 0x00, 0x26, + 0x01, 0x00, 0x27, 0x02, 0x00, 0x28, 0x01, 0x00, 0x29, 0x02, 0x00, 0x2A, 0x01, 0x00, 0x2B, 0x01, + 0x00, 0x0F, 0x00, 0x00, 0x02, 0x00, 0x2C, 0x01, 0x00, 0x2D, 0x01, 0x00, 0x2E, 0x02, 0x00, 0x2F, + 0x01, 0x00, 0x30, 0x02, 0x80, 0x18, 0x00, 0x00, 0x00, 0x7F, 0x01, 0x80, 0x19, 0x00, 0x00, 0x00, + 0x7F, 0x02, 0x80, 0x0A, 0x00, 0x03, 0xFF, 0xB2, 0x01, 0x80, 0x0A, 0x00, 0x03, 0xFF, 0xDB, 0x01, + 0x00, 0x31, 0x01, 0x00, 0x32, 0x01, 0x00, 0x33, 0x01, 0x80, 0x31, 0x00, 0x10, 0x00, 0x22, 0x02, + 0x00, 0x34, 0x02, 0x00, 0x0F, 0x00, 0x00, 0x02, 0x00, 0x14, 0x02, 0x00, 0x15, 0x01, 0x00, 0x16, + 0x02, 0x80, 0x0B, 0xFF, 0xEE, 0x00, 0x4C, 0x02, 0x00, 0x18, 0x01, 0x00, 0x19, 0x02, 0x00, 0x25, + 0x01, 0x00, 0x26, 0x01, 0x00, 0x27, 0x02, 0x00, 0x28, 0x01, 0x00, 0x29, 0x02, 0x00, 0x2A, 0x01, + 0x00, 0x35, 0x01, 0x00, 0x36, 0x02, 0x00, 0x0B, 0x00, 0x00, 0x02, 0x00, 0x37, 0x01, 0x00, 0x38, + 0x02, 0x00, 0x39, 0x01, 0x00, 0x3A, 0x02, 0x00, 0x3B, 0x02, 0x80, 0x28, 0xFF, 0xC8, 0x00, 0x0B, + 0x01, 0x00, 0x3C, 0x02, 0x00, 0x3D, 0x01, 0x00, 0x3E, 0x01, 0x00, 0x3F, 0x02, 0x00, 0x08, 0x00, + 0x00, 0x02, 0x00, 0x40, 0x01, 0x00, 0x41, 0x02, 0x00, 0x42, 0x01, 0x80, 0x2D, 0x00, 0x00, 0x00, + 0x7E, 0x01, 0x80, 0x2E, 0x00, 0x00, 0x00, 0x36, 0x02, 0x00, 0x43, 0x01, 0x00, 0x44, 0x02, 0x00, + 0x09, 0x00, 0x00, 0x02, 0x00, 0x45, 0x01, 0x00, 0x46, 0x02, 0x00, 0x47, 0x01, 0x00, 0x48, 0x02, + 0x00, 0x49, 0x01, 0x80, 0x2D, 0xFF, 0xDA, 0x00, 0x7D, 0x01, 0x80, 0x2E, 0xFF, 0xE5, 0x00, 0x36, + 0x02, 0x00, 0x4A, 0x01, 0x00, 0x0C, 0x00, 0x00, 0x02, 0x00, 0x25, 0x01, 0x00, 0x26, 0x01, 0x00, + 0x27, 0x02, 0x00, 0x28, 0x01, 0x00, 0x29, 0x02, 0x00, 0x2A, 0x01, 0x00, 0x10, 0x01, 0x80, 0x02, + 0xFF, 0xC9, 0xFF, 0xFF, 0x02, 0x80, 0x04, 0xFF, 0xB1, 0xFF, 0xFF, 0x02, 0x00, 0x11, 0x01, 0x00, + 0x12, 0x02, 0x00, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x4B, 0x01, 0x00, 0x4C, 0x02, 0x80, 0x14, 0x00, + 0x34, 0xFF, 0xDF, 0x02, 0x00, 0x4D, 0x01, 0x00, 0x4E, 0x02, 0x00, 0x4F, 0x01, 0x00, 0x50, 0x02, + 0x00, 0x51, 0x02, 0x00, 0x52, 0x02, 0x80, 0x18, 0x00, 0x7F, 0x00, 0x7F, 0x01, 0x80, 0x19, 0x00, + 0x7F, 0x00, 0x7F, 0x02, 0x00, 0x53, 0x03, 0x80, 0x2B, 0xFF, 0xF9, 0x00, 0x05, 0x01, 0x00, 0x0C, + 0x00, 0x00, 0x02, 0x00, 0x40, 0x01, 0x00, 0x41, 0x02, 0x00, 0x54, 0x01, 0x80, 0x38, 0xFF, 0xF3, + 0x00, 0x00, 0x02, 0x80, 0x2E, 0x00, 0x00, 0x00, 0x36, 0x02, 0x80, 0x47, 0x00, 0x00, 0x00, 0x2C, + 0x01, 0x00, 0x55, 0x02, 0x80, 0x47, 0x00, 0x00, 0x00, 0x0D, 0x01, 0x80, 0x55, 0x00, 0x00, 0xFF, + 0xE1, 0x02, 0x00, 0x43, 0x01, 0x00, 0x44, 0x02, 0x00, 0x0D, 0x00, 0x00, 0x02, 0x00, 0x39, 0x01, + 0x00, 0x3A, 0x02, 0x00, 0x3B, 0x02, 0x80, 0x28, 0xFF, 0xC8, 0x00, 0x0B, 0x01, 0x00, 0x3C, 0x02, + 0x80, 0x15, 0x00, 0x00, 0xFF, 0xF1, 0x01, 0x80, 0x16, 0x00, 0x00, 0xFF, 0xF1, 0x02, 0x80, 0x0B, + 0xFF, 0xEE, 0x00, 0x3D, 0x02, 0x00, 0x56, 0x01, 0x00, 0x57, 0x02, 0x00, 0x58, 0x01, 0x00, 0x59, + 0x02, 0x00, 0x0A, 0x00, 0x00, 0x02, 0x00, 0x5A, 0x01, 0x00, 0x5B, 0x02, 0x00, 0x5C, 0x01, 0x00, + 0x5D, 0x02, 0x00, 0x5E, 0x01, 0x00, 0x5F, 0x01, 0x00, 0x60, 0x02, 0x00, 0x61, 0x02, 0x00, 0x62, + 0x01, 0x00, 0x0A, 0x00, 0x00, 0x02, 0x00, 0x63, 0x01, 0x80, 0x41, 0x00, 0x3B, 0x00, 0x1F, 0x02, + 0x80, 0x56, 0x00, 0x00, 0xFF, 0xCB, 0x01, 0x80, 0x57, 0x00, 0x00, 0xFF, 0xCB, 0x02, 0x00, 0x64, + 0x01, 0x00, 0x65, 0x02, 0x80, 0x28, 0x00, 0x05, 0xFF, 0xF3, 0x01, 0x80, 0x18, 0x00, 0x00, 0x00, + 0x7F, 0x01, 0x80, 0x19, 0x00, 0x00, 0x00, 0x7F, 0x02, 0x00, 0x0C, 0x00, 0x00, 0x02, 0x00, 0x39, + 0x01, 0x00, 0x3A, 0x02, 0x00, 0x3B, 0x02, 0x80, 0x28, 0xFF, 0xC8, 0x00, 0x0B, 0x01, 0x00, 0x3C, + 0x02, 0x80, 0x15, 0x00, 0x00, 0xFF, 0xDF, 0x01, 0x80, 0x16, 0x00, 0x00, 0xFF, 0xDF, 0x02, 0x80, + 0x0B, 0xFF, 0xEE, 0x00, 0x2B, 0x02, 0x00, 0x66, 0x01, 0x80, 0x5B, 0x00, 0x2F, 0x00, 0x00, 0x02, + 0x80, 0x62, 0x00, 0x2F, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x02, 0x80, 0x18, 0x00, 0x00, + 0x00, 0x7F, 0x01, 0x80, 0x19, 0x00, 0x00, 0x00, 0x7F, 0x02, 0x80, 0x5A, 0x00, 0x00, 0xFF, 0xA3, + 0x01, 0x80, 0x5B, 0x00, 0x00, 0xFF, 0xC5, 0x02, 0x80, 0x62, 0x00, 0x00, 0xFF, 0xC5, 0x01, 0x80, + 0x47, 0x00, 0x00, 0x00, 0x2C, 0x01, 0x00, 0x55, 0x02, 0x80, 0x47, 0x00, 0x00, 0x00, 0x0D, 0x01, + 0x80, 0x55, 0x00, 0x00, 0xFF, 0xE1, 0x02, 0x00, 0x0B, 0x00, 0x00, 0x02, 0x00, 0x67, 0x01, 0x00, + 0x68, 0x02, 0x00, 0x69, 0x01, 0x00, 0x6A, 0x01, 0x00, 0x6B, 0x02, 0x00, 0x6C, 0x02, 0x80, 0x58, + 0xFF, 0xD2, 0xFF, 0xE0, 0x01, 0x80, 0x59, 0xFF, 0xD2, 0xFF, 0xE0, 0x02, 0x00, 0x6D, 0x01, 0x80, + 0x14, 0xFF, 0xDB, 0x00, 0x16, 0x01, 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x42, 0x01, 0x80, 0x2D, + 0x00, 0x00, 0x00, 0x7E, 0x01, 0x80, 0x2E, 0x00, 0x00, 0x00, 0x36, 0x02, 0x00, 0x10, 0x01, 0x80, + 0x02, 0xFF, 0xC9, 0xFF, 0xFF, 0x02, 0x80, 0x04, 0xFF, 0xB1, 0xFF, 0xFF, 0x02, 0x00, 0x11, 0x01, + 0x00, 0x12, 0x02, 0x80, 0x31, 0x00, 0x04, 0xFF, 0xED, 0x01, 0x00, 0x6E, 0x01, 0x80, 0x33, 0x00, + 0x04, 0xFF, 0x97, 0x01, 0x80, 0x31, 0x00, 0x14, 0xFF, 0xCB, 0x02, 0x80, 0x34, 0x00, 0x04, 0xFF, + 0xEC, 0x02, 0x80, 0x47, 0x00, 0x00, 0x00, 0x04, 0x01, 0x80, 0x55, 0x00, 0x00, 0xFF, 0xD8, 0x02, + 0x00, 0x0D, 0x00, 0x00, 0x02, 0x80, 0x31, 0xFF, 0xBB, 0xFF, 0xFF, 0x01, 0x80, 0x32, 0xFF, 0xBB, + 0xFF, 0xFF, 0x01, 0x00, 0x6F, 0x01, 0x80, 0x31, 0xFF, 0xCB, 0x00, 0x21, 0x02, 0x80, 0x34, 0xFF, + 0xBB, 0xFF, 0xFF, 0x02, 0x00, 0x18, 0x01, 0x00, 0x19, 0x02, 0x00, 0x70, 0x01, 0x00, 0x71, 0x02, + 0x00, 0x72, 0x02, 0x00, 0x73, 0x02, 0x80, 0x28, 0xFF, 0xEE, 0x00, 0x2B, 0x01, 0x00, 0x0E, 0x00, + 0x00, 0x02, 0x00, 0x74, 0x01, 0x80, 0x2D, 0xFF, 0xF1, 0x00, 0x7D, 0x01, 0x80, 0x2E, 0x00, 0x00, + 0x00, 0x36, 0x02, 0x80, 0x31, 0xFF, 0xFB, 0xFF, 0xBF, 0x01, 0x00, 0x75, 0x01, 0x00, 0x76, 0x01, + 0x80, 0x31, 0x00, 0x1D, 0xFF, 0xCF, 0x02, 0x00, 0x77, 0x02, 0x00, 0x40, 0x01, 0x00, 0x41, 0x02, + 0x00, 0x78, 0x01, 0x00, 0x79, 0x01, 0x80, 0x28, 0xFF, 0xF8, 0x00, 0x05, 0x01, 0x00, 0x0F, 0x00, + 0x00, 0x02, 0x00, 0x4D, 0x01, 0x00, 0x4B, 0x01, 0x00, 0x7A, 0x02, 0x80, 0x14, 0x00, 0x33, 0xFF, + 0xDC, 0x02, 0x00, 0x4E, 0x02, 0x00, 0x7B, 0x01, 0x00, 0x7C, 0x02, 0x80, 0x15, 0x00, 0x66, 0xFF, + 0xD5, 0x01, 0x00, 0x7D, 0x02, 0x80, 0x0B, 0x00, 0x43, 0x00, 0x21, 0x02, 0x00, 0x7E, 0x01, 0x00, + 0x7F, 0x01, 0x00, 0x80, 0x01, 0x00, 0x81, 0x02, 0x00, 0x0C, 0x00, 0x00, 0x02, 0x80, 0x54, 0x00, + 0x00, 0xFF, 0xBA, 0x01, 0x80, 0x38, 0xFF, 0xF3, 0xFF, 0xF3, 0x02, 0x00, 0x56, 0x01, 0x00, 0x57, + 0x02, 0x00, 0x58, 0x01, 0x00, 0x59, 0x02, 0x80, 0x47, 0x00, 0x00, 0xFF, 0xEA, 0x01, 0x80, 0x55, + 0x00, 0x00, 0xFF, 0xBE, 0x02, 0x80, 0x47, 0x00, 0x00, 0xFF, 0xCB, 0x01, 0x80, 0x55, 0x00, 0x00, + 0xFF, 0x9F, 0x02, 0x80, 0x2B, 0x00, 0x0A, 0xFF, 0xC0, 0x01, 0x00, 0x0F, 0x00, 0x00, 0x02, 0x00, + 0x82, 0x01, 0x00, 0x83, 0x01, 0x80, 0x18, 0x00, 0x7F, 0x00, 0x00, 0x01, 0x80, 0x19, 0x00, 0x7F, + 0x00, 0x00, 0x02, 0x00, 0x53, 0x03, 0x00, 0x84, 0x01, 0x00, 0x85, 0x02, 0x00, 0x86, 0x02, 0x80, + 0x31, 0x00, 0x1D, 0x00, 0x1D, 0x02, 0x00, 0x87, 0x01, 0x80, 0x0A, 0x00, 0x16, 0xFF, 0xF6, 0x02, + 0x00, 0x88, 0x02, 0x80, 0x31, 0xFF, 0xFB, 0x00, 0x2D, 0x01, 0x00, 0x89, 0x01, 0x00, 0x0B, 0x00, + 0x00, 0x02, 0x00, 0x8A, 0x01, 0x80, 0x46, 0x00, 0x01, 0xFF, 0xE9, 0x02, 0x00, 0x8B, 0x01, 0x80, + 0x78, 0xFF, 0xDF, 0x00, 0x0B, 0x02, 0x00, 0x8C, 0x01, 0x00, 0x8D, 0x01, 0x00, 0x8E, 0x02, 0x00, + 0x8F, 0x01, 0x00, 0x90, 0x02, 0x00, 0x91, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x92, 0x01, + 0x80, 0x02, 0xFF, 0xA7, 0x00, 0x58, 0x02, 0x00, 0x93, 0x01, 0x00, 0x94, 0x02, 0x00, 0x95, 0x02, + 0x00, 0x96, 0x01, 0x00, 0x97, 0x02, 0x00, 0x98, 0x01, 0x00, 0x99, 0x02, 0x00, 0x9A, 0x01, 0x00, + 0x9B, 0x02, 0x80, 0x9A, 0xFF, 0xE1, 0x00, 0x00, 0x01, 0x80, 0x9B, 0xFF, 0xE1, 0x00, 0x00, 0x02, + 0x00, 0x0A, 0x00, 0x00, 0x02, 0x80, 0x02, 0xFF, 0xA7, 0x00, 0x58, 0x02, 0x00, 0x9C, 0x01, 0x00, + 0x9D, 0x02, 0x00, 0x9E, 0x02, 0x80, 0x73, 0xFF, 0xBF, 0x00, 0x7F, 0x02, 0x80, 0x28, 0xFF, 0xAB, + 0x00, 0x2C, 0x01, 0x80, 0x18, 0x00, 0x7F, 0x00, 0x7F, 0x01, 0x80, 0x19, 0x00, 0x7F, 0x00, 0x7F, + 0x02, 0x00, 0x53, 0x03, 0x00, 0x0C, 0x00, 0x00, 0x02, 0x80, 0x17, 0x00, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x9F, 0x01, 0x00, 0xA0, 0x02, 0x80, 0x14, 0x00, 0x02, 0x00, 0x03, 0x02, 0x80, 0x4E, 0x00, + 0x39, 0xFF, 0xF0, 0x02, 0x00, 0xA1, 0x01, 0x80, 0x7F, 0x00, 0x3B, 0x00, 0x26, 0x01, 0x00, 0xA2, + 0x01, 0x80, 0x78, 0x00, 0x01, 0xFF, 0xB4, 0x02, 0x00, 0xA3, 0x02, 0x80, 0x28, 0xFF, 0xF4, 0xFF, + 0xF6, 0x01, 0x00, 0x0D, 0x00, 0x00, 0x02, 0x00, 0x25, 0x01, 0x00, 0x26, 0x01, 0x00, 0x27, 0x02, + 0x00, 0x28, 0x01, 0x00, 0x29, 0x02, 0x00, 0x2A, 0x01, 0x00, 0xA4, 0x01, 0x00, 0xA5, 0x02, 0x00, + 0xA6, 0x01, 0x00, 0xA7, 0x02, 0x80, 0xA6, 0xFF, 0xE1, 0x00, 0x00, 0x01, 0x80, 0xA7, 0xFF, 0xE1, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x26, 0x00, 0x2F, 0x00, 0x3A, 0x00, 0x43, + 0x00, 0x54, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x7F, 0x00, 0x8E, 0x00, 0x97, 0x00, 0xA0, 0x00, 0xAB, + 0x00, 0xC6, 0x00, 0xE1, 0x00, 0xF0, 0x01, 0x0B, 0x01, 0x1C, 0x01, 0x25, 0x01, 0x30, 0x01, 0x39, + 0x01, 0x44, 0x01, 0x55, 0x01, 0x5E, 0x01, 0x67, 0x01, 0x70, 0x01, 0x7B, 0x01, 0x86, 0x01, 0x8F, + 0x01, 0x9A, 0x01, 0xAB, 0x01, 0xB4, 0x01, 0xC1, 0x01, 0xCA, 0x01, 0xD3, 0x01, 0xF8, 0x02, 0x11, + 0x02, 0x1C, 0x02, 0x25, 0x02, 0x2E, 0x02, 0x37, 0x02, 0x40, 0x02, 0x4F, 0x02, 0x5A, 0x02, 0x65, + 0x02, 0x6E, 0x02, 0x77, 0x02, 0x90, 0x02, 0xA7, 0x02, 0xB0, 0x02, 0xBB, 0x02, 0xC6, 0x02, 0xD1, + 0x02, 0xF6, 0x03, 0x0F, 0x03, 0x1A, 0x03, 0x23, 0x03, 0x2E, 0x03, 0x37, 0x03, 0x48, 0x03, 0x51, + 0x03, 0x6A, 0x03, 0x75, 0x03, 0x8E, 0x03, 0x99, 0x03, 0xA2, 0x03, 0xAD, 0x03, 0xCE, 0x03, 0xE9, + 0x03, 0xF4, 0x03, 0xFD, 0x04, 0x16, 0x04, 0x2D, 0x04, 0x38, 0x04, 0x41, 0x04, 0x4C, 0x04, 0x57, + 0x04, 0x60, 0x04, 0x69, 0x04, 0x72, 0x04, 0x7F, 0x04, 0x88, 0x04, 0x99, 0x04, 0xA6, 0x04, 0xB1, + 0x04, 0xC2, 0x04, 0xCD, 0x04, 0xE2, 0x04, 0xFB, 0x05, 0x0C, 0x05, 0x17, 0x05, 0x20, 0x05, 0x2B, + 0x05, 0x34, 0x05, 0x4D, 0x05, 0x58, 0x05, 0x71, 0x05, 0x84, 0x05, 0x8D, 0x05, 0x98, 0x05, 0xB3, + 0x05, 0xC4, 0x05, 0xCF, 0x05, 0xDA, 0x05, 0xE3, 0x05, 0xEE, 0x05, 0xF7, 0x06, 0x02, 0x06, 0x0F, + 0x06, 0x1A, 0x06, 0x25, 0x06, 0x30, 0x06, 0x3B, 0x06, 0x4C, 0x06, 0x55, 0x06, 0x5E, 0x06, 0x69, + 0x06, 0x74, 0x06, 0x7F, 0x06, 0x8A, 0x06, 0x93, 0x06, 0x9C, 0x06, 0xAB, 0x06, 0xB6, 0x06, 0xBF, + 0x06, 0xD0, 0x06, 0xD9, 0x06, 0xE2, 0x06, 0xFB, 0x07, 0x0C, 0x07, 0x17, 0x07, 0x22, 0x07, 0x2D, + 0x07, 0x3E, 0x07, 0x4F, 0x07, 0x58, 0x07, 0x63, 0x07, 0x6C, 0x07, 0x77, 0x07, 0x86, 0x07, 0x91, + 0x07, 0x9A, 0x07, 0xA3, 0x07, 0xAC, 0x07, 0xB5, 0x07, 0xBE, 0x07, 0xD9, 0x07, 0xEA, 0x07, 0xF3, + 0x07, 0xFC, 0x08, 0x07, 0x08, 0x1C, 0x08, 0x35, 0x08, 0x46, 0x08, 0x5F, 0x08, 0x70, 0x08, 0x7B, + 0x08, 0x8C, 0x08, 0x95, 0x08, 0xA0, 0x08, 0xAF, 0x08, 0xB6, 0x08, 0xBF, 0x08, 0xCA, 0x08, 0xEF, + 0x09, 0x08, 0x09, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x7F, 0x81, 0x00, 0x0B, + 0x00, 0x7F, 0x00, 0x00, 0x00, 0x7F, 0xFA, 0x00, 0xF8, 0xFE, 0xFA, 0xFD, 0xF7, 0xF7, 0xFC, 0xF9, + 0xFE, 0xF8, 0xFF, 0xFA, 0x00, 0xFC, 0x00, 0xA8, 0x1C, 0x00, 0xFF, 0x00, 0x5B, 0x00, 0x03, 0x00, + 0x1E, 0x00, 0x1E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x19, 0xAD, 0x00, 0xFF, 0x00, + 0x67, 0x00, 0x4A, 0x00, 0x0F, 0x00, 0x16, 0x06, 0x00, 0x5B, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x03, + 0xFE, 0x06, 0xFC, 0x04, 0xFC, 0x01, 0xFD, 0x00, 0x06, 0x00, 0x53, 0x00, 0x01, 0x00, 0x18, 0xEB, + 0x00, 0x01, 0xF9, 0x03, 0xF9, 0x06, 0xFA, 0x06, 0xFD, 0x02, 0x00, 0x5B, 0x00, 0x23, 0x17, 0x17, + 0xE9, 0x06, 0x06, 0x00, 0x00, 0x00, 0x02, 0x06, 0x03, 0x06, 0x06, 0x03, 0x07, 0x02, 0x0A, 0xEB, + 0x00, 0x00, 0xE5, 0x05, 0x00, 0x00, 0x00, 0x1A, 0x65, 0x65, 0x9B, 0x00, 0x00, 0xDE, 0x1E, 0xFA, + 0x01, 0x00, 0xFF, 0x00, 0x0F, 0x00, 0x5D, 0x00, 0x0F, 0x00, 0x0F, 0xFF, 0x00, 0x27, 0x00, 0x19, + 0x00, 0x15, 0x00, 0x18, 0x03, 0x00, 0x7F, 0x00, 0x7F, 0x82, 0x00, 0x00, 0x81, 0x7E, 0x00, 0x0B, + 0x00, 0x7F, 0x00, 0x11, 0xE6, 0x0D, 0x00, 0xFB, 0x01, 0xFB, 0x03, 0xF9, 0x04, 0xFA, 0x03, 0xFD, + 0x06, 0xFD, 0x02, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x05, 0x00, 0x0B, 0x00, 0x7F, 0x00, 0x22, 0xE3, + 0x0D, 0x00, 0xFB, 0x01, 0xFB, 0x03, 0xF9, 0x04, 0xFA, 0x03, 0xFD, 0x06, 0xFD, 0x02, 0x00, 0x00, + 0x00, 0x02, 0xFF, 0x08, 0x00, 0x05, 0x00, 0x60, 0x00, 0x57, 0x01, 0x00, 0x1E, 0x06, 0x00, 0x22, + 0x9B, 0x00, 0x65, 0x9B, 0x0B, 0x00, 0x08, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x57, 0x00, 0x04, 0xFF, + 0x06, 0xFE, 0x08, 0xFC, 0x07, 0xF7, 0x09, 0xFA, 0x03, 0xF8, 0x03, 0xFA, 0x00, 0x00, 0x81, 0x06, + 0x00, 0x24, 0x00, 0x0D, 0xFD, 0x00, 0xFC, 0xFF, 0xFC, 0xFC, 0xFE, 0xFA, 0x00, 0xFE, 0x0D, 0x00, + 0x02, 0x00, 0x24, 0x00, 0x3F, 0xE9, 0xFA, 0x17, 0xE9, 0x03, 0x00, 0x7F, 0x00, 0x2D, 0x00, 0x52, + 0x81, 0x00, 0x00, 0xEE, 0xFF, 0x00, 0x25, 0x00, 0x50, 0x00, 0x19, 0x00, 0x19, 0x03, 0x00, 0x00, + 0x00, 0x69, 0x00, 0xD0, 0x19, 0x00, 0x00, 0x30, 0x06, 0x00, 0x01, 0x00, 0x39, 0x18, 0x00, 0x00, + 0x15, 0xF9, 0xFF, 0xF9, 0xFD, 0xFA, 0xFA, 0xFD, 0xFA, 0x02, 0x00, 0x01, 0x00, 0x7F, 0x32, 0xE7, + 0x00, 0x19, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x2A, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x18, 0x03, 0x00, 0x7E, 0x00, 0x2D, 0xE9, 0x2D, 0xEE, 0xE5, 0x2A, 0xEB, 0x03, + 0x00, 0x31, 0x00, 0x66, 0xCF, 0x18, 0x00, 0xDF, 0x2A, 0xF5, 0xFF, 0x00, 0x56, 0x00, 0x4C, 0x00, + 0x16, 0x00, 0x16, 0x03, 0x00, 0x2F, 0x00, 0x66, 0x2C, 0x00, 0x00, 0x19, 0xD4, 0x00, 0x06, 0x00, + 0x56, 0x00, 0x7D, 0xFA, 0xFD, 0xFA, 0xFA, 0xFD, 0xF9, 0xFF, 0xF9, 0x15, 0x00, 0x00, 0x18, 0x02, + 0x00, 0x2C, 0x00, 0x7F, 0xD4, 0x00, 0x00, 0xAA, 0x04, 0x00, 0x11, 0x00, 0x70, 0xFE, 0xFC, 0x14, + 0x00, 0x0B, 0x13, 0xF2, 0x00, 0xFF, 0x00, 0x1C, 0x00, 0x69, 0x00, 0x0D, 0x00, 0x0B, 0xFF, 0x00, + 0x19, 0x00, 0x26, 0x00, 0x19, 0x00, 0x36, 0x10, 0x00, 0x2F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x0A, + 0xFE, 0x0F, 0xFE, 0x09, 0xFD, 0x0A, 0xFB, 0x0A, 0xF8, 0x0A, 0xF9, 0x07, 0xF4, 0x08, 0xFC, 0x02, + 0xF9, 0x01, 0x00, 0xE9, 0x08, 0xF9, 0x06, 0xF5, 0x03, 0xF3, 0x02, 0xF3, 0x0A, 0x00, 0x17, 0x00, + 0x3C, 0x08, 0xFF, 0x0A, 0xFD, 0x05, 0xFC, 0x05, 0xFB, 0x06, 0xF7, 0xFE, 0x09, 0xFE, 0x06, 0xF7, + 0x0F, 0xF6, 0x0A, 0xF5, 0x09, 0x03, 0x00, 0x6F, 0x00, 0x1F, 0x10, 0x00, 0x00, 0x60, 0xF0, 0x00, + 0xFF, 0x00, 0x6B, 0x00, 0x2E, 0x00, 0x14, 0x00, 0x27, 0xFF, 0x00, 0x71, 0x00, 0x16, 0x00, 0x0E, + 0x00, 0x17, 0xFF, 0x00, 0x73, 0x00, 0x14, 0x00, 0x07, 0x00, 0x07, 0x02, 0x00, 0x6E, 0x00, 0x4D, + 0x00, 0x09, 0xF8, 0xFF, 0x05, 0x00, 0x6F, 0x00, 0x4D, 0x00, 0x32, 0xE1, 0x00, 0x0E, 0xF2, 0x08, + 0xF6, 0x06, 0xF5, 0x03, 0x00, 0x24, 0x00, 0x68, 0x2D, 0x00, 0x00, 0x07, 0xD3, 0x00, 0x03, 0x00, + 0x51, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x27, 0xD2, 0x00, 0xFF, 0x00, 0x51, 0x00, 0x00, 0x00, 0x2B, + 0x00, 0x26, 0xFF, 0x00, 0x67, 0x00, 0x24, 0x00, 0x17, 0x00, 0x17, 0x0A, 0x00, 0x7F, 0x00, 0x4B, + 0xFB, 0x00, 0xFB, 0xFE, 0x01, 0x00, 0xFA, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFC, 0xF7, 0xFF, 0xFB, + 0x00, 0xFB, 0x1A, 0x0D, 0x09, 0x00, 0x7F, 0x00, 0x39, 0xF8, 0x00, 0xFC, 0xFF, 0xFA, 0xFD, 0xFD, + 0xFD, 0xFC, 0xFA, 0xFD, 0xF9, 0xFF, 0xFB, 0x00, 0xFC, 0x1D, 0x0C, 0xFF, 0x00, 0x4E, 0x00, 0x49, + 0x00, 0x13, 0x00, 0x13, 0x03, 0x00, 0x45, 0x00, 0x36, 0x0C, 0x00, 0x04, 0x47, 0xF0, 0x00, 0x03, + 0x00, 0x45, 0x00, 0x69, 0x1B, 0x00, 0x00, 0x16, 0xE5, 0x00, 0x03, 0x00, 0x38, 0x00, 0x36, 0x0C, + 0x00, 0x00, 0x27, 0xF4, 0x00, 0x10, 0x00, 0x3F, 0x00, 0x7F, 0xE2, 0x00, 0x00, 0xF5, 0x01, 0xF1, + 0x02, 0xF7, 0x03, 0xF6, 0x05, 0xF6, 0x08, 0xF6, 0x07, 0xF9, 0x0C, 0xF8, 0x04, 0xFE, 0x07, 0xFF, + 0x00, 0x17, 0xF8, 0x07, 0xFA, 0x0B, 0xFD, 0x0D, 0xFE, 0x0D, 0x0A, 0x00, 0x54, 0x00, 0x43, 0xF8, + 0x00, 0xF9, 0x03, 0xFB, 0x04, 0xFB, 0x05, 0xFA, 0x09, 0x02, 0xF7, 0x02, 0xFA, 0x09, 0xF1, 0x09, + 0xF7, 0x08, 0xF9, 0x03, 0x00, 0x46, 0x00, 0x46, 0x39, 0x00, 0x00, 0x39, 0xC7, 0x00, 0xFF, 0x00, + 0x46, 0x00, 0x46, 0x00, 0x2F, 0x00, 0x2F, 0x03, 0x00, 0x20, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x2E, + 0xA1, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x21, 0x00, 0x49, 0x00, 0x24, 0x06, 0x00, 0x51, 0x00, 0x2E, + 0x09, 0xFE, 0x0F, 0xFE, 0x0A, 0x00, 0x0C, 0x02, 0x00, 0x04, 0xD0, 0x00, 0x02, 0x00, 0x43, 0x00, + 0x2A, 0x0C, 0x06, 0xF4, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xC5, 0x19, 0x00, 0x0F, 0xFE, + 0x0D, 0xFC, 0x0E, 0x1A, 0xFB, 0x0C, 0xF8, 0x09, 0xF0, 0x0A, 0xF4, 0x04, 0xF1, 0x04, 0x03, 0x00, + 0x00, 0x00, 0x3D, 0x07, 0x04, 0x0C, 0x03, 0xED, 0x01, 0x0A, 0x00, 0x36, 0x00, 0x3D, 0x0D, 0x1A, + 0xF4, 0x07, 0xF3, 0x02, 0xF9, 0xFF, 0xFA, 0xFF, 0xFB, 0xFC, 0x06, 0xFF, 0x0A, 0xFB, 0x08, 0xF8, + 0x04, 0xF9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0xDF, 0x00, 0xFF, 0x00, 0x21, + 0x00, 0x30, 0x00, 0x23, 0x00, 0x23, 0x03, 0x00, 0x51, 0x00, 0x57, 0x2E, 0x00, 0x00, 0x28, 0xD2, + 0x00, 0x0E, 0x00, 0x60, 0x00, 0x0C, 0xFA, 0x0A, 0xFB, 0x0D, 0xFE, 0x0B, 0x01, 0x0A, 0xF0, 0x11, + 0xFC, 0xFA, 0xFE, 0xFC, 0xFD, 0xF2, 0x00, 0xF6, 0x01, 0xF3, 0x03, 0xF6, 0x05, 0xF7, 0x04, 0xF9, + 0x24, 0x00, 0x0B, 0x00, 0x43, 0x00, 0x4B, 0xFE, 0xF2, 0x01, 0xF7, 0x01, 0xF8, 0x03, 0xF7, 0x03, + 0xFA, 0x03, 0xFA, 0x00, 0x09, 0x00, 0x07, 0x01, 0x06, 0x03, 0x07, 0x05, 0x05, 0x03, 0x00, 0x00, + 0x00, 0x1B, 0x34, 0x00, 0x00, 0x2F, 0xCC, 0x00, 0xFF, 0x00, 0x34, 0x00, 0x4A, 0x00, 0x33, 0x00, + 0x21, 0x0A, 0x00, 0x7F, 0x00, 0x46, 0xE6, 0x0D, 0x00, 0xFB, 0x01, 0xFB, 0x04, 0xF7, 0x03, 0xFC, + 0x03, 0xFD, 0x06, 0xFD, 0xFF, 0x00, 0x05, 0xFF, 0x05, 0x00, 0x09, 0x00, 0x7F, 0x00, 0x57, 0xE3, + 0x0D, 0x00, 0xFB, 0x01, 0xFB, 0x03, 0xF9, 0x04, 0xFA, 0x03, 0xFD, 0x06, 0xFD, 0x04, 0xFF, 0x08, + 0x00, 0x03, 0x00, 0x30, 0x00, 0x57, 0x34, 0x00, 0x00, 0x28, 0xCC, 0x00, 0xFF, 0x00, 0x34, 0x00, + 0x00, 0x00, 0x0E, 0x00, 0x0E, 0x03, 0x00, 0x00, 0x00, 0x52, 0x00, 0xAE, 0x7F, 0x00, 0x00, 0x12, + 0x03, 0x00, 0x4D, 0x00, 0x19, 0x32, 0xE8, 0x00, 0x21, 0xD5, 0x0B, 0x02, 0x00, 0x7D, 0x00, 0x00, + 0xCE, 0x19, 0x00, 0xE7, 0xFF, 0x00, 0x22, 0x00, 0x4F, 0x00, 0x24, 0x00, 0x32, 0x02, 0x00, 0x25, + 0x00, 0x7F, 0xDB, 0x00, 0x00, 0xB7, 0x04, 0x00, 0x0E, 0x00, 0x72, 0xFF, 0xFD, 0x10, 0x00, 0x0A, + 0x10, 0xF4, 0x00, 0xFF, 0x00, 0x18, 0x00, 0x6C, 0x00, 0x0B, 0x00, 0x09, 0x06, 0x00, 0x01, 0x00, + 0x3D, 0x01, 0xFB, 0x15, 0x29, 0xF5, 0xFC, 0xFC, 0xFB, 0xFB, 0xF7, 0xFE, 0xF4, 0x04, 0x00, 0x80, + 0x00, 0x00, 0x29, 0x00, 0x00, 0x7F, 0x00, 0x2A, 0xD7, 0x00, 0x03, 0x00, 0x39, 0x00, 0x7F, 0xC7, + 0x00, 0x00, 0xC7, 0x39, 0x00, 0x06, 0x00, 0x7F, 0x00, 0x7F, 0xE7, 0x00, 0x04, 0xFA, 0x03, 0xFD, + 0x06, 0xFD, 0x04, 0xFF, 0x08, 0x00, 0x03, 0x00, 0x44, 0x00, 0x4C, 0x3B, 0x00, 0x00, 0x33, 0xC5, + 0x00, 0x08, 0x00, 0x7F, 0x00, 0x5A, 0x00, 0x25, 0xD1, 0x00, 0x01, 0xF6, 0x07, 0xF5, 0x07, 0xF9, + 0x08, 0xFB, 0x06, 0xFE, 0x0A, 0xFE, 0x0A, 0x00, 0x48, 0x00, 0x5C, 0xFB, 0x00, 0xFB, 0xFF, 0x01, + 0x00, 0xFA, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFC, 0xF7, 0xFF, 0xFB, 0x00, 0xFB, 0x1A, 0x0D, 0x06, + 0x00, 0x48, 0x00, 0x4B, 0xF8, 0x00, 0xFC, 0xFF, 0xFA, 0xFD, 0xFD, 0xFD, 0xFC, 0xFA, 0x19, 0x00, + 0x03, 0x00, 0x2F, 0x00, 0x5D, 0x50, 0x00, 0x00, 0x22, 0xB0, 0x00, 0xFF, 0x00, 0x2F, 0x00, 0x5D, + 0x00, 0x21, 0x00, 0x21, 0x03, 0x00, 0x00, 0x00, 0x1A, 0x21, 0x00, 0x00, 0x65, 0xDF, 0x00, 0xFF, + 0x00, 0x21, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x20, 0x0A, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x39, 0xDC, + 0x02, 0xF7, 0x02, 0xF7, 0x04, 0xF3, 0xE6, 0x04, 0xF4, 0x08, 0xF7, 0x10, 0xF6, 0x0C, 0xFC, 0x0F, + 0xFC, 0x03, 0x00, 0x7F, 0x00, 0x42, 0xF7, 0xFA, 0xF6, 0xFE, 0x13, 0x00, 0x0A, 0x00, 0x48, 0x00, + 0x42, 0xF4, 0xE6, 0x0B, 0xF9, 0x0D, 0xFE, 0x07, 0x01, 0x06, 0x01, 0x05, 0x04, 0xFA, 0x01, 0xF5, + 0x06, 0xF9, 0x07, 0xFC, 0x07, 0x07, 0x00, 0x21, 0x00, 0x7F, 0xE6, 0x00, 0x00, 0xF2, 0x02, 0xF2, + 0x04, 0xF3, 0x04, 0xF5, 0x07, 0xF7, 0x09, 0xF9, 0xFF, 0x00, 0x2F, 0x00, 0x5D, 0x00, 0x0D, 0x00, + 0x0D, 0x03, 0x00, 0x7F, 0x00, 0x7F, 0xDF, 0x00, 0x00, 0xD9, 0x21, 0x00, 0x0B, 0x00, 0x48, 0x00, + 0x27, 0xFB, 0x00, 0xFB, 0xFF, 0x01, 0x00, 0xFA, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFC, 0xF7, 0xFF, + 0xFB, 0xFF, 0xFB, 0x00, 0xF9, 0x1B, 0x14, 0x06, 0x00, 0x47, 0x00, 0x10, 0x03, 0x06, 0xF4, 0xFD, + 0xF7, 0xF9, 0xFD, 0xFD, 0xFC, 0xFA, 0x19, 0x00, 0x03, 0x00, 0x5E, 0x00, 0x7F, 0xA2, 0x00, 0x00, + 0xDE, 0x5E, 0x00, 0x03, 0x00, 0x3F, 0x00, 0x3F, 0x40, 0x00, 0x00, 0x40, 0xC0, 0x00, 0xFF, 0x00, + 0x3F, 0x00, 0x3F, 0x00, 0x37, 0x00, 0x37, 0x03, 0x00, 0x3F, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x4A, + 0xE3, 0x00, 0xFF, 0x00, 0x3F, 0x00, 0x4A, 0x00, 0x1D, 0x00, 0x1D, 0x03, 0x00, 0x22, 0x00, 0x2C, + 0x1C, 0x00, 0x00, 0x3E, 0xE4, 0x00, 0x04, 0x00, 0x5C, 0x00, 0x47, 0xF8, 0x00, 0x00, 0xED, 0x02, + 0xEA, 0x06, 0xE2, 0x03, 0x00, 0x00, 0x00, 0x66, 0x1A, 0x00, 0x00, 0x19, 0xE6, 0x00, 0x03, 0x00, + 0x49, 0x00, 0x02, 0x10, 0x00, 0xFC, 0x47, 0xF4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x68, 0x1B, 0x00, + 0x00, 0x17, 0xE5, 0x00, 0x03, 0x00, 0x7F, 0x00, 0x14, 0x00, 0x6B, 0xD2, 0x00, 0x00, 0x95, 0x06, + 0x00, 0x51, 0x00, 0x51, 0x02, 0x09, 0x02, 0x0F, 0x00, 0x0A, 0xFE, 0x0C, 0xFC, 0x00, 0x00, 0xD0, + 0x02, 0x00, 0x55, 0x00, 0x43, 0xFA, 0x0C, 0x00, 0xF4, 0xFF, 0x00, 0x60, 0x00, 0x00, 0x00, 0x1F, + 0x00, 0x4D, 0x03, 0x00, 0x43, 0x00, 0x57, 0x3C, 0x00, 0x00, 0x28, 0xC4, 0x00, 0x03, 0x00, 0x7D, + 0xFF, 0xFF, 0x00, 0x10, 0xB9, 0xFC, 0x00, 0xF4, 0x03, 0x00, 0x7F, 0xFF, 0xFF, 0x00, 0x1B, 0xEA, + 0x00, 0x00, 0xE5, 0x03, 0x00, 0x5D, 0xFF, 0xF2, 0x00, 0x0C, 0xD9, 0x00, 0x00, 0xF4, 0xFF, 0x00, + 0x67, 0x00, 0x58, 0x00, 0x0C, 0x00, 0x0C, 0xFF, 0x00, 0x1A, 0x00, 0x2C, 0x00, 0x0A, 0x00, 0x0A, + 0x05, 0x00, 0x48, 0x00, 0x19, 0x0C, 0xF7, 0x12, 0xF7, 0x19, 0xFA, 0x00, 0x21, 0xD5, 0x0B, 0x03, + 0x00, 0x2E, 0x00, 0x53, 0x51, 0x00, 0x00, 0x2C, 0xAF, 0x00, 0xFF, 0x00, 0x1A, 0x00, 0x53, 0x00, + 0x64, 0x00, 0x20, 0x06, 0x00, 0x7D, 0x00, 0x13, 0xFD, 0x06, 0xFA, 0x06, 0xF9, 0x03, 0xF9, 0x01, + 0x00, 0xEB, 0x18, 0x00, 0x02, 0x00, 0x07, 0x00, 0x27, 0xF9, 0x15, 0x00, 0xF7, 0xFF, 0x00, 0x1F, + 0x00, 0x34, 0x00, 0x0B, 0x00, 0x0B, 0x0A, 0x00, 0x00, 0x00, 0x57, 0x1A, 0xF3, 0x00, 0x05, 0xFF, + 0x05, 0xFC, 0x09, 0xFD, 0x04, 0xFD, 0x03, 0xFA, 0x03, 0x01, 0x00, 0xFB, 0x01, 0xFB, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x4A, 0x19, 0x00, 0xFC, 0x06, 0xFD, 0x03, 0xFA, 0x03, 0xFC, 0x01, 0xF8, 0x00, + 0x03, 0x00, 0x69, 0x00, 0x7F, 0x00, 0xE5, 0x16, 0x00, 0x00, 0x1B, 0x03, 0x00, 0x36, 0x00, 0x7F, + 0x00, 0xF4, 0x47, 0xFC, 0x00, 0x10, 0x03, 0x00, 0x49, 0x00, 0x19, 0xD2, 0x00, 0x00, 0xE7, 0x2E, + 0x00, 0x06, 0x00, 0x21, 0x00, 0x02, 0x06, 0x03, 0x06, 0x06, 0x03, 0x07, 0x01, 0x07, 0xEA, 0x00, + 0x00, 0xE8, 0x06, 0x00, 0x49, 0x00, 0x01, 0x00, 0x18, 0xEA, 0x00, 0x01, 0xF9, 0x03, 0xF9, 0x06, + 0xFA, 0x06, 0xFD, 0x02, 0x00, 0x00, 0x00, 0x5E, 0x00, 0xA2, 0x5E, 0x5E, 0x03, 0x00, 0x2E, 0x00, + 0x47, 0x3D, 0x1E, 0xBE, 0x00, 0xFF, 0xE2, 0xFF, 0x00, 0x03, 0x00, 0x7D, 0x00, 0x11, 0x00, 0x11, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x36, 0xCC, 0x00, 0x05, 0x00, 0x39, 0x00, 0x5E, + 0x01, 0x00, 0x19, 0x05, 0x00, 0x1C, 0xAD, 0x00, 0x53, 0xAD, 0x03, 0x00, 0x71, 0x00, 0x2E, 0x0E, + 0x00, 0x00, 0x51, 0xF2, 0x00, 0xFF, 0x00, 0x6E, 0x00, 0x3B, 0x00, 0x11, 0x00, 0x21, 0xFF, 0x00, + 0x73, 0x00, 0x26, 0x00, 0x0C, 0x00, 0x13, 0xFF, 0x00, 0x74, 0x00, 0x25, 0x00, 0x06, 0x00, 0x06, + 0x02, 0x00, 0x70, 0x00, 0x55, 0x00, 0x07, 0xF9, 0x00, 0x02, 0x00, 0x71, 0x00, 0x55, 0x00, 0x2A, + 0xEB, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x77, 0x00, 0xE4, 0x57, 0x00, 0x04, 0x00, 0x06, 0x01, 0x08, + 0x02, 0x07, 0x04, 0x09, 0x09, 0x03, 0x06, 0x03, 0x08, 0x00, 0x06, 0x81, 0x00, 0x06, 0x00, 0x0D, + 0x00, 0x5B, 0x00, 0x03, 0xFF, 0x04, 0xFC, 0x04, 0xFA, 0x02, 0xFE, 0x00, 0x00, 0xF3, 0x02, 0x00, + 0x3F, 0x00, 0x5B, 0xFA, 0x17, 0xE9, 0xE9, 0xFF, 0x00, 0x48, 0x00, 0x68, 0x00, 0x14, 0x00, 0x0F, + 0x03, 0x00, 0x4C, 0x00, 0x3B, 0x00, 0xC5, 0x33, 0x00, 0x00, 0x3B, 0x08, 0x00, 0x5A, 0x00, 0x00, + 0x25, 0x00, 0x00, 0x2F, 0xF6, 0xFF, 0xF5, 0xF9, 0xF9, 0xF9, 0xFB, 0xF8, 0xFE, 0xFA, 0xFE, 0xF6, + 0x0A, 0x00, 0x5C, 0x00, 0x37, 0x00, 0x05, 0xFF, 0x05, 0x00, 0xFF, 0xFD, 0x06, 0xFD, 0x03, 0xFC, + 0x03, 0xF7, 0x04, 0xFB, 0x01, 0xFB, 0x00, 0x0D, 0xE6, 0x06, 0x00, 0x4B, 0x00, 0x37, 0x00, 0x08, + 0xFF, 0x04, 0xFD, 0x06, 0xFD, 0x03, 0xFA, 0x04, 0x00, 0xE7, 0x0A, 0x00, 0x30, 0x00, 0x00, 0x0D, + 0x1A, 0xFB, 0x00, 0xFB, 0xFF, 0xF7, 0xFC, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFA, 0x00, 0x01, 0xFF, + 0xFB, 0x00, 0xFB, 0x06, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x19, 0xFA, 0xFC, 0xFD, 0xFD, 0xFD, 0xFA, + 0xFF, 0xFC, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x94, 0x2E, 0x00, 0x00, 0x6C, 0x06, + 0x00, 0x2E, 0x00, 0x2E, 0xFE, 0xF7, 0xFE, 0xF1, 0x00, 0xF6, 0x02, 0xF4, 0x04, 0x00, 0x00, 0x30, + 0x02, 0x00, 0x2A, 0x00, 0x3C, 0x06, 0xF4, 0x00, 0x0C, 0x03, 0x00, 0x7F, 0x00, 0x3F, 0x00, 0x40, + 0x82, 0x00, 0x00, 0xEE, 0x05, 0x00, 0x37, 0x00, 0x66, 0xF4, 0x09, 0xEE, 0x09, 0xE8, 0x06, 0x00, + 0xDF, 0x2A, 0xF5, 0x01, 0x00, 0x7F, 0x00, 0x43, 0x00, 0x09, 0x02, 0x00, 0x7F, 0x00, 0x00, 0x00, + 0x4C, 0xB4, 0xB4, 0x03, 0x00, 0x33, 0x00, 0x00, 0x35, 0x00, 0x02, 0x17, 0xFA, 0x01, 0x10, 0x00, + 0x1E, 0x00, 0x0F, 0x02, 0x0D, 0x03, 0x0D, 0x06, 0x0B, 0x08, 0x07, 0x00, 0x17, 0xF9, 0xFF, 0xFC, + 0xFE, 0xF4, 0xF8, 0xF9, 0xF9, 0xF8, 0xF6, 0xFB, 0xF6, 0xFD, 0xF6, 0xFE, 0xF7, 0xFF, 0xF1, 0x00, + 0xF6, 0x1E, 0x00, 0x0A, 0x00, 0x37, 0x00, 0x57, 0xF4, 0xF7, 0xF6, 0xF6, 0xF7, 0xF1, 0xFE, 0xFA, + 0xFE, 0xF7, 0x06, 0x09, 0x05, 0x05, 0x05, 0x04, 0x0A, 0x03, 0x09, 0x01, 0x0A, 0x00, 0x2C, 0x00, + 0x7F, 0x00, 0xFB, 0x01, 0xFB, 0x00, 0x01, 0x03, 0xFA, 0x03, 0xFD, 0x04, 0xFD, 0x09, 0xFC, 0x05, + 0xFF, 0x05, 0x00, 0xF3, 0x1A, 0x06, 0x00, 0x3D, 0x00, 0x7F, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0xFA, + 0x03, 0xFD, 0x06, 0xFC, 0x00, 0x19 +}; + +const Level Game::_gameLevels[] = { + { "level1", "level1", "level1", 0x00, 1, 3 }, + { "level2", "level2", "level2", 0x2F, 1, 4 }, + { "level3", "level3", "dt", 0xFFFF, 3, 5 }, + { "level4", "level4_1", "level3_1", 0x34, 3, 6 }, + { "level4", "level4_2", "level3_2", 0x39, 3, 6 }, + { "level5", "level5_1", "level4_1", 0x35, 4, 7 }, + { "level5", "level5_2", "level4_2", 0xFFFF, 4, 7 } +}; + +const uint16_t Game::_scoreTable[] = { + 0, 200, 300, 400, 500, 800, 1000, 1200, 1500, 2000, 2200, 2500, 3000, 3200, 3500, 5000 +}; + +const uint8_t Game::_monsterListLevel1[] = { + 0x22, 0, 0x23, 0, 0xFF +}; + +const uint8_t Game::_monsterListLevel2[] = { + 0x22, 0, 0x23, 0, 0x4B, 0, 0x49, 1, 0x4D, 1, 0x76, 2, 0xFF +}; + +const uint8_t Game::_monsterListLevel3[] = { + 0x76, 2, 0xFF +}; + +const uint8_t Game::_monsterListLevel4_1[] = { + 0x4D, 1, 0x76, 2, 0xFF +}; + +const uint8_t Game::_monsterListLevel4_2[] = { + 0x76, 2, 0xAC, 2, 0xD7, 3, 0xFF +}; + +const uint8_t Game::_monsterListLevel5_1[] = { + 0xB0, 3, 0xD7, 3, 0xFF +}; + +const uint8_t Game::_monsterListLevel5_2[] = { + 0xB0, 3, 0xD7, 3, 0xD8, 3, 0xFF +}; + +const uint8_t *Game::_monsterListLevels[] = { + _monsterListLevel1, + _monsterListLevel2, + _monsterListLevel3, + _monsterListLevel4_1, + _monsterListLevel4_2, + _monsterListLevel5_1, + _monsterListLevel5_2 +}; + +const uint8_t Game::_monsterPals[4][32] = { + { // junkie + 0x00, 0x00, 0xAA, 0x0A, 0x65, 0x0A, 0x44, 0x08, 0x22, 0x06, 0x20, 0x03, 0x40, 0x05, 0x87, 0x0C, + 0x76, 0x0B, 0x34, 0x03, 0x55, 0x09, 0x30, 0x04, 0x60, 0x07, 0x55, 0x04, 0x77, 0x07, 0xFF, 0x0F + }, + { // mercenaire + 0x00, 0x00, 0x86, 0x0C, 0x66, 0x09, 0x44, 0x08, 0xFC, 0x05, 0xA2, 0x02, 0x49, 0x05, 0x02, 0x00, + 0x14, 0x02, 0x37, 0x04, 0x25, 0x03, 0x38, 0x06, 0xAF, 0x0C, 0x6F, 0x09, 0x4C, 0x07, 0xFF, 0x0F + }, + { // replicant + 0x00, 0x00, 0x79, 0x08, 0x44, 0x05, 0x55, 0x06, 0x66, 0x0B, 0x46, 0x05, 0x57, 0x06, 0x22, 0x03, + 0x44, 0x08, 0x33, 0x04, 0xAC, 0x08, 0x8A, 0x06, 0x68, 0x04, 0x56, 0x02, 0x35, 0x02, 0xCE, 0x0A + }, + { // glue + 0x00, 0x00, 0x6C, 0x00, 0x39, 0x02, 0x4C, 0x02, 0x27, 0x02, 0x10, 0x07, 0x15, 0x01, 0x00, 0x04, + 0x10, 0x05, 0x20, 0x08, 0x00, 0x02, 0x30, 0x09, 0x55, 0x0B, 0xFF, 0x0F, 0x33, 0x0A, 0xFF, 0x0F + } +}; + +const char *Game::_monsterNames[2][4] = { + { // PC + "junky", + "mercenai", + "replican", + "glue" + }, + { // Amiga + "junky", + "garde", + "replicant", + "glue" + } +}; + +const uint8_t LocaleData::_stringsTableFR[] = { + 0x5A, 0x00, 0x71, 0x00, 0x90, 0x00, 0x97, 0x01, 0x58, 0x02, 0x7B, 0x02, 0xC5, 0x02, 0xEA, 0x02, + 0x50, 0x03, 0x6C, 0x03, 0xA8, 0x03, 0xF7, 0x03, 0x46, 0x04, 0x98, 0x04, 0x1C, 0x05, 0x57, 0x05, + 0x69, 0x05, 0xE1, 0x05, 0xF4, 0x05, 0x19, 0x06, 0xB5, 0x06, 0x9C, 0x08, 0x11, 0x09, 0x2B, 0x09, + 0x8D, 0x09, 0xA6, 0x09, 0xB9, 0x09, 0xDC, 0x09, 0xEF, 0x09, 0x13, 0x0A, 0x15, 0x0A, 0x17, 0x0A, + 0x7F, 0x0A, 0x90, 0x0A, 0x21, 0x0B, 0x4A, 0x0B, 0x08, 0x0C, 0x20, 0x0C, 0x44, 0x0C, 0x77, 0x0C, + 0x0E, 0x0D, 0x55, 0x0D, 0x93, 0x0D, 0xBB, 0x0D, 0xF5, 0x0D, 0x4C, 0x45, 0x20, 0x46, 0x55, 0x53, + 0x49, 0x42, 0x4C, 0x45, 0x20, 0x45, 0x53, 0x54, 0x0A, 0x47, 0x52, 0x49, 0x4C, 0x4C, 0x45, 0x2E, + 0x00, 0x4D, 0x41, 0x49, 0x4E, 0x54, 0x45, 0x4E, 0x41, 0x4E, 0x54, 0x20, 0x43, 0x41, 0x0A, 0x44, + 0x4F, 0x49, 0x54, 0x20, 0x46, 0x4F, 0x4E, 0x43, 0x54, 0x49, 0x4F, 0x4E, 0x4E, 0x45, 0x52, 0x00, + 0xFF, 0xEB, 0xEC, 0x4A, 0x27, 0x53, 0x55, 0x49, 0x53, 0x20, 0x4A, 0x41, 0x43, 0x4B, 0x2E, 0x0A, + 0x54, 0x55, 0x20, 0x56, 0x45, 0x55, 0x58, 0x20, 0x44, 0x45, 0x53, 0x20, 0x46, 0x41, 0x55, 0x58, + 0x0A, 0x50, 0x41, 0x50, 0x49, 0x45, 0x52, 0x53, 0x3F, 0x0B, 0xFF, 0xE9, 0xEA, 0x4F, 0x55, 0x49, + 0x2C, 0x45, 0x54, 0x20, 0x4C, 0x45, 0x20, 0x50, 0x4C, 0x55, 0x53, 0x0A, 0x56, 0x49, 0x54, 0x45, + 0x20, 0x50, 0x4F, 0x53, 0x53, 0x49, 0x42, 0x4C, 0x45, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x31, 0x35, + 0x30, 0x30, 0x20, 0x43, 0x52, 0x45, 0x44, 0x49, 0x54, 0x53, 0x21, 0x0B, 0xFF, 0xE9, 0xEA, 0x31, + 0x35, 0x30, 0x30, 0x3F, 0x3F, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x4F, 0x55, 0x41, 0x49, 0x53, 0x2C, + 0x4A, 0x27, 0x50, 0x52, 0x45, 0x4E, 0x44, 0x53, 0x0A, 0x55, 0x4E, 0x20, 0x47, 0x52, 0x4F, 0x53, + 0x20, 0x52, 0x49, 0x53, 0x51, 0x55, 0x45, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x4D, 0x41, 0x49, 0x53, + 0x20, 0x4A, 0x45, 0x20, 0x4E, 0x27, 0x41, 0x49, 0x20, 0x50, 0x41, 0x53, 0x0A, 0x41, 0x53, 0x53, + 0x45, 0x5A, 0x2E, 0x2E, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x56, 0x41, 0x20, 0x41, 0x20, 0x4C, 0x27, + 0x41, 0x47, 0x45, 0x4E, 0x43, 0x45, 0x0A, 0x50, 0x4F, 0x55, 0x52, 0x20, 0x4C, 0x27, 0x45, 0x4D, + 0x50, 0x4C, 0x4F, 0x49, 0x20, 0x45, 0x54, 0x0A, 0x54, 0x55, 0x20, 0x41, 0x55, 0x52, 0x41, 0x53, + 0x20, 0x55, 0x4E, 0x20, 0x4A, 0x4F, 0x42, 0x2E, 0x0B, 0x45, 0x54, 0x20, 0x52, 0x45, 0x56, 0x49, + 0x45, 0x4E, 0x53, 0x20, 0x4D, 0x45, 0x0A, 0x56, 0x4F, 0x49, 0x52, 0x20, 0x51, 0x55, 0x41, 0x4E, + 0x44, 0x20, 0x54, 0x55, 0x0A, 0x41, 0x55, 0x52, 0x41, 0x53, 0x20, 0x44, 0x45, 0x0A, 0x4C, 0x27, + 0x41, 0x52, 0x47, 0x45, 0x4E, 0x54, 0x00, 0xFF, 0xEB, 0xEC, 0x4A, 0x27, 0x43, 0x4F, 0x4E, 0x4E, + 0x41, 0x49, 0x53, 0x20, 0x43, 0x45, 0x0A, 0x47, 0x41, 0x52, 0x53, 0x20, 0x4C, 0x41, 0x2E, 0x20, + 0x49, 0x4C, 0x20, 0x41, 0x0A, 0x55, 0x4E, 0x20, 0x41, 0x4D, 0x49, 0x20, 0x51, 0x55, 0x49, 0x20, + 0x45, 0x53, 0x54, 0x0A, 0x55, 0x4E, 0x20, 0x52, 0x4F, 0x42, 0x4F, 0x54, 0x2D, 0x46, 0x4C, 0x49, + 0x43, 0x2E, 0x0B, 0x4F, 0x55, 0x20, 0x50, 0x55, 0x49, 0x53, 0x2D, 0x4A, 0x45, 0x0A, 0x54, 0x52, + 0x4F, 0x55, 0x56, 0x45, 0x52, 0x20, 0x43, 0x45, 0x54, 0x20, 0x41, 0x4D, 0x49, 0x3F, 0x0B, 0x56, + 0x41, 0x20, 0x56, 0x4F, 0x49, 0x52, 0x20, 0x41, 0x20, 0x4C, 0x41, 0x0A, 0x52, 0x45, 0x53, 0x54, + 0x52, 0x49, 0x43, 0x54, 0x45, 0x44, 0x20, 0x41, 0x52, 0x45, 0x41, 0x0A, 0x31, 0x2E, 0x4A, 0x45, + 0x20, 0x43, 0x52, 0x4F, 0x49, 0x53, 0x20, 0x51, 0x55, 0x27, 0x49, 0x4C, 0x0A, 0x45, 0x53, 0x54, + 0x20, 0x44, 0x45, 0x20, 0x47, 0x41, 0x52, 0x44, 0x45, 0x0B, 0x4D, 0x41, 0x49, 0x53, 0x20, 0x46, + 0x41, 0x49, 0x53, 0x20, 0x47, 0x41, 0x46, 0x46, 0x45, 0x0A, 0x43, 0x45, 0x53, 0x20, 0x54, 0x59, + 0x50, 0x45, 0x53, 0x2D, 0x4C, 0x41, 0x20, 0x0A, 0x53, 0x4F, 0x4E, 0x54, 0x20, 0x44, 0x41, 0x4E, + 0x47, 0x45, 0x55, 0x52, 0x45, 0x55, 0x58, 0x00, 0xFF, 0xEB, 0xEC, 0x4A, 0x45, 0x20, 0x4E, 0x45, + 0x20, 0x53, 0x41, 0x49, 0x53, 0x20, 0x52, 0x49, 0x45, 0x4E, 0x0A, 0x44, 0x45, 0x20, 0x50, 0x4C, + 0x55, 0x53, 0x2C, 0x20, 0x47, 0x41, 0x4D, 0x49, 0x4E, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x43, 0x59, + 0x2D, 0x42, 0x30, 0x32, 0x31, 0x20, 0x56, 0x45, 0x55, 0x54, 0x0A, 0x50, 0x41, 0x53, 0x53, 0x45, + 0x52, 0x20, 0x55, 0x4E, 0x20, 0x4D, 0x41, 0x52, 0x43, 0x48, 0x45, 0x0A, 0x41, 0x56, 0x45, 0x43, + 0x20, 0x54, 0x4F, 0x49, 0x2E, 0x0B, 0x49, 0x4C, 0x20, 0x54, 0x27, 0x41, 0x54, 0x54, 0x45, 0x4E, + 0x44, 0x52, 0x41, 0x0A, 0x44, 0x45, 0x52, 0x52, 0x49, 0x45, 0x52, 0x45, 0x20, 0x4C, 0x45, 0x20, + 0x42, 0x41, 0x52, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x56, 0x41, 0x20, 0x41, 0x55, 0x20, 0x42, 0x41, + 0x52, 0x2C, 0x20, 0x50, 0x45, 0x54, 0x49, 0x54, 0x0A, 0x43, 0x59, 0x2D, 0x42, 0x30, 0x32, 0x31, + 0x20, 0x54, 0x27, 0x41, 0x54, 0x54, 0x45, 0x4E, 0x44, 0x00, 0xFF, 0xEB, 0xEC, 0x4E, 0x45, 0x20, + 0x54, 0x49, 0x52, 0x45, 0x20, 0x50, 0x41, 0x53, 0x2E, 0x0A, 0x4A, 0x27, 0x53, 0x55, 0x49, 0x53, + 0x20, 0x50, 0x41, 0x53, 0x0A, 0x43, 0x59, 0x2D, 0x42, 0x30, 0x32, 0x31, 0x2E, 0x0B, 0x53, 0x41, + 0x20, 0x50, 0x4C, 0x41, 0x4E, 0x51, 0x55, 0x45, 0x20, 0x45, 0x53, 0x54, 0x0A, 0x45, 0x4E, 0x20, + 0x44, 0x45, 0x53, 0x53, 0x4F, 0x55, 0x53, 0x0B, 0x43, 0x27, 0x45, 0x53, 0x54, 0x20, 0x53, 0x4F, + 0x4E, 0x20, 0x43, 0x4F, 0x50, 0x41, 0x49, 0x4E, 0x0A, 0x4C, 0x45, 0x20, 0x46, 0x4C, 0x49, 0x43, + 0x2C, 0x20, 0x51, 0x55, 0x49, 0x20, 0x41, 0x0A, 0x4C, 0x41, 0x20, 0x43, 0x4C, 0x45, 0x2E, 0x00, + 0xFF, 0xEB, 0xEC, 0x4A, 0x45, 0x20, 0x4E, 0x45, 0x20, 0x53, 0x41, 0x49, 0x53, 0x20, 0x52, 0x49, + 0x45, 0x4E, 0x0A, 0x44, 0x45, 0x20, 0x50, 0x4C, 0x55, 0x53, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x4D, + 0x4F, 0x4E, 0x53, 0x49, 0x45, 0x55, 0x52, 0x2E, 0x2E, 0x2E, 0x0A, 0x55, 0x4E, 0x20, 0x44, 0x45, + 0x4E, 0x4F, 0x4D, 0x4D, 0x45, 0x20, 0x4A, 0x41, 0x43, 0x4B, 0x0A, 0x56, 0x4F, 0x55, 0x53, 0x20, + 0x44, 0x4F, 0x4E, 0x4E, 0x45, 0x20, 0x52, 0x2E, 0x44, 0x2E, 0x56, 0x0A, 0x50, 0x52, 0x45, 0x53, + 0x20, 0x44, 0x55, 0x20, 0x42, 0x41, 0x52, 0x00, 0x4A, 0x45, 0x20, 0x56, 0x4F, 0x55, 0x44, 0x52, + 0x41, 0x49, 0x53, 0x20, 0x55, 0x4E, 0x0A, 0x50, 0x45, 0x52, 0x4D, 0x49, 0x53, 0x20, 0x44, 0x45, + 0x0A, 0x54, 0x52, 0x41, 0x56, 0x41, 0x49, 0x4C, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x41, 0x48, 0x20, + 0x4E, 0x4F, 0x4E, 0x2E, 0x43, 0x27, 0x45, 0x53, 0x54, 0x20, 0x50, 0x41, 0x53, 0x0A, 0x49, 0x43, + 0x49, 0x2E, 0x20, 0x56, 0x4F, 0x59, 0x45, 0x5A, 0x20, 0x4C, 0x45, 0x0A, 0x47, 0x55, 0x49, 0x43, + 0x48, 0x45, 0x54, 0x20, 0x43, 0x2E, 0x00, 0x4A, 0x45, 0x20, 0x56, 0x4F, 0x55, 0x44, 0x52, 0x41, + 0x49, 0x53, 0x20, 0x55, 0x4E, 0x0A, 0x50, 0x45, 0x52, 0x4D, 0x49, 0x53, 0x20, 0x64, 0x65, 0x0A, + 0x54, 0x52, 0x41, 0x56, 0x41, 0x49, 0x4C, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x42, 0x4F, 0x4E, 0x2E, + 0x2E, 0x2E, 0x20, 0x4F, 0x4B, 0x2C, 0x4C, 0x45, 0x0A, 0x47, 0x4F, 0x55, 0x56, 0x45, 0x52, 0x4E, + 0x45, 0x55, 0x52, 0x20, 0x56, 0x41, 0x0A, 0x56, 0x4F, 0x55, 0x53, 0x20, 0x52, 0x45, 0x43, 0x45, + 0x56, 0x4F, 0x49, 0x52, 0x2E, 0x00, 0x4A, 0x45, 0x20, 0x56, 0x4F, 0x55, 0x44, 0x52, 0x41, 0x49, + 0x53, 0x20, 0x55, 0x4E, 0x0A, 0x50, 0x45, 0x52, 0x4D, 0x49, 0x53, 0x20, 0x44, 0x45, 0x0A, 0x54, + 0x52, 0x41, 0x56, 0x41, 0x49, 0x4C, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x41, 0x48, 0x20, 0x4E, 0x4F, + 0x4E, 0x2E, 0x43, 0x45, 0x20, 0x4E, 0x27, 0x45, 0x53, 0x54, 0x0A, 0x50, 0x41, 0x53, 0x20, 0x49, + 0x43, 0x49, 0x2E, 0x20, 0x56, 0x4F, 0x59, 0x45, 0x5A, 0x0A, 0x4C, 0x45, 0x20, 0x47, 0x55, 0x49, + 0x43, 0x48, 0x45, 0x54, 0x20, 0x42, 0x2E, 0x00, 0x4A, 0x45, 0x20, 0x56, 0x4F, 0x55, 0x44, 0x52, + 0x41, 0x49, 0x53, 0x0A, 0x50, 0x41, 0x52, 0x4C, 0x45, 0x52, 0x20, 0x41, 0x20, 0x4A, 0x41, 0x43, + 0x4B, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x41, 0x48, 0x20, 0x4F, 0x55, 0x41, 0x49, 0x53, 0x3F, 0x20, + 0x4A, 0x41, 0x43, 0x4B, 0x0A, 0x4E, 0x27, 0x45, 0x53, 0x54, 0x20, 0x50, 0x41, 0x53, 0x20, 0x4C, + 0x41, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x48, 0x55, 0x4D, 0x2E, 0x2E, 0x2E, 0x4A, 0x45, 0x20, 0x56, + 0x49, 0x45, 0x4E, 0x53, 0x0A, 0x44, 0x45, 0x20, 0x4C, 0x41, 0x20, 0x50, 0x41, 0x52, 0x54, 0x20, + 0x44, 0x45, 0x0A, 0x4D, 0x4F, 0x4E, 0x20, 0x41, 0x4D, 0x49, 0x20, 0x49, 0x41, 0x4E, 0x2E, 0x0B, + 0xFF, 0xEB, 0xEC, 0x4F, 0x4B, 0x2E, 0x4A, 0x41, 0x43, 0x4B, 0x20, 0x54, 0x27, 0x41, 0x54, 0x54, + 0x45, 0x4E, 0x44, 0x0A, 0x44, 0x45, 0x48, 0x4F, 0x52, 0x53, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x50, + 0x41, 0x53, 0x53, 0x45, 0x20, 0x54, 0x4F, 0x4E, 0x20, 0x43, 0x48, 0x45, 0x4D, 0x49, 0x4E, 0x0A, + 0x47, 0x41, 0x4D, 0x49, 0x4E, 0x2E, 0x20, 0x54, 0x27, 0x45, 0x53, 0x20, 0x54, 0x52, 0x4F, 0x50, + 0x0A, 0x4A, 0x45, 0x55, 0x4E, 0x45, 0x20, 0x50, 0x4F, 0x55, 0x52, 0x0A, 0x43, 0x4F, 0x4E, 0x53, + 0x4F, 0x4D, 0x4D, 0x45, 0x52, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x50, 0x41, 0x50, 0x49, 0x45, 0x52, + 0x53, 0x20, 0x53, 0x2E, 0x56, 0x2E, 0x50, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x4A, 0x45, 0x20, 0x53, + 0x55, 0x49, 0x53, 0x20, 0x4C, 0x45, 0x0A, 0x43, 0x4F, 0x55, 0x52, 0x53, 0x49, 0x45, 0x52, 0x2E, + 0x0B, 0xFF, 0xEB, 0xEC, 0x41, 0x48, 0x20, 0x4F, 0x55, 0x49, 0x21, 0x56, 0x4F, 0x49, 0x4C, 0x41, + 0x2C, 0x0A, 0x41, 0x4D, 0x45, 0x4E, 0x45, 0x5A, 0x20, 0x43, 0x45, 0x20, 0x50, 0x41, 0x51, 0x55, + 0x45, 0x54, 0x0A, 0x41, 0x20, 0x4C, 0x27, 0x41, 0x47, 0x45, 0x4E, 0x43, 0x45, 0x20, 0x44, 0x45, + 0x0A, 0x56, 0x4F, 0x59, 0x41, 0x47, 0x45, 0x2E, 0x0B, 0x45, 0x54, 0x20, 0x46, 0x41, 0x49, 0x54, + 0x45, 0x53, 0x0A, 0x41, 0x54, 0x54, 0x45, 0x4E, 0x54, 0x49, 0x4F, 0x4E, 0x2C, 0x20, 0x43, 0x41, + 0x0A, 0x41, 0x20, 0x44, 0x45, 0x20, 0x4C, 0x41, 0x20, 0x56, 0x41, 0x4C, 0x45, 0x55, 0x52, 0x2E, + 0x00, 0x4C, 0x45, 0x20, 0x54, 0x45, 0x4D, 0x50, 0x20, 0x45, 0x53, 0x54, 0x0A, 0x45, 0x43, 0x4F, + 0x55, 0x4C, 0x45, 0x00, 0x49, 0x4C, 0x20, 0x59, 0x20, 0x41, 0x20, 0x55, 0x4E, 0x0A, 0x45, 0x4D, + 0x50, 0x4C, 0x41, 0x43, 0x45, 0x4D, 0x45, 0x4E, 0x54, 0x20, 0x50, 0x4F, 0x55, 0x52, 0x0A, 0x4C, + 0x41, 0x20, 0x43, 0x41, 0x52, 0x54, 0x45, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x4D, 0x45, 0x52, 0x43, + 0x49, 0x20, 0x43, 0x4F, 0x4E, 0x52, 0x41, 0x44, 0x2E, 0x0A, 0x43, 0x45, 0x53, 0x20, 0x46, 0x4C, + 0x49, 0x43, 0x53, 0x0A, 0x4D, 0x27, 0x41, 0x55, 0x52, 0x41, 0x49, 0x45, 0x4E, 0x54, 0x20, 0x46, + 0x41, 0x49, 0x54, 0x0A, 0x4C, 0x41, 0x20, 0x50, 0x45, 0x41, 0x55, 0x0B, 0x42, 0x4F, 0x4E, 0x2C, + 0x4A, 0x45, 0x20, 0x53, 0x55, 0x50, 0x50, 0x4F, 0x53, 0x45, 0x0A, 0x51, 0x55, 0x45, 0x20, 0x54, + 0x55, 0x20, 0x4E, 0x45, 0x20, 0x54, 0x45, 0x0A, 0x52, 0x41, 0x50, 0x45, 0x4C, 0x4C, 0x45, 0x53, + 0x20, 0x50, 0x41, 0x53, 0x20, 0x44, 0x45, 0x0A, 0x54, 0x4F, 0x4E, 0x20, 0x41, 0x4D, 0x49, 0x20, + 0x49, 0x41, 0x4E, 0x2E, 0x0B, 0x41, 0x4C, 0x4C, 0x45, 0x5A, 0x2C, 0x41, 0x53, 0x53, 0x49, 0x45, + 0x44, 0x53, 0x0A, 0x54, 0x4F, 0x49, 0x20, 0x53, 0x55, 0x52, 0x20, 0x43, 0x45, 0x0A, 0x53, 0x49, + 0x45, 0x47, 0x45, 0x2C, 0x4F, 0x4E, 0x20, 0x56, 0x41, 0x20, 0x59, 0x0A, 0x52, 0x45, 0x4D, 0x45, + 0x44, 0x49, 0x45, 0x52, 0x00, 0x49, 0x41, 0x4E, 0x2C, 0x43, 0x4F, 0x4D, 0x4D, 0x45, 0x4E, 0x54, + 0x0A, 0x46, 0x41, 0x49, 0x52, 0x45, 0x20, 0x50, 0x4F, 0x55, 0x52, 0x0A, 0x41, 0x4C, 0x4C, 0x45, + 0x52, 0x20, 0x53, 0x55, 0x52, 0x20, 0x54, 0x45, 0x52, 0x52, 0x45, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, + 0x4C, 0x45, 0x20, 0x56, 0x4F, 0x59, 0x41, 0x47, 0x45, 0x20, 0x45, 0x53, 0x54, 0x0A, 0x48, 0x4F, + 0x52, 0x53, 0x20, 0x44, 0x45, 0x20, 0x50, 0x52, 0x49, 0x58, 0x2E, 0x0B, 0x4C, 0x45, 0x20, 0x53, + 0x45, 0x55, 0x4C, 0x20, 0x4D, 0x4F, 0x59, 0x45, 0x4E, 0x0A, 0x53, 0x45, 0x52, 0x41, 0x49, 0x54, + 0x20, 0x51, 0x55, 0x45, 0x20, 0x54, 0x55, 0x0A, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x49, 0x50, + 0x45, 0x53, 0x20, 0x41, 0x55, 0x0A, 0x44, 0x45, 0x41, 0x54, 0x48, 0x20, 0x54, 0x4F, 0x57, 0x45, + 0x52, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x44, 0x45, 0x41, 0x54, 0x48, 0x20, 0x54, 0x4F, 0x57, 0x45, + 0x52, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x4F, 0x55, 0x49, 0x2C, 0x43, 0x27, 0x45, 0x53, 0x54, 0x20, + 0x55, 0x4E, 0x20, 0x4A, 0x45, 0x55, 0x0A, 0x54, 0x45, 0x4C, 0x45, 0x56, 0x49, 0x53, 0x45, 0x2E, + 0x4C, 0x45, 0x0A, 0x47, 0x41, 0x47, 0x4E, 0x41, 0x4E, 0x54, 0x20, 0x52, 0x45, 0x43, 0x4F, 0x49, + 0x54, 0x0A, 0x55, 0x4E, 0x20, 0x42, 0x49, 0x4C, 0x4C, 0x45, 0x54, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, + 0x4F, 0x4B, 0x2E, 0x49, 0x4C, 0x20, 0x4D, 0x45, 0x20, 0x46, 0x41, 0x55, 0x54, 0x0A, 0x41, 0x55, + 0x53, 0x53, 0x49, 0x20, 0x44, 0x45, 0x53, 0x20, 0x46, 0x41, 0x55, 0x58, 0x0A, 0x50, 0x41, 0x50, + 0x49, 0x45, 0x52, 0x53, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x4E, 0x4F, 0x20, 0x50, 0x52, 0x4F, 0x42, + 0x4C, 0x45, 0x4D, 0x4F, 0x2C, 0x0A, 0x56, 0x41, 0x20, 0x41, 0x55, 0x20, 0x42, 0x41, 0x52, 0x2C, + 0x20, 0x45, 0x54, 0x0A, 0x44, 0x45, 0x4D, 0x41, 0x4E, 0x44, 0x45, 0x20, 0x4A, 0x41, 0x43, 0x4B, + 0x0A, 0x44, 0x45, 0x20, 0x4D, 0x41, 0x20, 0x50, 0x41, 0x52, 0x54, 0x2E, 0x0B, 0x41, 0x48, 0x2C, + 0x41, 0x55, 0x20, 0x46, 0x41, 0x49, 0x54, 0x2C, 0x4A, 0x45, 0x0A, 0x54, 0x27, 0x41, 0x49, 0x20, + 0x4D, 0x49, 0x53, 0x20, 0x44, 0x41, 0x4E, 0x53, 0x20, 0x4C, 0x41, 0x0A, 0x50, 0x4F, 0x43, 0x48, + 0x45, 0x20, 0x4C, 0x45, 0x20, 0x43, 0x48, 0x41, 0x4D, 0x50, 0x0A, 0x44, 0x45, 0x20, 0x50, 0x52, + 0x4F, 0x54, 0x45, 0x43, 0x54, 0x49, 0x4F, 0x4E, 0x0B, 0x51, 0x55, 0x45, 0x20, 0x54, 0x55, 0x20, + 0x4D, 0x27, 0x41, 0x56, 0x41, 0x49, 0x53, 0x0A, 0x43, 0x4F, 0x4D, 0x4D, 0x41, 0x4E, 0x44, 0x45, + 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x50, 0x41, 0x52, 0x46, 0x41, 0x49, 0x54, 0x2E, 0x4A, 0x45, 0x20, + 0x54, 0x45, 0x0A, 0x52, 0x45, 0x4D, 0x45, 0x52, 0x43, 0x49, 0x45, 0x2E, 0x20, 0x41, 0x20, 0x4C, + 0x41, 0x0A, 0x50, 0x52, 0x4F, 0x43, 0x48, 0x41, 0x49, 0x4E, 0x45, 0x2C, 0x20, 0x49, 0x41, 0x4E, + 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x42, 0x4F, 0x4E, 0x4E, 0x45, 0x20, 0x43, 0x48, 0x41, 0x4E, 0x43, + 0x45, 0x2E, 0x4A, 0x45, 0x0A, 0x54, 0x45, 0x20, 0x43, 0x4F, 0x4E, 0x54, 0x41, 0x43, 0x54, 0x45, + 0x52, 0x41, 0x49, 0x0A, 0x41, 0x20, 0x54, 0x4F, 0x4E, 0x20, 0x41, 0x52, 0x52, 0x49, 0x56, 0x45, + 0x20, 0x53, 0x55, 0x52, 0x0A, 0x54, 0x45, 0x52, 0x52, 0x45, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x42, + 0x49, 0x45, 0x4E, 0x56, 0x45, 0x4E, 0x55, 0x45, 0x20, 0x41, 0x0A, 0x4E, 0x45, 0x57, 0x20, 0x57, + 0x41, 0x53, 0x48, 0x49, 0x4E, 0x47, 0x54, 0x4F, 0x4E, 0x2C, 0x0A, 0x4A, 0x45, 0x55, 0x4E, 0x45, + 0x20, 0x48, 0x4F, 0x4D, 0x4D, 0x45, 0x2E, 0x0B, 0x56, 0x4F, 0x49, 0x43, 0x49, 0x20, 0x55, 0x4E, + 0x20, 0x50, 0x4C, 0x41, 0x4E, 0x0A, 0x44, 0x45, 0x20, 0x4C, 0x41, 0x20, 0x56, 0x49, 0x4C, 0x4C, + 0x45, 0x2C, 0x20, 0x49, 0x4C, 0x0A, 0x50, 0x4F, 0x55, 0x52, 0x52, 0x41, 0x20, 0x56, 0x4F, 0x55, + 0x53, 0x20, 0x45, 0x54, 0x52, 0x45, 0x0A, 0x55, 0x54, 0x49, 0x4C, 0x45, 0x2E, 0x0B, 0xFF, 0xE9, + 0xEA, 0x4D, 0x45, 0x52, 0x43, 0x49, 0x2C, 0x4D, 0x4F, 0x4E, 0x53, 0x49, 0x45, 0x55, 0x52, 0x2E, + 0x00, 0xFF, 0xEB, 0xEC, 0x42, 0x4F, 0x4E, 0x20, 0x53, 0x45, 0x4A, 0x4F, 0x55, 0x52, 0x2C, 0x50, + 0x41, 0x52, 0x4D, 0x49, 0x0A, 0x4E, 0x4F, 0x55, 0x53, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x50, 0x4F, + 0x55, 0x52, 0x20, 0x54, 0x52, 0x41, 0x56, 0x41, 0x49, 0x4C, 0x4C, 0x45, 0x52, 0x0A, 0x49, 0x4C, + 0x20, 0x56, 0x4F, 0x55, 0x53, 0x20, 0x46, 0x41, 0x55, 0x54, 0x20, 0x55, 0x4E, 0x0A, 0x50, 0x45, + 0x52, 0x4D, 0x49, 0x53, 0x2E, 0x0B, 0x56, 0x4F, 0x55, 0x53, 0x20, 0x50, 0x4F, 0x55, 0x52, 0x52, + 0x45, 0x5A, 0x20, 0x45, 0x4E, 0x0A, 0x4F, 0x42, 0x54, 0x45, 0x4E, 0x49, 0x52, 0x20, 0x55, 0x4E, + 0x20, 0x41, 0x55, 0x0A, 0x43, 0x45, 0x4E, 0x54, 0x52, 0x45, 0x20, 0x41, 0x44, 0x4D, 0x49, 0x4E, + 0x49, 0x53, 0x2D, 0x0A, 0x2D, 0x54, 0x52, 0x41, 0x54, 0x49, 0x46, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, + 0x4A, 0x45, 0x20, 0x4E, 0x27, 0x41, 0x49, 0x20, 0x50, 0x41, 0x53, 0x20, 0x4C, 0x45, 0x0A, 0x54, + 0x45, 0x4D, 0x50, 0x53, 0x2E, 0x00, 0x42, 0x4F, 0x4E, 0x4A, 0x4F, 0x55, 0x52, 0x20, 0x43, 0x48, + 0x45, 0x5A, 0x0A, 0x56, 0x4F, 0x55, 0x53, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x4A, 0x27, 0x41, 0x49, + 0x20, 0x44, 0x45, 0x4A, 0x41, 0x20, 0x56, 0x55, 0x0A, 0x43, 0x45, 0x20, 0x54, 0x59, 0x50, 0x45, + 0x20, 0x4C, 0x41, 0x20, 0x41, 0x55, 0x0A, 0x42, 0x41, 0x52, 0x2E, 0x00, 0x42, 0x4F, 0x4E, 0x4A, + 0x4F, 0x55, 0x52, 0x20, 0x43, 0x48, 0x45, 0x5A, 0x0A, 0x56, 0x4F, 0x55, 0x53, 0x2E, 0x00, 0x4F, + 0x55, 0x49, 0x2C, 0x4A, 0x45, 0x20, 0x4C, 0x45, 0x0A, 0x43, 0x4F, 0x4E, 0x4E, 0x41, 0x49, 0x53, + 0x2E, 0x43, 0x27, 0x45, 0x53, 0x54, 0x20, 0x55, 0x4E, 0x0A, 0x48, 0x41, 0x42, 0x49, 0x54, 0x55, + 0x45, 0x2E, 0x00, 0x20, 0x00, 0x20, 0x00, 0x4A, 0x45, 0x20, 0x56, 0x4F, 0x55, 0x44, 0x52, 0x41, + 0x49, 0x53, 0x20, 0x55, 0x4E, 0x0A, 0x50, 0x45, 0x52, 0x4D, 0x49, 0x53, 0x20, 0x44, 0x45, 0x0A, + 0x54, 0x52, 0x41, 0x56, 0x41, 0x49, 0x4C, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x50, 0x41, 0x53, 0x20, + 0x44, 0x45, 0x20, 0x50, 0x52, 0x4F, 0x42, 0x4C, 0x45, 0x4D, 0x45, 0x0A, 0x50, 0x4F, 0x55, 0x52, + 0x20, 0x41, 0x56, 0x4F, 0x49, 0x52, 0x20, 0x55, 0x4E, 0x0A, 0x50, 0x45, 0x52, 0x4D, 0x49, 0x53, + 0x2E, 0x2E, 0x2E, 0x0B, 0x49, 0x4C, 0x20, 0x4D, 0x45, 0x20, 0x46, 0x41, 0x55, 0x54, 0x0A, 0x56, + 0x4F, 0x54, 0x52, 0x45, 0x20, 0x43, 0x41, 0x52, 0x54, 0x45, 0x20, 0x49, 0x44, 0x2E, 0x00, 0xFF, + 0xEB, 0xEC, 0x41, 0x55, 0x20, 0x53, 0x45, 0x43, 0x4F, 0x55, 0x52, 0x53, 0x2E, 0x2E, 0x2E, 0x00, + 0xFF, 0xEB, 0xEC, 0x41, 0x49, 0x44, 0x45, 0x5A, 0x20, 0x4D, 0x4F, 0x49, 0x2C, 0x4A, 0x45, 0x55, + 0x4E, 0x45, 0x0A, 0x48, 0x4F, 0x4D, 0x4D, 0x45, 0x2E, 0x4A, 0x27, 0x41, 0x49, 0x20, 0x45, 0x54, + 0x45, 0x0A, 0x41, 0x54, 0x54, 0x41, 0x51, 0x55, 0x45, 0x20, 0x50, 0x41, 0x52, 0x20, 0x44, 0x45, + 0x53, 0x0A, 0x4D, 0x55, 0x54, 0x41, 0x4E, 0x54, 0x53, 0x2E, 0x2E, 0x2E, 0x0B, 0x45, 0x54, 0x20, + 0x4A, 0x45, 0x20, 0x4E, 0x45, 0x20, 0x50, 0x45, 0x55, 0x58, 0x0A, 0x50, 0x4C, 0x55, 0x53, 0x20, + 0x4D, 0x41, 0x52, 0x43, 0x48, 0x45, 0x52, 0x0B, 0x52, 0x45, 0x54, 0x52, 0x4F, 0x55, 0x56, 0x45, + 0x5A, 0x20, 0x4D, 0x4F, 0x4E, 0x0A, 0x54, 0x45, 0x4C, 0x45, 0x50, 0x4F, 0x52, 0x54, 0x45, 0x55, + 0x52, 0x2C, 0x0A, 0x49, 0x4C, 0x20, 0x4D, 0x45, 0x20, 0x46, 0x41, 0x55, 0x54, 0x20, 0x44, 0x45, + 0x53, 0x0A, 0x53, 0x4F, 0x49, 0x4E, 0x53, 0x20, 0x55, 0x52, 0x47, 0x45, 0x4E, 0x54, 0x53, 0x2E, + 0x00, 0xFF, 0xEB, 0xEC, 0x4D, 0x45, 0x52, 0x43, 0x49, 0x2E, 0x56, 0x4F, 0x55, 0x53, 0x20, 0x56, + 0x45, 0x4E, 0x45, 0x5A, 0x0A, 0x44, 0x45, 0x20, 0x4D, 0x45, 0x20, 0x53, 0x41, 0x55, 0x56, 0x45, + 0x52, 0x20, 0x4C, 0x41, 0x0A, 0x56, 0x49, 0x45, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x50, 0x4F, 0x55, + 0x52, 0x20, 0x41, 0x4C, 0x4C, 0x45, 0x52, 0x20, 0x41, 0x20, 0x4E, 0x45, 0x57, 0x0A, 0x57, 0x41, + 0x53, 0x48, 0x49, 0x4E, 0x47, 0x54, 0x4F, 0x4E, 0x2C, 0x54, 0x55, 0x0A, 0x44, 0x4F, 0x49, 0x53, + 0x20, 0x53, 0x41, 0x55, 0x54, 0x45, 0x52, 0x20, 0x44, 0x41, 0x4E, 0x53, 0x0A, 0x43, 0x45, 0x20, + 0x47, 0x52, 0x41, 0x4E, 0x44, 0x20, 0x54, 0x52, 0x4F, 0x55, 0x0B, 0x4D, 0x41, 0x49, 0x53, 0x20, + 0x41, 0x20, 0x54, 0x41, 0x20, 0x50, 0x4C, 0x41, 0x43, 0x45, 0x0A, 0x4A, 0x27, 0x55, 0x54, 0x49, + 0x4C, 0x49, 0x53, 0x45, 0x52, 0x41, 0x49, 0x53, 0x0A, 0x55, 0x4E, 0x45, 0x20, 0x43, 0x45, 0x49, + 0x4E, 0x54, 0x55, 0x52, 0x45, 0x0A, 0x41, 0x4E, 0x54, 0x49, 0x2D, 0x47, 0x2E, 0x0B, 0xFF, 0xE9, + 0xEA, 0x4F, 0x55, 0x20, 0x50, 0x55, 0x49, 0x53, 0x2D, 0x4A, 0x45, 0x20, 0x45, 0x4E, 0x0A, 0x54, + 0x52, 0x4F, 0x55, 0x56, 0x45, 0x52, 0x20, 0x55, 0x4E, 0x45, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x48, + 0x45, 0x2E, 0x48, 0x45, 0x2E, 0x4A, 0x45, 0x20, 0x50, 0x45, 0x55, 0x58, 0x0A, 0x54, 0x45, 0x20, + 0x4C, 0x41, 0x20, 0x56, 0x45, 0x4E, 0x44, 0x52, 0x45, 0x3A, 0x0A, 0x35, 0x30, 0x30, 0x20, 0x43, + 0x52, 0x45, 0x44, 0x49, 0x54, 0x53, 0x2E, 0x00, 0x42, 0x4F, 0x4E, 0x20, 0x56, 0x4F, 0x59, 0x41, + 0x47, 0x45, 0x2C, 0x4A, 0x45, 0x55, 0x4E, 0x45, 0x0A, 0x48, 0x4F, 0x4D, 0x4D, 0x45, 0x2E, 0x00, + 0x49, 0x4C, 0x20, 0x46, 0x41, 0x55, 0x44, 0x52, 0x41, 0x49, 0x54, 0x0A, 0x55, 0x4E, 0x45, 0x20, + 0x50, 0x49, 0x4C, 0x45, 0x0A, 0x43, 0x48, 0x41, 0x52, 0x47, 0x45, 0x45, 0x20, 0x41, 0x20, 0x42, + 0x4C, 0x4F, 0x43, 0x00, 0x4A, 0x45, 0x20, 0x56, 0x4F, 0x55, 0x44, 0x52, 0x41, 0x49, 0x53, 0x20, + 0x55, 0x4E, 0x0A, 0x50, 0x45, 0x52, 0x4D, 0x49, 0x53, 0x20, 0x44, 0x45, 0x0A, 0x54, 0x52, 0x41, + 0x56, 0x41, 0x49, 0x4C, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x50, 0x52, 0x45, 0x4D, 0x49, 0x45, 0x52, + 0x20, 0x45, 0x54, 0x41, 0x47, 0x45, 0x00, 0x55, 0x4E, 0x45, 0x20, 0x56, 0x4F, 0x49, 0x58, 0x0A, + 0x49, 0x4E, 0x54, 0x45, 0x52, 0x49, 0x45, 0x55, 0x52, 0x45, 0x20, 0x73, 0x65, 0x0A, 0x46, 0x41, + 0x49, 0x54, 0x20, 0x45, 0x4E, 0x54, 0x45, 0x4E, 0x44, 0x52, 0x45, 0x3A, 0x0B, 0xFF, 0xEB, 0xEC, + 0x46, 0x41, 0x49, 0x53, 0x2D, 0x4D, 0x4F, 0x49, 0x0A, 0x43, 0x4F, 0x4E, 0x46, 0x49, 0x41, 0x4E, + 0x43, 0x45, 0x2E, 0x50, 0x4F, 0x53, 0x45, 0x0A, 0x4C, 0x41, 0x20, 0x43, 0x48, 0x41, 0x52, 0x47, + 0x45, 0x0A, 0x41, 0x54, 0x4F, 0x4D, 0x49, 0x51, 0x55, 0x45, 0x20, 0x49, 0x43, 0x49, 0x2E, 0x2E, + 0x2E, 0x0B, 0x45, 0x54, 0x20, 0x46, 0x55, 0x49, 0x53, 0x20, 0x41, 0x56, 0x41, 0x4E, 0x54, 0x0A, + 0x51, 0x55, 0x27, 0x45, 0x4C, 0x4C, 0x45, 0x20, 0x4E, 0x27, 0x41, 0x54, 0x2D, 0x0A, 0x2D, 0x54, + 0x45, 0x49, 0x47, 0x4E, 0x45, 0x20, 0x4C, 0x45, 0x20, 0x4E, 0x4F, 0x59, 0x41, 0x55, 0x0A, 0x44, + 0x45, 0x20, 0x4C, 0x41, 0x20, 0x50, 0x4C, 0x41, 0x4E, 0x45, 0x54, 0x45, 0x2E, 0x00, 0xFF, 0xEB, + 0xEC, 0x4A, 0x45, 0x20, 0x56, 0x4F, 0x55, 0x53, 0x20, 0x53, 0x55, 0x49, 0x53, 0x2C, 0x0A, 0x4A, + 0x45, 0x55, 0x4E, 0x45, 0x20, 0x48, 0x4F, 0x4D, 0x4D, 0x45, 0x2E, 0x0B, 0x47, 0x55, 0x49, 0x44, + 0x45, 0x5A, 0x2D, 0x4D, 0x4F, 0x49, 0x0A, 0x4A, 0x55, 0x53, 0x51, 0x55, 0x27, 0x41, 0x55, 0x20, + 0x43, 0x45, 0x4E, 0x54, 0x52, 0x45, 0x0A, 0x44, 0x45, 0x20, 0x52, 0x45, 0x43, 0x48, 0x45, 0x52, + 0x43, 0x48, 0x45, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x4D, 0x45, 0x52, 0x43, 0x49, 0x20, 0x44, 0x45, + 0x20, 0x56, 0x4F, 0x54, 0x52, 0x45, 0x0A, 0x41, 0x49, 0x44, 0x45, 0x2E, 0x2E, 0x2E, 0x0B, 0x49, + 0x4C, 0x20, 0x4E, 0x27, 0x59, 0x20, 0x41, 0x20, 0x50, 0x4C, 0x55, 0x53, 0x0A, 0x44, 0x45, 0x20, + 0x44, 0x41, 0x4E, 0x47, 0x45, 0x52, 0x2C, 0x0A, 0x4D, 0x41, 0x49, 0x4E, 0x54, 0x45, 0x4E, 0x41, + 0x4E, 0x54, 0x00, 0xFF, 0xEB, 0xEC, 0x41, 0x4C, 0x4F, 0x52, 0x53, 0x2C, 0x4D, 0x27, 0x41, 0x56, + 0x45, 0x5A, 0x0A, 0x56, 0x4F, 0x55, 0x53, 0x20, 0x41, 0x50, 0x50, 0x4F, 0x52, 0x54, 0x45, 0x0A, + 0x4C, 0x45, 0x20, 0x50, 0x41, 0x51, 0x55, 0x45, 0x54, 0x3F, 0x00, 0x43, 0x4F, 0x4D, 0x42, 0x49, + 0x45, 0x4E, 0x20, 0x43, 0x4F, 0x55, 0x54, 0x45, 0x0A, 0x55, 0x4E, 0x20, 0x42, 0x49, 0x4C, 0x4C, + 0x45, 0x54, 0x20, 0x50, 0x4F, 0x55, 0x52, 0x0A, 0x4C, 0x41, 0x20, 0x54, 0x45, 0x52, 0x52, 0x45, + 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x35, 0x30, 0x20, 0x30, 0x30, 0x30, 0x20, 0x43, 0x52, 0x45, 0x44, + 0x49, 0x54, 0x53, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x44, 0x4F, 0x4E, 0x4E, 0x41, 0x4E, 0x54, 0x2C, + 0x44, 0x4F, 0x4E, 0x4E, 0x41, 0x4E, 0x54, 0x2E, 0x0A, 0x31, 0x35, 0x30, 0x30, 0x20, 0x43, 0x52, + 0x45, 0x44, 0x49, 0x54, 0x53, 0x20, 0x45, 0x54, 0x0A, 0x4C, 0x45, 0x53, 0x20, 0x50, 0x41, 0x50, + 0x49, 0x45, 0x52, 0x53, 0x20, 0x53, 0x4F, 0x4E, 0x54, 0x0A, 0x41, 0x20, 0x54, 0x4F, 0x49, 0x2E, + 0x00 +}; + +const uint8_t LocaleData::_stringsTableEN[] = { + 0x5A, 0x00, 0x6D, 0x00, 0x83, 0x00, 0x97, 0x01, 0x48, 0x02, 0x6C, 0x02, 0xB7, 0x02, 0xE9, 0x02, + 0x40, 0x03, 0x5F, 0x03, 0x9F, 0x03, 0xDB, 0x03, 0x1D, 0x04, 0x59, 0x04, 0xDD, 0x04, 0x08, 0x05, + 0x1A, 0x05, 0x83, 0x05, 0x8E, 0x05, 0xAC, 0x05, 0x39, 0x06, 0x23, 0x08, 0x8E, 0x08, 0xA2, 0x08, + 0xF3, 0x08, 0x09, 0x09, 0x28, 0x09, 0x51, 0x09, 0x70, 0x09, 0x93, 0x09, 0x95, 0x09, 0x97, 0x09, + 0xEE, 0x09, 0x00, 0x0A, 0x80, 0x0A, 0xA2, 0x0A, 0x4B, 0x0B, 0x64, 0x0B, 0x8F, 0x0B, 0xB7, 0x0B, + 0x40, 0x0C, 0x76, 0x0C, 0xC7, 0x0C, 0xF4, 0x0C, 0x26, 0x0D, 0x54, 0x68, 0x65, 0x20, 0x66, 0x75, + 0x73, 0x65, 0x20, 0x69, 0x73, 0x0A, 0x62, 0x6C, 0x6F, 0x77, 0x6E, 0x2E, 0x00, 0x54, 0x68, 0x61, + 0x74, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x0A, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x6E, 0x6F, + 0x77, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x49, 0x27, 0x6D, 0x20, 0x4A, 0x61, 0x63, 0x6B, 0x2E, 0x59, + 0x6F, 0x75, 0x27, 0x72, 0x65, 0x0A, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x73, 0x6F, 0x6D, 0x65, + 0x20, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x0A, 0x70, 0x61, 0x70, 0x65, 0x72, 0x73, 0x3F, 0x0B, 0xFF, + 0xE9, 0xEA, 0x59, 0x65, 0x73, 0x2C, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x73, 0x0A, 0x71, 0x75, 0x69, + 0x63, 0x6B, 0x6C, 0x79, 0x20, 0x61, 0x73, 0x0A, 0x70, 0x6F, 0x73, 0x73, 0x69, 0x62, 0x6C, 0x65, + 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x31, 0x35, 0x30, 0x30, 0x20, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, + 0x73, 0x21, 0x0B, 0xFF, 0xE9, 0xEA, 0x31, 0x35, 0x30, 0x30, 0x3F, 0x3F, 0x3F, 0x0B, 0xFF, 0xEB, + 0xEC, 0x59, 0x65, 0x61, 0x68, 0x2C, 0x49, 0x27, 0x6D, 0x20, 0x74, 0x61, 0x6B, 0x69, 0x6E, 0x67, + 0x0A, 0x61, 0x20, 0x62, 0x69, 0x67, 0x20, 0x72, 0x69, 0x73, 0x6B, 0x20, 0x68, 0x65, 0x72, 0x65, + 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x42, 0x75, 0x74, 0x20, 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, + 0x0A, 0x68, 0x61, 0x76, 0x65, 0x20, 0x65, 0x6E, 0x6F, 0x75, 0x67, 0x68, 0x2E, 0x2E, 0x2E, 0x0B, + 0xFF, 0xEB, 0xEC, 0x47, 0x6F, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x0A, 0x45, 0x6D, 0x70, + 0x6C, 0x6F, 0x79, 0x6D, 0x65, 0x6E, 0x74, 0x0A, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x2C, 0x20, + 0x79, 0x6F, 0x75, 0x27, 0x6C, 0x6C, 0x0A, 0x66, 0x69, 0x6E, 0x64, 0x20, 0x77, 0x6F, 0x72, 0x6B, + 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x2E, 0x0B, 0x41, 0x6E, 0x64, 0x20, 0x63, 0x6F, 0x6D, 0x65, + 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x74, 0x6F, 0x0A, 0x6D, 0x65, 0x20, 0x77, 0x68, 0x65, 0x6E, + 0x20, 0x79, 0x6F, 0x75, 0x27, 0x76, 0x65, 0x0A, 0x67, 0x6F, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6D, 0x6F, 0x6E, 0x65, 0x79, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x49, 0x20, 0x6B, 0x6E, 0x6F, 0x77, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x67, 0x75, 0x79, 0x2E, 0x0A, 0x48, 0x65, 0x20, 0x68, 0x61, + 0x73, 0x20, 0x61, 0x20, 0x66, 0x72, 0x69, 0x65, 0x6E, 0x64, 0x0A, 0x69, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x6F, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x57, 0x68, 0x65, + 0x72, 0x65, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x49, 0x20, 0x66, 0x69, 0x6E, 0x64, 0x0A, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x66, 0x72, 0x69, 0x65, 0x6E, 0x64, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x47, 0x6F, + 0x20, 0x74, 0x6F, 0x20, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x65, 0x64, 0x0A, 0x41, + 0x72, 0x65, 0x61, 0x20, 0x31, 0x2C, 0x20, 0x49, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x0A, 0x68, + 0x65, 0x27, 0x73, 0x20, 0x6F, 0x6E, 0x20, 0x64, 0x75, 0x74, 0x79, 0x0A, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x2E, 0x0B, 0x42, 0x75, 0x74, 0x20, 0x62, 0x65, 0x20, 0x63, 0x61, 0x72, 0x65, 0x66, 0x75, + 0x6C, 0x2C, 0x0A, 0x74, 0x68, 0x6F, 0x73, 0x65, 0x20, 0x67, 0x75, 0x79, 0x73, 0x20, 0x61, 0x72, + 0x65, 0x0A, 0x6D, 0x65, 0x61, 0x6E, 0x21, 0x00, 0xFF, 0xEB, 0xEC, 0x49, 0x20, 0x64, 0x6F, 0x6E, + 0x27, 0x74, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x0A, 0x61, 0x6E, 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x2C, 0x0A, 0x73, 0x6F, 0x6E, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x43, + 0x59, 0x2D, 0x42, 0x30, 0x32, 0x31, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x73, 0x0A, 0x74, 0x6F, 0x20, + 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x61, 0x20, 0x64, 0x65, 0x61, 0x6C, 0x0A, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x79, 0x6F, 0x75, 0x2E, 0x0B, 0x48, 0x65, 0x27, 0x6C, 0x6C, 0x20, 0x62, 0x65, 0x20, 0x77, + 0x61, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x0A, 0x62, 0x65, 0x68, 0x69, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x62, 0x61, 0x72, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x47, 0x6F, 0x20, 0x74, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x62, 0x61, 0x72, 0x2C, 0x0A, 0x73, 0x6F, 0x6E, 0x2C, 0x20, 0x43, 0x59, + 0x2D, 0x42, 0x30, 0x32, 0x31, 0x27, 0x73, 0x0A, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x79, 0x6F, 0x75, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x44, 0x6F, 0x6E, 0x27, + 0x74, 0x20, 0x73, 0x68, 0x6F, 0x6F, 0x74, 0x2C, 0x49, 0x27, 0x6D, 0x0A, 0x6E, 0x6F, 0x74, 0x20, + 0x43, 0x59, 0x2D, 0x42, 0x30, 0x32, 0x31, 0x21, 0x0B, 0x48, 0x69, 0x73, 0x20, 0x68, 0x69, 0x64, + 0x65, 0x6F, 0x75, 0x74, 0x27, 0x73, 0x0A, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x62, 0x65, 0x6C, 0x6F, + 0x77, 0x2E, 0x0B, 0x48, 0x69, 0x73, 0x20, 0x70, 0x61, 0x6C, 0x2C, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x6F, 0x70, 0x0A, 0x68, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6B, 0x65, 0x79, 0x2E, 0x00, + 0xFF, 0xEB, 0xEC, 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x0A, + 0x61, 0x6E, 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x2E, 0x00, 0xFF, + 0xEB, 0xEC, 0x53, 0x69, 0x72, 0x2E, 0x2E, 0x2E, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x67, 0x75, + 0x79, 0x0B, 0x63, 0x61, 0x6C, 0x6C, 0x65, 0x64, 0x20, 0x4A, 0x61, 0x63, 0x6B, 0x0A, 0x61, 0x72, + 0x72, 0x61, 0x6E, 0x67, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x65, 0x65, 0x74, 0x0A, 0x79, + 0x6F, 0x75, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x61, 0x72, 0x2E, 0x00, 0x49, + 0x27, 0x64, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x61, 0x0A, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x70, + 0x65, 0x72, 0x6D, 0x69, 0x74, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x4E, 0x6F, 0x2C, 0x20, 0x69, 0x74, + 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x0A, 0x68, 0x65, 0x72, 0x65, 0x2E, 0x20, 0x53, 0x65, 0x65, + 0x20, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x0A, 0x43, 0x2E, 0x00, 0x49, 0x27, 0x64, 0x20, 0x6C, + 0x69, 0x6B, 0x65, 0x20, 0x61, 0x0A, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x70, 0x65, 0x72, 0x6D, 0x69, + 0x74, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x47, 0x6F, 0x6F, 0x64, 0x2E, 0x2E, 0x2E, 0x4F, 0x2E, 0x6B, + 0x2E, 0x2C, 0x74, 0x68, 0x65, 0x0A, 0x62, 0x6F, 0x73, 0x73, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, + 0x73, 0x65, 0x65, 0x0A, 0x79, 0x6F, 0x75, 0x20, 0x6E, 0x6F, 0x77, 0x2E, 0x00, 0x49, 0x27, 0x64, + 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x61, 0x0A, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x70, 0x65, 0x72, + 0x6D, 0x69, 0x74, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x4E, 0x6F, 0x2C, 0x20, 0x69, 0x74, 0x27, 0x73, + 0x20, 0x6E, 0x6F, 0x74, 0x0A, 0x68, 0x65, 0x72, 0x65, 0x2E, 0x20, 0x53, 0x65, 0x65, 0x20, 0x57, + 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x0A, 0x42, 0x2E, 0x00, 0x49, 0x27, 0x64, 0x20, 0x6C, 0x69, 0x6B, + 0x65, 0x20, 0x74, 0x6F, 0x0A, 0x73, 0x70, 0x65, 0x61, 0x6B, 0x20, 0x74, 0x6F, 0x20, 0x4A, 0x61, + 0x63, 0x6B, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x4F, 0x68, 0x20, 0x79, 0x65, 0x61, 0x68, 0x3F, 0x20, + 0x4A, 0x61, 0x63, 0x6B, 0x27, 0x73, 0x0A, 0x6E, 0x6F, 0x74, 0x20, 0x68, 0x65, 0x72, 0x65, 0x2E, + 0x0B, 0xFF, 0xE9, 0xEA, 0x49, 0x27, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x73, 0x65, + 0x6E, 0x74, 0x0A, 0x62, 0x79, 0x20, 0x6D, 0x79, 0x20, 0x66, 0x72, 0x69, 0x65, 0x6E, 0x64, 0x0A, + 0x49, 0x61, 0x6E, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x4F, 0x2E, 0x6B, 0x2E, 0x20, 0x4A, 0x61, 0x63, + 0x6B, 0x27, 0x73, 0x0A, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x6F, 0x72, 0x20, + 0x79, 0x6F, 0x75, 0x0A, 0x6F, 0x75, 0x74, 0x73, 0x69, 0x64, 0x65, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, + 0x42, 0x65, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x73, 0x6F, 0x6E, 0x2E, 0x0A, 0x59, 0x6F, 0x75, + 0x27, 0x72, 0x65, 0x20, 0x74, 0x6F, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x6E, 0x67, 0x0A, 0x74, 0x6F, + 0x20, 0x64, 0x72, 0x69, 0x6E, 0x6B, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x50, 0x61, 0x70, 0x65, 0x72, + 0x73, 0x20, 0x70, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x2E, 0x00, 0x49, 0x27, 0x6D, 0x20, 0x74, 0x68, + 0x65, 0x0A, 0x6D, 0x65, 0x73, 0x73, 0x65, 0x6E, 0x67, 0x65, 0x72, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, + 0x4F, 0x68, 0x20, 0x79, 0x65, 0x73, 0x21, 0x20, 0x48, 0x65, 0x72, 0x65, 0x2C, 0x0A, 0x74, 0x61, + 0x6B, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x72, 0x63, 0x65, 0x6C, 0x0A, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x76, 0x65, 0x6C, 0x0A, 0x61, 0x67, 0x65, + 0x6E, 0x63, 0x79, 0x2E, 0x0B, 0x41, 0x6E, 0x64, 0x20, 0x62, 0x65, 0x20, 0x63, 0x61, 0x72, 0x65, + 0x66, 0x75, 0x6C, 0x0A, 0x69, 0x74, 0x27, 0x73, 0x20, 0x76, 0x61, 0x6C, 0x75, 0x61, 0x62, 0x6C, + 0x65, 0x2E, 0x00, 0x54, 0x49, 0x4D, 0x45, 0x20, 0x49, 0x53, 0x20, 0x55, 0x50, 0x00, 0x54, 0x68, + 0x65, 0x72, 0x65, 0x27, 0x73, 0x20, 0x61, 0x20, 0x70, 0x6C, 0x61, 0x63, 0x65, 0x0A, 0x66, 0x6F, + 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x61, 0x72, 0x64, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x54, + 0x68, 0x61, 0x6E, 0x6B, 0x73, 0x2C, 0x20, 0x43, 0x6F, 0x6E, 0x72, 0x61, 0x64, 0x2E, 0x0A, 0x54, + 0x68, 0x6F, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x70, 0x73, 0x0A, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x27, + 0x76, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6D, 0x79, 0x0A, 0x68, 0x69, 0x64, 0x65, 0x21, 0x0B, + 0x57, 0x65, 0x6C, 0x6C, 0x2C, 0x49, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x73, 0x65, 0x0A, 0x79, + 0x6F, 0x75, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x0A, 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, 0x65, + 0x72, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x0A, 0x6F, 0x6C, 0x64, 0x20, 0x70, 0x61, 0x6C, 0x20, 0x49, + 0x61, 0x6E, 0x2E, 0x0B, 0x54, 0x61, 0x6B, 0x65, 0x20, 0x61, 0x20, 0x73, 0x65, 0x61, 0x74, 0x2C, + 0x0A, 0x77, 0x65, 0x27, 0x6C, 0x6C, 0x20, 0x66, 0x69, 0x78, 0x20, 0x74, 0x68, 0x61, 0x74, 0x0A, + 0x73, 0x68, 0x6F, 0x72, 0x74, 0x6C, 0x79, 0x2E, 0x00, 0x49, 0x61, 0x6E, 0x2C, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x64, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x0A, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x64, 0x6F, 0x20, 0x74, 0x6F, 0x0A, 0x67, 0x65, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x45, 0x41, + 0x52, 0x54, 0x48, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x54, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x73, 0x74, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x0A, 0x74, 0x69, 0x63, 0x6B, 0x65, 0x74, 0x20, 0x69, + 0x73, 0x0A, 0x61, 0x73, 0x74, 0x72, 0x6F, 0x6E, 0x6F, 0x6D, 0x69, 0x63, 0x61, 0x6C, 0x2E, 0x0B, + 0x54, 0x68, 0x65, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x77, 0x61, 0x79, 0x0A, 0x77, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x62, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x79, 0x6F, 0x75, 0x0A, 0x74, 0x6F, + 0x20, 0x74, 0x61, 0x6B, 0x65, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x69, 0x6E, 0x0A, 0x44, 0x65, + 0x61, 0x74, 0x68, 0x20, 0x54, 0x6F, 0x77, 0x65, 0x72, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x44, 0x65, + 0x61, 0x74, 0x68, 0x20, 0x54, 0x6F, 0x77, 0x65, 0x72, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x59, 0x65, + 0x73, 0x2C, 0x69, 0x74, 0x27, 0x73, 0x20, 0x61, 0x0A, 0x74, 0x65, 0x6C, 0x65, 0x76, 0x69, 0x73, + 0x69, 0x6F, 0x6E, 0x20, 0x67, 0x61, 0x6D, 0x65, 0x2E, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x77, 0x69, + 0x6E, 0x6E, 0x65, 0x72, 0x20, 0x67, 0x65, 0x74, 0x73, 0x0A, 0x61, 0x20, 0x74, 0x69, 0x63, 0x6B, + 0x65, 0x74, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x4F, 0x2E, 0x6B, 0x2E, 0x43, 0x61, 0x6E, 0x20, 0x79, + 0x6F, 0x75, 0x0A, 0x73, 0x75, 0x70, 0x70, 0x6C, 0x79, 0x20, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x0A, + 0x70, 0x61, 0x70, 0x65, 0x72, 0x73, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x4E, 0x6F, 0x20, 0x70, 0x72, + 0x6F, 0x62, 0x6C, 0x65, 0x6D, 0x2E, 0x0A, 0x47, 0x6F, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x62, 0x61, 0x72, 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x73, 0x6B, 0x20, 0x66, 0x6F, 0x72, + 0x0A, 0x4A, 0x61, 0x63, 0x6B, 0x2E, 0x0B, 0x53, 0x61, 0x79, 0x20, 0x49, 0x20, 0x73, 0x65, 0x6E, + 0x74, 0x20, 0x79, 0x6F, 0x75, 0x2E, 0x0A, 0x4F, 0x68, 0x2C, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x77, 0x61, 0x79, 0x2E, 0x2E, 0x2E, 0x0B, 0x49, 0x20, 0x70, 0x75, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x66, 0x6F, 0x72, 0x63, 0x65, 0x0A, 0x66, 0x69, 0x65, 0x6C, 0x64, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x61, 0x73, 0x6B, 0x65, 0x64, 0x0A, 0x6D, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x69, + 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x0A, 0x70, 0x6F, 0x63, 0x6B, 0x65, 0x74, 0x2E, 0x0B, 0xFF, + 0xE9, 0xEA, 0x47, 0x72, 0x65, 0x61, 0x74, 0x2E, 0x54, 0x68, 0x61, 0x6E, 0x6B, 0x0A, 0x79, 0x6F, + 0x75, 0x2C, 0x20, 0x49, 0x61, 0x6E, 0x2E, 0x27, 0x54, 0x69, 0x6C, 0x6C, 0x0A, 0x74, 0x68, 0x65, + 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x2E, 0x2E, 0x2E, 0x0B, 0xFF, 0xEB, + 0xEC, 0x47, 0x6F, 0x6F, 0x64, 0x20, 0x6C, 0x75, 0x63, 0x6B, 0x2E, 0x49, 0x27, 0x6C, 0x6C, 0x0A, + 0x62, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x6F, 0x75, 0x63, 0x68, 0x20, 0x77, 0x68, 0x65, 0x6E, + 0x0A, 0x79, 0x6F, 0x75, 0x20, 0x67, 0x65, 0x74, 0x20, 0x74, 0x6F, 0x0A, 0x45, 0x61, 0x72, 0x74, + 0x68, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x57, 0x65, 0x6C, 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x74, 0x6F, + 0x0A, 0x4E, 0x65, 0x77, 0x20, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6E, 0x67, 0x74, 0x6F, 0x6E, 0x2C, + 0x0A, 0x79, 0x6F, 0x75, 0x6E, 0x67, 0x20, 0x6D, 0x61, 0x6E, 0x2E, 0x0B, 0x48, 0x65, 0x72, 0x65, + 0x27, 0x73, 0x20, 0x61, 0x20, 0x6D, 0x61, 0x70, 0x20, 0x6F, 0x66, 0x0A, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x69, 0x74, 0x79, 0x2C, 0x77, 0x68, 0x69, 0x63, 0x68, 0x0A, 0x79, 0x6F, 0x75, 0x20, 0x6D, + 0x61, 0x79, 0x20, 0x66, 0x69, 0x6E, 0x64, 0x0A, 0x75, 0x73, 0x65, 0x66, 0x75, 0x6C, 0x2E, 0x0B, + 0xFF, 0xE9, 0xEA, 0x54, 0x68, 0x61, 0x6E, 0x6B, 0x20, 0x79, 0x6F, 0x75, 0x2E, 0x00, 0xFF, 0xEB, + 0xEC, 0x48, 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x6E, 0x69, 0x63, 0x65, 0x0A, 0x64, 0x61, 0x79, + 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x59, 0x6F, 0x75, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x68, 0x61, + 0x76, 0x65, 0x20, 0x61, 0x0A, 0x70, 0x65, 0x72, 0x6D, 0x69, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x6F, + 0x72, 0x64, 0x65, 0x72, 0x0A, 0x74, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x2E, 0x0B, 0x59, 0x6F, + 0x75, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x67, 0x65, 0x74, 0x20, 0x6F, 0x6E, 0x65, 0x0A, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x41, 0x64, 0x6D, 0x69, 0x6E, 0x0A, 0x43, 0x65, 0x6E, 0x74, 0x65, + 0x72, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x68, 0x61, + 0x76, 0x65, 0x0A, 0x74, 0x69, 0x6D, 0x65, 0x2E, 0x00, 0x47, 0x6F, 0x6F, 0x64, 0x20, 0x6D, 0x6F, + 0x72, 0x6E, 0x69, 0x6E, 0x67, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x47, 0x6F, 0x6F, 0x64, 0x20, 0x6D, + 0x6F, 0x72, 0x6E, 0x69, 0x6E, 0x67, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x49, 0x27, 0x76, 0x65, 0x20, + 0x73, 0x65, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x61, 0x74, 0x0A, 0x67, 0x75, 0x79, 0x20, 0x62, 0x65, + 0x66, 0x6F, 0x72, 0x65, 0x20, 0x69, 0x6E, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x62, 0x61, 0x72, 0x2E, + 0x00, 0x47, 0x6F, 0x6F, 0x64, 0x20, 0x6D, 0x6F, 0x72, 0x6E, 0x69, 0x6E, 0x67, 0x2E, 0x0B, 0xFF, + 0xEB, 0xEC, 0x47, 0x6F, 0x6F, 0x64, 0x20, 0x6D, 0x6F, 0x72, 0x6E, 0x69, 0x6E, 0x67, 0x2E, 0x00, + 0xFF, 0xEB, 0xEC, 0x59, 0x65, 0x73, 0x2C, 0x49, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x68, 0x69, + 0x6D, 0x2E, 0x0A, 0x48, 0x65, 0x27, 0x73, 0x20, 0x61, 0x20, 0x72, 0x65, 0x67, 0x75, 0x6C, 0x61, + 0x72, 0x2E, 0x00, 0x20, 0x00, 0x20, 0x00, 0x49, 0x27, 0x64, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, + 0x61, 0x0A, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x70, 0x65, 0x72, 0x6D, 0x69, 0x74, 0x2E, 0x0B, 0xFF, + 0xEB, 0xEC, 0x54, 0x68, 0x65, 0x72, 0x65, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x0A, 0x70, 0x72, 0x6F, + 0x62, 0x6C, 0x65, 0x6D, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x0A, 0x61, 0x20, 0x70, + 0x65, 0x72, 0x6D, 0x69, 0x74, 0x2E, 0x2E, 0x2E, 0x0B, 0x49, 0x20, 0x6E, 0x65, 0x65, 0x64, 0x20, + 0x79, 0x6F, 0x75, 0x72, 0x20, 0x49, 0x44, 0x0A, 0x63, 0x61, 0x72, 0x64, 0x2E, 0x00, 0xFF, 0xEB, + 0xEC, 0x48, 0x45, 0x4C, 0x50, 0x2E, 0x2E, 0x2E, 0x48, 0x45, 0x4C, 0x50, 0x2E, 0x2E, 0x2E, 0x00, + 0xFF, 0xEB, 0xEC, 0x48, 0x65, 0x6C, 0x70, 0x20, 0x6D, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x6E, 0x67, + 0x0A, 0x6D, 0x61, 0x6E, 0x2E, 0x20, 0x49, 0x27, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x0A, + 0x61, 0x74, 0x74, 0x61, 0x63, 0x6B, 0x65, 0x64, 0x20, 0x62, 0x79, 0x0A, 0x6D, 0x75, 0x74, 0x61, + 0x6E, 0x74, 0x73, 0x2E, 0x2E, 0x2E, 0x0B, 0x61, 0x6E, 0x64, 0x20, 0x49, 0x20, 0x63, 0x61, 0x6E, + 0x27, 0x74, 0x0A, 0x77, 0x61, 0x6C, 0x6B, 0x2E, 0x0B, 0x46, 0x69, 0x6E, 0x64, 0x20, 0x6D, 0x79, + 0x0A, 0x74, 0x65, 0x6C, 0x65, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x72, 0x2C, 0x49, 0x0A, 0x6E, 0x65, + 0x65, 0x64, 0x20, 0x75, 0x72, 0x67, 0x65, 0x6E, 0x74, 0x20, 0x6D, 0x65, 0x64, 0x2D, 0x0A, 0x69, + 0x63, 0x61, 0x6C, 0x20, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x2E, 0x00, + 0xFF, 0xEB, 0xEC, 0x54, 0x68, 0x61, 0x6E, 0x6B, 0x73, 0x2E, 0x59, 0x6F, 0x75, 0x20, 0x6A, 0x75, + 0x73, 0x74, 0x0A, 0x73, 0x61, 0x76, 0x65, 0x64, 0x20, 0x6D, 0x79, 0x20, 0x6C, 0x69, 0x66, 0x65, + 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x54, 0x6F, 0x20, 0x67, 0x65, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x4E, + 0x65, 0x77, 0x0A, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6E, 0x67, 0x74, 0x6F, 0x6E, 0x2C, 0x79, 0x6F, + 0x75, 0x0A, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x6A, 0x75, 0x6D, 0x70, 0x0A, 0x69, + 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x68, 0x6F, 0x6C, 0x65, 0x2C, 0x0B, 0x62, + 0x75, 0x74, 0x20, 0x69, 0x66, 0x20, 0x49, 0x20, 0x77, 0x65, 0x72, 0x65, 0x0A, 0x79, 0x6F, 0x75, + 0x20, 0x49, 0x27, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x61, 0x6E, 0x0A, 0x41, 0x6E, 0x74, 0x69, + 0x2D, 0x47, 0x20, 0x62, 0x65, 0x6C, 0x74, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x57, 0x68, 0x65, 0x72, + 0x65, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x49, 0x20, 0x66, 0x69, 0x6E, 0x64, 0x0A, 0x6F, 0x6E, 0x65, + 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x4E, 0x6F, 0x77, 0x2C, 0x20, 0x49, 0x20, 0x63, 0x61, 0x6E, 0x0A, + 0x73, 0x65, 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6F, 0x6E, 0x65, 0x3A, 0x0A, 0x35, 0x30, + 0x30, 0x20, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x42, 0x6F, + 0x6E, 0x20, 0x76, 0x6F, 0x79, 0x61, 0x67, 0x65, 0x2C, 0x79, 0x6F, 0x75, 0x6E, 0x67, 0x0A, 0x6D, + 0x61, 0x6E, 0x2E, 0x00, 0x49, 0x20, 0x6E, 0x65, 0x65, 0x64, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6C, + 0x6C, 0x79, 0x0A, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x64, 0x20, 0x6D, 0x61, 0x67, 0x6E, 0x65, + 0x74, 0x69, 0x63, 0x0A, 0x63, 0x61, 0x72, 0x74, 0x72, 0x69, 0x64, 0x67, 0x65, 0x2E, 0x00, 0x49, + 0x27, 0x64, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x61, 0x0A, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x70, + 0x65, 0x72, 0x6D, 0x69, 0x74, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x46, 0x69, 0x72, 0x73, 0x74, 0x20, + 0x66, 0x6C, 0x6F, 0x6F, 0x72, 0x2E, 0x00, 0x41, 0x6E, 0x20, 0x69, 0x6E, 0x6E, 0x65, 0x72, 0x20, + 0x76, 0x6F, 0x69, 0x63, 0x65, 0x0A, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x73, + 0x20, 0x79, 0x6F, 0x75, 0x72, 0x0A, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x73, 0x2E, 0x0B, + 0xFF, 0xEB, 0xEC, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x6D, 0x65, 0x2C, 0x73, 0x6F, 0x6E, 0x2C, + 0x70, 0x75, 0x74, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x0A, 0x63, + 0x68, 0x61, 0x72, 0x67, 0x65, 0x20, 0x68, 0x65, 0x72, 0x65, 0x2E, 0x2E, 0x2E, 0x0B, 0x61, 0x6E, + 0x64, 0x20, 0x66, 0x6C, 0x65, 0x65, 0x20, 0x61, 0x73, 0x0A, 0x73, 0x6F, 0x6F, 0x6E, 0x20, 0x61, + 0x73, 0x20, 0x69, 0x74, 0x0A, 0x72, 0x65, 0x61, 0x63, 0x68, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x0A, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x74, 0x27, 0x73, 0x20, 0x63, 0x6F, 0x72, 0x65, 0x2E, 0x00, + 0xFF, 0xEB, 0xEC, 0x4C, 0x65, 0x61, 0x64, 0x20, 0x6F, 0x6E, 0x2C, 0x79, 0x6F, 0x75, 0x6E, 0x67, + 0x0A, 0x6D, 0x61, 0x6E, 0x2E, 0x0B, 0x54, 0x61, 0x6B, 0x65, 0x20, 0x6D, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x0A, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x43, 0x65, + 0x6E, 0x74, 0x65, 0x72, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x54, 0x68, 0x61, 0x6E, 0x6B, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x66, 0x6F, 0x72, 0x0A, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x68, 0x65, 0x6C, 0x70, + 0x2E, 0x2E, 0x2E, 0x0B, 0x49, 0x20, 0x61, 0x72, 0x72, 0x69, 0x76, 0x65, 0x64, 0x20, 0x73, 0x61, + 0x66, 0x65, 0x6C, 0x79, 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x27, 0x73, + 0x20, 0x6E, 0x6F, 0x0A, 0x6C, 0x6F, 0x6E, 0x67, 0x65, 0x72, 0x20, 0x61, 0x6E, 0x79, 0x0A, 0x64, + 0x61, 0x6E, 0x67, 0x65, 0x72, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x57, 0x65, 0x6C, 0x6C, 0x20, 0x74, + 0x68, 0x65, 0x6E, 0x2C, 0x68, 0x61, 0x76, 0x65, 0x0A, 0x79, 0x6F, 0x75, 0x20, 0x62, 0x72, 0x6F, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x6D, 0x65, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x72, 0x63, + 0x65, 0x6C, 0x3F, 0x00, 0x48, 0x6F, 0x77, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x0A, 0x74, 0x69, 0x63, 0x6B, 0x65, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x45, 0x61, 0x72, 0x74, + 0x68, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x35, 0x30, 0x2C, 0x30, 0x30, 0x30, 0x20, 0x63, 0x72, 0x65, + 0x64, 0x69, 0x74, 0x73, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x49, 0x20, 0x73, 0x63, 0x72, 0x61, 0x74, + 0x63, 0x68, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x0A, 0x62, 0x61, 0x63, 0x6B, 0x2C, 0x79, 0x6F, 0x75, + 0x20, 0x73, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x0A, 0x6D, 0x69, 0x6E, 0x65, 0x3A, 0x0B, 0x31, + 0x35, 0x30, 0x30, 0x20, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x0A, + 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x70, 0x65, 0x72, 0x73, 0x20, 0x61, 0x72, 0x65, 0x0A, 0x79, + 0x6F, 0x75, 0x72, 0x73, 0x2E, 0x00 +}; + +const uint8_t LocaleData::_stringsTableDE[] = { + 0x5A, 0x00, 0x7B, 0x00, 0x9B, 0x00, 0xB0, 0x01, 0x63, 0x02, 0x87, 0x02, 0xD3, 0x02, 0x04, 0x03, + 0x6D, 0x03, 0x86, 0x03, 0xBF, 0x03, 0x0E, 0x04, 0x5E, 0x04, 0xAD, 0x04, 0x30, 0x05, 0x60, 0x05, + 0x73, 0x05, 0xDD, 0x05, 0xEE, 0x05, 0x09, 0x06, 0xC0, 0x06, 0xBB, 0x08, 0x24, 0x09, 0x39, 0x09, + 0x87, 0x09, 0x9F, 0x09, 0xBE, 0x09, 0xEF, 0x09, 0x0E, 0x0A, 0x30, 0x0A, 0x32, 0x0A, 0x34, 0x0A, + 0x9D, 0x0A, 0xB2, 0x0A, 0x42, 0x0B, 0x66, 0x0B, 0x1F, 0x0C, 0x3B, 0x0C, 0x6C, 0x0C, 0x9D, 0x0C, + 0x39, 0x0D, 0x74, 0x0D, 0xC5, 0x0D, 0xED, 0x0D, 0x20, 0x0E, 0x44, 0x49, 0x45, 0x20, 0x53, 0x49, + 0x43, 0x48, 0x45, 0x52, 0x55, 0x4E, 0x47, 0x0A, 0x49, 0x53, 0x54, 0x0A, 0x44, 0x55, 0x52, 0x43, + 0x48, 0x47, 0x45, 0x42, 0x52, 0x41, 0x4E, 0x4E, 0x54, 0x2E, 0x00, 0x44, 0x41, 0x53, 0x20, 0x4D, + 0x5B, 0x53, 0x53, 0x54, 0x45, 0x20, 0x4A, 0x45, 0x54, 0x5A, 0x54, 0x0A, 0x46, 0x55, 0x4E, 0x4B, + 0x54, 0x49, 0x4F, 0x4E, 0x49, 0x45, 0x52, 0x45, 0x4E, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x49, 0x43, + 0x48, 0x20, 0x42, 0x49, 0x4E, 0x20, 0x4A, 0x41, 0x43, 0x4B, 0x2E, 0x0A, 0x53, 0x49, 0x45, 0x20, + 0x57, 0x4F, 0x4C, 0x4C, 0x45, 0x4E, 0x0A, 0x47, 0x45, 0x46, 0x5C, 0x4C, 0x53, 0x43, 0x48, 0x54, + 0x45, 0x0A, 0x50, 0x41, 0x50, 0x49, 0x45, 0x52, 0x45, 0x3F, 0x0B, 0xFF, 0xE9, 0xEA, 0x4A, 0x41, + 0x2C, 0x20, 0x55, 0x4E, 0x44, 0x20, 0x53, 0x4F, 0x0A, 0x53, 0x43, 0x48, 0x4E, 0x45, 0x4C, 0x4C, + 0x20, 0x57, 0x49, 0x45, 0x0A, 0x4D, 0x5D, 0x47, 0x4C, 0x49, 0x43, 0x48, 0x2E, 0x0B, 0xFF, 0xEB, + 0xEC, 0x31, 0x35, 0x30, 0x30, 0x20, 0x43, 0x52, 0x45, 0x44, 0x49, 0x54, 0x53, 0x21, 0x0B, 0xFF, + 0xE9, 0xEA, 0x31, 0x35, 0x30, 0x30, 0x3F, 0x3F, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x4A, 0x41, 0x2C, + 0x20, 0x45, 0x53, 0x20, 0x49, 0x53, 0x54, 0x20, 0x45, 0x49, 0x4E, 0x0A, 0x47, 0x52, 0x4F, 0x53, + 0x53, 0x45, 0x53, 0x20, 0x52, 0x49, 0x53, 0x49, 0x4B, 0x4F, 0x0B, 0xFF, 0xE9, 0xEA, 0x41, 0x42, + 0x45, 0x52, 0x20, 0x49, 0x43, 0x48, 0x20, 0x48, 0x41, 0x42, 0x45, 0x0A, 0x4E, 0x49, 0x43, 0x48, + 0x54, 0x20, 0x47, 0x45, 0x4E, 0x55, 0x47, 0x2E, 0x2E, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x47, 0x45, + 0x48, 0x45, 0x4E, 0x20, 0x53, 0x49, 0x45, 0x20, 0x5A, 0x55, 0x4D, 0x0A, 0x41, 0x52, 0x42, 0x45, + 0x49, 0x54, 0x53, 0x41, 0x4D, 0x54, 0x2C, 0x20, 0x44, 0x4F, 0x52, 0x54, 0x0A, 0x46, 0x49, 0x4E, + 0x44, 0x45, 0x4E, 0x20, 0x53, 0x49, 0x45, 0x0A, 0x41, 0x52, 0x42, 0x45, 0x49, 0x54, 0x2E, 0x0B, + 0x55, 0x4E, 0x44, 0x20, 0x4B, 0x4F, 0x4D, 0x4D, 0x45, 0x4E, 0x20, 0x53, 0x49, 0x45, 0x0A, 0x5A, + 0x55, 0x52, 0x5B, 0x43, 0x4B, 0x2C, 0x20, 0x57, 0x45, 0x4E, 0x4E, 0x20, 0x53, 0x49, 0x45, 0x0A, + 0x44, 0x41, 0x53, 0x20, 0x47, 0x45, 0x4C, 0x44, 0x20, 0x48, 0x41, 0x42, 0x45, 0x4E, 0x2E, 0x00, + 0xFF, 0xEB, 0xEC, 0x49, 0x43, 0x48, 0x20, 0x4B, 0x45, 0x4E, 0x4E, 0x45, 0x0A, 0x43, 0x59, 0x2D, + 0x42, 0x30, 0x32, 0x31, 0x2E, 0x0A, 0x53, 0x45, 0x49, 0x4E, 0x20, 0x46, 0x52, 0x45, 0x55, 0x4E, + 0x44, 0x20, 0x49, 0x53, 0x54, 0x0A, 0x42, 0x45, 0x49, 0x20, 0x44, 0x45, 0x52, 0x20, 0x50, 0x4F, + 0x4C, 0x49, 0x5A, 0x45, 0x49, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x57, 0x4F, 0x20, 0x4B, 0x41, 0x4E, + 0x4E, 0x20, 0x49, 0x43, 0x48, 0x0A, 0x44, 0x45, 0x4E, 0x20, 0x46, 0x49, 0x4E, 0x44, 0x45, 0x4E, + 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x49, 0x4E, 0x20, 0x44, 0x45, 0x52, 0x20, 0x56, 0x45, 0x52, 0x42, + 0x4F, 0x2D, 0x0A, 0x54, 0x45, 0x4E, 0x45, 0x4E, 0x20, 0x5A, 0x4F, 0x4E, 0x45, 0x2E, 0x20, 0x45, + 0x52, 0x0A, 0x49, 0x53, 0x54, 0x20, 0x44, 0x4F, 0x52, 0x54, 0x0A, 0x41, 0x4E, 0x47, 0x45, 0x53, + 0x54, 0x45, 0x4C, 0x4C, 0x54, 0x2E, 0x0B, 0x41, 0x42, 0x45, 0x52, 0x2C, 0x20, 0x50, 0x41, 0x53, + 0x53, 0x20, 0x41, 0x55, 0x46, 0x21, 0x0A, 0x44, 0x49, 0x45, 0x53, 0x45, 0x20, 0x4C, 0x45, 0x55, + 0x54, 0x45, 0x20, 0x53, 0x49, 0x4E, 0x44, 0x0A, 0x47, 0x45, 0x46, 0x5C, 0x48, 0x52, 0x4C, 0x49, + 0x43, 0x48, 0x00, 0xFF, 0xEB, 0xEC, 0x4D, 0x45, 0x48, 0x52, 0x20, 0x57, 0x45, 0x49, 0x53, 0x53, + 0x20, 0x49, 0x43, 0x48, 0x0A, 0x4E, 0x49, 0x43, 0x48, 0x54, 0x2C, 0x20, 0x4D, 0x45, 0x49, 0x4E, + 0x0A, 0x53, 0x4F, 0x48, 0x4E, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x43, 0x59, 0x2D, 0x42, 0x4F, 0x32, + 0x31, 0x20, 0x4D, 0x5D, 0x43, 0x48, 0x54, 0x45, 0x0A, 0x45, 0x49, 0x4E, 0x20, 0x47, 0x45, 0x53, + 0x43, 0x48, 0x5C, 0x46, 0x54, 0x0A, 0x4D, 0x49, 0x54, 0x20, 0x44, 0x49, 0x52, 0x20, 0x4D, 0x41, + 0x43, 0x48, 0x45, 0x4E, 0x2E, 0x0B, 0x45, 0x52, 0x20, 0x57, 0x41, 0x52, 0x54, 0x45, 0x54, 0x20, + 0x48, 0x49, 0x4E, 0x54, 0x45, 0x52, 0x0A, 0x44, 0x45, 0x52, 0x20, 0x4B, 0x4E, 0x45, 0x49, 0x50, + 0x45, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x47, 0x45, 0x48, 0x20, 0x5A, 0x55, 0x52, 0x20, 0x4B, 0x4E, + 0x45, 0x49, 0x50, 0x45, 0x2C, 0x0A, 0x43, 0x59, 0x2D, 0x42, 0x4F, 0x32, 0x31, 0x20, 0x57, 0x41, + 0x52, 0x54, 0x45, 0x54, 0x0A, 0x44, 0x4F, 0x52, 0x54, 0x20, 0x41, 0x55, 0x46, 0x20, 0x44, 0x49, + 0x43, 0x48, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x4E, 0x49, 0x43, 0x48, 0x54, 0x20, 0x53, 0x43, 0x48, + 0x49, 0x45, 0x53, 0x53, 0x45, 0x4E, 0x2C, 0x0A, 0x49, 0x43, 0x48, 0x20, 0x42, 0x49, 0x4E, 0x20, + 0x4E, 0x49, 0x43, 0x48, 0x54, 0x0A, 0x43, 0x59, 0x2D, 0x42, 0x4F, 0x32, 0x31, 0x21, 0x0B, 0x53, + 0x45, 0x49, 0x4E, 0x20, 0x56, 0x45, 0x52, 0x53, 0x54, 0x45, 0x43, 0x4B, 0x0A, 0x49, 0x53, 0x54, + 0x20, 0x47, 0x41, 0x4E, 0x5A, 0x20, 0x55, 0x4E, 0x54, 0x45, 0x4E, 0x2E, 0x0B, 0x44, 0x45, 0x52, + 0x20, 0x50, 0x4F, 0x4C, 0x49, 0x5A, 0x49, 0x53, 0x54, 0x20, 0x48, 0x41, 0x54, 0x0A, 0x44, 0x45, + 0x4E, 0x20, 0x53, 0x43, 0x48, 0x4C, 0x5B, 0x53, 0x53, 0x45, 0x4C, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, + 0x4D, 0x45, 0x48, 0x52, 0x20, 0x57, 0x45, 0x49, 0x53, 0x53, 0x0A, 0x49, 0x43, 0x48, 0x20, 0x4E, + 0x49, 0x43, 0x48, 0x54, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x53, 0x49, 0x52, 0x2E, 0x2E, 0x2E, 0x20, + 0x4A, 0x41, 0x43, 0x4B, 0x20, 0x48, 0x41, 0x54, 0x0A, 0x45, 0x49, 0x4E, 0x20, 0x54, 0x52, 0x45, + 0x46, 0x46, 0x45, 0x4E, 0x0A, 0x42, 0x45, 0x49, 0x20, 0x44, 0x45, 0x52, 0x20, 0x4B, 0x4E, 0x45, + 0x49, 0x50, 0x45, 0x0A, 0x41, 0x52, 0x52, 0x41, 0x4E, 0x47, 0x49, 0x45, 0x52, 0x54, 0x00, 0x49, + 0x43, 0x48, 0x20, 0x4D, 0x5D, 0x43, 0x48, 0x54, 0x45, 0x20, 0x45, 0x49, 0x4E, 0x45, 0x0A, 0x41, + 0x52, 0x42, 0x45, 0x49, 0x54, 0x53, 0x45, 0x52, 0x4C, 0x41, 0x55, 0x42, 0x4E, 0x49, 0x53, 0x0B, + 0xFF, 0xEB, 0xEC, 0x4E, 0x45, 0x49, 0x4E, 0x2C, 0x20, 0x4E, 0x49, 0x43, 0x48, 0x54, 0x0A, 0x48, + 0x49, 0x45, 0x52, 0x2E, 0x20, 0x47, 0x45, 0x48, 0x45, 0x4E, 0x20, 0x53, 0x49, 0x45, 0x0A, 0x5A, + 0x55, 0x20, 0x53, 0x43, 0x48, 0x41, 0x4C, 0x54, 0x45, 0x52, 0x20, 0x43, 0x2E, 0x00, 0x49, 0x43, + 0x48, 0x20, 0x4D, 0x5D, 0x43, 0x48, 0x54, 0x45, 0x20, 0x45, 0x49, 0x4E, 0x45, 0x0A, 0x41, 0x52, + 0x42, 0x45, 0x49, 0x54, 0x53, 0x45, 0x52, 0x4C, 0x41, 0x55, 0x42, 0x4E, 0x49, 0x53, 0x0B, 0xFF, + 0xEB, 0xEC, 0x47, 0x55, 0x54, 0x2E, 0x2E, 0x2E, 0x20, 0x4F, 0x2E, 0x4B, 0x2E, 0x2C, 0x20, 0x44, + 0x45, 0x52, 0x0A, 0x43, 0x48, 0x45, 0x46, 0x20, 0x57, 0x49, 0x4C, 0x4C, 0x20, 0x53, 0x49, 0x45, + 0x0A, 0x4A, 0x45, 0x54, 0x5A, 0x54, 0x20, 0x53, 0x45, 0x48, 0x45, 0x4E, 0x2E, 0x00, 0x49, 0x43, + 0x48, 0x20, 0x4D, 0x5D, 0x43, 0x48, 0x54, 0x45, 0x20, 0x45, 0x49, 0x4E, 0x45, 0x0A, 0x41, 0x52, + 0x42, 0x45, 0x49, 0x54, 0x53, 0x45, 0x52, 0x4C, 0x41, 0x55, 0x42, 0x4E, 0x49, 0x53, 0x0B, 0xFF, + 0xEB, 0xEC, 0x4E, 0x45, 0x49, 0x4E, 0x2C, 0x20, 0x4E, 0x49, 0x43, 0x48, 0x54, 0x0A, 0x48, 0x49, + 0x45, 0x52, 0x2E, 0x20, 0x47, 0x45, 0x48, 0x45, 0x4E, 0x20, 0x53, 0x49, 0x45, 0x0A, 0x5A, 0x55, + 0x20, 0x53, 0x43, 0x48, 0x41, 0x4C, 0x54, 0x45, 0x52, 0x20, 0x42, 0x2E, 0x00, 0x49, 0x43, 0x48, + 0x20, 0x4D, 0x5D, 0x43, 0x48, 0x54, 0x45, 0x0A, 0x4A, 0x41, 0x43, 0x4B, 0x20, 0x53, 0x50, 0x52, + 0x45, 0x43, 0x48, 0x45, 0x4E, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x41, 0x43, 0x48, 0x20, 0x4A, 0x41, + 0x3F, 0x20, 0x4A, 0x41, 0x43, 0x4B, 0x0A, 0x49, 0x53, 0x54, 0x20, 0x4E, 0x49, 0x43, 0x48, 0x54, + 0x20, 0x44, 0x41, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x49, 0x43, 0x48, 0x20, 0x4B, 0x4F, 0x4D, 0x4D, + 0x45, 0x20, 0x56, 0x4F, 0x4E, 0x0A, 0x4D, 0x45, 0x49, 0x4E, 0x45, 0x4D, 0x20, 0x46, 0x52, 0x45, + 0x55, 0x4E, 0x44, 0x0A, 0x49, 0x41, 0x4E, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x4F, 0x2E, 0x4B, 0x2E, + 0x20, 0x4A, 0x41, 0x43, 0x4B, 0x20, 0x57, 0x41, 0x52, 0x54, 0x45, 0x54, 0x0A, 0x44, 0x52, 0x41, + 0x55, 0x53, 0x53, 0x45, 0x4E, 0x20, 0x41, 0x55, 0x46, 0x0A, 0x44, 0x49, 0x43, 0x48, 0x2E, 0x00, + 0xFF, 0xEB, 0xEC, 0x4E, 0x45, 0x45, 0x2C, 0x20, 0x4D, 0x45, 0x49, 0x4E, 0x20, 0x53, 0x4F, 0x48, + 0x4E, 0x2E, 0x0A, 0x44, 0x55, 0x20, 0x42, 0x49, 0x53, 0x54, 0x20, 0x5A, 0x55, 0x20, 0x4A, 0x55, + 0x4E, 0x47, 0x0A, 0x5A, 0x55, 0x4D, 0x20, 0x54, 0x52, 0x49, 0x4E, 0x4B, 0x45, 0x4E, 0x2E, 0x00, + 0xFF, 0xEB, 0xEC, 0x50, 0x41, 0x50, 0x49, 0x45, 0x52, 0x45, 0x2C, 0x20, 0x42, 0x49, 0x54, 0x54, + 0x45, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x49, 0x43, 0x48, 0x20, 0x42, 0x49, 0x4E, 0x20, 0x44, 0x45, + 0x52, 0x0A, 0x42, 0x4F, 0x54, 0x45, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x4F, 0x48, 0x20, 0x4A, 0x41, + 0x21, 0x0A, 0x44, 0x49, 0x45, 0x53, 0x45, 0x53, 0x20, 0x50, 0x41, 0x4B, 0x45, 0x54, 0x0A, 0x4D, + 0x55, 0x53, 0x53, 0x20, 0x5A, 0x55, 0x4D, 0x0A, 0x52, 0x45, 0x49, 0x53, 0x45, 0x42, 0x5B, 0x52, + 0x4F, 0x0B, 0x53, 0x45, 0x49, 0x45, 0x4E, 0x20, 0x53, 0x49, 0x45, 0x0A, 0x56, 0x4F, 0x52, 0x53, + 0x49, 0x43, 0x48, 0x54, 0x49, 0x47, 0x2C, 0x0A, 0x45, 0x53, 0x20, 0x49, 0x53, 0x54, 0x20, 0x53, + 0x45, 0x48, 0x52, 0x0A, 0x57, 0x45, 0x52, 0x54, 0x56, 0x4F, 0x4C, 0x4C, 0x00, 0x5A, 0x45, 0x49, + 0x54, 0x20, 0x41, 0x42, 0x47, 0x45, 0x4C, 0x41, 0x55, 0x46, 0x45, 0x4E, 0x2E, 0x00, 0x44, 0x49, + 0x45, 0x20, 0x4B, 0x41, 0x52, 0x54, 0x45, 0x20, 0x48, 0x41, 0x54, 0x0A, 0x45, 0x49, 0x4E, 0x45, + 0x4E, 0x20, 0x50, 0x4C, 0x41, 0x54, 0x5A, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x44, 0x41, 0x4E, 0x4B, + 0x45, 0x2C, 0x20, 0x43, 0x4F, 0x4E, 0x52, 0x41, 0x44, 0x2E, 0x0A, 0x44, 0x49, 0x45, 0x20, 0x50, + 0x4F, 0x4C, 0x49, 0x5A, 0x49, 0x53, 0x54, 0x45, 0x4E, 0x0A, 0x48, 0x5C, 0x54, 0x54, 0x45, 0x4E, + 0x20, 0x4D, 0x45, 0x49, 0x4E, 0x20, 0x56, 0x45, 0x52, 0x2D, 0x0A, 0x53, 0x54, 0x45, 0x43, 0x4B, + 0x20, 0x47, 0x45, 0x46, 0x55, 0x4E, 0x44, 0x45, 0x4E, 0x2E, 0x0B, 0x44, 0x55, 0x20, 0x45, 0x52, + 0x49, 0x4E, 0x4E, 0x45, 0x52, 0x53, 0x54, 0x0A, 0x44, 0x49, 0x43, 0x48, 0x20, 0x57, 0x4F, 0x48, + 0x4C, 0x20, 0x4E, 0x49, 0x43, 0x48, 0x54, 0x0A, 0x41, 0x4E, 0x20, 0x44, 0x45, 0x49, 0x4E, 0x45, + 0x4E, 0x20, 0x41, 0x4C, 0x54, 0x45, 0x4E, 0x0A, 0x4B, 0x55, 0x4D, 0x50, 0x45, 0x4C, 0x20, 0x49, + 0x41, 0x4E, 0x2E, 0x0B, 0x53, 0x45, 0x54, 0x5A, 0x20, 0x44, 0x49, 0x43, 0x48, 0x2C, 0x20, 0x57, + 0x49, 0x52, 0x0A, 0x42, 0x52, 0x49, 0x4E, 0x47, 0x45, 0x4E, 0x20, 0x44, 0x45, 0x49, 0x4E, 0x20, + 0x47, 0x45, 0x2D, 0x0A, 0x44, 0x5C, 0x43, 0x48, 0x54, 0x4E, 0x49, 0x53, 0x20, 0x57, 0x49, 0x45, + 0x44, 0x45, 0x52, 0x0A, 0x49, 0x4E, 0x20, 0x4F, 0x52, 0x44, 0x4E, 0x55, 0x4E, 0x47, 0x2E, 0x00, + 0x49, 0x41, 0x4E, 0x2C, 0x20, 0x57, 0x41, 0x53, 0x20, 0x4D, 0x55, 0x53, 0x53, 0x0A, 0x49, 0x43, + 0x48, 0x20, 0x4D, 0x41, 0x43, 0x48, 0x45, 0x4E, 0x2C, 0x20, 0x55, 0x4D, 0x0A, 0x5A, 0x55, 0x52, + 0x20, 0x45, 0x52, 0x44, 0x45, 0x20, 0x5A, 0x55, 0x0A, 0x4B, 0x4F, 0x4D, 0x4D, 0x45, 0x4E, 0x3F, + 0x0B, 0x44, 0x45, 0x52, 0x20, 0x50, 0x52, 0x45, 0x49, 0x53, 0x20, 0x46, 0x5B, 0x52, 0x0A, 0x44, + 0x41, 0x53, 0x20, 0x54, 0x49, 0x43, 0x4B, 0x45, 0x54, 0x20, 0x49, 0x53, 0x54, 0x0A, 0x41, 0x53, + 0x54, 0x52, 0x4F, 0x4E, 0x4F, 0x4D, 0x49, 0x53, 0x43, 0x48, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x44, + 0x45, 0x52, 0x20, 0x45, 0x49, 0x4E, 0x5A, 0x49, 0x47, 0x45, 0x20, 0x57, 0x45, 0x47, 0x0A, 0x57, + 0x5C, 0x52, 0x45, 0x20, 0x44, 0x49, 0x45, 0x0A, 0x54, 0x45, 0x49, 0x4C, 0x4E, 0x41, 0x48, 0x4D, + 0x45, 0x0A, 0x41, 0x4D, 0x20, 0x54, 0x4F, 0x44, 0x45, 0x53, 0x54, 0x55, 0x52, 0x4D, 0x2E, 0x0B, + 0xFF, 0xE9, 0xEA, 0x54, 0x4F, 0x44, 0x45, 0x53, 0x54, 0x55, 0x52, 0x4D, 0x3F, 0x0B, 0xFF, 0xEB, + 0xEC, 0x44, 0x41, 0x53, 0x20, 0x49, 0x53, 0x54, 0x20, 0x45, 0x49, 0x4E, 0x45, 0x0A, 0x46, 0x45, + 0x52, 0x4E, 0x53, 0x45, 0x48, 0x53, 0x48, 0x4F, 0x57, 0x2E, 0x0A, 0x44, 0x45, 0x52, 0x20, 0x47, + 0x45, 0x57, 0x49, 0x4E, 0x4E, 0x45, 0x52, 0x20, 0x42, 0x45, 0x2D, 0x0A, 0x4B, 0x4F, 0x4D, 0x4D, + 0x54, 0x20, 0x45, 0x49, 0x4E, 0x20, 0x54, 0x49, 0x43, 0x4B, 0x45, 0x54, 0x0B, 0xFF, 0xE9, 0xEA, + 0x4B, 0x41, 0x4E, 0x4E, 0x53, 0x54, 0x20, 0x44, 0x55, 0x20, 0x4D, 0x49, 0x52, 0x0A, 0x46, 0x41, + 0x4C, 0x53, 0x43, 0x48, 0x45, 0x20, 0x50, 0x41, 0x50, 0x49, 0x45, 0x52, 0x45, 0x0A, 0x42, 0x45, + 0x53, 0x4F, 0x52, 0x47, 0x45, 0x4E, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x4B, 0x45, 0x49, 0x4E, 0x20, + 0x50, 0x52, 0x4F, 0x42, 0x4C, 0x45, 0x4D, 0x2E, 0x0A, 0x47, 0x45, 0x48, 0x20, 0x5A, 0x55, 0x52, + 0x20, 0x4B, 0x4E, 0x45, 0x49, 0x50, 0x45, 0x2C, 0x0A, 0x55, 0x4E, 0x44, 0x20, 0x46, 0x52, 0x41, + 0x47, 0x0A, 0x4E, 0x41, 0x43, 0x48, 0x20, 0x4A, 0x41, 0x43, 0x4B, 0x2E, 0x0B, 0x53, 0x41, 0x47, + 0x2C, 0x20, 0x44, 0x41, 0x53, 0x53, 0x20, 0x44, 0x55, 0x20, 0x56, 0x4F, 0x4E, 0x0A, 0x4D, 0x49, + 0x52, 0x20, 0x4B, 0x4F, 0x4D, 0x4D, 0x53, 0x54, 0x2E, 0x0A, 0x41, 0x43, 0x48, 0x2E, 0x2E, 0x2E, + 0x0B, 0x2E, 0x2E, 0x49, 0x43, 0x48, 0x20, 0x48, 0x41, 0x42, 0x45, 0x20, 0x5B, 0x42, 0x52, 0x49, + 0x2D, 0x0A, 0x47, 0x45, 0x4E, 0x53, 0x20, 0x45, 0x49, 0x4E, 0x20, 0x53, 0x43, 0x48, 0x55, 0x54, + 0x5A, 0x2D, 0x0A, 0x46, 0x45, 0x4C, 0x44, 0x2C, 0x20, 0x49, 0x4E, 0x20, 0x44, 0x45, 0x49, 0x4E, + 0x45, 0x0A, 0x54, 0x41, 0x53, 0x43, 0x48, 0x45, 0x20, 0x47, 0x45, 0x53, 0x54, 0x45, 0x43, 0x4B, + 0x54, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x47, 0x52, 0x4F, 0x53, 0x53, 0x41, 0x52, 0x54, 0x49, 0x47, + 0x2E, 0x0A, 0x44, 0x41, 0x4E, 0x4B, 0x45, 0x2C, 0x20, 0x49, 0x41, 0x4E, 0x2E, 0x20, 0x42, 0x49, + 0x53, 0x0A, 0x44, 0x45, 0x4D, 0x4E, 0x5C, 0x43, 0x48, 0x53, 0x54, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, + 0x49, 0x43, 0x48, 0x20, 0x4D, 0x45, 0x4C, 0x44, 0x45, 0x20, 0x4D, 0x49, 0x43, 0x48, 0x2C, 0x0A, + 0x57, 0x45, 0x4E, 0x4E, 0x20, 0x44, 0x55, 0x20, 0x41, 0x55, 0x46, 0x0A, 0x44, 0x45, 0x52, 0x20, + 0x45, 0x52, 0x44, 0x45, 0x20, 0x42, 0x49, 0x53, 0x54, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x57, 0x49, + 0x4C, 0x4C, 0x4B, 0x4F, 0x4D, 0x4D, 0x45, 0x4E, 0x20, 0x49, 0x4E, 0x0A, 0x4E, 0x45, 0x57, 0x20, + 0x57, 0x41, 0x53, 0x48, 0x49, 0x4E, 0x47, 0x54, 0x4F, 0x4E, 0x2C, 0x0A, 0x4A, 0x55, 0x4E, 0x47, + 0x45, 0x52, 0x20, 0x4D, 0x41, 0x4E, 0x4E, 0x2E, 0x0B, 0x48, 0x49, 0x45, 0x52, 0x20, 0x49, 0x53, + 0x54, 0x20, 0x45, 0x49, 0x4E, 0x0A, 0x53, 0x54, 0x41, 0x44, 0x54, 0x50, 0x4C, 0x41, 0x4E, 0x2C, + 0x0A, 0x53, 0x49, 0x45, 0x20, 0x57, 0x45, 0x52, 0x44, 0x45, 0x4E, 0x20, 0x49, 0x48, 0x4E, 0x0A, + 0x42, 0x52, 0x41, 0x55, 0x43, 0x48, 0x45, 0x4E, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x44, 0x41, 0x4E, + 0x4B, 0x45, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x53, 0x43, 0x48, 0x5D, 0x4E, 0x45, 0x4E, 0x20, 0x54, + 0x41, 0x47, 0x0A, 0x4E, 0x4F, 0x43, 0x48, 0x21, 0x00, 0xFF, 0xEB, 0xEC, 0x53, 0x49, 0x45, 0x20, + 0x42, 0x52, 0x41, 0x55, 0x43, 0x48, 0x45, 0x4E, 0x0A, 0x45, 0x49, 0x4E, 0x45, 0x20, 0x41, 0x52, + 0x42, 0x45, 0x49, 0x54, 0x53, 0x2D, 0x0A, 0x45, 0x52, 0x4C, 0x41, 0x55, 0x42, 0x4E, 0x49, 0x53, + 0x2E, 0x0B, 0x53, 0x49, 0x45, 0x20, 0x42, 0x45, 0x4B, 0x4F, 0x4D, 0x4D, 0x45, 0x4E, 0x0A, 0x45, + 0x49, 0x4E, 0x45, 0x20, 0x49, 0x4E, 0x20, 0x44, 0x45, 0x52, 0x0A, 0x56, 0x45, 0x52, 0x57, 0x41, + 0x4C, 0x54, 0x55, 0x4E, 0x47, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x49, 0x43, 0x48, 0x20, 0x48, 0x41, + 0x42, 0x45, 0x20, 0x4B, 0x45, 0x49, 0x4E, 0x45, 0x0A, 0x5A, 0x45, 0x49, 0x54, 0x2E, 0x00, 0x47, + 0x55, 0x54, 0x45, 0x4E, 0x20, 0x4D, 0x4F, 0x52, 0x47, 0x45, 0x4E, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, + 0x47, 0x55, 0x54, 0x45, 0x4E, 0x20, 0x4D, 0x4F, 0x52, 0x47, 0x45, 0x4E, 0x2E, 0x00, 0xFF, 0xEB, + 0xEC, 0x49, 0x43, 0x48, 0x20, 0x53, 0x41, 0x48, 0x20, 0x44, 0x49, 0x45, 0x53, 0x45, 0x4E, 0x0A, + 0x54, 0x59, 0x50, 0x45, 0x4E, 0x20, 0x53, 0x43, 0x48, 0x4F, 0x4E, 0x20, 0x4D, 0x41, 0x4C, 0x0A, + 0x49, 0x4E, 0x20, 0x44, 0x45, 0x52, 0x20, 0x4B, 0x4E, 0x45, 0x49, 0x50, 0x45, 0x2E, 0x00, 0x47, + 0x55, 0x54, 0x45, 0x4E, 0x20, 0x4D, 0x4F, 0x52, 0x47, 0x45, 0x4E, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, + 0x47, 0x55, 0x54, 0x45, 0x4E, 0x20, 0x4D, 0x4F, 0x52, 0x47, 0x45, 0x4E, 0x2E, 0x00, 0xFF, 0xEB, + 0xEC, 0x49, 0x43, 0x48, 0x20, 0x4B, 0x45, 0x4E, 0x4E, 0x45, 0x20, 0x49, 0x48, 0x4E, 0x2E, 0x0A, + 0x49, 0x53, 0x54, 0x20, 0x53, 0x54, 0x41, 0x4D, 0x4D, 0x4B, 0x55, 0x4E, 0x44, 0x45, 0x2E, 0x00, + 0x20, 0x00, 0x20, 0x00, 0x49, 0x43, 0x48, 0x20, 0x4D, 0x5D, 0x43, 0x48, 0x54, 0x45, 0x20, 0x45, + 0x49, 0x4E, 0x45, 0x0A, 0x41, 0x52, 0x42, 0x45, 0x49, 0x54, 0x53, 0x45, 0x52, 0x4C, 0x41, 0x55, + 0x42, 0x4E, 0x49, 0x53, 0x0B, 0xFF, 0xEB, 0xEC, 0x4B, 0x45, 0x49, 0x4E, 0x20, 0x50, 0x52, 0x4F, + 0x42, 0x4C, 0x45, 0x4D, 0x2C, 0x0A, 0x45, 0x49, 0x4E, 0x45, 0x20, 0x45, 0x52, 0x4C, 0x41, 0x55, + 0x42, 0x4E, 0x49, 0x53, 0x0A, 0x5A, 0x55, 0x20, 0x42, 0x45, 0x4B, 0x4F, 0x4D, 0x4D, 0x45, 0x4E, + 0x2E, 0x2E, 0x2E, 0x0B, 0x49, 0x43, 0x48, 0x20, 0x42, 0x45, 0x4E, 0x5D, 0x54, 0x49, 0x47, 0x45, + 0x0A, 0x49, 0x48, 0x52, 0x45, 0x20, 0x4B, 0x41, 0x52, 0x54, 0x45, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, + 0x48, 0x49, 0x4C, 0x46, 0x45, 0x2E, 0x2E, 0x2E, 0x0A, 0x48, 0x49, 0x4C, 0x46, 0x45, 0x2E, 0x2E, + 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x48, 0x45, 0x4C, 0x46, 0x45, 0x4E, 0x20, 0x53, 0x49, 0x45, 0x20, + 0x4D, 0x49, 0x52, 0x2E, 0x0A, 0x49, 0x43, 0x48, 0x20, 0x57, 0x55, 0x52, 0x44, 0x45, 0x20, 0x56, + 0x4F, 0x4E, 0x0A, 0x4D, 0x55, 0x54, 0x41, 0x4E, 0x54, 0x45, 0x4E, 0x0A, 0x41, 0x4E, 0x47, 0x45, + 0x47, 0x52, 0x49, 0x46, 0x46, 0x45, 0x4E, 0x2E, 0x2E, 0x2E, 0x0B, 0x55, 0x4E, 0x44, 0x20, 0x49, + 0x43, 0x48, 0x20, 0x4B, 0x41, 0x4E, 0x4E, 0x0A, 0x4E, 0x49, 0x43, 0x48, 0x54, 0x20, 0x4C, 0x41, + 0x55, 0x46, 0x45, 0x4E, 0x2E, 0x0B, 0x48, 0x4F, 0x4C, 0x45, 0x4E, 0x20, 0x53, 0x49, 0x45, 0x20, + 0x4D, 0x45, 0x49, 0x4E, 0x45, 0x4E, 0x0A, 0x54, 0x45, 0x4C, 0x45, 0x50, 0x4F, 0x52, 0x54, 0x45, + 0x52, 0x2C, 0x20, 0x49, 0x43, 0x48, 0x0A, 0x42, 0x52, 0x41, 0x55, 0x43, 0x48, 0x45, 0x20, 0x5C, + 0x52, 0x5A, 0x54, 0x2D, 0x0A, 0x4C, 0x49, 0x43, 0x48, 0x45, 0x20, 0x48, 0x49, 0x4C, 0x46, 0x45, + 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x44, 0x41, 0x4E, 0x4B, 0x45, 0x2E, 0x20, 0x53, 0x49, 0x45, 0x20, + 0x52, 0x45, 0x54, 0x2D, 0x0A, 0x54, 0x45, 0x54, 0x45, 0x4E, 0x20, 0x4D, 0x45, 0x49, 0x4E, 0x20, + 0x4C, 0x45, 0x42, 0x45, 0x4E, 0x00, 0xFF, 0xEB, 0xEC, 0x53, 0x50, 0x52, 0x49, 0x4E, 0x47, 0x45, + 0x4E, 0x20, 0x53, 0x49, 0x45, 0x20, 0x49, 0x4E, 0x0A, 0x44, 0x49, 0x45, 0x53, 0x45, 0x53, 0x20, + 0x4C, 0x4F, 0x43, 0x48, 0x2C, 0x0B, 0x55, 0x4D, 0x20, 0x4E, 0x41, 0x43, 0x48, 0x20, 0x4E, 0x45, + 0x57, 0x0A, 0x57, 0x41, 0x53, 0x48, 0x49, 0x4E, 0x47, 0x54, 0x4F, 0x4E, 0x0A, 0x5A, 0x55, 0x20, + 0x4B, 0x4F, 0x4D, 0x4D, 0x45, 0x4E, 0x2E, 0x0B, 0x41, 0x42, 0x45, 0x52, 0x2C, 0x20, 0x49, 0x43, + 0x48, 0x20, 0x57, 0x5B, 0x52, 0x44, 0x45, 0x0A, 0x45, 0x49, 0x4E, 0x45, 0x4E, 0x20, 0x41, 0x4E, + 0x54, 0x49, 0x2D, 0x47, 0x2D, 0x0A, 0x47, 0x5B, 0x52, 0x54, 0x45, 0x4C, 0x20, 0x42, 0x45, 0x4E, + 0x55, 0x54, 0x5A, 0x45, 0x4E, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x57, 0x4F, 0x20, 0x4B, 0x41, 0x4E, + 0x4E, 0x20, 0x49, 0x43, 0x48, 0x0A, 0x45, 0x49, 0x4E, 0x45, 0x4E, 0x20, 0x42, 0x45, 0x4B, 0x4F, + 0x4D, 0x4D, 0x45, 0x4E, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x4E, 0x55, 0x4E, 0x2C, 0x20, 0x49, 0x43, + 0x48, 0x0A, 0x56, 0x45, 0x52, 0x4B, 0x41, 0x55, 0x46, 0x45, 0x20, 0x45, 0x49, 0x4E, 0x45, 0x4E, + 0x3A, 0x0A, 0x35, 0x30, 0x30, 0x20, 0x43, 0x52, 0x45, 0x44, 0x49, 0x54, 0x53, 0x2E, 0x00, 0xFF, + 0xEB, 0xEC, 0x47, 0x55, 0x54, 0x45, 0x20, 0x52, 0x45, 0x49, 0x53, 0x45, 0x2C, 0x0A, 0x4A, 0x55, + 0x4E, 0x47, 0x45, 0x52, 0x20, 0x4D, 0x41, 0x4E, 0x4E, 0x2E, 0x00, 0x49, 0x43, 0x48, 0x20, 0x42, + 0x52, 0x41, 0x55, 0x43, 0x48, 0x45, 0x20, 0x45, 0x49, 0x4E, 0x0A, 0x41, 0x55, 0x46, 0x47, 0x45, + 0x4C, 0x41, 0x44, 0x45, 0x4E, 0x45, 0x53, 0x20, 0x4D, 0x41, 0x2D, 0x0A, 0x47, 0x4E, 0x45, 0x54, + 0x2D, 0x43, 0x41, 0x52, 0x54, 0x52, 0x49, 0x44, 0x47, 0x45, 0x2E, 0x00, 0x49, 0x43, 0x48, 0x20, + 0x4D, 0x5D, 0x43, 0x48, 0x54, 0x45, 0x20, 0x45, 0x49, 0x4E, 0x45, 0x0A, 0x41, 0x52, 0x42, 0x45, + 0x49, 0x54, 0x53, 0x45, 0x52, 0x4C, 0x41, 0x55, 0x42, 0x4E, 0x49, 0x53, 0x0B, 0xFF, 0xEB, 0xEC, + 0x45, 0x52, 0x53, 0x54, 0x45, 0x20, 0x45, 0x54, 0x41, 0x47, 0x45, 0x2E, 0x00, 0x45, 0x49, 0x4E, + 0x45, 0x20, 0x49, 0x4E, 0x4E, 0x45, 0x52, 0x45, 0x0A, 0x53, 0x54, 0x49, 0x4D, 0x4D, 0x45, 0x0A, + 0x55, 0x4E, 0x54, 0x45, 0x52, 0x42, 0x52, 0x49, 0x43, 0x48, 0x54, 0x0A, 0x44, 0x45, 0x49, 0x4E, + 0x45, 0x20, 0x47, 0x45, 0x44, 0x41, 0x4E, 0x4B, 0x45, 0x4E, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x56, + 0x45, 0x52, 0x54, 0x52, 0x41, 0x55, 0x20, 0x4D, 0x49, 0x52, 0x2C, 0x0A, 0x42, 0x52, 0x49, 0x4E, + 0x47, 0x20, 0x44, 0x49, 0x45, 0x20, 0x41, 0x54, 0x4F, 0x4D, 0x2D, 0x0A, 0x4C, 0x41, 0x44, 0x55, + 0x4E, 0x47, 0x20, 0x48, 0x49, 0x45, 0x52, 0x20, 0x41, 0x4E, 0x2E, 0x2E, 0x0B, 0x55, 0x4E, 0x44, + 0x20, 0x46, 0x4C, 0x49, 0x45, 0x48, 0x45, 0x2C, 0x20, 0x42, 0x45, 0x2D, 0x0A, 0x56, 0x4F, 0x52, + 0x20, 0x53, 0x49, 0x45, 0x20, 0x44, 0x41, 0x53, 0x20, 0x48, 0x45, 0x52, 0x5A, 0x0A, 0x44, 0x45, + 0x53, 0x20, 0x50, 0x4C, 0x41, 0x4E, 0x45, 0x54, 0x45, 0x4E, 0x0A, 0x45, 0x52, 0x52, 0x45, 0x49, + 0x43, 0x48, 0x54, 0x20, 0x48, 0x41, 0x54, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x5A, 0x55, 0x4D, 0x20, + 0x46, 0x4F, 0x52, 0x53, 0x43, 0x48, 0x55, 0x4E, 0x47, 0x53, 0x2D, 0x0A, 0x5A, 0x45, 0x4E, 0x54, + 0x52, 0x55, 0x4D, 0x2C, 0x20, 0x42, 0x49, 0x54, 0x54, 0x45, 0x2E, 0x0B, 0x4E, 0x41, 0x43, 0x48, + 0x20, 0x49, 0x48, 0x4E, 0x45, 0x4E, 0x2C, 0x0A, 0x4A, 0x55, 0x4E, 0x47, 0x45, 0x52, 0x20, 0x4D, + 0x41, 0x4E, 0x4E, 0x00, 0xFF, 0xEB, 0xEC, 0x44, 0x41, 0x4E, 0x4B, 0x45, 0x20, 0x46, 0x5B, 0x52, + 0x0A, 0x49, 0x48, 0x52, 0x45, 0x20, 0x48, 0x49, 0x4C, 0x46, 0x45, 0x0B, 0x49, 0x43, 0x48, 0x20, + 0x42, 0x49, 0x4E, 0x20, 0x53, 0x49, 0x43, 0x48, 0x45, 0x52, 0x0A, 0x41, 0x4E, 0x47, 0x45, 0x4B, + 0x4F, 0x4D, 0x4D, 0x45, 0x4E, 0x2E, 0x20, 0x45, 0x53, 0x0A, 0x42, 0x45, 0x53, 0x54, 0x45, 0x48, + 0x54, 0x20, 0x4B, 0x45, 0x49, 0x4E, 0x45, 0x0A, 0x47, 0x45, 0x46, 0x41, 0x48, 0x52, 0x20, 0x4D, + 0x45, 0x48, 0x52, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x48, 0x41, 0x42, 0x45, 0x4E, 0x20, 0x53, 0x49, + 0x45, 0x20, 0x4D, 0x49, 0x52, 0x0A, 0x44, 0x41, 0x53, 0x20, 0x50, 0x41, 0x4B, 0x45, 0x54, 0x0A, + 0x4D, 0x49, 0x54, 0x47, 0x45, 0x42, 0x52, 0x41, 0x43, 0x48, 0x54, 0x3F, 0x00, 0x57, 0x41, 0x53, + 0x20, 0x4B, 0x4F, 0x53, 0x54, 0x45, 0x54, 0x20, 0x45, 0x49, 0x4E, 0x0A, 0x54, 0x49, 0x43, 0x4B, + 0x45, 0x54, 0x20, 0x5A, 0x55, 0x52, 0x0A, 0x45, 0x52, 0x44, 0x45, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, + 0x35, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x20, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x2E, 0x00, + 0xFF, 0xEB, 0xEC, 0x45, 0x49, 0x4E, 0x45, 0x20, 0x48, 0x41, 0x4E, 0x44, 0x0A, 0x57, 0x5C, 0x53, + 0x43, 0x48, 0x54, 0x0A, 0x44, 0x49, 0x45, 0x20, 0x41, 0x4E, 0x44, 0x45, 0x52, 0x45, 0x2E, 0x0B, + 0x31, 0x2E, 0x35, 0x30, 0x30, 0x20, 0x43, 0x52, 0x45, 0x44, 0x49, 0x54, 0x53, 0x0A, 0x55, 0x4E, + 0x44, 0x20, 0x44, 0x49, 0x45, 0x20, 0x50, 0x41, 0x50, 0x49, 0x45, 0x52, 0x45, 0x0A, 0x47, 0x45, + 0x48, 0x5D, 0x52, 0x45, 0x4E, 0x20, 0x44, 0x49, 0x52, 0x2E, 0x00 +}; + +const uint8_t LocaleData::_stringsTableSP[] = { + 0x5A, 0x00, 0x71, 0x00, 0x8F, 0x00, 0xA7, 0x01, 0x71, 0x02, 0x8D, 0x02, 0xD8, 0x02, 0x09, 0x03, + 0x6E, 0x03, 0x84, 0x03, 0xBE, 0x03, 0x08, 0x04, 0x51, 0x04, 0x9B, 0x04, 0x18, 0x05, 0x49, 0x05, + 0x60, 0x05, 0xC3, 0x05, 0xD4, 0x05, 0xF2, 0x05, 0x8D, 0x06, 0x9B, 0x08, 0x10, 0x09, 0x2A, 0x09, + 0x89, 0x09, 0x9D, 0x09, 0xBA, 0x09, 0xE1, 0x09, 0xFE, 0x09, 0x21, 0x0A, 0x23, 0x0A, 0x25, 0x0A, + 0x8D, 0x0A, 0xA1, 0x0A, 0x2A, 0x0B, 0x51, 0x0B, 0x05, 0x0C, 0x1F, 0x0C, 0x48, 0x0C, 0x7A, 0x0C, + 0x06, 0x0D, 0x40, 0x0D, 0x89, 0x0D, 0xAD, 0x0D, 0xE8, 0x0D, 0x48, 0x41, 0x20, 0x53, 0x41, 0x4C, + 0x54, 0x41, 0x44, 0x4F, 0x0A, 0x45, 0x4C, 0x20, 0x46, 0x55, 0x53, 0x49, 0x42, 0x4C, 0x45, 0x2E, + 0x00, 0x45, 0x53, 0x54, 0x4F, 0x20, 0x44, 0x45, 0x42, 0x45, 0x52, 0x49, 0x41, 0x0A, 0x46, 0x55, + 0x4E, 0x43, 0x49, 0x4F, 0x4E, 0x41, 0x52, 0x20, 0x41, 0x48, 0x4F, 0x52, 0x41, 0x2E, 0x00, 0xFF, + 0xEB, 0xEC, 0x53, 0x4F, 0x59, 0x20, 0x4A, 0x41, 0x43, 0x4B, 0x2E, 0x40, 0x45, 0x53, 0x54, 0x41, + 0x53, 0x0A, 0x42, 0x55, 0x53, 0x43, 0x41, 0x4E, 0x44, 0x4F, 0x0A, 0x44, 0x4F, 0x43, 0x55, 0x4D, + 0x45, 0x4E, 0x54, 0x41, 0x43, 0x49, 0x4F, 0x4E, 0x0A, 0x46, 0x41, 0x4C, 0x53, 0x41, 0x3F, 0x0B, + 0xFF, 0xE9, 0xEA, 0x53, 0x49, 0x2C, 0x20, 0x59, 0x20, 0x4C, 0x4F, 0x0A, 0x4D, 0x41, 0x53, 0x20, + 0x52, 0x41, 0x50, 0x49, 0x44, 0x4F, 0x0A, 0x50, 0x4F, 0x53, 0x49, 0x42, 0x4C, 0x45, 0x2E, 0x0B, + 0xFF, 0xEB, 0xEC, 0x7B, 0x31, 0x35, 0x30, 0x30, 0x20, 0x43, 0x52, 0x45, 0x44, 0x49, 0x54, 0x4F, + 0x53, 0x21, 0x0B, 0xFF, 0xE9, 0xEA, 0x40, 0x40, 0x40, 0x31, 0x35, 0x30, 0x30, 0x3F, 0x3F, 0x3F, + 0x0B, 0xFF, 0xEB, 0xEC, 0x53, 0x49, 0x49, 0x49, 0x2C, 0x20, 0x43, 0x4F, 0x52, 0x52, 0x4F, 0x20, + 0x55, 0x4E, 0x0A, 0x47, 0x52, 0x41, 0x4E, 0x20, 0x50, 0x45, 0x4C, 0x49, 0x47, 0x52, 0x4F, 0x0A, + 0x41, 0x51, 0x55, 0x49, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x50, 0x45, 0x52, 0x4F, 0x2C, 0x20, 0x59, + 0x4F, 0x20, 0x4E, 0x4F, 0x0A, 0x54, 0x45, 0x4E, 0x47, 0x4F, 0x20, 0x53, 0x55, 0x46, 0x49, 0x43, + 0x49, 0x45, 0x4E, 0x54, 0x45, 0x0B, 0xFF, 0xEB, 0xEC, 0x56, 0x45, 0x20, 0x41, 0x20, 0x4C, 0x41, + 0x20, 0x4F, 0x46, 0x49, 0x43, 0x49, 0x4E, 0x41, 0x0A, 0x44, 0x45, 0x20, 0x45, 0x4D, 0x50, 0x4C, + 0x45, 0x4F, 0x2C, 0x0A, 0x41, 0x4C, 0x4C, 0x49, 0x20, 0x45, 0x4E, 0x43, 0x4F, 0x4E, 0x54, 0x52, + 0x41, 0x52, 0x41, 0x53, 0x0A, 0x54, 0x52, 0x41, 0x42, 0x41, 0x4A, 0x4F, 0x2E, 0x0B, 0x59, 0x20, + 0x56, 0x55, 0x45, 0x4C, 0x56, 0x45, 0x20, 0x41, 0x20, 0x56, 0x45, 0x52, 0x4D, 0x45, 0x0A, 0x43, + 0x55, 0x41, 0x4E, 0x44, 0x4F, 0x20, 0x54, 0x45, 0x4E, 0x47, 0x41, 0x53, 0x0A, 0x4C, 0x41, 0x20, + 0x50, 0x41, 0x53, 0x54, 0x41, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x43, 0x4F, 0x4E, 0x4F, 0x5A, 0x43, + 0x4F, 0x20, 0x41, 0x20, 0x45, 0x53, 0x45, 0x0A, 0x54, 0x49, 0x4F, 0x2E, 0x20, 0x54, 0x49, 0x45, + 0x4E, 0x45, 0x20, 0x55, 0x4E, 0x0A, 0x41, 0x4D, 0x49, 0x47, 0x4F, 0x20, 0x45, 0x4E, 0x20, 0x4C, + 0x41, 0x0A, 0x50, 0x4F, 0x4C, 0x49, 0x43, 0x49, 0x41, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x40, 0x44, + 0x4F, 0x4E, 0x44, 0x45, 0x20, 0x50, 0x55, 0x45, 0x44, 0x4F, 0x0A, 0x45, 0x4E, 0x43, 0x4F, 0x4E, + 0x54, 0x52, 0x41, 0x52, 0x20, 0x41, 0x0A, 0x45, 0x53, 0x45, 0x20, 0x41, 0x4D, 0x49, 0x47, 0x4F, + 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x56, 0x45, 0x20, 0x41, 0x4C, 0x20, 0x41, 0x52, 0x45, 0x41, 0x0A, + 0x52, 0x45, 0x53, 0x54, 0x52, 0x49, 0x4E, 0x47, 0x49, 0x44, 0x41, 0x20, 0x31, 0x2C, 0x0A, 0x43, + 0x52, 0x45, 0x4F, 0x20, 0x51, 0x55, 0x45, 0x20, 0x45, 0x53, 0x54, 0x41, 0x20, 0x44, 0x45, 0x0A, + 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x49, 0x4F, 0x20, 0x41, 0x4C, 0x4C, 0x49, 0x2E, 0x0B, 0x50, + 0x45, 0x52, 0x4F, 0x20, 0x54, 0x45, 0x4E, 0x20, 0x43, 0x55, 0x49, 0x44, 0x41, 0x44, 0x4F, 0x2C, + 0x0A, 0x7B, 0x45, 0x53, 0x4F, 0x53, 0x20, 0x54, 0x49, 0x4F, 0x53, 0x20, 0x53, 0x4F, 0x4E, 0x0A, + 0x55, 0x4E, 0x4F, 0x53, 0x20, 0x4D, 0x49, 0x53, 0x45, 0x52, 0x41, 0x42, 0x4C, 0x45, 0x53, 0x21, + 0x00, 0xFF, 0xEB, 0xEC, 0x59, 0x4F, 0x20, 0x4E, 0x4F, 0x20, 0x53, 0x45, 0x0A, 0x4E, 0x41, 0x44, + 0x41, 0x20, 0x4D, 0x41, 0x53, 0x2C, 0x0A, 0x48, 0x49, 0x4A, 0x4F, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, + 0x43, 0x59, 0x2D, 0x42, 0x30, 0x32, 0x31, 0x20, 0x51, 0x55, 0x49, 0x45, 0x52, 0x45, 0x0A, 0x48, + 0x41, 0x43, 0x45, 0x52, 0x20, 0x55, 0x4E, 0x20, 0x54, 0x52, 0x41, 0x54, 0x4F, 0x0A, 0x43, 0x4F, + 0x4E, 0x54, 0x49, 0x47, 0x4F, 0x2E, 0x0B, 0x45, 0x53, 0x54, 0x41, 0x52, 0x41, 0x20, 0x45, 0x53, + 0x50, 0x45, 0x52, 0x41, 0x4E, 0x44, 0x4F, 0x0A, 0x44, 0x45, 0x54, 0x52, 0x41, 0x53, 0x20, 0x44, + 0x45, 0x4C, 0x20, 0x42, 0x41, 0x52, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x56, 0x45, 0x54, 0x45, 0x20, + 0x41, 0x4C, 0x20, 0x42, 0x41, 0x52, 0x2C, 0x0A, 0x48, 0x49, 0x4A, 0x4F, 0x2C, 0x20, 0x43, 0x59, + 0x2D, 0x42, 0x30, 0x32, 0x31, 0x20, 0x54, 0x45, 0x0A, 0x45, 0x53, 0x54, 0x41, 0x20, 0x45, 0x53, + 0x50, 0x45, 0x52, 0x41, 0x4E, 0x44, 0x4F, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x7B, 0x4E, 0x4F, 0x20, + 0x44, 0x49, 0x53, 0x50, 0x41, 0x52, 0x45, 0x53, 0x2C, 0x20, 0x59, 0x4F, 0x0A, 0x4E, 0x4F, 0x20, + 0x53, 0x4F, 0x59, 0x20, 0x43, 0x59, 0x2D, 0x42, 0x30, 0x32, 0x31, 0x21, 0x0B, 0x53, 0x55, 0x20, + 0x45, 0x53, 0x43, 0x4F, 0x4E, 0x44, 0x52, 0x49, 0x4A, 0x4F, 0x0A, 0x45, 0x53, 0x54, 0x41, 0x20, + 0x41, 0x48, 0x49, 0x20, 0x41, 0x42, 0x41, 0x4A, 0x4F, 0x2E, 0x0B, 0x53, 0x55, 0x20, 0x43, 0x4F, + 0x4C, 0x45, 0x47, 0x41, 0x2C, 0x0A, 0x45, 0x4C, 0x20, 0x50, 0x4F, 0x4C, 0x49, 0x0A, 0x54, 0x49, + 0x45, 0x4E, 0x45, 0x20, 0x4C, 0x41, 0x20, 0x4C, 0x4C, 0x41, 0x56, 0x45, 0x2E, 0x00, 0xFF, 0xEB, + 0xEC, 0x59, 0x4F, 0x20, 0x4E, 0x4F, 0x20, 0x53, 0x45, 0x0A, 0x4E, 0x41, 0x44, 0x41, 0x20, 0x4D, + 0x41, 0x53, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x55, 0x4E, 0x20, 0x54, 0x49, 0x4F, 0x20, 0x4C, 0x4C, + 0x41, 0x4D, 0x41, 0x44, 0x4F, 0x0B, 0x4A, 0x41, 0x43, 0x4B, 0x20, 0x41, 0x43, 0x4F, 0x52, 0x44, + 0x4F, 0x0A, 0x52, 0x45, 0x55, 0x4E, 0x49, 0x52, 0x53, 0x45, 0x20, 0x43, 0x4F, 0x4E, 0x20, 0x55, + 0x44, 0x2E, 0x0A, 0x45, 0x4E, 0x20, 0x45, 0x4C, 0x20, 0x42, 0x41, 0x52, 0x2E, 0x00, 0x51, 0x55, + 0x45, 0x52, 0x52, 0x49, 0x41, 0x20, 0x55, 0x4E, 0x0A, 0x50, 0x45, 0x52, 0x4D, 0x49, 0x53, 0x4F, + 0x20, 0x44, 0x45, 0x0A, 0x54, 0x52, 0x41, 0x42, 0x41, 0x4A, 0x4F, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, + 0x4E, 0x4F, 0x2C, 0x20, 0x4E, 0x4F, 0x20, 0x45, 0x53, 0x20, 0x41, 0x51, 0x55, 0x49, 0x2E, 0x0A, + 0x56, 0x41, 0x59, 0x41, 0x20, 0x41, 0x20, 0x4C, 0x41, 0x0A, 0x56, 0x45, 0x4E, 0x54, 0x41, 0x4E, + 0x49, 0x4C, 0x4C, 0x41, 0x20, 0x43, 0x2E, 0x00, 0x51, 0x55, 0x45, 0x52, 0x52, 0x49, 0x41, 0x20, + 0x55, 0x4E, 0x0A, 0x50, 0x45, 0x52, 0x4D, 0x49, 0x53, 0x4F, 0x20, 0x44, 0x45, 0x0A, 0x54, 0x52, + 0x41, 0x42, 0x41, 0x4A, 0x4F, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x42, 0x49, 0x45, 0x4E, 0x20, 0x2E, + 0x2E, 0x4F, 0x2E, 0x4B, 0x2E, 0x2C, 0x0A, 0x45, 0x4C, 0x20, 0x4A, 0x45, 0x46, 0x45, 0x20, 0x4C, + 0x45, 0x0A, 0x52, 0x45, 0x43, 0x49, 0x42, 0x49, 0x52, 0x41, 0x20, 0x41, 0x48, 0x4F, 0x52, 0x41, + 0x00, 0x51, 0x55, 0x45, 0x52, 0x52, 0x49, 0x41, 0x20, 0x55, 0x4E, 0x0A, 0x50, 0x45, 0x52, 0x4D, + 0x49, 0x53, 0x4F, 0x20, 0x44, 0x45, 0x0A, 0x54, 0x52, 0x41, 0x42, 0x41, 0x4A, 0x4F, 0x2E, 0x0B, + 0xFF, 0xEB, 0xEC, 0x4E, 0x4F, 0x2C, 0x20, 0x4E, 0x4F, 0x20, 0x45, 0x53, 0x20, 0x41, 0x51, 0x55, + 0x49, 0x2E, 0x0A, 0x56, 0x41, 0x59, 0x41, 0x20, 0x41, 0x20, 0x4C, 0x41, 0x0A, 0x56, 0x45, 0x4E, + 0x54, 0x41, 0x4E, 0x49, 0x4C, 0x4C, 0x41, 0x20, 0x42, 0x2E, 0x00, 0x51, 0x55, 0x49, 0x45, 0x52, + 0x4F, 0x20, 0x48, 0x41, 0x42, 0x4C, 0x41, 0x52, 0x0A, 0x43, 0x4F, 0x4E, 0x20, 0x4A, 0x41, 0x43, + 0x4B, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x40, 0x41, 0x48, 0x20, 0x53, 0x49, 0x3F, 0x20, 0x4A, 0x41, + 0x43, 0x4B, 0x20, 0x4E, 0x4F, 0x0A, 0x45, 0x53, 0x54, 0x41, 0x20, 0x41, 0x51, 0x55, 0x49, 0x20, + 0x41, 0x48, 0x4F, 0x52, 0x41, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x4D, 0x45, 0x20, 0x45, 0x4E, 0x56, + 0x49, 0x41, 0x0A, 0x4D, 0x49, 0x20, 0x41, 0x4D, 0x49, 0x47, 0x4F, 0x20, 0x49, 0x41, 0x4E, 0x2E, + 0x0B, 0xFF, 0xEB, 0xEC, 0x4F, 0x2E, 0x4B, 0x2E, 0x20, 0x4A, 0x41, 0x43, 0x4B, 0x20, 0x54, 0x45, + 0x0A, 0x45, 0x53, 0x54, 0x41, 0x20, 0x45, 0x53, 0x50, 0x45, 0x52, 0x41, 0x4E, 0x44, 0x4F, 0x0A, + 0x41, 0x46, 0x55, 0x45, 0x52, 0x41, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x54, 0x49, 0x52, 0x41, 0x4C, + 0x4F, 0x2C, 0x20, 0x48, 0x49, 0x4A, 0x4F, 0x2E, 0x0A, 0x45, 0x52, 0x45, 0x53, 0x20, 0x44, 0x45, + 0x4D, 0x41, 0x53, 0x49, 0x41, 0x44, 0x4F, 0x0A, 0x4A, 0x4F, 0x56, 0x45, 0x4E, 0x20, 0x50, 0x41, + 0x52, 0x41, 0x20, 0x42, 0x45, 0x42, 0x45, 0x52, 0x00, 0xFF, 0xEB, 0xEC, 0x50, 0x41, 0x50, 0x45, + 0x4C, 0x45, 0x53, 0x2C, 0x0A, 0x50, 0x4F, 0x52, 0x20, 0x46, 0x41, 0x56, 0x4F, 0x52, 0x2E, 0x00, + 0x53, 0x4F, 0x59, 0x20, 0x45, 0x4C, 0x0A, 0x4D, 0x45, 0x4E, 0x53, 0x41, 0x4A, 0x45, 0x52, 0x4F, + 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x7B, 0x41, 0x48, 0x20, 0x53, 0x49, 0x21, 0x20, 0x4C, 0x4C, 0x45, + 0x56, 0x41, 0x0A, 0x45, 0x53, 0x54, 0x45, 0x20, 0x50, 0x41, 0x51, 0x55, 0x45, 0x54, 0x45, 0x20, + 0x41, 0x0A, 0x4C, 0x41, 0x20, 0x41, 0x47, 0x45, 0x4E, 0x43, 0x49, 0x41, 0x20, 0x44, 0x45, 0x0A, + 0x56, 0x49, 0x41, 0x4A, 0x45, 0x53, 0x2E, 0x0B, 0x59, 0x20, 0x54, 0x45, 0x4E, 0x20, 0x43, 0x55, + 0x49, 0x44, 0x41, 0x44, 0x4F, 0x2C, 0x0A, 0x45, 0x53, 0x20, 0x56, 0x41, 0x4C, 0x49, 0x4F, 0x53, + 0x4F, 0x2E, 0x00, 0x54, 0x49, 0x45, 0x4D, 0x50, 0x4F, 0x20, 0x43, 0x4F, 0x4E, 0x43, 0x4C, 0x55, + 0x49, 0x44, 0x4F, 0x00, 0x48, 0x41, 0x59, 0x20, 0x55, 0x4E, 0x20, 0x4C, 0x55, 0x47, 0x41, 0x52, + 0x0A, 0x50, 0x41, 0x52, 0x41, 0x20, 0x4C, 0x41, 0x20, 0x54, 0x41, 0x52, 0x4A, 0x45, 0x54, 0x41, + 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x47, 0x52, 0x41, 0x43, 0x49, 0x41, 0x53, 0x2C, 0x20, 0x43, 0x4F, + 0x4E, 0x52, 0x41, 0x44, 0x2E, 0x0A, 0x7B, 0x45, 0x53, 0x54, 0x4F, 0x53, 0x20, 0x50, 0x4F, 0x4C, + 0x49, 0x53, 0x0A, 0x48, 0x41, 0x42, 0x52, 0x49, 0x41, 0x4E, 0x20, 0x43, 0x4F, 0x4E, 0x53, 0x45, + 0x47, 0x55, 0x49, 0x44, 0x4F, 0x0A, 0x4D, 0x49, 0x20, 0x50, 0x45, 0x4C, 0x4C, 0x45, 0x4A, 0x4F, + 0x21, 0x0B, 0x42, 0x49, 0x45, 0x4E, 0x2C, 0x53, 0x55, 0x50, 0x4F, 0x4E, 0x47, 0x4F, 0x20, 0x51, + 0x55, 0x45, 0x0A, 0x4E, 0x4F, 0x20, 0x52, 0x45, 0x43, 0x55, 0x45, 0x52, 0x44, 0x41, 0x53, 0x20, + 0x41, 0x0A, 0x54, 0x55, 0x20, 0x56, 0x49, 0x45, 0x4A, 0x4F, 0x0A, 0x41, 0x4D, 0x49, 0x47, 0x4F, + 0x20, 0x49, 0x41, 0x4E, 0x2E, 0x0B, 0x53, 0x49, 0x45, 0x4E, 0x54, 0x41, 0x54, 0x45, 0x2C, 0x0A, + 0x41, 0x52, 0x52, 0x45, 0x47, 0x4C, 0x41, 0x52, 0x45, 0x4D, 0x4F, 0x53, 0x0A, 0x45, 0x53, 0x54, + 0x4F, 0x20, 0x45, 0x4E, 0x53, 0x45, 0x47, 0x55, 0x49, 0x44, 0x41, 0x2E, 0x00, 0x49, 0x41, 0x4E, + 0x2C, 0x20, 0x40, 0x51, 0x55, 0x45, 0x20, 0x54, 0x49, 0x45, 0x4E, 0x45, 0x0A, 0x55, 0x4E, 0x4F, + 0x20, 0x51, 0x55, 0x45, 0x20, 0x48, 0x41, 0x43, 0x45, 0x52, 0x20, 0x0A, 0x50, 0x41, 0x52, 0x41, + 0x20, 0x49, 0x52, 0x20, 0x41, 0x0A, 0x4C, 0x41, 0x20, 0x54, 0x49, 0x45, 0x52, 0x52, 0x41, 0x3F, + 0x0B, 0xFF, 0xEB, 0xEC, 0x45, 0x4C, 0x20, 0x50, 0x52, 0x45, 0x43, 0x49, 0x4F, 0x20, 0x44, 0x45, + 0x4C, 0x0A, 0x42, 0x49, 0x4C, 0x4C, 0x45, 0x54, 0x45, 0x20, 0x45, 0x53, 0x0A, 0x41, 0x53, 0x54, + 0x52, 0x4F, 0x4E, 0x4F, 0x4D, 0x49, 0x43, 0x4F, 0x2E, 0x0B, 0x53, 0x4F, 0x4C, 0x4F, 0x20, 0x54, + 0x45, 0x20, 0x51, 0x55, 0x45, 0x44, 0x41, 0x0A, 0x50, 0x41, 0x52, 0x54, 0x49, 0x43, 0x49, 0x50, + 0x41, 0x52, 0x20, 0x45, 0x4E, 0x20, 0x4C, 0x41, 0x0A, 0x54, 0x4F, 0x52, 0x52, 0x45, 0x20, 0x44, + 0x45, 0x20, 0x4C, 0x41, 0x0A, 0x4D, 0x55, 0x45, 0x52, 0x54, 0x45, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, + 0x40, 0x4C, 0x41, 0x20, 0x54, 0x4F, 0x52, 0x52, 0x45, 0x0A, 0x44, 0x45, 0x20, 0x4C, 0x41, 0x20, + 0x4D, 0x55, 0x45, 0x52, 0x54, 0x45, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x45, 0x53, 0x20, 0x55, 0x4E, + 0x20, 0x43, 0x4F, 0x4E, 0x43, 0x55, 0x52, 0x53, 0x4F, 0x0A, 0x44, 0x45, 0x20, 0x4C, 0x41, 0x20, + 0x54, 0x45, 0x4C, 0x45, 0x2E, 0x20, 0x45, 0x4C, 0x0A, 0x47, 0x41, 0x4E, 0x41, 0x44, 0x4F, 0x52, + 0x20, 0x4F, 0x42, 0x54, 0x49, 0x45, 0x4E, 0x45, 0x0A, 0x55, 0x4E, 0x20, 0x42, 0x49, 0x4C, 0x4C, + 0x45, 0x54, 0x45, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x4F, 0x2E, 0x4B, 0x2E, 0x20, 0x40, 0x50, 0x55, + 0x45, 0x44, 0x45, 0x53, 0x0A, 0x43, 0x4F, 0x4E, 0x53, 0x45, 0x47, 0x55, 0x49, 0x52, 0x4D, 0x45, + 0x0A, 0x44, 0x4F, 0x43, 0x55, 0x4D, 0x45, 0x4E, 0x54, 0x41, 0x43, 0x49, 0x4F, 0x4E, 0x0A, 0x46, + 0x41, 0x4C, 0x53, 0x41, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x53, 0x49, 0x4E, 0x20, 0x50, 0x52, 0x4F, + 0x42, 0x4C, 0x45, 0x4D, 0x41, 0x53, 0x2E, 0x0A, 0x56, 0x45, 0x20, 0x41, 0x4C, 0x20, 0x42, 0x41, + 0x52, 0x20, 0x59, 0x0A, 0x50, 0x52, 0x45, 0x47, 0x55, 0x4E, 0x54, 0x41, 0x20, 0x50, 0x4F, 0x52, + 0x0A, 0x4A, 0x41, 0x43, 0x4B, 0x2E, 0x0B, 0x44, 0x49, 0x4C, 0x45, 0x20, 0x51, 0x55, 0x45, 0x20, + 0x54, 0x45, 0x0A, 0x45, 0x4E, 0x56, 0x49, 0x4F, 0x20, 0x59, 0x4F, 0x2E, 0x20, 0x41, 0x48, 0x2C, + 0x0A, 0x50, 0x4F, 0x52, 0x20, 0x43, 0x49, 0x45, 0x52, 0x54, 0x4F, 0x2E, 0x2E, 0x2E, 0x0B, 0x50, + 0x55, 0x53, 0x45, 0x20, 0x45, 0x4C, 0x20, 0x43, 0x41, 0x4D, 0x50, 0x4F, 0x20, 0x44, 0x45, 0x0A, + 0x46, 0x55, 0x45, 0x52, 0x5A, 0x41, 0x20, 0x51, 0x55, 0x45, 0x20, 0x4D, 0x45, 0x0A, 0x50, 0x45, + 0x44, 0x49, 0x53, 0x54, 0x45, 0x20, 0x45, 0x4E, 0x20, 0x54, 0x55, 0x0A, 0x42, 0x4F, 0x4C, 0x53, + 0x49, 0x4C, 0x4C, 0x4F, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x43, 0x48, 0x41, 0x43, 0x48, 0x49, 0x2E, + 0x20, 0x47, 0x52, 0x41, 0x43, 0x49, 0x41, 0x53, 0x0A, 0x49, 0x41, 0x4E, 0x2E, 0x20, 0x48, 0x41, + 0x53, 0x54, 0x41, 0x20, 0x4C, 0x41, 0x0A, 0x50, 0x52, 0x4F, 0x58, 0x49, 0x4D, 0x41, 0x2E, 0x2E, + 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x42, 0x55, 0x45, 0x4E, 0x41, 0x20, 0x53, 0x55, 0x45, 0x52, 0x54, + 0x45, 0x2E, 0x0A, 0x43, 0x4F, 0x4E, 0x54, 0x41, 0x43, 0x54, 0x41, 0x52, 0x45, 0x4D, 0x4F, 0x53, + 0x0A, 0x41, 0x20, 0x54, 0x55, 0x20, 0x4C, 0x4C, 0x45, 0x47, 0x41, 0x44, 0x41, 0x20, 0x41, 0x0A, + 0x4C, 0x41, 0x20, 0x54, 0x49, 0x45, 0x52, 0x52, 0x41, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x42, 0x49, + 0x45, 0x4E, 0x56, 0x45, 0x4E, 0x49, 0x44, 0x4F, 0x20, 0x41, 0x0A, 0x4E, 0x45, 0x57, 0x20, 0x57, + 0x41, 0x53, 0x48, 0x49, 0x4E, 0x47, 0x54, 0x4F, 0x4E, 0x2C, 0x0A, 0x4A, 0x4F, 0x56, 0x45, 0x4E, + 0x43, 0x49, 0x54, 0x4F, 0x2E, 0x0B, 0x41, 0x51, 0x55, 0x49, 0x20, 0x54, 0x49, 0x45, 0x4E, 0x45, + 0x53, 0x20, 0x55, 0x4E, 0x0A, 0x4D, 0x41, 0x50, 0x41, 0x20, 0x44, 0x45, 0x20, 0x4C, 0x41, 0x0A, + 0x43, 0x49, 0x55, 0x44, 0x41, 0x44, 0x20, 0x51, 0x55, 0x45, 0x20, 0x54, 0x45, 0x0A, 0x53, 0x45, + 0x52, 0x41, 0x20, 0x4D, 0x55, 0x59, 0x20, 0x55, 0x54, 0x49, 0x4C, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, + 0x4D, 0x55, 0x43, 0x48, 0x41, 0x53, 0x20, 0x47, 0x52, 0x41, 0x43, 0x49, 0x41, 0x53, 0x2E, 0x00, + 0xFF, 0xEB, 0xEC, 0x51, 0x55, 0x45, 0x20, 0x54, 0x45, 0x4E, 0x47, 0x41, 0x20, 0x55, 0x4E, 0x0A, + 0x42, 0x55, 0x45, 0x4E, 0x20, 0x44, 0x49, 0x41, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x44, 0x45, 0x42, + 0x45, 0x20, 0x54, 0x45, 0x4E, 0x45, 0x52, 0x20, 0x55, 0x4E, 0x0A, 0x50, 0x45, 0x52, 0x4D, 0x49, + 0x53, 0x4F, 0x20, 0x50, 0x41, 0x52, 0x41, 0x0A, 0x50, 0x4F, 0x44, 0x45, 0x52, 0x20, 0x54, 0x52, + 0x41, 0x42, 0x41, 0x4A, 0x41, 0x52, 0x2E, 0x0B, 0x50, 0x55, 0x45, 0x44, 0x45, 0x20, 0x43, 0x4F, + 0x4E, 0x53, 0x45, 0x47, 0x55, 0x49, 0x52, 0x0A, 0x55, 0x4E, 0x4F, 0x20, 0x45, 0x4E, 0x20, 0x45, + 0x4C, 0x20, 0x43, 0x45, 0x4E, 0x54, 0x52, 0x4F, 0x0A, 0x41, 0x44, 0x4D, 0x49, 0x4E, 0x49, 0x53, + 0x54, 0x52, 0x41, 0x54, 0x49, 0x56, 0x4F, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x4E, 0x4F, 0x20, 0x54, + 0x45, 0x4E, 0x47, 0x4F, 0x0A, 0x54, 0x49, 0x45, 0x4D, 0x50, 0x4F, 0x2E, 0x00, 0x42, 0x55, 0x45, + 0x4E, 0x4F, 0x53, 0x20, 0x44, 0x49, 0x41, 0x53, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x42, 0x55, 0x45, + 0x4E, 0x4F, 0x53, 0x20, 0x44, 0x49, 0x41, 0x53, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x48, 0x45, 0x20, + 0x56, 0x49, 0x53, 0x54, 0x4F, 0x20, 0x41, 0x20, 0x45, 0x53, 0x45, 0x0A, 0x54, 0x49, 0x4F, 0x20, + 0x41, 0x4E, 0x54, 0x45, 0x53, 0x20, 0x45, 0x4E, 0x0A, 0x45, 0x4C, 0x20, 0x42, 0x41, 0x52, 0x2E, + 0x00, 0x42, 0x55, 0x45, 0x4E, 0x4F, 0x53, 0x20, 0x44, 0x49, 0x41, 0x53, 0x2E, 0x0B, 0xFF, 0xEB, + 0xEC, 0x42, 0x55, 0x45, 0x4E, 0x4F, 0x53, 0x20, 0x44, 0x49, 0x41, 0x53, 0x2E, 0x00, 0xFF, 0xEB, + 0xEC, 0x53, 0x49, 0x2C, 0x20, 0x4C, 0x45, 0x20, 0x43, 0x4F, 0x4E, 0x4F, 0x5A, 0x43, 0x4F, 0x2E, + 0x0A, 0x45, 0x53, 0x20, 0x55, 0x4E, 0x20, 0x48, 0x41, 0x42, 0x49, 0x54, 0x55, 0x41, 0x4C, 0x2E, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x51, 0x55, 0x45, 0x52, 0x52, 0x49, 0x41, 0x20, 0x55, 0x4E, 0x0A, + 0x50, 0x45, 0x52, 0x4D, 0x49, 0x53, 0x4F, 0x20, 0x44, 0x45, 0x0A, 0x54, 0x52, 0x41, 0x42, 0x41, + 0x4A, 0x4F, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x4E, 0x4F, 0x20, 0x48, 0x41, 0x59, 0x20, 0x50, 0x52, + 0x4F, 0x42, 0x4C, 0x45, 0x4D, 0x41, 0x2E, 0x0A, 0x50, 0x41, 0x52, 0x41, 0x20, 0x43, 0x4F, 0x4E, + 0x53, 0x45, 0x47, 0x55, 0x49, 0x52, 0x0A, 0x55, 0x4E, 0x20, 0x50, 0x45, 0x52, 0x4D, 0x49, 0x53, + 0x4F, 0x2E, 0x2E, 0x2E, 0x0B, 0x4E, 0x45, 0x43, 0x45, 0x53, 0x49, 0x54, 0x4F, 0x20, 0x53, 0x55, + 0x0A, 0x54, 0x41, 0x52, 0x4A, 0x45, 0x54, 0x41, 0x20, 0x49, 0x44, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, + 0x41, 0x59, 0x55, 0x44, 0x41, 0x2E, 0x2E, 0x2E, 0x41, 0x59, 0x55, 0x44, 0x41, 0x2E, 0x2E, 0x2E, + 0x00, 0xFF, 0xEB, 0xEC, 0x41, 0x59, 0x55, 0x44, 0x45, 0x4D, 0x45, 0x2C, 0x20, 0x4A, 0x4F, 0x56, + 0x45, 0x4E, 0x2E, 0x0A, 0x48, 0x45, 0x20, 0x53, 0x49, 0x44, 0x4F, 0x20, 0x41, 0x54, 0x41, 0x43, + 0x41, 0x44, 0x4F, 0x0A, 0x50, 0x4F, 0x52, 0x20, 0x55, 0x4E, 0x4F, 0x53, 0x20, 0x0A, 0x4D, 0x55, + 0x54, 0x41, 0x4E, 0x54, 0x45, 0x53, 0x2E, 0x2E, 0x2E, 0x0B, 0x59, 0x20, 0x4E, 0x4F, 0x20, 0x50, + 0x55, 0x45, 0x44, 0x4F, 0x0A, 0x43, 0x41, 0x4D, 0x49, 0x4E, 0x41, 0x52, 0x2E, 0x0B, 0x42, 0x55, + 0x53, 0x51, 0x55, 0x45, 0x20, 0x4D, 0x49, 0x0A, 0x54, 0x45, 0x4C, 0x45, 0x50, 0x4F, 0x52, 0x54, + 0x41, 0x44, 0x4F, 0x52, 0x2E, 0x0B, 0x4E, 0x45, 0x43, 0x45, 0x53, 0x49, 0x54, 0x4F, 0x0A, 0x41, + 0x53, 0x49, 0x53, 0x54, 0x45, 0x4E, 0x43, 0x49, 0x41, 0x0A, 0x4D, 0x45, 0x44, 0x49, 0x43, 0x41, + 0x20, 0x55, 0x52, 0x47, 0x45, 0x4E, 0x54, 0x45, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x47, 0x52, 0x41, + 0x43, 0x49, 0x41, 0x53, 0x2E, 0x41, 0x43, 0x41, 0x42, 0x41, 0x53, 0x0A, 0x44, 0x45, 0x20, 0x53, + 0x41, 0x4C, 0x56, 0x41, 0x52, 0x4D, 0x45, 0x0A, 0x4C, 0x41, 0x20, 0x56, 0x49, 0x44, 0x41, 0x2E, + 0x00, 0xFF, 0xEB, 0xEC, 0x50, 0x41, 0x52, 0x41, 0x20, 0x49, 0x52, 0x20, 0x41, 0x20, 0x4E, 0x45, + 0x57, 0x0A, 0x57, 0x41, 0x53, 0x48, 0x49, 0x4E, 0x47, 0x54, 0x4F, 0x4E, 0x2C, 0x0A, 0x54, 0x49, + 0x45, 0x4E, 0x45, 0x20, 0x51, 0x55, 0x45, 0x20, 0x53, 0x41, 0x4C, 0x54, 0x41, 0x52, 0x0A, 0x50, + 0x4F, 0x52, 0x20, 0x45, 0x53, 0x54, 0x45, 0x20, 0x41, 0x47, 0x55, 0x4A, 0x45, 0x52, 0x4F, 0x0B, + 0x50, 0x45, 0x52, 0x4F, 0x20, 0x59, 0x4F, 0x20, 0x51, 0x55, 0x45, 0x20, 0x54, 0x55, 0x0A, 0x55, + 0x53, 0x41, 0x52, 0x49, 0x41, 0x20, 0x55, 0x4E, 0x0A, 0x43, 0x49, 0x4E, 0x54, 0x55, 0x52, 0x4F, + 0x4E, 0x20, 0x41, 0x4E, 0x54, 0x49, 0x2D, 0x47, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x40, 0x44, 0x4F, + 0x4E, 0x44, 0x45, 0x20, 0x50, 0x55, 0x45, 0x44, 0x4F, 0x0A, 0x45, 0x4E, 0x43, 0x4F, 0x4E, 0x54, + 0x52, 0x41, 0x52, 0x20, 0x55, 0x4E, 0x4F, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x41, 0x48, 0x4F, 0x52, + 0x41, 0x2C, 0x20, 0x50, 0x55, 0x45, 0x44, 0x4F, 0x0A, 0x56, 0x45, 0x4E, 0x44, 0x45, 0x52, 0x54, + 0x45, 0x20, 0x55, 0x4E, 0x4F, 0x3A, 0x0A, 0x35, 0x30, 0x30, 0x20, 0x43, 0x52, 0x45, 0x44, 0x49, + 0x54, 0x4F, 0x53, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x42, 0x4F, 0x4E, 0x20, 0x56, 0x4F, 0x59, 0x41, + 0x47, 0x45, 0x2C, 0x0A, 0x4A, 0x4F, 0x56, 0x45, 0x4E, 0x43, 0x49, 0x54, 0x4F, 0x2E, 0x00, 0x4E, + 0x45, 0x43, 0x45, 0x53, 0x49, 0x54, 0x4F, 0x20, 0x55, 0x4E, 0x0A, 0x43, 0x41, 0x52, 0x54, 0x55, + 0x43, 0x48, 0x4F, 0x0A, 0x4D, 0x41, 0x47, 0x4E, 0x45, 0x54, 0x49, 0x43, 0x4F, 0x0A, 0x52, 0x45, + 0x43, 0x41, 0x52, 0x47, 0x41, 0x44, 0x4F, 0x00, 0x51, 0x55, 0x45, 0x52, 0x52, 0x49, 0x41, 0x20, + 0x55, 0x4E, 0x0A, 0x50, 0x45, 0x52, 0x4D, 0x49, 0x53, 0x4F, 0x20, 0x44, 0x45, 0x0A, 0x54, 0x52, + 0x41, 0x42, 0x41, 0x4A, 0x4F, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x50, 0x52, 0x49, 0x4D, 0x45, 0x52, + 0x41, 0x20, 0x50, 0x4C, 0x41, 0x4E, 0x54, 0x41, 0x2E, 0x00, 0x55, 0x4E, 0x41, 0x20, 0x56, 0x4F, + 0x5A, 0x20, 0x49, 0x4E, 0x54, 0x45, 0x52, 0x49, 0x4F, 0x52, 0x0A, 0x49, 0x4E, 0x54, 0x45, 0x52, + 0x52, 0x55, 0x4D, 0x50, 0x45, 0x20, 0x54, 0x55, 0x53, 0x0A, 0x50, 0x45, 0x4E, 0x53, 0x41, 0x4D, + 0x49, 0x45, 0x4E, 0x54, 0x4F, 0x53, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x43, 0x52, 0x45, 0x45, 0x4D, + 0x45, 0x2C, 0x20, 0x48, 0x49, 0x4A, 0x4F, 0x2C, 0x0A, 0x50, 0x4F, 0x4E, 0x20, 0x4C, 0x41, 0x20, + 0x43, 0x41, 0x52, 0x47, 0x41, 0x0A, 0x41, 0x54, 0x4F, 0x4D, 0x49, 0x43, 0x41, 0x20, 0x41, 0x51, + 0x55, 0x49, 0x2E, 0x2E, 0x2E, 0x0B, 0x59, 0x20, 0x48, 0x55, 0x59, 0x45, 0x20, 0x45, 0x4E, 0x20, + 0x43, 0x55, 0x41, 0x4E, 0x54, 0x4F, 0x0A, 0x41, 0x4C, 0x43, 0x41, 0x4E, 0x43, 0x45, 0x20, 0x45, + 0x4C, 0x0A, 0x4E, 0x55, 0x43, 0x4C, 0x45, 0x4F, 0x20, 0x44, 0x45, 0x4C, 0x0A, 0x50, 0x4C, 0x41, + 0x4E, 0x45, 0x54, 0x41, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x47, 0x55, 0x49, 0x41, 0x4D, 0x45, 0x2C, + 0x0A, 0x4A, 0x4F, 0x56, 0x45, 0x4E, 0x43, 0x49, 0x54, 0x4F, 0x2E, 0x0B, 0x4C, 0x4C, 0x45, 0x56, + 0x41, 0x4D, 0x45, 0x20, 0x41, 0x4C, 0x20, 0x0A, 0x43, 0x45, 0x4E, 0x54, 0x52, 0x4F, 0x20, 0x44, + 0x45, 0x0A, 0x49, 0x4E, 0x56, 0x45, 0x53, 0x54, 0x49, 0x47, 0x41, 0x43, 0x49, 0x4F, 0x4E, 0x00, + 0xFF, 0xEB, 0xEC, 0x47, 0x52, 0x41, 0x43, 0x49, 0x41, 0x53, 0x20, 0x50, 0x4F, 0x52, 0x0A, 0x54, + 0x55, 0x20, 0x41, 0x59, 0x55, 0x44, 0x41, 0x2E, 0x2E, 0x2E, 0x0B, 0x48, 0x45, 0x20, 0x4C, 0x4C, + 0x45, 0x47, 0x41, 0x44, 0x4F, 0x0A, 0x53, 0x49, 0x4E, 0x20, 0x50, 0x52, 0x4F, 0x42, 0x4C, 0x45, + 0x4D, 0x41, 0x53, 0x0A, 0x59, 0x20, 0x59, 0x41, 0x20, 0x4E, 0x4F, 0x20, 0x48, 0x41, 0x59, 0x0A, + 0x50, 0x45, 0x4C, 0x49, 0x47, 0x52, 0x4F, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x42, 0x49, 0x45, 0x4E, + 0x2C, 0x20, 0x40, 0x4D, 0x45, 0x20, 0x48, 0x41, 0x53, 0x0A, 0x54, 0x52, 0x41, 0x49, 0x44, 0x4F, + 0x20, 0x45, 0x4C, 0x0A, 0x50, 0x41, 0x51, 0x55, 0x45, 0x54, 0x45, 0x3F, 0x00, 0x40, 0x43, 0x55, + 0x41, 0x4E, 0x54, 0x4F, 0x20, 0x43, 0x55, 0x45, 0x53, 0x54, 0x41, 0x0A, 0x55, 0x4E, 0x20, 0x42, + 0x49, 0x4C, 0x4C, 0x45, 0x54, 0x45, 0x20, 0x41, 0x0A, 0x4C, 0x41, 0x20, 0x54, 0x49, 0x45, 0x52, + 0x52, 0x41, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x35, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x20, 0x43, 0x52, + 0x45, 0x44, 0x49, 0x54, 0x4F, 0x53, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x46, 0x41, 0x56, 0x4F, 0x52, + 0x2C, 0x20, 0x43, 0x4F, 0x4E, 0x0A, 0x46, 0x41, 0x56, 0x4F, 0x52, 0x20, 0x53, 0x45, 0x0A, 0x50, + 0x41, 0x47, 0x41, 0x3A, 0x0B, 0x31, 0x35, 0x30, 0x30, 0x20, 0x43, 0x52, 0x45, 0x44, 0x49, 0x54, + 0x4F, 0x53, 0x20, 0x59, 0x0A, 0x4C, 0x4F, 0x53, 0x20, 0x50, 0x41, 0x50, 0x45, 0x4C, 0x45, 0x53, + 0x0A, 0x53, 0x4F, 0x4E, 0x20, 0x54, 0x55, 0x59, 0x4F, 0x53, 0x2E, 0x00 +}; + +const uint8_t LocaleData::_stringsTableIT[] = { + 0x5A, 0x00, 0x71, 0x00, 0x8A, 0x00, 0xA2, 0x01, 0x56, 0x02, 0x75, 0x02, 0xBB, 0x02, 0xEE, 0x02, + 0x59, 0x03, 0x72, 0x03, 0xA8, 0x03, 0xF3, 0x03, 0x3F, 0x04, 0x8A, 0x04, 0x0C, 0x05, 0x3E, 0x05, + 0x52, 0x05, 0xB6, 0x05, 0xC4, 0x05, 0xE3, 0x05, 0x7D, 0x06, 0x8D, 0x08, 0xF7, 0x08, 0x0A, 0x09, + 0x5E, 0x09, 0x6F, 0x09, 0x8A, 0x09, 0xAE, 0x09, 0xC9, 0x09, 0xED, 0x09, 0xEF, 0x09, 0xF1, 0x09, + 0x5E, 0x0A, 0x72, 0x0A, 0xF8, 0x0A, 0x1B, 0x0B, 0xCB, 0x0B, 0xEA, 0x0B, 0x17, 0x0C, 0x47, 0x0C, + 0xD7, 0x0C, 0x10, 0x0D, 0x61, 0x0D, 0x86, 0x0D, 0xC1, 0x0D, 0x49, 0x6C, 0x20, 0x66, 0x75, 0x73, + 0x69, 0x62, 0x69, 0x6C, 0x65, 0x20, 0x5C, 0x0A, 0x73, 0x61, 0x6C, 0x74, 0x61, 0x74, 0x6F, 0x2E, + 0x00, 0x4F, 0x72, 0x61, 0x20, 0x64, 0x6F, 0x76, 0x72, 0x65, 0x62, 0x62, 0x65, 0x0A, 0x66, 0x75, + 0x6E, 0x7A, 0x69, 0x6F, 0x6E, 0x61, 0x72, 0x65, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x53, 0x6F, 0x6E, + 0x6F, 0x20, 0x4A, 0x61, 0x63, 0x6B, 0x2E, 0x20, 0x53, 0x74, 0x61, 0x69, 0x0A, 0x63, 0x65, 0x72, + 0x63, 0x61, 0x6E, 0x64, 0x6F, 0x20, 0x64, 0x65, 0x69, 0x0A, 0x64, 0x6F, 0x63, 0x75, 0x6D, 0x65, + 0x6E, 0x74, 0x69, 0x0A, 0x66, 0x61, 0x6C, 0x73, 0x69, 0x3F, 0x0B, 0xFF, 0xE9, 0xEA, 0x53, 0x69, + 0x2C, 0x20, 0x65, 0x20, 0x69, 0x6C, 0x20, 0x70, 0x69, 0x5F, 0x0A, 0x70, 0x72, 0x65, 0x73, 0x74, + 0x6F, 0x0A, 0x70, 0x6F, 0x73, 0x73, 0x69, 0x62, 0x69, 0x6C, 0x65, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, + 0x31, 0x35, 0x30, 0x30, 0x20, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x69, 0x21, 0x0B, 0xFF, 0xE9, + 0xEA, 0x31, 0x35, 0x30, 0x30, 0x3F, 0x3F, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x43, 0x65, 0x72, 0x74, + 0x6F, 0x2C, 0x20, 0x73, 0x74, 0x6F, 0x0A, 0x70, 0x72, 0x65, 0x6E, 0x64, 0x65, 0x6E, 0x64, 0x6F, + 0x20, 0x75, 0x6E, 0x0A, 0x67, 0x72, 0x6F, 0x73, 0x73, 0x6F, 0x20, 0x72, 0x69, 0x73, 0x63, 0x68, + 0x69, 0x6F, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x4D, 0x61, 0x20, 0x6E, 0x6F, 0x6E, 0x20, 0x6E, 0x65, + 0x20, 0x68, 0x6F, 0x0A, 0x61, 0x62, 0x62, 0x61, 0x73, 0x74, 0x61, 0x6E, 0x7A, 0x61, 0x2E, 0x2E, + 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x56, 0x61, 0x69, 0x20, 0x61, 0x6C, 0x6C, 0x27, 0x55, 0x66, 0x66, + 0x69, 0x63, 0x69, 0x6F, 0x0A, 0x64, 0x69, 0x20, 0x43, 0x6F, 0x6C, 0x6C, 0x6F, 0x63, 0x61, 0x6D, + 0x65, 0x6E, 0x74, 0x6F, 0x2E, 0x0A, 0x4C, 0x5B, 0x20, 0x74, 0x72, 0x6F, 0x76, 0x65, 0x72, 0x61, + 0x69, 0x0A, 0x64, 0x65, 0x6C, 0x20, 0x6C, 0x61, 0x76, 0x6F, 0x72, 0x6F, 0x2E, 0x0B, 0x45, 0x20, + 0x74, 0x6F, 0x72, 0x6E, 0x61, 0x20, 0x64, 0x61, 0x20, 0x6D, 0x65, 0x0A, 0x71, 0x75, 0x61, 0x6E, + 0x64, 0x6F, 0x20, 0x61, 0x76, 0x72, 0x61, 0x69, 0x0A, 0x69, 0x20, 0x73, 0x6F, 0x6C, 0x64, 0x69, + 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x43, 0x6F, 0x6E, 0x6F, 0x73, 0x63, 0x6F, 0x20, 0x71, 0x75, 0x65, + 0x6C, 0x20, 0x74, 0x69, 0x70, 0x6F, 0x2E, 0x0A, 0x48, 0x61, 0x20, 0x75, 0x6E, 0x20, 0x61, 0x6D, + 0x69, 0x63, 0x6F, 0x0A, 0x6E, 0x65, 0x6C, 0x6C, 0x61, 0x20, 0x70, 0x6F, 0x6C, 0x69, 0x7A, 0x69, + 0x61, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x44, 0x6F, 0x76, 0x65, 0x20, 0x70, 0x6F, 0x73, 0x73, 0x6F, + 0x0A, 0x74, 0x72, 0x6F, 0x76, 0x61, 0x72, 0x65, 0x20, 0x6C, 0x27, 0x61, 0x6D, 0x69, 0x63, 0x6F, + 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x56, 0x61, 0x69, 0x20, 0x61, 0x20, 0x52, 0x65, 0x73, 0x74, 0x72, + 0x69, 0x63, 0x74, 0x65, 0x64, 0x0A, 0x41, 0x72, 0x65, 0x61, 0x20, 0x31, 0x2C, 0x20, 0x70, 0x65, + 0x6E, 0x73, 0x6F, 0x0A, 0x63, 0x68, 0x65, 0x20, 0x73, 0x69, 0x61, 0x20, 0x64, 0x69, 0x0A, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x7A, 0x69, 0x6F, 0x20, 0x6C, 0x5B, 0x2E, 0x0B, 0x4D, 0x61, 0x20, 0x73, + 0x74, 0x61, 0x69, 0x20, 0x61, 0x74, 0x74, 0x65, 0x6E, 0x74, 0x6F, 0x2C, 0x0A, 0x71, 0x75, 0x65, + 0x69, 0x20, 0x74, 0x69, 0x70, 0x69, 0x20, 0x73, 0x6F, 0x6E, 0x6F, 0x0A, 0x64, 0x65, 0x69, 0x20, + 0x64, 0x75, 0x72, 0x69, 0x21, 0x00, 0xFF, 0xEB, 0xEC, 0x4E, 0x6F, 0x6E, 0x20, 0x73, 0x6F, 0x0A, + 0x6E, 0x69, 0x65, 0x6E, 0x74, 0x61, 0x6C, 0x74, 0x72, 0x6F, 0x2C, 0x0A, 0x72, 0x61, 0x67, 0x61, + 0x7A, 0x7A, 0x6F, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x43, 0x59, 0x2D, 0x42, 0x30, 0x32, 0x31, 0x20, + 0x76, 0x75, 0x6F, 0x6C, 0x65, 0x0A, 0x66, 0x61, 0x72, 0x74, 0x69, 0x20, 0x75, 0x6E, 0x61, 0x0A, + 0x70, 0x72, 0x6F, 0x70, 0x6F, 0x73, 0x74, 0x61, 0x2E, 0x0B, 0x54, 0x69, 0x20, 0x73, 0x74, 0x61, + 0x0A, 0x61, 0x73, 0x70, 0x65, 0x74, 0x74, 0x61, 0x6E, 0x64, 0x6F, 0x0A, 0x64, 0x69, 0x65, 0x74, + 0x72, 0x6F, 0x20, 0x61, 0x6C, 0x20, 0x62, 0x61, 0x72, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x56, 0x61, + 0x69, 0x20, 0x61, 0x6C, 0x20, 0x62, 0x61, 0x72, 0x2C, 0x0A, 0x72, 0x61, 0x67, 0x61, 0x7A, 0x7A, + 0x6F, 0x2C, 0x20, 0x43, 0x59, 0x2D, 0x42, 0x30, 0x32, 0x31, 0x0A, 0x74, 0x69, 0x20, 0x73, 0x74, + 0x61, 0x0A, 0x61, 0x73, 0x70, 0x65, 0x74, 0x74, 0x61, 0x6E, 0x64, 0x6F, 0x2E, 0x00, 0xFF, 0xEB, + 0xEC, 0x4E, 0x6F, 0x6E, 0x20, 0x73, 0x70, 0x61, 0x72, 0x61, 0x72, 0x65, 0x2C, 0x20, 0x6E, 0x6F, + 0x6E, 0x0A, 0x73, 0x6F, 0x6E, 0x6F, 0x20, 0x43, 0x59, 0x2D, 0x42, 0x30, 0x32, 0x31, 0x21, 0x0B, + 0x49, 0x6C, 0x20, 0x73, 0x75, 0x6F, 0x20, 0x72, 0x69, 0x66, 0x75, 0x67, 0x69, 0x6F, 0x0A, 0x5C, + 0x20, 0x64, 0x69, 0x20, 0x73, 0x6F, 0x74, 0x74, 0x6F, 0x2E, 0x0B, 0x49, 0x6C, 0x20, 0x73, 0x75, + 0x6F, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x67, 0x6E, 0x6F, 0x2C, 0x0A, 0x69, 0x6C, 0x20, 0x70, + 0x6F, 0x6C, 0x69, 0x7A, 0x69, 0x6F, 0x74, 0x74, 0x6F, 0x2C, 0x0A, 0x68, 0x61, 0x20, 0x6C, 0x61, + 0x20, 0x63, 0x68, 0x69, 0x61, 0x76, 0x65, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x4E, 0x6F, 0x6E, 0x20, + 0x73, 0x6F, 0x20, 0x6E, 0x69, 0x65, 0x6E, 0x74, 0x65, 0x0A, 0x64, 0x69, 0x20, 0x70, 0x69, 0x5F, + 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x53, 0x69, 0x67, 0x6E, 0x6F, 0x72, 0x65, 0x2E, 0x2E, 0x2E, 0x20, + 0x75, 0x6E, 0x0A, 0x63, 0x65, 0x72, 0x74, 0x6F, 0x20, 0x4A, 0x61, 0x63, 0x6B, 0x0A, 0x76, 0x69, + 0x20, 0x61, 0x73, 0x70, 0x65, 0x74, 0x74, 0x61, 0x0A, 0x76, 0x69, 0x63, 0x69, 0x6E, 0x6F, 0x20, + 0x61, 0x6C, 0x20, 0x62, 0x61, 0x72, 0x2E, 0x00, 0x56, 0x6F, 0x72, 0x72, 0x65, 0x69, 0x20, 0x75, + 0x6E, 0x20, 0x70, 0x65, 0x72, 0x2D, 0x0A, 0x6D, 0x65, 0x73, 0x73, 0x6F, 0x20, 0x64, 0x69, 0x20, + 0x6C, 0x61, 0x76, 0x6F, 0x72, 0x6F, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x4E, 0x6F, 0x2C, 0x20, 0x6E, + 0x6F, 0x6E, 0x20, 0x71, 0x75, 0x69, 0x2E, 0x0A, 0x43, 0x68, 0x69, 0x65, 0x64, 0x65, 0x74, 0x65, + 0x20, 0x61, 0x6C, 0x6C, 0x6F, 0x0A, 0x73, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x6C, 0x6C, 0x6F, 0x20, + 0x43, 0x2E, 0x00, 0x56, 0x6F, 0x72, 0x72, 0x65, 0x69, 0x20, 0x75, 0x6E, 0x20, 0x70, 0x65, 0x72, + 0x2D, 0x0A, 0x6D, 0x65, 0x73, 0x73, 0x6F, 0x20, 0x64, 0x69, 0x20, 0x6C, 0x61, 0x76, 0x6F, 0x72, + 0x6F, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x42, 0x65, 0x6E, 0x65, 0x2E, 0x2E, 0x2E, 0x4F, 0x2E, 0x6B, + 0x2E, 0x2C, 0x20, 0x69, 0x6C, 0x0A, 0x63, 0x61, 0x70, 0x6F, 0x20, 0x76, 0x69, 0x20, 0x72, 0x69, + 0x63, 0x65, 0x76, 0x65, 0x72, 0x5B, 0x0A, 0x61, 0x64, 0x65, 0x73, 0x73, 0x6F, 0x2E, 0x00, 0x56, + 0x6F, 0x72, 0x72, 0x65, 0x69, 0x20, 0x75, 0x6E, 0x20, 0x70, 0x65, 0x72, 0x2D, 0x0A, 0x6D, 0x65, + 0x73, 0x73, 0x6F, 0x20, 0x64, 0x69, 0x20, 0x6C, 0x61, 0x76, 0x6F, 0x72, 0x6F, 0x2E, 0x0B, 0xFF, + 0xEB, 0xEC, 0x4E, 0x6F, 0x2C, 0x20, 0x6E, 0x6F, 0x6E, 0x20, 0x71, 0x75, 0x69, 0x2E, 0x0A, 0x43, + 0x68, 0x69, 0x65, 0x64, 0x65, 0x74, 0x65, 0x20, 0x61, 0x6C, 0x6C, 0x6F, 0x0A, 0x73, 0x70, 0x6F, + 0x72, 0x74, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x42, 0x2E, 0x00, 0x56, 0x6F, 0x72, 0x72, 0x65, 0x69, + 0x20, 0x70, 0x61, 0x72, 0x6C, 0x61, 0x72, 0x65, 0x0A, 0x63, 0x6F, 0x6E, 0x20, 0x4A, 0x61, 0x63, + 0x6B, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x41, 0x68, 0x20, 0x73, 0x69, 0x3F, 0x20, 0x4A, 0x61, 0x63, + 0x6B, 0x0A, 0x6E, 0x6F, 0x6E, 0x20, 0x63, 0x27, 0x5C, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x53, 0x6F, + 0x6E, 0x6F, 0x20, 0x73, 0x74, 0x61, 0x74, 0x6F, 0x0A, 0x6D, 0x61, 0x6E, 0x64, 0x61, 0x74, 0x6F, + 0x20, 0x64, 0x61, 0x6C, 0x20, 0x6D, 0x69, 0x6F, 0x0A, 0x61, 0x6D, 0x69, 0x63, 0x6F, 0x20, 0x49, + 0x61, 0x6E, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x4F, 0x2E, 0x6B, 0x2E, 0x20, 0x4A, 0x61, 0x63, 0x6B, + 0x0A, 0x74, 0x69, 0x20, 0x73, 0x74, 0x61, 0x20, 0x61, 0x73, 0x70, 0x65, 0x74, 0x2D, 0x0A, 0x74, + 0x61, 0x6E, 0x64, 0x6F, 0x20, 0x66, 0x75, 0x6F, 0x72, 0x69, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x4E, + 0x69, 0x65, 0x6E, 0x74, 0x65, 0x20, 0x64, 0x61, 0x20, 0x66, 0x61, 0x72, 0x65, 0x2E, 0x0A, 0x53, + 0x65, 0x69, 0x20, 0x74, 0x72, 0x6F, 0x70, 0x70, 0x6F, 0x20, 0x67, 0x69, 0x6F, 0x2D, 0x0A, 0x76, + 0x61, 0x6E, 0x65, 0x20, 0x70, 0x65, 0x72, 0x20, 0x62, 0x65, 0x72, 0x65, 0x2E, 0x00, 0xFF, 0xEB, + 0xEC, 0x44, 0x6F, 0x63, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x69, 0x20, 0x70, 0x72, 0x65, 0x67, 0x6F, + 0x2E, 0x00, 0x53, 0x6F, 0x6E, 0x6F, 0x20, 0x69, 0x6C, 0x0A, 0x63, 0x6F, 0x72, 0x72, 0x69, 0x65, + 0x72, 0x65, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x4F, 0x68, 0x20, 0x62, 0x65, 0x6E, 0x65, 0x21, 0x20, + 0x45, 0x63, 0x63, 0x6F, 0x2C, 0x0A, 0x70, 0x6F, 0x72, 0x74, 0x61, 0x20, 0x69, 0x6C, 0x20, 0x70, + 0x61, 0x63, 0x63, 0x6F, 0x0A, 0x61, 0x6C, 0x6C, 0x27, 0x61, 0x67, 0x65, 0x6E, 0x7A, 0x69, 0x61, + 0x0A, 0x76, 0x69, 0x61, 0x67, 0x67, 0x69, 0x2E, 0x0B, 0x45, 0x20, 0x66, 0x61, 0x69, 0x20, 0x61, + 0x74, 0x74, 0x65, 0x6E, 0x7A, 0x69, 0x6F, 0x6E, 0x65, 0x0A, 0x5C, 0x20, 0x70, 0x72, 0x65, 0x7A, + 0x69, 0x6F, 0x73, 0x6F, 0x2E, 0x00, 0x54, 0x45, 0x4D, 0x50, 0x4F, 0x20, 0x53, 0x43, 0x41, 0x44, + 0x55, 0x54, 0x4F, 0x00, 0x43, 0x27, 0x5C, 0x20, 0x75, 0x6E, 0x61, 0x20, 0x66, 0x65, 0x73, 0x73, + 0x75, 0x72, 0x61, 0x0A, 0x70, 0x65, 0x72, 0x20, 0x6C, 0x61, 0x20, 0x73, 0x63, 0x68, 0x65, 0x64, + 0x61, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x47, 0x72, 0x61, 0x7A, 0x69, 0x65, 0x2C, 0x20, 0x43, 0x6F, + 0x6E, 0x72, 0x61, 0x64, 0x2E, 0x0A, 0x51, 0x75, 0x65, 0x69, 0x20, 0x70, 0x6F, 0x6C, 0x69, 0x7A, + 0x69, 0x6F, 0x74, 0x74, 0x69, 0x0A, 0x6D, 0x69, 0x20, 0x73, 0x74, 0x61, 0x76, 0x61, 0x6E, 0x6F, + 0x20, 0x70, 0x65, 0x72, 0x0A, 0x73, 0x63, 0x6F, 0x70, 0x72, 0x69, 0x72, 0x65, 0x21, 0x0B, 0x42, + 0x65, 0x68, 0x2C, 0x20, 0x69, 0x6D, 0x6D, 0x61, 0x67, 0x69, 0x6E, 0x6F, 0x0A, 0x63, 0x68, 0x65, + 0x20, 0x6E, 0x6F, 0x6E, 0x20, 0x74, 0x69, 0x0A, 0x72, 0x69, 0x63, 0x6F, 0x72, 0x64, 0x69, 0x20, + 0x64, 0x65, 0x6C, 0x20, 0x74, 0x75, 0x6F, 0x0A, 0x63, 0x61, 0x72, 0x6F, 0x20, 0x61, 0x6D, 0x69, + 0x63, 0x6F, 0x20, 0x49, 0x61, 0x6E, 0x2E, 0x0B, 0x53, 0x69, 0x65, 0x64, 0x69, 0x74, 0x69, 0x2C, + 0x0A, 0x72, 0x69, 0x73, 0x6F, 0x6C, 0x76, 0x65, 0x72, 0x65, 0x6D, 0x6F, 0x0A, 0x74, 0x75, 0x74, + 0x74, 0x6F, 0x20, 0x66, 0x72, 0x61, 0x20, 0x70, 0x6F, 0x63, 0x6F, 0x2E, 0x00, 0x49, 0x61, 0x6E, + 0x2C, 0x20, 0x63, 0x6F, 0x73, 0x61, 0x20, 0x64, 0x65, 0x76, 0x6F, 0x0A, 0x66, 0x61, 0x72, 0x65, + 0x20, 0x70, 0x65, 0x72, 0x20, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x65, 0x0A, 0x73, 0x75, 0x6C, 0x6C, + 0x61, 0x20, 0x54, 0x45, 0x52, 0x52, 0x41, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x49, 0x6C, 0x20, 0x63, + 0x6F, 0x73, 0x74, 0x6F, 0x20, 0x64, 0x69, 0x20, 0x75, 0x6E, 0x0A, 0x62, 0x69, 0x67, 0x6C, 0x69, + 0x65, 0x74, 0x74, 0x6F, 0x20, 0x5C, 0x0A, 0x61, 0x73, 0x74, 0x72, 0x6F, 0x6E, 0x6F, 0x6D, 0x69, + 0x63, 0x6F, 0x2E, 0x0B, 0x4C, 0x27, 0x75, 0x6E, 0x69, 0x63, 0x6F, 0x20, 0x6D, 0x6F, 0x64, 0x6F, + 0x0A, 0x73, 0x61, 0x72, 0x65, 0x62, 0x62, 0x65, 0x20, 0x71, 0x75, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, + 0x64, 0x69, 0x20, 0x70, 0x61, 0x72, 0x74, 0x65, 0x63, 0x69, 0x70, 0x61, 0x72, 0x65, 0x20, 0x61, + 0x6C, 0x0A, 0x44, 0x65, 0x61, 0x74, 0x68, 0x20, 0x54, 0x6F, 0x77, 0x65, 0x72, 0x2E, 0x0B, 0xFF, + 0xE9, 0xEA, 0x44, 0x65, 0x61, 0x74, 0x68, 0x20, 0x54, 0x6F, 0x77, 0x65, 0x72, 0x3F, 0x0B, 0xFF, + 0xEB, 0xEC, 0x53, 0x69, 0x2C, 0x5C, 0x20, 0x75, 0x6E, 0x20, 0x67, 0x69, 0x6F, 0x63, 0x6F, 0x0A, + 0x74, 0x65, 0x6C, 0x65, 0x76, 0x69, 0x73, 0x69, 0x76, 0x6F, 0x2E, 0x20, 0x49, 0x6C, 0x0A, 0x76, + 0x69, 0x6E, 0x63, 0x69, 0x74, 0x6F, 0x72, 0x65, 0x20, 0x72, 0x69, 0x63, 0x65, 0x76, 0x65, 0x0A, + 0x75, 0x6E, 0x20, 0x62, 0x69, 0x67, 0x6C, 0x69, 0x65, 0x74, 0x74, 0x6F, 0x2E, 0x0B, 0xFF, 0xE9, + 0xEA, 0x4F, 0x2E, 0x6B, 0x2E, 0x20, 0x4D, 0x69, 0x20, 0x70, 0x75, 0x6F, 0x69, 0x0A, 0x66, 0x6F, + 0x72, 0x6E, 0x69, 0x72, 0x65, 0x20, 0x64, 0x65, 0x69, 0x0A, 0x64, 0x6F, 0x63, 0x75, 0x6D, 0x65, + 0x6E, 0x74, 0x69, 0x20, 0x66, 0x61, 0x6C, 0x73, 0x69, 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x4E, 0x6F, + 0x20, 0x70, 0x72, 0x6F, 0x62, 0x6C, 0x65, 0x6D, 0x6F, 0x2E, 0x0A, 0x56, 0x61, 0x69, 0x20, 0x61, + 0x6C, 0x20, 0x62, 0x61, 0x72, 0x0A, 0x65, 0x20, 0x63, 0x68, 0x69, 0x65, 0x64, 0x69, 0x20, 0x64, + 0x69, 0x0A, 0x4A, 0x61, 0x63, 0x6B, 0x2E, 0x0B, 0x44, 0x69, 0x67, 0x6C, 0x69, 0x20, 0x63, 0x68, + 0x65, 0x20, 0x74, 0x69, 0x20, 0x68, 0x6F, 0x0A, 0x6D, 0x61, 0x6E, 0x64, 0x61, 0x74, 0x6F, 0x20, + 0x69, 0x6F, 0x2E, 0x0A, 0x4F, 0x68, 0x2C, 0x61, 0x20, 0x70, 0x72, 0x6F, 0x70, 0x6F, 0x73, 0x69, + 0x74, 0x6F, 0x2E, 0x2E, 0x0B, 0x54, 0x69, 0x20, 0x68, 0x6F, 0x20, 0x6D, 0x65, 0x73, 0x73, 0x6F, + 0x0A, 0x6E, 0x65, 0x6C, 0x6C, 0x65, 0x20, 0x74, 0x61, 0x73, 0x63, 0x68, 0x65, 0x20, 0x69, 0x6C, + 0x0A, 0x63, 0x61, 0x6D, 0x70, 0x6F, 0x20, 0x64, 0x69, 0x20, 0x66, 0x6F, 0x72, 0x7A, 0x61, 0x0A, + 0x63, 0x68, 0x65, 0x20, 0x76, 0x6F, 0x6C, 0x65, 0x76, 0x69, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x4F, + 0x74, 0x74, 0x69, 0x6D, 0x6F, 0x2E, 0x20, 0x47, 0x72, 0x61, 0x7A, 0x69, 0x65, 0x0A, 0x49, 0x61, + 0x6E, 0x2E, 0x20, 0x43, 0x69, 0x20, 0x76, 0x65, 0x64, 0x69, 0x61, 0x6D, 0x6F, 0x0A, 0x61, 0x6C, + 0x6C, 0x61, 0x20, 0x70, 0x72, 0x6F, 0x73, 0x73, 0x69, 0x6D, 0x61, 0x2E, 0x2E, 0x2E, 0x00, 0xFF, + 0xEB, 0xEC, 0x42, 0x75, 0x6F, 0x6E, 0x61, 0x20, 0x66, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x61, 0x2E, + 0x0A, 0x74, 0x69, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x74, 0x74, 0x65, 0x72, 0x5E, 0x0A, 0x71, + 0x75, 0x61, 0x6E, 0x64, 0x6F, 0x20, 0x61, 0x72, 0x72, 0x69, 0x76, 0x65, 0x72, 0x61, 0x69, 0x0A, + 0x73, 0x75, 0x6C, 0x6C, 0x61, 0x20, 0x74, 0x65, 0x72, 0x72, 0x61, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, + 0x42, 0x65, 0x6E, 0x76, 0x65, 0x6E, 0x75, 0x74, 0x6F, 0x20, 0x61, 0x0A, 0x4E, 0x65, 0x77, 0x20, + 0x57, 0x61, 0x73, 0x68, 0x69, 0x6E, 0x67, 0x74, 0x6F, 0x6E, 0x2C, 0x0A, 0x67, 0x69, 0x6F, 0x76, + 0x61, 0x6E, 0x6F, 0x74, 0x74, 0x6F, 0x2E, 0x0B, 0x45, 0x63, 0x63, 0x6F, 0x20, 0x75, 0x6E, 0x61, + 0x20, 0x6D, 0x61, 0x70, 0x70, 0x61, 0x0A, 0x64, 0x65, 0x6C, 0x6C, 0x61, 0x20, 0x63, 0x69, 0x74, + 0x74, 0x5B, 0x20, 0x63, 0x68, 0x65, 0x0A, 0x70, 0x6F, 0x74, 0x72, 0x5B, 0x20, 0x65, 0x73, 0x73, + 0x65, 0x72, 0x74, 0x69, 0x0A, 0x75, 0x74, 0x69, 0x6C, 0x65, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x47, + 0x72, 0x61, 0x7A, 0x69, 0x65, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x42, 0x75, 0x6F, 0x6E, 0x61, 0x0A, + 0x67, 0x69, 0x6F, 0x72, 0x6E, 0x61, 0x74, 0x61, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x44, 0x65, 0x76, + 0x69, 0x20, 0x61, 0x76, 0x65, 0x72, 0x65, 0x20, 0x75, 0x6E, 0x0A, 0x70, 0x65, 0x72, 0x6D, 0x65, + 0x73, 0x73, 0x6F, 0x20, 0x70, 0x65, 0x72, 0x0A, 0x6C, 0x61, 0x76, 0x6F, 0x72, 0x61, 0x72, 0x65, + 0x0B, 0x50, 0x75, 0x6F, 0x69, 0x20, 0x6F, 0x74, 0x74, 0x65, 0x6E, 0x65, 0x72, 0x6E, 0x65, 0x0A, + 0x75, 0x6E, 0x6F, 0x20, 0x61, 0x6C, 0x20, 0x43, 0x65, 0x6E, 0x74, 0x72, 0x6F, 0x0A, 0x41, 0x6D, + 0x6D, 0x69, 0x6E, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x76, 0x6F, 0x2E, 0x00, 0xFF, 0xEB, + 0xEC, 0x4E, 0x6F, 0x6E, 0x20, 0x68, 0x6F, 0x0A, 0x74, 0x65, 0x6D, 0x70, 0x6F, 0x2E, 0x00, 0x42, + 0x75, 0x6F, 0x6E, 0x67, 0x69, 0x6F, 0x72, 0x6E, 0x6F, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x42, 0x75, + 0x6F, 0x6E, 0x67, 0x69, 0x6F, 0x72, 0x6E, 0x6F, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x48, 0x6F, 0x20, + 0x76, 0x69, 0x73, 0x74, 0x6F, 0x20, 0x71, 0x75, 0x65, 0x6C, 0x0A, 0x74, 0x69, 0x70, 0x6F, 0x20, + 0x70, 0x72, 0x69, 0x6D, 0x61, 0x0A, 0x61, 0x6C, 0x20, 0x62, 0x61, 0x72, 0x2E, 0x00, 0x42, 0x75, + 0x6F, 0x6E, 0x67, 0x69, 0x6F, 0x72, 0x6E, 0x6F, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x42, 0x75, 0x6F, + 0x6E, 0x67, 0x69, 0x6F, 0x72, 0x6E, 0x6F, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x53, 0x69, 0x2C, 0x20, + 0x6C, 0x6F, 0x20, 0x63, 0x6F, 0x6E, 0x6F, 0x73, 0x63, 0x6F, 0x2E, 0x0A, 0x45, 0x27, 0x20, 0x63, + 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x65, 0x20, 0x66, 0x69, 0x73, 0x73, 0x6F, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x56, 0x6F, 0x72, 0x72, 0x65, 0x69, 0x20, 0x75, 0x6E, 0x20, 0x70, 0x65, 0x72, 0x2D, 0x0A, + 0x6D, 0x65, 0x73, 0x73, 0x6F, 0x20, 0x64, 0x69, 0x20, 0x6C, 0x61, 0x76, 0x6F, 0x72, 0x6F, 0x2E, + 0x0B, 0xFF, 0xEB, 0xEC, 0x4E, 0x6F, 0x6E, 0x20, 0x63, 0x27, 0x5C, 0x20, 0x70, 0x72, 0x6F, 0x62, + 0x6C, 0x65, 0x6D, 0x61, 0x0A, 0x61, 0x64, 0x20, 0x61, 0x76, 0x65, 0x72, 0x65, 0x20, 0x75, 0x6E, + 0x0A, 0x70, 0x65, 0x72, 0x6D, 0x65, 0x73, 0x73, 0x6F, 0x2E, 0x2E, 0x2E, 0x0B, 0x4C, 0x61, 0x20, + 0x73, 0x75, 0x61, 0x20, 0x63, 0x61, 0x72, 0x74, 0x61, 0x20, 0x64, 0x69, 0x0A, 0x69, 0x64, 0x65, + 0x6E, 0x74, 0x69, 0x74, 0x5B, 0x2C, 0x20, 0x70, 0x72, 0x65, 0x67, 0x6F, 0x2E, 0x00, 0xFF, 0xEB, + 0xEC, 0x41, 0x49, 0x55, 0x54, 0x4F, 0x2E, 0x2E, 0x2E, 0x41, 0x49, 0x55, 0x54, 0x4F, 0x2E, 0x2E, + 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x41, 0x69, 0x75, 0x74, 0x61, 0x6D, 0x69, 0x20, 0x67, 0x69, 0x6F, + 0x76, 0x61, 0x6E, 0x65, 0x2E, 0x0A, 0x53, 0x6F, 0x6E, 0x6F, 0x20, 0x73, 0x74, 0x61, 0x74, 0x6F, + 0x0A, 0x61, 0x74, 0x74, 0x61, 0x63, 0x63, 0x61, 0x74, 0x6F, 0x20, 0x64, 0x61, 0x69, 0x0A, 0x6D, + 0x75, 0x74, 0x61, 0x6E, 0x74, 0x69, 0x2E, 0x2E, 0x2E, 0x0B, 0x65, 0x20, 0x6E, 0x6F, 0x6E, 0x20, + 0x70, 0x6F, 0x73, 0x73, 0x6F, 0x0A, 0x63, 0x61, 0x6D, 0x6D, 0x69, 0x6E, 0x61, 0x72, 0x65, 0x2E, + 0x0B, 0x54, 0x72, 0x6F, 0x76, 0x61, 0x20, 0x69, 0x6C, 0x20, 0x6D, 0x69, 0x6F, 0x0A, 0x74, 0x65, + 0x6C, 0x65, 0x74, 0x72, 0x61, 0x73, 0x70, 0x6F, 0x72, 0x74, 0x6F, 0x2C, 0x68, 0x6F, 0x0A, 0x62, + 0x69, 0x73, 0x6F, 0x67, 0x6E, 0x6F, 0x20, 0x64, 0x69, 0x0A, 0x63, 0x75, 0x72, 0x65, 0x20, 0x75, + 0x72, 0x67, 0x65, 0x6E, 0x74, 0x69, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x47, 0x72, 0x61, 0x7A, 0x69, + 0x65, 0x2E, 0x20, 0x4D, 0x69, 0x20, 0x68, 0x61, 0x69, 0x0A, 0x73, 0x61, 0x6C, 0x76, 0x61, 0x74, + 0x6F, 0x20, 0x6C, 0x61, 0x20, 0x76, 0x69, 0x74, 0x61, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x50, 0x65, + 0x72, 0x20, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x65, 0x20, 0x61, 0x20, 0x4E, 0x65, 0x77, 0x0A, 0x57, + 0x61, 0x73, 0x68, 0x69, 0x6E, 0x67, 0x74, 0x6F, 0x6E, 0x2C, 0x20, 0x64, 0x65, 0x76, 0x69, 0x0A, + 0x73, 0x61, 0x6C, 0x74, 0x61, 0x72, 0x65, 0x20, 0x69, 0x6E, 0x0A, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x6F, 0x20, 0x62, 0x75, 0x63, 0x6F, 0x2C, 0x0B, 0x6D, 0x61, 0x20, 0x73, 0x65, 0x20, 0x66, 0x6F, + 0x73, 0x73, 0x69, 0x20, 0x69, 0x6E, 0x0A, 0x74, 0x65, 0x2C, 0x20, 0x75, 0x73, 0x65, 0x72, 0x65, + 0x69, 0x20, 0x75, 0x6E, 0x61, 0x0A, 0x63, 0x69, 0x6E, 0x74, 0x75, 0x72, 0x61, 0x20, 0x41, 0x6E, + 0x74, 0x69, 0x2D, 0x47, 0x2E, 0x0B, 0xFF, 0xE9, 0xEA, 0x44, 0x6F, 0x76, 0x65, 0x20, 0x70, 0x6F, + 0x73, 0x73, 0x6F, 0x0A, 0x74, 0x72, 0x6F, 0x76, 0x61, 0x72, 0x6E, 0x65, 0x20, 0x75, 0x6E, 0x61, + 0x3F, 0x0B, 0xFF, 0xEB, 0xEC, 0x53, 0x75, 0x62, 0x69, 0x74, 0x6F, 0x2C, 0x20, 0x74, 0x65, 0x20, + 0x6E, 0x65, 0x0A, 0x76, 0x65, 0x6E, 0x64, 0x6F, 0x20, 0x75, 0x6E, 0x61, 0x3A, 0x0A, 0x35, 0x30, + 0x30, 0x20, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x69, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x42, 0x75, + 0x6F, 0x6E, 0x20, 0x76, 0x69, 0x61, 0x67, 0x67, 0x69, 0x6F, 0x2C, 0x0A, 0x67, 0x69, 0x6F, 0x76, + 0x61, 0x6E, 0x65, 0x20, 0x75, 0x6F, 0x6D, 0x6F, 0x2E, 0x00, 0x48, 0x6F, 0x20, 0x62, 0x69, 0x73, + 0x6F, 0x67, 0x6E, 0x6F, 0x20, 0x64, 0x69, 0x0A, 0x75, 0x6E, 0x61, 0x20, 0x63, 0x61, 0x72, 0x74, + 0x75, 0x63, 0x63, 0x69, 0x61, 0x0A, 0x6D, 0x61, 0x67, 0x6E, 0x65, 0x74, 0x69, 0x63, 0x61, 0x20, + 0x63, 0x61, 0x72, 0x69, 0x63, 0x61, 0x00, 0x56, 0x6F, 0x72, 0x72, 0x65, 0x69, 0x20, 0x75, 0x6E, + 0x20, 0x70, 0x65, 0x72, 0x2D, 0x0A, 0x6D, 0x65, 0x73, 0x73, 0x6F, 0x20, 0x64, 0x69, 0x20, 0x6C, + 0x61, 0x76, 0x6F, 0x72, 0x6F, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x50, 0x72, 0x69, 0x6D, 0x6F, 0x20, + 0x70, 0x69, 0x61, 0x6E, 0x6F, 0x2E, 0x00, 0x55, 0x6E, 0x61, 0x20, 0x76, 0x6F, 0x63, 0x65, 0x20, + 0x69, 0x6E, 0x74, 0x65, 0x2D, 0x0A, 0x72, 0x69, 0x6F, 0x72, 0x65, 0x20, 0x69, 0x6E, 0x74, 0x65, + 0x72, 0x72, 0x6F, 0x6D, 0x70, 0x65, 0x0A, 0x69, 0x20, 0x74, 0x75, 0x6F, 0x69, 0x20, 0x70, 0x65, + 0x6E, 0x73, 0x69, 0x65, 0x72, 0x69, 0x2E, 0x0B, 0xFF, 0xEB, 0xEC, 0x46, 0x69, 0x64, 0x61, 0x74, + 0x69, 0x2C, 0x20, 0x6D, 0x65, 0x74, 0x74, 0x69, 0x0A, 0x6C, 0x61, 0x20, 0x63, 0x61, 0x72, 0x69, + 0x63, 0x61, 0x0A, 0x61, 0x74, 0x6F, 0x6D, 0x69, 0x63, 0x61, 0x20, 0x71, 0x75, 0x69, 0x2E, 0x2E, + 0x2E, 0x0B, 0x65, 0x20, 0x73, 0x63, 0x61, 0x70, 0x70, 0x61, 0x20, 0x6E, 0x6F, 0x6E, 0x0A, 0x61, + 0x70, 0x70, 0x65, 0x6E, 0x61, 0x20, 0x72, 0x61, 0x67, 0x67, 0x69, 0x75, 0x6E, 0x67, 0x65, 0x0A, + 0x69, 0x6C, 0x20, 0x6E, 0x75, 0x63, 0x6C, 0x65, 0x6F, 0x0A, 0x64, 0x65, 0x6C, 0x20, 0x70, 0x69, + 0x61, 0x6E, 0x65, 0x74, 0x61, 0x2E, 0x00, 0xFF, 0xEB, 0xEC, 0x46, 0x61, 0x69, 0x20, 0x73, 0x74, + 0x72, 0x61, 0x64, 0x61, 0x2C, 0x0A, 0x67, 0x69, 0x6F, 0x76, 0x61, 0x6E, 0x65, 0x20, 0x75, 0x6F, + 0x6D, 0x6F, 0x2E, 0x0B, 0x50, 0x6F, 0x72, 0x74, 0x61, 0x6D, 0x69, 0x20, 0x61, 0x6C, 0x0A, 0x43, + 0x65, 0x6E, 0x74, 0x72, 0x6F, 0x20, 0x52, 0x69, 0x63, 0x65, 0x72, 0x63, 0x68, 0x65, 0x2E, 0x00, + 0xFF, 0xEB, 0xEC, 0x47, 0x72, 0x61, 0x7A, 0x69, 0x65, 0x20, 0x70, 0x65, 0x72, 0x20, 0x69, 0x6C, + 0x0A, 0x74, 0x75, 0x6F, 0x20, 0x61, 0x69, 0x75, 0x74, 0x6F, 0x2E, 0x2E, 0x2E, 0x0B, 0x53, 0x6F, + 0x6E, 0x6F, 0x20, 0x61, 0x72, 0x72, 0x69, 0x76, 0x61, 0x74, 0x6F, 0x0A, 0x73, 0x61, 0x6E, 0x6F, + 0x20, 0x65, 0x20, 0x73, 0x61, 0x6C, 0x76, 0x6F, 0x0A, 0x65, 0x20, 0x6E, 0x6F, 0x6E, 0x20, 0x63, + 0x27, 0x5C, 0x20, 0x70, 0x69, 0x5F, 0x0A, 0x70, 0x65, 0x72, 0x69, 0x63, 0x6F, 0x6C, 0x6F, 0x2E, + 0x00, 0xFF, 0xEB, 0xEC, 0x41, 0x6C, 0x6C, 0x6F, 0x72, 0x61, 0x2C, 0x20, 0x68, 0x61, 0x69, 0x0A, + 0x70, 0x6F, 0x72, 0x74, 0x61, 0x74, 0x6F, 0x20, 0x69, 0x6C, 0x0A, 0x70, 0x61, 0x63, 0x63, 0x68, + 0x65, 0x74, 0x74, 0x6F, 0x3F, 0x00, 0x51, 0x75, 0x61, 0x6E, 0x74, 0x6F, 0x20, 0x63, 0x6F, 0x73, + 0x74, 0x61, 0x20, 0x75, 0x6E, 0x0A, 0x62, 0x69, 0x67, 0x6C, 0x69, 0x65, 0x74, 0x74, 0x6F, 0x20, + 0x70, 0x65, 0x72, 0x0A, 0x6C, 0x61, 0x20, 0x74, 0x65, 0x72, 0x72, 0x61, 0x3F, 0x0B, 0xFF, 0xEB, + 0xEC, 0x35, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x20, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x69, 0x2E, + 0x00, 0xFF, 0xEB, 0xEC, 0x49, 0x6F, 0x20, 0x64, 0x5E, 0x20, 0x75, 0x6E, 0x61, 0x20, 0x6D, 0x61, + 0x6E, 0x6F, 0x20, 0x61, 0x0A, 0x74, 0x65, 0x20, 0x65, 0x20, 0x74, 0x75, 0x20, 0x6E, 0x65, 0x20, + 0x64, 0x61, 0x69, 0x0A, 0x75, 0x6E, 0x61, 0x20, 0x61, 0x20, 0x6D, 0x65, 0x3A, 0x0B, 0x31, 0x35, + 0x30, 0x30, 0x20, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x69, 0x20, 0x65, 0x0A, 0x69, 0x20, 0x64, + 0x6F, 0x63, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x69, 0x0A, 0x73, 0x6F, 0x6E, 0x6F, 0x20, 0x74, 0x75, + 0x6F, 0x69, 0x2E, 0x00 +}; + +const char *LocaleData::_textsTableFR[] = { + "CONTINUER OU ABANDONNER ?", + "TEMPS", + "CONTINUER", + "ABANDONNER", + "TERMINEE", + "NIVEAU", + "START", + "DIFFICULTE", + "MOT DE PASSE", + "INFO", + "QUITTER", + "NIVEAU DE DIFFICULTE :", + "FACILE", + "NORMAL", + "EXPERT", + "ENTREZ LE MOT DE PASSE POUR", + "ACCEDER AU NIVEAU SOUHAITE:", + "REPRENDRE", + "ABANDONNER", + "CHARGER", + "SAUVEGARDER", + "PARTIE" +}; + +const char *LocaleData::_textsTableEN[] = { + "CONTINUE OR ABORT THIS GAME ?", + "TIME", + "CONTINUE", + "ABORT", + "COMPLETED", + "LEVEL", + "START", + "SKILL", + "PASSWORD", + "INFO", + "QUIT", + "SKILL LEVEL :", + "EASY", + "NORMAL", + "EXPERT", + "Enter password for desired", + "level :", + "RESUME GAME", + "ABORT GAME", + "LOAD GAME", + "SAVE GAME", + "SLOT" +}; + +const char *LocaleData::_textsTableDE[] = { + "WEITERSPIELEN ODER ABBRECHEN ?", + "ZEIT : ", + "WEITERSPIELEN", + "ABBRECHEN", + "FERTIG", + "LEVEL", + "START", + "SKILL", + "PASSWORD", + "INFO", + "END", + "SKILL LEVEL :", + "LEICHT", + "NORMAL", + "PROFI", + "GEBEN SIE DAS PASSWORT F[R", + "DAS GEW[NSCHTE LEVEL EIN :", + "WEITERSPIELEN", + "SPIEL ABBRECHEN", + "LADEN", + "SPEICHERN", + "SPIEL" +}; + +const char *LocaleData::_textsTableSP[] = { + "CONTINUAR O TERMINAR JUEGO ?", + "TIEMPO", + "SEGUIR", + "PARAR", + "PUNTOS", + "NIVEL", + "EMPEZAR", + "DIFICULTAD", + "CONTRASE}A", + "INFO", + "SALIR", + "NIVEL DE DIFICULTAD :", + "SENCILLO", + "NORMAL", + "EXPERTO", + "ESCRIBA LA CONTRASE}A", + "PARA EL NIVEL DESEADO :", + "REANUDAR JUEGO", + "PARAR JUEGO", + "CARGAR DATOS", + "GUARDAR DATOS", + "JUEGO" +}; + +const char *LocaleData::_textsTableIT[] = { + "CONTINUA O ABBANDONA GIOCO", + "TEMPO", + "CONTINUA", + "ESCI", + "ABBANDONA", + "LIVELLO", + "INIZIO", + "ABILITA", + "PASSWORD", + "INFORMAZIONI", + "ESCI", + "LIVELLO ABILITA :", + "FACILE", + "NORMAL", + "EXPERTO", + "INSERISCI LA PASSWORD PER", + "IL LIVELLO DESIDERATO :", + "RIPRENDI GIOCO", + "ESCI DAL GIOCO", + "CARICA IL GIOCO", + "SALVA IL GIOCO", + "SLOT" +}; + +const uint16_t Resource::_voicesOffsetsTable[] = { + 0x0064, 0x006A, 0x0070, 0x0084, 0x0090, 0x0096, 0x009E, 0x00A4, 0x00AE, 0x00B4, + 0x00BC, 0x00C4, 0x00CC, 0x00D4, 0x00E0, 0x00E6, 0x00EC, 0x00F6, 0x00FC, 0x0102, + 0x010C, 0x0126, 0x0130, 0x0136, 0x013E, 0x0144, 0x014C, 0x0152, 0x015A, 0x0160, + 0x0166, 0x016C, 0x0176, 0x017C, 0x0186, 0x018C, 0x0198, 0x019E, 0x01A4, 0x01AC, + 0x01B6, 0x01BE, 0x01C6, 0x01CC, 0x01D4, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0x0000, 0x0001, 0x0073, 0x0073, 0x0001, 0x0050, 0x00C3, 0x0008, 0x00D7, 0x007D, + 0x0078, 0x007D, 0x0087, 0x005A, 0x00E1, 0x0087, 0x0555, 0x0004, 0x00D7, 0x0069, + 0x00EB, 0x00A5, 0x0825, 0x0001, 0x008C, 0x08B1, 0x0002, 0x00CD, 0x0073, 0x09F1, + 0x0001, 0x0113, 0x0B04, 0x0003, 0x0113, 0x008C, 0x00B9, 0x0D5C, 0x0001, 0x0096, + 0x0DF2, 0x0002, 0x00AF, 0x0082, 0x0F23, 0x0002, 0x0069, 0x009B, 0x1027, 0x0002, + 0x0069, 0x00EB, 0x117B, 0x0002, 0x0069, 0x00C3, 0x12A7, 0x0004, 0x0064, 0x00AA, + 0x0078, 0x00DC, 0x1509, 0x0001, 0x00B4, 0x15BD, 0x0001, 0x0046, 0x1603, 0x0003, + 0x0050, 0x0118, 0x00A5, 0x1810, 0x0001, 0x0041, 0x1851, 0x0001, 0x0082, 0x18D3, + 0x0003, 0x0104, 0x00D7, 0x00AF, 0x1B5D, 0x000B, 0x00AA, 0x00BE, 0x0127, 0x005A, + 0x00F5, 0x00AA, 0x0104, 0x00BE, 0x00DC, 0x00B9, 0x00D7, 0x2413, 0x0003, 0x00C3, + 0x00E6, 0x003C, 0x25F8, 0x0001, 0x0069, 0x2661, 0x0002, 0x00BE, 0x00AF, 0x27CE, + 0x0001, 0x0050, 0x281E, 0x0002, 0x0041, 0x0037, 0x2896, 0x0001, 0x011D, 0x29B3, + 0x0002, 0x0041, 0x003C, 0x2A30, 0x0001, 0x00A5, 0x2AD5, 0x0001, 0x0000, 0x2AD5, + 0x0001, 0x0000, 0x2AD5, 0x0003, 0x005A, 0x00B9, 0x0073, 0x2C5B, 0x0001, 0x005F, + 0x2CBA, 0x0003, 0x00DC, 0x0064, 0x00F0, 0x2EEA, 0x0001, 0x00B9, 0x2FA3, 0x0004, + 0x0181, 0x013B, 0x005F, 0x0154, 0x3412, 0x0001, 0x00AF, 0x34C1, 0x0001, 0x00A0, + 0x3561, 0x0002, 0x0069, 0x003C, 0x3606, 0x0003, 0x0000, 0x00FA, 0x00F0, 0x37F0, + 0x0002, 0x006E, 0x00A0, 0x38FE, 0x0002, 0x0064, 0x00E6, 0x3A48, 0x0001, 0x00A5, + 0x3AED, 0x0002, 0x0078, 0x0087, 0x3BEC, 0x0002, 0x00AA, 0x00F0 +}; + +const uint32_t Resource::_spmOffsetsTable[1287] = { + 0x00000, 0x000C5, 0x001AC, 0x00299, 0x00383, 0x00454, 0x0053B, 0x00627, + 0x00713, 0x007EA, 0x008C8, 0x009AE, 0x00A9B, 0x00B80, 0x00D39, 0x00EF5, + 0x00FE1, 0x010C2, 0x011AD, 0x01362, 0x01513, 0x016BA, 0x017A1, 0x0188A, + 0x0198C, 0x01A62, 0x01B2C, 0x01BD4, 0x01C78, 0x01D04, 0x01D9F, 0x01E40, + 0x01EFF, 0x01FD2, 0x0209C, 0x02167, 0x02232, 0x022EB, 0x02397, 0x02433, + 0x024CC, 0x02558, 0x025D3, 0x02662, 0x02739, 0x027C1, 0x0285E, 0x0290D, + 0x029E6, 0x02AC4, 0x02BA7, 0x02C8A, 0x02E09, 0x02ECF, 0x02FA2, 0x0313E, + 0x032F3, 0x03499, 0x0363A, 0x037BA, 0x0393F, 0x03AD4, 0x03C63, 0x03D24, + 0x03DF5, 0x03F99, 0x0413F, 0x042DA, 0x04472, 0x045FA, 0x0477D, 0x048F0, + 0x049DA, 0x04AC2, 0x04BA6, 0x04C88, 0x04E2B, 0x04FC0, 0x0514D, 0x052D6, + 0x0544D, 0x055D7, 0x0569F, 0x05854, 0x059CC, 0x05B57, 0x05CE4, 0x05E49, + 0x05F9E, 0x060F8, 0x061BA, 0x0628A, 0x0636B, 0x0643E, 0x06505, 0x065D6, + 0x0674A, 0x068D1, 0x06A5E, 0x06BC3, 0x06D10, 0x06E5B, 0x06FA3, 0x070DD, + 0x07219, 0x0734C, 0x0749A, 0x075F9, 0x0776A, 0x078FB, 0x07A8B, 0x07B60, + 0x07C25, 0x07CEB, 0x07DC8, 0x07E9F, 0x0803F, 0x081DD, 0x08371, 0x08444, + 0x0852C, 0x085EF, 0x086BA, 0x08839, 0x08992, 0x08AE7, 0x08C58, 0x08D27, + 0x08DED, 0x08EAF, 0x08F71, 0x0901F, 0x090D1, 0x09189, 0x09239, 0x092E5, + 0x0938F, 0x094D7, 0x09608, 0x0969B, 0x09724, 0x0979B, 0x09816, 0x0989F, + 0x0995B, 0x09AC8, 0x09C4A, 0x09DD5, 0x09F61, 0x0A020, 0x0A0DF, 0x0A184, + 0x0A218, 0x0A2BD, 0x0A3EE, 0x0A509, 0x0A633, 0x0A755, 0x0A86D, 0x0A8FF, + 0x0A99B, 0x0AA38, 0x0AB65, 0x0AC9E, 0x0ADFF, 0x0AF7A, 0x0B051, 0x0B121, + 0x0B1F6, 0x0B2CF, 0x0B3B6, 0x0B49D, 0x0B596, 0x0B681, 0x0B744, 0x0B801, + 0x0B8B2, 0x0B954, 0x0B9F5, 0x0BAA1, 0x0BBFF, 0x0BD69, 0x0BED3, 0x0C03A, + 0x0C188, 0x0C2DD, 0x0C422, 0x0C4C8, 0x0C55C, 0x0C5EF, 0x0C683, 0x0C734, + 0x0C7FC, 0x0C8D1, 0x0CA54, 0x0CBC0, 0x0CD36, 0x0CEA7, 0x0CF5A, 0x0D0C2, + 0x0D188, 0x0D272, 0x0D3C2, 0x0D503, 0x0D631, 0x0D75C, 0x0D87E, 0x0D933, + 0x0D9E2, 0x0DA9D, 0x0DB5C, 0x0DC96, 0x0DD51, 0x0DE39, 0x0DF3E, 0x0E041, + 0x0E129, 0x0E211, 0x0E383, 0x0E4E5, 0x0E619, 0x0E732, 0x0E848, 0x0E944, + 0x0EA47, 0x0EB52, 0x0EC5F, 0x0ED6F, 0x0EE6F, 0x0EF59, 0x0EFD4, 0x0F04A, + 0x0F119, 0x0F1DF, 0x0F2B1, 0x0F38F, 0x0F462, 0x0F57A, 0x0F6B1, 0x0F807, + 0x0F8D2, 0x0F9B5, 0x0FA9E, 0x0FBA3, 0x0FC4B, 0x0FD2C, 0x0FD92, 0x0FE5B, + 0x0FEC6, 0x0FF2B, 0x0FF8B, 0x0FFFB, 0x10078, 0x10101, 0x1019D, 0x1024D, + 0x10320, 0x103FA, 0x1057D, 0x106FC, 0x1087B, 0x10945, 0x10A14, 0x10AE7, + 0x10BC3, 0x10C92, 0x10D63, 0x10E3A, 0x10F12, 0x10FF6, 0x111AA, 0x1133F, + 0x114DA, 0x11672, 0x11814, 0x119BA, 0x11B60, 0x11CF3, 0x11E7D, 0x12015, + 0x121C3, 0x12368, 0x1250D, 0x126AB, 0x1284D, 0x129E7, 0x12B85, 0x12D39, + 0x12EC8, 0x1303F, 0x1319E, 0x132E5, 0x13410, 0x1352C, 0x135C5, 0x13669, + 0x13711, 0x13841, 0x1395D, 0x13A69, 0x13C00, 0x13CDB, 0x13DAF, 0x13E81, + 0x13F53, 0x14076, 0x14196, 0x1422F, 0x142C7, 0x14360, 0x143F7, 0x144CF, + 0x145A8, 0x14680, 0x14757, 0x1482F, 0x14907, 0x149E1, 0x14AB3, 0x14B89, + 0x14C5D, 0x14D3D, 0x14E1E, 0x14F05, 0x14FF1, 0x150D7, 0x1527C, 0x153BD, + 0x15478, 0x15561, 0x1566D, 0x15772, 0x15862, 0x1596B, 0x15A7C, 0x15B83, + 0x15C81, 0x15D80, 0x15E7F, 0x15F7F, 0x16072, 0x1613D, 0x16211, 0x162EA, + 0x163A0, 0x16438, 0x164B9, 0x1652A, 0x16604, 0x166E4, 0x167BE, 0x16948, + 0x16AE2, 0x16C57, 0x16D17, 0x16DF1, 0x16F96, 0x17083, 0x17168, 0x17249, + 0x1732F, 0x17411, 0x174F1, 0x175BC, 0x176A9, 0x17791, 0x17870, 0x17952, + 0x17AF2, 0x17C96, 0x17E2F, 0x17F04, 0x17FD9, 0x180AE, 0x18183, 0x18253, + 0x1831D, 0x183F2, 0x18583, 0x18703, 0x18884, 0x18A01, 0x18B7C, 0x18CFD, + 0x18E8A, 0x1900D, 0x1919F, 0x19348, 0x194EA, 0x1967D, 0x197FA, 0x19989, + 0x19B14, 0x19BE9, 0x19CC0, 0x19DA9, 0x19E77, 0x19F49, 0x1A01B, 0x1A0FA, + 0x1A1C0, 0x1A298, 0x1A37E, 0x1A3F7, 0x1A574, 0x1A6CD, 0x1A812, 0x1A94A, + 0x1AA80, 0x1AB98, 0x1ACA3, 0x1ADD8, 0x1AEC3, 0x1AF9C, 0x1B071, 0x1B125, + 0x1B1E1, 0x1B2A7, 0x1B339, 0x1B39F, 0x1B411, 0x1B54D, 0x1B6A1, 0x1B814, + 0x1B9A9, 0x1BA87, 0x1BB73, 0x1BCE7, 0x1BE2C, 0x1BF22, 0x1BFD9, 0x1C04E, + 0x1C0B2, 0x1C10C, 0x1C166, 0x1C1C0, 0x1C363, 0x1C454, 0x1C534, 0x1C616, + 0x1C706, 0x1C7EC, 0x1C8D3, 0x1C9B7, 0x1CAA4, 0x1CC5C, 0x1CDB4, 0x1CF00, + 0x1D044, 0x1D1A2, 0x1D2ED, 0x1D3F7, 0x1D49F, 0x1D540, 0x1D5FD, 0x1D703, + 0x1D80A, 0x1D91E, 0x1DA48, 0x1DB58, 0x1DC63, 0x1DD2D, 0x1DDB2, 0x1DE1D, + 0x1DE74, 0x1DEBB, 0x1DFD0, 0x1E0C0, 0x1E177, 0x1E2CF, 0x1E402, 0x1E505, + 0x1E5C1, 0x1E627, 0x1E705, 0x1E7A8, 0x1E81A, 0x1E874, 0x1E8CE, 0x1E928, + 0x1E982, 0x1E9E5, 0x1EA64, 0x1EB07, 0x1EBB6, 0x1EC81, 0x1ED58, 0x1EE30, + 0x1EF08, 0x1F01D, 0x1F0C0, 0x1F170, 0x1F233, 0x1F3D3, 0x1F5BD, 0x1F6C3, + 0x1F7B7, 0x1F89C, 0x1FA67, 0x1FC0B, 0x1FD7D, 0x1FEAB, 0x1FFBD, 0x2019E, + 0x20354, 0x20511, 0x206C1, 0x2089E, 0x20A66, 0x20B44, 0x20C87, 0x20D0D, + 0x20D8B, 0x20E0D, 0x20E7F, 0x20ED9, 0x20F4B, 0x20FD3, 0x21059, 0x210DF, + 0x21179, 0x21223, 0x212E4, 0x2139E, 0x21458, 0x2151F, 0x215D2, 0x216A0, + 0x21770, 0x2182D, 0x218EB, 0x219AD, 0x21A1B, 0x21A9D, 0x21B37, 0x21BE4, + 0x21C9E, 0x21D5E, 0x21E1C, 0x21EE3, 0x21FAF, 0x22067, 0x2211E, 0x22210, + 0x22321, 0x2244D, 0x22516, 0x225D5, 0x2269C, 0x2280B, 0x229A3, 0x22B6B, + 0x22C45, 0x22DE5, 0x22F76, 0x2310E, 0x232A7, 0x2345B, 0x23623, 0x2B9D7, + 0x2BB9B, 0x2BD57, 0x2BF22, 0x2C0ED, 0x2C2AD, 0x2C46C, 0x2C631, 0x2C7F8, + 0x2C9B4, 0x2CB6F, 0x2CD2A, 0x2CEE7, 0x2D0B0, 0x2D284, 0x2D458, 0x2D622, + 0x2D7E8, 0x2D9AF, 0x2DB6F, 0x2DD41, 0x2DF14, 0x2E104, 0x2E309, 0x2E517, + 0x2E71C, 0x2E92F, 0x2EB47, 0x2ED4C, 0x2EF2E, 0x2F0FF, 0x2F2D5, 0x2F4A7, + 0x2F670, 0x2F827, 0x2F9D3, 0x2FB73, 0x2FD28, 0x2FEDD, 0x300AD, 0x3029A, + 0x30487, 0x3065D, 0x30833, 0x30A08, 0x30BDF, 0x30DB5, 0x30F8E, 0x30F93, + 0x31168, 0x3133D, 0x31512, 0x316E7, 0x318BC, 0x31A91, 0x31C5E, 0x31E22, + 0x31FE1, 0x32194, 0x3232E, 0x3249F, 0x325E5, 0x3270A, 0x32835, 0x3297C, + 0x32B67, 0x32D5D, 0x32F34, 0x330EC, 0x33299, 0x33428, 0x335B5, 0x33714, + 0x3382E, 0x3393B, 0x339FF, 0x33A95, 0x33B50, 0x33C13, 0x33CA2, 0x33D21, + 0x33D8F, 0x33DE7, 0x33E35, 0x3402E, 0x341EF, 0x34343, 0x344AE, 0x345D6, + 0x346DF, 0x347E7, 0x348D1, 0x34967, 0x349FD, 0x34A7B, 0x23726, 0x237A3, + 0x23826, 0x238AD, 0x23936, 0x23A3A, 0x23B3E, 0x23BC8, 0x23CD9, 0x23DEF, + 0x23F0B, 0x240C2, 0x241AD, 0x24295, 0x2443F, 0x245E5, 0x2478B, 0x24933, + 0x24ACD, 0x24C66, 0x24E09, 0x24FD1, 0x251A7, 0x2537F, 0x25483, 0x255E7, + 0x256DA, 0x257C6, 0x25837, 0x258B9, 0x25953, 0x25A00, 0x25AC1, 0x25B9C, + 0x25C7D, 0x25D5C, 0x25E3C, 0x25F14, 0x26029, 0x260D7, 0x261FA, 0x262A0, + 0x26348, 0x263F8, 0x264AD, 0x26557, 0x265FF, 0x266A7, 0x26752, 0x2687D, + 0x26922, 0x269C2, 0x26A74, 0x26BE6, 0x26D86, 0x26E49, 0x26F08, 0x26FEA, + 0x270CC, 0x271AC, 0x2728E, 0x27370, 0x27451, 0x2751C, 0x275EB, 0x276B5, + 0x27792, 0x2792E, 0x27ABD, 0x27C55, 0x27D33, 0x27E06, 0x27F00, 0x2800C, + 0x280A3, 0x281CD, 0x282E7, 0x283FE, 0x284A6, 0x28572, 0x2863D, 0x286FD, + 0x287A8, 0x28849, 0x288E2, 0x2896D, 0x289F4, 0x28A75, 0x28AF7, 0x28B80, + 0x28C1B, 0x28CD2, 0x2B9D7, 0x2BBB2, 0x2BD81, 0x2BF42, 0x2C105, 0x2C2CA, + 0x2C47D, 0x2C645, 0x2C817, 0x2C9F2, 0x2CBB2, 0x2CD68, 0x2CF20, 0x2D0CA, + 0x2D265, 0x2D420, 0x2D5F4, 0x2D6D6, 0x2D7C2, 0x2D97B, 0x2DA59, 0x2DB2E, + 0x2DC07, 0x2DCF3, 0x2DDDB, 0x2DEC6, 0x2E091, 0x2E256, 0x2E41A, 0x2E5DE, + 0x2E7B7, 0x2E956, 0x2EAFE, 0x2ECA7, 0x2EE55, 0x2F035, 0x2F215, 0x2F3E5, + 0x2F4D2, 0x2F5C1, 0x2F786, 0x2F953, 0x2FB21, 0x2FD03, 0x2FEEA, 0x300CE, + 0x302CB, 0x304D5, 0x306DF, 0x308C9, 0x30AB3, 0x30C87, 0x30E5B, 0x3102F, + 0x31203, 0x313D7, 0x315BB, 0x31787, 0x3195B, 0x31B2F, 0x31D03, 0x31EE9, + 0x320CC, 0x322AC, 0x3247B, 0x3265B, 0x3283B, 0x32A2D, 0x32C1F, 0x32E11, + 0x33003, 0x331D3, 0x33379, 0x3351E, 0x336BF, 0x33883, 0x33A44, 0x33C05, + 0x33DD8, 0x33F9C, 0x3415C, 0x34341, 0x34514, 0x34608, 0x346EF, 0x347D6, + 0x348CE, 0x34AA5, 0x34C78, 0x34E6A, 0x3505C, 0x3524E, 0x35440, 0x35632, + 0x35824, 0x3590C, 0x35AB2, 0x35C7D, 0x35E3A, 0x35FF0, 0x36184, 0x36313, + 0x36470, 0x36597, 0x36662, 0x3672A, 0x367C4, 0x3682B, 0x36878, 0x368B1, + 0x368D5, 0x368E7, 0x36AAE, 0x36C67, 0x36E0A, 0x36F74, 0x3708E, 0x37163, + 0x3723A, 0x37332, 0x37456, 0x375A7, 0x3771B, 0x37893, 0x379EE, 0x37B39, + 0x37C54, 0x37CD8, 0x37D08, 0x37D0F, 0x37EBC, 0x3804C, 0x3823E, 0x38404, + 0x385BF, 0x387B2, 0x38997, 0x38B7E, 0x38D55, 0x38F2C, 0x39103, 0x392DB, + 0x394B0, 0x3967B, 0x3983C, 0x39A03, 0x39B8C, 0x39CF6, 0x39E55, 0x39F90, + 0x3A0CB, 0x3A209, 0x3A353, 0x3A49B, 0x3A5D6, 0x3A711, 0x28D70, 0x2B9D7, + 0x2BBAD, 0x2BD84, 0x2BF5A, 0x2C127, 0x2C2F5, 0x2C4C2, 0x2C683, 0x2C856, + 0x2CA2D, 0x2CBFF, 0x2CDD9, 0x2CFA6, 0x2D173, 0x2D341, 0x2D50F, 0x2D6E9, + 0x2D8C4, 0x2DA9E, 0x2DC74, 0x2DE4E, 0x2DF33, 0x2E006, 0x2E180, 0x2E2D6, + 0x2E408, 0x2E524, 0x2E63F, 0x2E75A, 0x2E875, 0x2E99C, 0x2EABE, 0x2EB90, + 0x2ECE8, 0x2EEA1, 0x2F029, 0x2F16D, 0x2F298, 0x2F3B0, 0x2F58A, 0x2F67B, + 0x2F76C, 0x2F85C, 0x2F94B, 0x2FA3A, 0x2FB2B, 0x2FC1B, 0x2FD0C, 0x2FEE6, + 0x300B9, 0x30288, 0x30447, 0x305F6, 0x306FC, 0x308CB, 0x30AA5, 0x30C5A, + 0x30DE0, 0x30F36, 0x31074, 0x3119A, 0x3123D, 0x313AB, 0x31555, 0x3176D, + 0x319A0, 0x31AC3, 0x31BD2, 0x31CE3, 0x31ECA, 0x320A8, 0x3226E, 0x323FE, + 0x32580, 0x326F4, 0x32860, 0x329BE, 0x32B37, 0x32CAB, 0x32E3A, 0x32FFC, + 0x331D6, 0x333B0, 0x3358A, 0x33764, 0x3393E, 0x33B18, 0x33CF3, 0x33ECD, + 0x340A7, 0x34281, 0x3445B, 0x34635, 0x34810, 0x349EB, 0x34AD6, 0x34C9B, + 0x34E56, 0x35010, 0x351C3, 0x35375, 0x354C5, 0x355C5, 0x35653, 0x35726, + 0x35840, 0x35990, 0x35B2B, 0x35CF4, 0x35DE4, 0x35ED5, 0x360AB, 0x36279, + 0x36427, 0x365A6, 0x366D2, 0x36780, 0x36819, 0x3687D, 0x368D6, 0x36948, + 0x369F6, 0x36AC8, 0x36BA6, 0x36C90, 0x36D92, 0x36EB8, 0x3701A, 0x371AC, + 0x37363, 0x3752D, 0x37704, 0x3789D, 0x379FF, 0x37B42, 0x37C69, 0x37D38, + 0x37DDB, 0x37E63, 0x37EED, 0x37F8E, 0x38054, 0x3813E, 0x3824C, 0x3837E, + 0x383D7, 0x38431, 0x3848B, 0x384E5, 0x3853E, 0x38598, 0x385F2, 0x3864C, + 0x386D4, 0x3875E, 0x387E6, 0x38870, 0x388F7, 0x38969, 0x389CF, 0x38A32, + 0x38A95, 0x38AF8, 0x38B49, 0x38B6F, 0x38D4A, 0x38E4C, 0x38F6D, 0x3915D, + 0x2B9D7, 0x2BACB, 0x2BBC0, 0x2BD7C, 0x2BF38, 0x2C106, 0x2C1F8, 0x2C2E9, + 0x2C3DC, 0x2C4D0, 0x2C5C2, 0x2C788, 0x2C942, 0x2CAFF, 0x2CCCA, 0x2CE9B, + 0x2CF91, 0x2D083, 0x2D24D, 0x2D40E, 0x2D5CF, 0x2D795, 0x2D966, 0x2DA59, + 0x2DB4E, 0x2DC39, 0x2DD18, 0x2DDDB, 0x2DE7D, 0x2DF0A, 0x2DFD9, 0x2E094, + 0x2E0D6, 0x2E130, 0x2E170, 0x2E1B9, 0x2E214, 0x2E293, 0x2E308, 0x2E36E, + 0x2E3B9, 0x2E401, 0x2E443, 0x2E48E, 0x2E4E9, 0x2E569, 0x2E5DF, 0x2E645, + 0x2E692, 0x2E6DC, 0x2E763, 0x2E7E1, 0x2E867, 0x2E8C6, 0x2E972, 0x2EA3A, + 0x2EAAF, 0x2EB2F, 0x2EBDB, 0x2EC43, 0x2EC8B, 0x2ECD3, 0x2ED1A, 0x2ED60, + 0x2EDA8, 0x2EE32, 0x2EF19, 0x2EFD5, 0x2F069, 0x2F0B2, 0x2F11D, 0x2F1B9, + 0x2F285, 0x2F30A, 0x2F39E, 0x2F431, 0x2F4D1, 0x2F54E, 0x2F5B9, 0x2F61C, + 0x2F68C, 0x2F705, 0x2F796, 0x2F839, 0x2F8CA, 0x2F962, 0x2F9EC, 0x2FA7C, + 0x2FB0D, 0x2FC08, 0x2FCE8, 0x2FD61, 0x2FDD4, 0x2FE48, 0x2FEBA, 0x2FF26, + 0x2FFAF, 0x30040, 0x300BA, 0x3012E, 0x301AF, 0x3027A, 0x30321, 0x30372, + 0x303B9, 0x303F8, 0x3043A, 0x304C2, 0x30541, 0x30578, 0x30601, 0x30690, + 0x30707, 0x30750, 0x30794, 0x30811, 0x308FA, 0x309F0, 0x30A74, 0x30AE9, + 0x30B5C, 0x30BCC, 0x30C38, 0x30CC0, 0x30D4F, 0x30DC8, 0x30E3B, 0x31015, + 0x311CE, 0x3137B, 0x31512, 0x3169F, 0x31807, 0x31921, 0x319C2, 0x31A27, + 0x31A82, 0x31ABE, 0x31C9B, 0x31E7F, 0x32040, 0x321D6, 0x322F6, 0x3238A, + 0x323D4, 0x32420, 0x32474, 0x324D9, 0x3254B, 0x325CF, 0x32659, 0x326C1, + 0x326CF, 0x32897, 0x32A64, 0x32B5B, 0x32C53, 0x32D4C, 0x32E3F, 0x32F2C, + 0x33013, 0x330F9, 0x331D9, 0x332BC, 0x333AD, 0x3359C, 0x3376B, 0x33854, + 0x33932, 0x339FF, 0x33AC0, 0x33B72, 0x33C1F, 0x33CBE, 0x33DFD, 0x33F3B, + 0x34070, 0x341A4, 0x342D2, 0x343FC, 0x34522, 0x34654, 0x34700, 0x34855, + 0x34991, 0x28D75, 0x2903C, 0x292F0, 0x29562, 0x297CB, 0x298EF, 0x299F6, + 0x29AE4, 0x29B54, 0x29CEA, 0x29E90, 0x2A03A, 0x2A1E4, 0x2A39E, 0x2A578, + 0x2A67C, 0x2A84B, 0x2A9D1, 0x2AB7E, 0x2AD36, 0x2AEF3, 0x2B08C, 0x2B223, + 0x2B3DE, 0x2B595, 0x2B74A, 0x2B7C6, 0x2B847, 0x2B8CE, 0x2B952 +}; + +const char *Resource::_splNames[] = { + "pneuma05.spl", + "bip00105.spl", + "bip00205.spl", + "laser205.spl", + "tir2", + "explo.spl", + "mort0105.spl", + "mort0310.spl", + "bouclier.spl", + "asc_debut", + "asc_milieu", + "asc_fin", + "verre_casse", + "chalu110.spl", + "saut.spl", + "trappe.spl", + "impact_shield.spl", + "stby0105.spl", + "teletower.spl", + "desint.spl", + "recharge.spl", + "mitrail.spl", + "touche.spl", + "coup", + "chenille.spl", + "robot.spl", + "tombe.spl", + "porte_ferme.spl", + "canon_down", + "elec.spl", + "mater210.spl", + "mater07.spl", + "mur_bouge.spl", + "taxi.spl", + "souris.spl", + "et.spl", + "et_touche.spl", + "et_transform.spl", + "alien_move.spl", + "jungle2", + "jungle1", + "piaf2", + "goute_eau", + "piaf1", + "pas1", + "pas2", + "croa", + "alien1", + "alien2", + "alien3", + "ventilo", + "poussiere", + "bip", + "electri", + "machine", + "alarme2", + "cerveau", + "reflet", + "roule_boule", + "hehe3", + "recept", + "bestiole", + "lampe", + "mine", + "effort", + "frappe", + 0 +}; + +const Game::pge_OpcodeProc Game::_pge_opcodeTable[] = { + /* 0x00 */ + 0, + &Game::pge_op_isInpUp, + &Game::pge_op_isInpBackward, + &Game::pge_op_isInpDown, + /* 0x04 */ + &Game::pge_op_isInpForward, + &Game::pge_op_isInpUpMod, + &Game::pge_op_isInpBackwardMod, + &Game::pge_op_isInpDownMod, + /* 0x08 */ + &Game::pge_op_isInpForwardMod, + &Game::pge_op_isInpIdle, + &Game::pge_op_isInpNoMod, + &Game::pge_op_getCollision0u, + /* 0x0C */ + &Game::pge_op_getCollision00, + &Game::pge_op_getCollision0d, + &Game::pge_op_getCollision1u, + &Game::pge_op_getCollision10, + /* 0x10 */ + &Game::pge_op_getCollision1d, + &Game::pge_op_getCollision2u, + &Game::pge_op_getCollision20, + &Game::pge_op_getCollision2d, + /* 0x14 */ + &Game::pge_op_doesNotCollide0u, + &Game::pge_op_doesNotCollide00, + &Game::pge_op_doesNotCollide0d, + &Game::pge_op_doesNotCollide1u, + /* 0x18 */ + &Game::pge_op_doesNotCollide10, + &Game::pge_op_doesNotCollide1d, + &Game::pge_op_doesNotCollide2u, + &Game::pge_op_doesNotCollide20, + /* 0x1C */ + &Game::pge_op_doesNotCollide2d, + &Game::pge_op_collides0o0d, + &Game::pge_op_collides2o2d, + &Game::pge_op_collides0o0u, + /* 0x20 */ + &Game::pge_op_collides2o2u, + &Game::pge_op_collides2u2o, + &Game::pge_op_isInGroup, + &Game::pge_op_updateGroup0, + /* 0x24 */ + &Game::pge_op_updateGroup1, + &Game::pge_op_updateGroup2, + &Game::pge_op_updateGroup3, + &Game::pge_op_isPiegeDead, + /* 0x28 */ + &Game::pge_op_collides1u2o, + &Game::pge_op_collides1u1o, + &Game::pge_op_collides1o1u, + &Game::pge_o_unk0x2B, + /* 0x2C */ + &Game::pge_o_unk0x2C, + &Game::pge_o_unk0x2D, + &Game::pge_op_nop, + &Game::pge_op_pickupObject, + /* 0x30 */ + &Game::pge_op_addItemToInventory, + &Game::pge_op_copyPiege, + &Game::pge_op_canUseCurrentInventoryItem, + &Game::pge_op_removeItemFromInventory, + /* 0x34 */ + &Game::pge_o_unk0x34, + &Game::pge_op_isInpMod, + &Game::pge_op_setCollisionState1, + &Game::pge_op_setCollisionState0, + /* 0x38 */ + &Game::pge_op_isInGroup1, + &Game::pge_op_isInGroup2, + &Game::pge_op_isInGroup3, + &Game::pge_op_isInGroup4, + /* 0x3C */ + &Game::pge_o_unk0x3C, + &Game::pge_o_unk0x3D, + &Game::pge_op_setPiegeCounter, + &Game::pge_op_decPiegeCounter, + /* 0x40 */ + &Game::pge_o_unk0x40, + &Game::pge_op_wakeUpPiege, + &Game::pge_op_removePiege, + &Game::pge_op_removePiegeIfNotNear, + /* 0x44 */ + &Game::pge_op_loadPiegeCounter, + &Game::pge_o_unk0x45, + &Game::pge_o_unk0x46, + &Game::pge_o_unk0x47, + /* 0x48 */ + &Game::pge_o_unk0x48, + &Game::pge_o_unk0x49, + &Game::pge_o_unk0x4A, + &Game::pge_op_killPiege, + /* 0x4C */ + &Game::pge_op_isInCurrentRoom, + &Game::pge_op_isNotInCurrentRoom, + &Game::pge_op_scrollPosY, + &Game::pge_op_playDefaultDeathCutscene, + /* 0x50 */ + &Game::pge_o_unk0x50, + 0, + &Game::pge_o_unk0x52, + &Game::pge_o_unk0x53, + /* 0x54 */ + &Game::pge_op_isPiegeNear, + &Game::pge_op_setLife, + &Game::pge_op_incLife, + &Game::pge_op_setPiegeDefaultAnim, + /* 0x58 */ + &Game::pge_op_setLifeCounter, + &Game::pge_op_decLifeCounter, + &Game::pge_op_playCutscene, + &Game::pge_op_isTempVar2Set, + /* 0x5C */ + &Game::pge_op_playDeathCutscene, + &Game::pge_o_unk0x5D, + &Game::pge_o_unk0x5E, + &Game::pge_o_unk0x5F, + /* 0x60 */ + &Game::pge_op_findAndCopyPiege, + &Game::pge_op_isInRandomRange, + &Game::pge_o_unk0x62, + &Game::pge_o_unk0x63, + /* 0x64 */ + &Game::pge_o_unk0x64, + &Game::pge_op_addToCredits, + &Game::pge_op_subFromCredits, + &Game::pge_o_unk0x67, + /* 0x68 */ + &Game::pge_op_setCollisionState2, + &Game::pge_op_saveState, + &Game::pge_o_unk0x6A, + &Game::pge_op_isInGroupSlice, + /* 0x6C */ + &Game::pge_o_unk0x6C, + &Game::pge_op_isCollidingObject, + &Game::pge_o_unk0x6E, + &Game::pge_o_unk0x6F, + /* 0x70 */ + &Game::pge_o_unk0x70, + &Game::pge_o_unk0x71, + &Game::pge_o_unk0x72, + &Game::pge_o_unk0x73, + /* 0x74 */ + &Game::pge_op_collides4u, + &Game::pge_op_doesNotCollide4u, + &Game::pge_op_isBelowConrad, + &Game::pge_op_isAboveConrad, + /* 0x78 */ + &Game::pge_op_isNotFacingConrad, + &Game::pge_op_isFacingConrad, + &Game::pge_op_collides2u1u, + &Game::pge_op_displayText, + /* 0x7C */ + &Game::pge_o_unk0x7C, + &Game::pge_op_playSound, + &Game::pge_o_unk0x7E, + &Game::pge_o_unk0x7F, + /* 0x80 */ + &Game::pge_op_setPiegePosX, + &Game::pge_op_setPiegePosModX, + &Game::pge_op_changeRoom, + &Game::pge_op_hasInventoryItem, + /* 0x84 */ + &Game::pge_op_changeLevel, + &Game::pge_op_shakeScreen, + &Game::pge_o_unk0x86, + &Game::pge_op_playSoundGroup, + /* 0x88 */ + &Game::pge_op_adjustPos, + 0, + &Game::pge_op_setTempVar1, + &Game::pge_op_isTempVar1Set +}; + +const uint8_t Game::_pge_modKeysTable[] = { + 0x40, 0x10, 0x20 +}; + +const uint8_t Game::_protectionCodeData[] = { + 0xF9, 0x77, 0x79, 0xF9, 0xF7, 0x39, 0x79, 0x97, 0x39, 0xF9, 0x19, 0x59, 0xB9, 0x59, 0x39, 0xC9, + 0xB9, 0x19, 0xB9, 0x47, 0xB7, 0x49, 0xC9, 0xF9, 0xB9, 0x77, 0xD9, 0x07, 0x77, 0x47, 0xC9, 0x79, + 0x47, 0xF9, 0xD9, 0x19, 0x39, 0xD9, 0xB9, 0x79, 0x39, 0xD9, 0x39, 0xB9, 0x39, 0xF9, 0x19, 0x59, + 0xF9, 0xB7, 0xB9, 0x39, 0x27, 0x79, 0xB9, 0x49, 0x39, 0xD9, 0xB7, 0x07, 0xF9, 0x37, 0x99, 0x07, + 0x37, 0xD9, 0x39, 0xF9, 0xB9, 0x99, 0xB9, 0x79, 0x19, 0x59, 0xB9, 0xF9, 0x39, 0xF7, 0x39, 0x07, + 0xF9, 0x39, 0xD9, 0xD9, 0x99, 0x17, 0xD9, 0xB9, 0x77, 0xD7, 0x47, 0x77, 0x87, 0x39, 0xF9, 0x77, + 0x19, 0x59, 0xB9, 0x79, 0xB9, 0x19, 0x49, 0xD7, 0xB9, 0x99, 0x19, 0x59, 0x47, 0xF9, 0x37, 0x59, + 0x87, 0x37, 0x49, 0xC9, 0xD7, 0x77, 0xB9, 0x17, 0xD9, 0xD9, 0x17, 0x19, 0x79, 0xB7, 0xB9, 0x39, + 0x39, 0xC9, 0x39, 0x97, 0x39, 0xD9, 0x39, 0xC9, 0x39, 0xF7, 0xF9, 0x17, 0xD9, 0xC9, 0xF9, 0x99, + 0xF9, 0xB7, 0x39, 0x17, 0x37, 0x99, 0xF9, 0x97, 0x27, 0x39, 0x19, 0x99, 0x19, 0x59, 0x39, 0x79, + 0x49, 0x19, 0x39, 0x39, 0x39, 0xD9, 0xB9, 0xF9, 0x0F, 0x1F, 0xDF, 0x17, 0x19, 0xD9, 0x49, 0x49, + 0x79, 0x17, 0x39, 0xD9, 0x79, 0x19, 0x97, 0x27, 0x87, 0x67, 0xB9, 0x79, 0x19, 0x59, 0x19, 0xD9, + 0x59, 0x59, 0x79, 0x99, 0xB9, 0x19, 0x19, 0x39, 0x97, 0x99, 0x3F, 0x17, 0x17, 0x97, 0x3F, 0x39, + 0xF9, 0x99, 0xF9, 0xB7, 0x17, 0x79, 0x39, 0xC9, 0x39, 0xD9, 0x39, 0x99, 0x39, 0x17, 0x39, 0xF9, + 0xB9, 0x19, 0x19, 0x59, 0xD9, 0x19, 0xB7, 0x99, 0xC9, 0xC9, 0xD9, 0xB7, 0x19, 0x79, 0x1F, 0x7F, + 0x79, 0xD9, 0x37, 0x99, 0xF7, 0xF9, 0xB9, 0xF9, 0x39, 0xF7, 0x19, 0x59, 0xB9, 0x99, 0x39, 0x37, + 0x39, 0x39, 0xC9, 0x19, 0xC9, 0x37, 0xF9, 0xD9, 0xE7, 0x4F, 0xD9, 0xF9, 0x9F, 0x19, 0xD9, 0xD9, + 0x19, 0x79, 0x99, 0x19, 0xB9, 0x79, 0x19, 0x59, 0x39, 0xF7, 0x19, 0xB9, 0x39, 0xD9, 0x19, 0x59, + 0x99, 0x37, 0x79, 0xF9, 0x39, 0xF7, 0x39, 0x49, 0x59, 0x99, 0x59, 0xF7, 0xD9, 0x87, 0xB7, 0x39, + 0xF9, 0xB9, 0xB9, 0x19, 0x39, 0xC9, 0x39, 0xF9, 0x39, 0xF7, 0x19, 0x59, 0x39, 0x79, 0x97, 0x1F, + 0xF9, 0x77, 0x39, 0x19, 0x39, 0x99, 0x1F, 0xC9, 0x49, 0xB9, 0xD9, 0xD9, 0xF9, 0xB7, 0x49, 0xF9, + 0x39, 0xF9, 0x19, 0x59, 0x39, 0xB9, 0x39, 0x97, 0x39, 0x37, 0xB9, 0x19, 0xD9, 0x47, 0x67, 0xE7, + 0x37, 0xC9, 0x19, 0x99, 0x27, 0x39, 0x47, 0xF9, 0x87, 0x87, 0x17, 0x37, 0xD9, 0x19, 0x39, 0xC9, + 0x39, 0xF9, 0xB9, 0xF9, 0xB9, 0x49, 0x19, 0x97, 0x19, 0x59, 0x67, 0xE7, 0x47, 0xC9, 0xF9, 0x37, + 0xD9, 0x17, 0x19, 0x99, 0xC9, 0xF9, 0x79, 0x79, 0x39, 0x9F, 0xB7, 0x19, 0x39, 0x99, 0x19, 0xB9, + 0x39, 0xF9, 0xB9, 0x99, 0xB9, 0x79, 0x19, 0x59, 0xC9, 0x47, 0x79, 0x39, 0x7F, 0xFF, 0xF9, 0xB7, + 0x37, 0x79, 0x39, 0xD9, 0xB9, 0x99, 0x47, 0xD9, 0x99, 0x19, 0x39, 0x99, 0x39, 0x37, 0x39, 0x77, + 0x39, 0x77, 0x39, 0xF9, 0x19, 0x59, 0xC9, 0x79, 0xF9, 0xB7, 0x99, 0xD9, 0xC9, 0x17, 0xF9, 0x39, + 0x37, 0xE7, 0xD9, 0xF9, 0x0F, 0x77, 0xC9, 0x39, 0xB9, 0x99, 0x39, 0xF9, 0x19, 0x59, 0xB9, 0x39, + 0x39, 0xD9, 0x39, 0xF7, 0x39, 0xB7, 0x1F, 0x99, 0x19, 0xD9, 0x79, 0x77, 0x99, 0x99, 0xC9, 0x39, + 0x19, 0x99, 0x9F, 0x17, 0xD9, 0x19, 0xB9, 0x79, 0x39, 0xF9, 0xB9, 0x19, 0x19, 0x59, 0x39, 0x79, + 0x39, 0xF9, 0xD9, 0xF9, 0xC9, 0x4F, 0xBF, 0x9F, 0xB9, 0xB9, 0x17, 0x1F, 0xC9, 0x99, 0x19, 0x79, + 0x37, 0x77, 0x77, 0xD9, 0x19, 0x59, 0xB9, 0x99, 0x39, 0xD9, 0xB9, 0x39, 0x39, 0x37, 0x39, 0xC9, + 0x39, 0x3F, 0x37, 0xF9, 0x39, 0x99, 0xC9, 0xC9, 0x17, 0xB7, 0x79, 0x19, 0xC9, 0xB9, 0x7F, 0x37, + 0x39, 0x79, 0xB9, 0x19, 0x19, 0x59, 0x39, 0x39, 0x39, 0xD9, 0x39, 0xC9, 0xB9, 0x19, 0xD9, 0xD9, + 0x19, 0x39, 0x49, 0x19, 0x17, 0x37, 0x77, 0x79, 0x39, 0xD9, 0x39, 0x37, 0xF9, 0xC9, 0xF9, 0x79, + 0x39, 0xF9, 0x19, 0x59, 0x39, 0x79, 0xB9, 0xF9, 0x19, 0x59, 0xB9, 0x39, 0xC9, 0xB9, 0x79, 0x77, + 0xB7, 0x9F, 0xF7, 0x0F, 0x49, 0xF9, 0x39, 0xD9, 0xF9, 0x79, 0xB7, 0x7F, 0xC7, 0xD7, 0x49, 0x19, + 0x39, 0x97, 0x39, 0x37, 0x19, 0xF7, 0x59, 0x59, 0x79, 0xF9, 0xF7, 0x39, 0x7F, 0x49, 0x9F, 0xF9, + 0x39, 0x9F, 0x47, 0x19, 0x59, 0xF9, 0xC9, 0xC9, 0x39, 0x37, 0xF9, 0x39, 0xB9, 0x79, 0x19, 0x59, + 0x39, 0x99, 0x19, 0xB9, 0x39, 0xF9, 0xB9, 0x99, 0x79, 0x9F, 0xE7, 0xD9, 0x19, 0x79, 0x87, 0x87, + 0xC9, 0xF9, 0x39, 0x99, 0xC9, 0x39, 0x39, 0x37, 0xF7, 0x99, 0xB9, 0x79, 0x19, 0x59, 0x39, 0xD9, + 0xB9, 0x39, 0x39, 0xD9, 0x39, 0xF7, 0xC9, 0x37, 0x77, 0x79, 0x39, 0x19, 0xD9, 0x37, 0xF9, 0x77, + 0x39, 0x19, 0x1F, 0x7F, 0xC9, 0x39, 0xF9, 0x37, 0xB9, 0x79, 0x19, 0x59, 0xB9, 0x79, 0x39, 0x37, + 0xB9, 0xF9, 0xB9, 0x79, 0xF9, 0x37, 0x37, 0xD7, 0x9F, 0xF9, 0x5F, 0xE7, 0x9F, 0xC9, 0x39, 0x99, + 0x39, 0x9F, 0x9F, 0x79, 0xF9, 0x19, 0x19, 0x59, 0xB9, 0x59, 0x39, 0xD9, 0xB9, 0x19, 0x39, 0x39, + 0x39, 0xD9, 0xC9, 0x77, 0x9F, 0x07, 0x99, 0x99, 0xC9, 0x37, 0x77, 0x79, 0x39, 0x19, 0xF7, 0x39, + 0x7F, 0x49, 0x9F, 0xF9, 0x39, 0xC9, 0xB9, 0x79, 0x39, 0xF9, 0x39, 0x77, 0x39, 0xF9, 0x39, 0xF7, + 0xD7, 0x79, 0xF9, 0x39, 0x9F, 0xF7, 0x79, 0xF9, 0x0F, 0x39, 0x49, 0xB9, 0xD9, 0x77, 0x39, 0xDF, + 0x07, 0x19, 0xB9, 0x79, 0x19, 0x59, 0x39, 0xC9, 0xB9, 0x19, 0xB9, 0x19, 0x39, 0xF9, 0xD9, 0xB7, + 0x37, 0x39, 0x37, 0x19, 0x39, 0x47, 0xF9, 0x39, 0x39, 0xB7, 0x19, 0xD9, 0xE7, 0x87, 0x07, 0xB7, + 0xB9, 0x99, 0xB9, 0x59, 0x39, 0x37, 0x39, 0xF7, 0xB9, 0x99, 0x39, 0xD9, 0xD9, 0x99, 0x99, 0x79, + 0xF9, 0x39, 0x79, 0xD9, 0x19, 0x79, 0xB9, 0x87, 0xD7, 0x1F, 0x77, 0xF9, 0x79, 0xB9, 0x39, 0x19, + 0x39, 0x97, 0x39, 0xF9, 0x99, 0x79, 0xE7, 0x07, 0xA7, 0x5F, 0xD9, 0x79, 0xF9, 0x39, 0x17, 0x3F, + 0x39, 0x79, 0x5F, 0xFF, 0x27, 0xF9, 0x99, 0x99, 0x47, 0xB7, 0x37, 0x27, 0xF9, 0x79, 0x87, 0x3F, + 0x97, 0x99, 0x47, 0xB7, 0x59, 0x99, 0xB9, 0xD9, 0xC9, 0x49, 0xB7, 0x39, 0x37, 0xD9, 0xF9, 0xB7, + 0x37, 0x37, 0x39, 0xF9 +}; + +const uint8_t Game::_protectionPal[] = { + 0x00, 0x00, 0x00, 0x42, 0x00, 0x63, 0x00, 0x00, 0x0F, 0xFF, 0x0F, 0xF0, 0x07, 0x77, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const char *Menu::_passwords[8][3] = { + { "JAGUAR", "BANTHA", "TOHOLD" }, + { "COMBEL", "SHIVA", "PICOLO" }, + { "ANTIC", "KASYYK", "FUGU" }, + { "NOLAN", "SARLAC", "CAPSUL" }, + { "ARTHUR", "MAENOC", "ZZZAP" }, + { "SHIRYU", "SULUST", "MANIAC" }, + { "RENDER", "NEPTUN", "NO WAY" }, + { "BELUGA", "BELUGA", "BELUGA" } +}; + +const uint8_t Video::_conradPal1[] = { + 0x00, 0x00, 0xCC, 0x0C, 0x8F, 0x08, 0x7E, 0x07, 0x6C, 0x06, 0x5B, 0x05, 0x4A, 0x04, 0x63, 0x09, + 0x52, 0x07, 0x41, 0x06, 0x30, 0x06, 0x76, 0x0C, 0x14, 0x09, 0x25, 0x0B, 0x88, 0x08, 0xFF, 0x0F +}; + +const uint8_t Video::_conradPal2[] = { + 0x00, 0x00, 0x7C, 0x0B, 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x26, 0x0A, + 0x14, 0x08, 0x03, 0x06, 0x02, 0x04, 0x43, 0x09, 0x02, 0x06, 0x02, 0x07, 0x6A, 0x0A, 0xFF, 0x0F +}; + +const uint8_t Video::_textPal[] = { + 0x00, 0x00, 0x11, 0x01, 0x22, 0x02, 0xEF, 0x0E, 0x00, 0x0F, 0xF0, 0x0F, 0xA0, 0x0E, 0xB0, 0x0F, + 0xA0, 0x0E, 0xA0, 0x0E, 0xAA, 0x0A, 0xF0, 0x00, 0xCC, 0x0C, 0xDF, 0x0D, 0xEE, 0x0E, 0xEE, 0x0E +}; + +const uint8_t Video::_palSlot0xF[] = { + 0x00, 0x00, 0x00, 0x1F, 0x17, 0x2B, 0x2B, 0x1F, 0x37, 0x37, 0x2B, 0x47, 0x43, 0x37, 0x53, 0x4F, + 0x43, 0x63, 0x5F, 0x53, 0x6F, 0x6F, 0x63, 0x7F, 0x7F, 0x73, 0x8B, 0x8F, 0x87, 0x9B, 0x9F, 0x97, + 0xA7, 0xAF, 0xA7, 0xB3, 0xBF, 0xBB, 0xBF, 0xCF, 0xCF, 0xCF, 0x00, 0x33, 0x00, 0x17, 0x0F, 0x1F +}; + +const int8_t ModPlayer::_sineWaveTable[] = { + 0, 24, 49, 74, 97, 120, -115, -95, -76, -59, -44, -32, -21, -12, -6, -3, + -1, -3, -6, -12, -21, -32, -44, -59, -76, -95, -115, 120, 97, 74, 49, 24, + 0, -24, -49, -74, -97, -120, 115, 95, 76, 59, 44, 32, 21, 12, 6, 3, + 1, 3, 6, 12, 21, 32, 44, 59, 76, 95, 115, -120, -97, -74, -49, -24 +}; + +const uint16_t ModPlayer::_periodTable[] = { + 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453, // C-1 to B-1 Finetune 0 + 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226, // C-2 to B-2 Finetune 0 + 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113, // C-3 to B-3 Finetune 0 + 850, 802, 757, 715, 674, 637, 601, 567, 535, 505, 477, 450, // C-1 to B-1 Finetune +1 + 425, 401, 379, 357, 337, 318, 300, 284, 268, 253, 239, 225, // C-2 to B-2 Finetune +1 + 213, 201, 189, 179, 169, 159, 150, 142, 134, 126, 119, 113, // C-3 to B-3 Finetune +1 + 844, 796, 752, 709, 670, 632, 597, 563, 532, 502, 474, 447, // C-1 to B-1 Finetune +2 + 422, 398, 376, 355, 335, 316, 298, 282, 266, 251, 237, 224, // C-2 to B-2 Finetune +2 + 211, 199, 188, 177, 167, 158, 149, 141, 133, 125, 118, 112, // C-3 to B-3 Finetune +2 + 838, 791, 746, 704, 665, 628, 592, 559, 528, 498, 470, 444, // C-1 to B-1 Finetune +3 + 419, 395, 373, 352, 332, 314, 296, 280, 264, 249, 235, 222, // C-2 to B-2 Finetune +3 + 209, 198, 187, 176, 166, 157, 148, 140, 132, 125, 118, 111, // C-3 to B-3 Finetune +3 + 832, 785, 741, 699, 660, 623, 588, 555, 524, 495, 467, 441, // C-1 to B-1 Finetune +4 + 416, 392, 370, 350, 330, 312, 294, 278, 262, 247, 233, 220, // C-2 to B-2 Finetune +4 + 208, 196, 185, 175, 165, 156, 147, 139, 131, 124, 117, 110, // C-3 to B-3 Finetune +4 + 826, 779, 736, 694, 655, 619, 584, 551, 520, 491, 463, 437, // C-1 to B-1 Finetune +5 + 413, 390, 368, 347, 328, 309, 292, 276, 260, 245, 232, 219, // C-2 to B-2 Finetune +5 + 206, 195, 184, 174, 164, 155, 146, 138, 130, 123, 116, 109, // C-3 to B-3 Finetune +5 + 820, 774, 730, 689, 651, 614, 580, 547, 516, 487, 460, 434, // C-1 to B-1 Finetune +6 + 410, 387, 365, 345, 325, 307, 290, 274, 258, 244, 230, 217, // C-2 to B-2 Finetune +6 + 205, 193, 183, 172, 163, 154, 145, 137, 129, 122, 115, 109, // C-3 to B-3 Finetune +6 + 814, 768, 725, 684, 646, 610, 575, 543, 513, 484, 457, 431, // C-1 to B-1 Finetune +7 + 407, 384, 363, 342, 323, 305, 288, 272, 256, 242, 228, 216, // C-2 to B-2 Finetune +7 + 204, 192, 181, 171, 161, 152, 144, 136, 128, 121, 114, 108, // C-3 to B-3 Finetune +7 + 907, 856, 808, 762, 720, 678, 640, 604, 570, 538, 504, 480, // C-1 to B-1 Finetune -8 + 453, 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, // C-2 to B-2 Finetune -8 + 226, 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, // C-3 to B-3 Finetune -8 + 900, 850, 802, 757, 715, 675, 636, 601, 567, 535, 505, 477, // C-1 to B-1 Finetune -7 + 450, 425, 401, 379, 357, 337, 318, 300, 284, 268, 253, 238, // C-2 to B-2 Finetune -7 + 225, 212, 200, 189, 179, 169, 159, 150, 142, 134, 126, 119, // C-3 to B-3 Finetune -7 + 894, 844, 796, 752, 709, 670, 632, 597, 563, 532, 502, 474, // C-1 to B-1 Finetune -6 + 447, 422, 398, 376, 355, 335, 316, 298, 282, 266, 251, 237, // C-2 to B-2 Finetune -6 + 223, 211, 199, 188, 177, 167, 158, 149, 141, 133, 125, 118, // C-3 to B-3 Finetune -6 + 887, 838, 791, 746, 704, 665, 628, 592, 559, 528, 498, 470, // C-1 to B-1 Finetune -5 + 444, 419, 395, 373, 352, 332, 314, 296, 280, 264, 249, 235, // C-2 to B-2 Finetune -5 + 222, 209, 198, 187, 176, 166, 157, 148, 140, 132, 125, 118, // C-3 to B-3 Finetune -5 + 881, 832, 785, 741, 699, 660, 623, 588, 555, 524, 494, 467, // C-1 to B-1 Finetune -4 + 441, 416, 392, 370, 350, 330, 312, 294, 278, 262, 247, 233, // C-2 to B-2 Finetune -4 + 220, 208, 196, 185, 175, 165, 156, 147, 139, 131, 123, 117, // C-3 to B-3 Finetune -4 + 875, 826, 779, 736, 694, 655, 619, 584, 551, 520, 491, 463, // C-1 to B-1 Finetune -3 + 437, 413, 390, 368, 347, 338, 309, 292, 276, 260, 245, 232, // C-2 to B-2 Finetune -3 + 219, 206, 195, 184, 174, 164, 155, 146, 138, 130, 123, 116, // C-3 to B-3 Finetune -3 + 868, 820, 774, 730, 689, 651, 614, 580, 547, 516, 487, 460, // C-1 to B-1 Finetune -2 + 434, 410, 387, 365, 345, 325, 307, 290, 274, 258, 244, 230, // C-2 to B-2 Finetune -2 + 217, 205, 193, 183, 172, 163, 154, 145, 137, 129, 122, 115, // C-3 to B-3 Finetune -2 + 862, 814, 768, 725, 684, 646, 610, 575, 543, 513, 484, 457, // C-1 to B-1 Finetune -1 + 431, 407, 384, 363, 342, 323, 305, 288, 272, 256, 242, 228, // C-2 to B-2 Finetune -1 + 216, 203, 192, 181, 171, 161, 152, 144, 136, 128, 121, 114 // C-3 to B-3 Finetune -1 +}; + +const char *ModPlayer::_modulesFiles[][2] = { + { "intro", "mod.flashback-introb" }, // introl3 + { "options", "mod.flashback-options2" }, // option3 + { "journal", "mod.flashback-options1" }, // journal3 + { "ceinture", "mod.flashback-ceinturea" }, // chute3 + { "desinteg", "mod.flashback-desintegr" }, // desinte3 + { "reunion", "mod.flashback-reunion" }, // capture3 + { "voyage", "mod.flashback-voyage" }, // voyage3 + { "level4", "mod.flashback-teleporta" }, // telepor3 + { "planetexplo", "mod.flashback-teleport2" }, // planexp3 + { "fin", "mod.flashback-fin" }, // end31 + { "ascenseur", "mod.flashback-ascenseur" }, // lift3 + { "logo", "mod.flashback-logo" }, // present3 + { "game_over", "mod.flashback-game_over" }, // gameove3 + { "holocube", "mod.flashback-holocube" }, // holo3 + { "memoire", "mod.flashback-memoire" }, // memory3 + { "chute", "mod.flashback-chute" }, // chutevi3 + { "debut", "mod.flashback-jungle" }, // reveil3 + { "missions", "mod.flashback-missionca" }, // misvali3 + { "taxi", "mod.flashback-taxi" }, // taxi3 + { "donneobj", "mod.flashback-donneobjt" }, // donner3 + { "missions2", "mod.flashback-fin2" } // mission3 +// { 0, 0, }, // objet3 +// { 0, 0, }, // recharg3 +// { 0, 0, }, // generat3 +// { 0, 0, }, // pont3 +// { 0, 0, } // rechage3 +}; + +const int ModPlayer::_modulesFilesCount = ARRAYSIZE(_modulesFiles); + +const char *SeqPlayer::_namesTable[] = { + /* 0x00 */ + "WAKEUP", // 'DEBUT' (0x0000) num 0 + "TKHOLOCB", // 'OBJET' (0x0001) num 3 + "TAKEKEY0", // 'OBJET' (0x0001) num 4 + 0, + /* 0x04 */ + "TKGUN", // 'OBJET' (0x0001) num 2 + "RECHARG0", // 'GEN' (0x0003) num 0 + "FALLJUNG", // 'CHUTE' (0x0004) num 0 + 0, + /* 0x08 */ + 0, + "DISINTEG", // 'DESINTEG' (0x0006) num 0 + "TKCRED0", // 'OBJET' (0x0001) num 1 + 0, + /* 0x0C */ + 0, + "INTRO", // 'INTRO1' (0x8007) num 0 + "RCHGBATT", // 'GEN' (0x0003) num 1 + "TAKEBATT", // 'OBJET' (0x0001) num 11 + /* 0x10 */ + "TKTELER0", // 'OBJET' (0x0001) num 5 + "HOLOCUBE", // 'HOLOSEQ' (0x0009) num 0 + "TKCARD", // 'OBJET' (0x0001) num 6 + 0, + /* 0x14 */ + "BRIDGE", // 'PONT' (0x000B) num 0 + "GVTELER", // 'OBJET' (0x0001) num 10 + 0, + 0, + /* 0x18 */ + 0, + "HOLOMAP", // 'MAP' (0x000D) num 4 + "MAP1", // 'MAP' (0x000D) num 0 + "MAP2", // 'MAP' (0x000D) num 1 + /* 0x1C */ + "MAP3", // 'MAP' (0x000D) num 2 + "MAP4", // 'MAP' (0x000D) num 3 + 0, + 0, + /* 0x20 */ + "GIVEPACK", // 'OBJET' (0x0001) num 12 + "GIVEPACK", // 'OBJET' (0x0001) num 13 + "GETWORKP", // 'OBJET' (0x0001) num 14 + "GETID", // 'OBJET' (0x0001) num 15 + /* 0x24 */ + "TKFUSE", // 'OBJET' (0x0001) num 16 + "MISSION1", // 'MISSIONS' (0x000F) num 0 + "MISSION2", // 'MISSIONS' (0x000F) num 1 + "MISSION2", // 'MISSIONS' (0x000F) num 1 + /* 0x28 */ + "MISSION3", // 'MISSIONS' (0x000F) num 3 + "MISSION4", // 'MISSIONS' (0x000F) num 2 + "MISSION5", // 'MISSIONS' (0x000F) num 4 + "GIVEID1", // 'OBJET' (0x0001) num 8 + /* 0x2C */ + "GVCREDS1", // 'OBJET' (0x0001) num 7 + "MISSVALD", // 'MISSIONS' (0x000F) num 5 + 0, + "ANTIG", // 'CHUTE' (0x0004) num 1 + /* 0x30 */ + "MEMORY", // 'MEMO' (0x0011) num 0 + "GETANTIG", // 'OBJET' (0x0001) num 9 + "TAXI", // 'TAXI' (0x0012) num 0 + 0, + /* 0x34 */ + "VOYAGE", // 'VOYAGE' (0x0014) num 0 + "TELEPORT", // 'TELEPORT' (0x0015) num 0 + "LIFTUP", // 'LIFT' (0x0016) num 0 + "LIFTDOWN", // 'LIFT' (0x0016) num 1 + /* 0x38 */ + 0, + "SPY", // 'ESPIONS' (0x0017) num 0 + "GETDYNAM", // 'OBJET' (0x0001) num 17 + "JOURNAL", // 'LOG' (0x0018) num 0 + /* 0x3C */ + "TKTELEX0", // 'OBJET' (0x0001) num 19 + "END", // 'FIN' (0x0019) num 0 + "GENEXPL", // 'GENEXP' (0x001A) num 0 + "BADEND", // 'FIN' (0x0019) num 1 + /* 0x40 */ + 0, // 'LOGOS' (0x001B) num 0 + "GAMEOVER", // 'OVER' (0x001C) num 0 + "MISSEND1", // 'MISSIONS' (0x000F) num 6 + "MISSEND1", // 'MISSIONS' (0x000F) num 6 + /* 0x44 */ + "MISSEND2", // 'MISSIONS' (0x000F) num 7 + "MISSEND3", // 'MISSIONS' (0x000F) num 8 + "MISSEND4", // 'MISSIONS' (0x000F) num 9 + "MISSEND5", // 'MISSIONS' (0x000F) num 10 + /* 0x48 */ + 0, // 'SCORE' (0x001D) num 0 + 0, // 'LOGOS' (0x001B) num 1 + 0, // 'INTRO2' (0x001E) num 0 +}; + +const uint8_t SfxPlayer::_musicData68[] = { + 0x00, 0x1B, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x18, 0xFF, 0xF4, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, + 0x02, 0x01, 0x04, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x0A, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x0D, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x14, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x16, 0x04, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x0F +}; + +const uint8_t SfxPlayer::_musicData70[] = { + 0x00, 0x12, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x02, 0x01, 0x00, 0x00, 0x01, 0x0D, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x03, 0x16, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00 +}; + +const uint8_t SfxPlayer::_musicData72[] = { + 0x00, 0x4F, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x24, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x05, 0x02, 0x01, 0x04, 0x1B, 0x01, 0x08, 0x00, 0x00, 0x04, 0x1D, 0x01, 0x05, + 0x02, 0x01, 0x04, 0x1B, 0x01, 0x0A, 0x02, 0x01, 0x04, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x04, 0x1B, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x1D, 0x01, 0x0A, 0x02, 0x01, 0x04, 0x1B, 0x01, 0x0D, 0x00, 0x00, + 0x04, 0x1D, 0x01, 0x0A, 0x02, 0x01, 0x04, 0x1B, 0x01, 0x0F, 0x02, 0x01, 0x04, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x1B, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x1D, 0x01, 0x11, 0x02, 0x01, 0x04, 0x1B, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x1D, 0x01, 0x10, 0x02, 0x01, 0x04, 0x1B, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x04, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x04, 0x1D, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x04, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x04, 0x1B, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x04, 0x1B, 0x01, 0x10, 0x03, 0x01, + 0x04, 0x1D, 0x01, 0x0F, 0x03, 0x01, 0x04, 0x1B, 0x01, 0x0D, 0x02, 0x01, 0x04, 0x1D, 0x01, 0x0F, + 0x03, 0x01, 0x04, 0x1B, 0x01, 0x0D, 0x02, 0x01, 0x04, 0x1D, 0x01, 0x0A, 0x03, 0x01, 0x04, 0x1B, + 0x01, 0x08, 0x03, 0x01, 0x04, 0x1D, 0x01, 0x08, 0x02, 0x01, 0x04, 0x1B, 0x01, 0x0A, 0x00, 0x00, + 0x04, 0x1D, 0x01, 0x08, 0x00, 0x00, 0x04, 0x1B, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x1D, 0x00, 0x00, + 0x03, 0x01, 0x04, 0x1B, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x1D, 0x01, 0x08, 0x00, 0x00, 0x04, 0x1B, + 0x01, 0x0A, 0x02, 0x01, 0x04, 0x1D, 0x01, 0x08, 0x00, 0x00, 0x04, 0x1B, 0x01, 0x0A, 0x02, 0x01, + 0x04, 0x1D, 0x00, 0x00, 0x02, 0x01, 0x04, 0x1B, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x1D, 0x01, 0x08, + 0x03, 0x01, 0x04, 0x1B, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x1D, 0x01, 0x0D, 0x00, 0x00, 0x04, 0x1B, + 0x01, 0x0F, 0x00, 0x00, 0x04, 0x1D, 0x01, 0x08, 0x02, 0x01, 0x04, 0x1B, 0x01, 0x0A, 0x00, 0x00, + 0x04, 0x1D, 0x01, 0x08, 0x00, 0x00, 0x04, 0x1B, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x1D, 0x00, 0x00, + 0x03, 0x01, 0x04, 0x1B, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x1D, 0x01, 0x08, 0x00, 0x00, 0x04, 0x1B, + 0x01, 0x0A, 0x02, 0x01, 0x04, 0x1D, 0x01, 0x08, 0x00, 0x00, 0x04, 0x1B, 0x01, 0x0A, 0x02, 0x01, + 0x04, 0x1D, 0x00, 0x00, 0x02, 0x01, 0x04, 0x1B, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x1D, 0x01, 0x08, + 0x03, 0x01, 0x04, 0x1B, 0x01, 0x03, 0x00, 0x00, 0x04, 0x1D, 0x01, 0x05, 0x00, 0x00, 0x04, 0x1B, + 0x01, 0x08, 0x00, 0x00, 0x04, 0x1D, 0x01, 0x08, 0x02, 0x01, 0x04, 0x1B, 0x01, 0x0A, 0x00, 0x00, + 0x04, 0x1D, 0x01, 0x08, 0x00, 0x00, 0x04, 0x1B, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x1D, 0x00, 0x00, + 0x03, 0x01, 0x04, 0x1B, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x1D, 0x01, 0x08, 0x00, 0x00, 0x04, 0x1B, + 0x01, 0x0A, 0x02, 0x01, 0x04, 0x1D, 0x01, 0x08, 0x00, 0x00, 0x04, 0x1B, 0x01, 0x0A, 0x02, 0x01, + 0x04, 0x1D, 0x00, 0x00, 0x02, 0x01, 0x04, 0x1B, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x1D, 0x01, 0x08, + 0x03, 0x01, 0x04, 0x1B, 0x01, 0x0A, 0x03, 0x01, 0x04, 0x1D, 0x01, 0x0D, 0x03, 0x01, 0x04, 0x1B, + 0x01, 0x0F, 0x03, 0x01, 0x04, 0x1D, 0x01, 0x0A, 0x02, 0x01, 0x04, 0x1B +}; + +const uint8_t SfxPlayer::_musicData73[] = { + 0x00, 0x41, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x0C, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x04, 0x0A, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x11, 0x01, 0x08, + 0x03, 0x01, 0x04, 0x12, 0x01, 0x0A, 0x02, 0x01, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x11, + 0x01, 0x0A, 0x02, 0x01, 0x04, 0x12, 0x00, 0x00, 0x03, 0x01, 0x04, 0x0A, 0x01, 0x05, 0x00, 0x00, + 0x04, 0x11, 0x01, 0x08, 0x02, 0x01, 0x04, 0x0A, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x11, 0x01, 0x08, + 0x03, 0x01, 0x04, 0x12, 0x01, 0x0A, 0x02, 0x01, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x11, + 0x01, 0x0A, 0x02, 0x01, 0x04, 0x12, 0x00, 0x00, 0x03, 0x01, 0x04, 0x0A, 0x01, 0x05, 0x00, 0x00, + 0x04, 0x11, 0x01, 0x08, 0x02, 0x01, 0x04, 0x0A, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x11, 0x01, 0x08, + 0x03, 0x01, 0x04, 0x12, 0x01, 0x0A, 0x02, 0x01, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x11, + 0x01, 0x0A, 0x02, 0x01, 0x04, 0x12, 0x00, 0x00, 0x03, 0x01, 0x04, 0x0A, 0x01, 0x0D, 0x00, 0x00, + 0x04, 0x11, 0x00, 0x00, 0x02, 0x01, 0x04, 0x0A, 0x01, 0x0F, 0x02, 0x01, 0x04, 0x11, 0x01, 0x0C, + 0x03, 0x01, 0x04, 0x12, 0x01, 0x0D, 0x02, 0x01, 0x04, 0x0A, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x11, + 0x01, 0x05, 0x02, 0x01, 0x04, 0x12, 0x01, 0x08, 0x03, 0x01, 0x04, 0x0A, 0x01, 0x0D, 0x00, 0x00, + 0x04, 0x11, 0x01, 0x08, 0x02, 0x01, 0x04, 0x0A, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x11, 0x01, 0x08, + 0x03, 0x01, 0x04, 0x12, 0x01, 0x0A, 0x02, 0x01, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x11, + 0x01, 0x0A, 0x02, 0x01, 0x04, 0x12, 0x00, 0x00, 0x03, 0x01, 0x04, 0x0A, 0x01, 0x05, 0x00, 0x00, + 0x04, 0x11, 0x01, 0x08, 0x02, 0x01, 0x04, 0x0A, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x11, 0x01, 0x08, + 0x03, 0x01, 0x04, 0x12, 0x01, 0x0A, 0x02, 0x01, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x11, + 0x01, 0x0A, 0x02, 0x01, 0x04, 0x12, 0x00, 0x00, 0x03, 0x01, 0x04, 0x0A, 0x01, 0x05, 0x00, 0x00, + 0x04, 0x11, 0x01, 0x08, 0x02, 0x01, 0x04, 0x0A, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x11, 0x01, 0x08, + 0x03, 0x01, 0x04, 0x12, 0x01, 0x0A, 0x02, 0x01, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x11, + 0x01, 0x0A, 0x02, 0x01, 0x04, 0x12, 0x00, 0x00, 0x03, 0x01, 0x04, 0x0A, 0x01, 0x0D, 0x00, 0x00, + 0x04, 0x11, 0x00, 0x00, 0x02, 0x01, 0x04, 0x0A, 0x01, 0x0F, 0x02, 0x01, 0x04, 0x11, 0x01, 0x0C, + 0x03, 0x01, 0x04, 0x12, 0x01, 0x0D, 0x02, 0x01, 0x04, 0x0A, 0x01, 0x0A, 0x00, 0x00, 0x04, 0x11, + 0x01, 0x05, 0x02, 0x01, 0x04, 0x12, 0x01, 0x08, 0x03, 0x01, 0x04, 0x0A, 0x01, 0x0D, 0x03, 0x01, + 0x04, 0x11, 0x01, 0x0A, 0x02, 0x01, 0x04, 0x0A +}; + +const uint8_t SfxPlayer::_musicData74[] = { + 0x00, 0x41, 0x00, 0x07, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x24, 0x00, 0x0C, 0x00, 0x24, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x05, 0x27, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x04, 0x08, 0x01, 0x08, + 0x03, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x04, 0x08, + 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x03, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, + 0x04, 0x08, 0x01, 0x06, 0x02, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, + 0x03, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x03, 0x01, 0x00, 0x00, 0x01, 0x0B, 0x05, 0x27, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x04, 0x08, 0x01, 0x08, + 0x03, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x04, 0x08, + 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x03, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, + 0x04, 0x08, 0x01, 0x06, 0x02, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, + 0x03, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x03, 0x01, 0x00, 0x00, 0x01, 0x0B, 0x05, 0x27, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x04, 0x08, 0x01, 0x08, + 0x03, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x04, 0x08, + 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x03, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, + 0x04, 0x08, 0x01, 0x06, 0x02, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, + 0x03, 0x01, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x00, 0x00, + 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x0B, 0x03, 0x01, 0x00, 0x00, 0x01, 0x0D, 0x05, 0x27, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x00, 0x00 +}; + +const uint8_t SfxPlayer::_musicData75[] = { + 0x00, 0x41, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x24, 0x00, 0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, + 0x05, 0x27, 0x04, 0x14, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x03, 0x01, 0x04, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x04, 0x14, 0x01, 0x08, 0x05, 0x27, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, + 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x03, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x04, 0x12, 0x01, 0x08, 0x05, 0x27, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, + 0x05, 0x27, 0x04, 0x14, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x03, 0x01, 0x04, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x04, 0x14, 0x01, 0x08, 0x05, 0x27, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, + 0x05, 0x27, 0x04, 0x12, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x06, 0x03, 0x01, 0x04, 0x11, + 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x05, 0x27, 0x04, 0x12, 0x01, 0x06, 0x05, 0x27, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, + 0x05, 0x27, 0x04, 0x14, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x03, 0x01, 0x04, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x04, 0x14, 0x01, 0x08, 0x05, 0x27, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, + 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x03, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x04, 0x12, 0x01, 0x08, 0x05, 0x27, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, + 0x05, 0x27, 0x04, 0x14, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x03, 0x01, 0x04, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x04, 0x14, 0x01, 0x08, 0x05, 0x27, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, + 0x05, 0x27, 0x00, 0x00, 0x01, 0x08, 0x05, 0x27, 0x00, 0x00, 0x01, 0x06, 0x03, 0x01, 0x00, 0x00, + 0x01, 0x06, 0x03, 0x01, 0x00, 0x00, 0x01, 0x05, 0x03, 0x01, 0x00, 0x00, 0x01, 0x06, 0x03, 0x01, + 0x00, 0x00, 0x01, 0x08, 0x02, 0x01, 0x00, 0x00 +}; + +const uint8_t SfxPlayer::_musicDataSample1[] = { + 0x08, 0x2C, 0x00, 0x40, 0x07, 0x2A, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x04, + 0x03, 0x05, 0x07, 0x08, 0x08, 0x0B, 0x0E, 0x0F, 0x11, 0x14, 0x14, 0x16, 0x18, 0x1C, 0x20, 0x1E, + 0x1A, 0x1A, 0x1F, 0x22, 0x1F, 0x19, 0x16, 0x27, 0x1C, 0xC8, 0x0F, 0x7F, 0x30, 0xA0, 0x97, 0x0F, + 0x73, 0x50, 0xC4, 0x96, 0xE7, 0x15, 0xFC, 0xFD, 0x12, 0x0C, 0xE6, 0xEF, 0x0F, 0xF8, 0xE3, 0xFF, + 0x47, 0x4E, 0x08, 0xD2, 0xEA, 0x27, 0x3B, 0x22, 0x09, 0x03, 0xFF, 0xF2, 0xF3, 0x03, 0x00, 0xEA, + 0xDE, 0xD4, 0xC7, 0xC2, 0xBC, 0xB4, 0xB6, 0xB8, 0xA8, 0x96, 0x95, 0x99, 0x9C, 0x9F, 0xA0, 0xA0, + 0xA3, 0xA4, 0xA4, 0xB3, 0xCB, 0xD7, 0xDB, 0xDF, 0xEA, 0xFD, 0x0F, 0x1C, 0x26, 0x37, 0x4B, 0x57, + 0x5F, 0x6A, 0x73, 0x78, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x78, 0x6C, 0x64, 0x5E, 0x58, 0x4B, 0x40, 0x3A, 0x2E, 0x1E, 0x16, 0x11, 0x0B, 0x06, 0xFE, + 0xF3, 0xE9, 0xE2, 0xDD, 0xDE, 0xE3, 0xE0, 0xD7, 0xCE, 0xCC, 0xCE, 0xD3, 0xD4, 0xCF, 0xCB, 0xCF, + 0xD2, 0xCF, 0xCD, 0xCF, 0xD1, 0xD6, 0xD9, 0xD3, 0xCD, 0xD3, 0xDE, 0xDF, 0xDA, 0xD8, 0xD9, 0xDF, + 0xE5, 0xE4, 0xDE, 0xDF, 0xE4, 0xEA, 0xED, 0xEE, 0xF2, 0xF4, 0xF7, 0xF5, 0xF5, 0xFE, 0x0B, 0x0C, + 0x0B, 0x0F, 0x13, 0x13, 0x11, 0x13, 0x1B, 0x26, 0x23, 0x1B, 0x1D, 0x1C, 0x1E, 0x20, 0x1E, 0x1F, + 0x1E, 0x15, 0x17, 0x20, 0x10, 0x07, 0x15, 0x14, 0x0B, 0x0B, 0x08, 0x04, 0x07, 0x04, 0xFA, 0xFB, + 0xFE, 0xFB, 0xFB, 0xFB, 0xF6, 0xF1, 0xF4, 0xF9, 0xFC, 0x00, 0x01, 0xFE, 0xF8, 0xF7, 0xFB, 0x03, + 0x0C, 0x11, 0x0F, 0x08, 0xFE, 0xFE, 0x0B, 0x1B, 0x1E, 0x11, 0x04, 0x04, 0x09, 0x0C, 0x0D, 0x08, + 0x08, 0x0C, 0x09, 0x00, 0xF4, 0xF2, 0xFB, 0x03, 0x02, 0xFA, 0xF6, 0xF5, 0xF4, 0xF6, 0xF9, 0xFA, + 0xF9, 0xFD, 0x01, 0x02, 0x01, 0xFE, 0x01, 0x0C, 0x10, 0x0D, 0x0A, 0x08, 0x0B, 0x14, 0x19, 0x1A, + 0x1B, 0x19, 0x15, 0x17, 0x18, 0x15, 0x17, 0x1E, 0x1C, 0x16, 0x11, 0x11, 0x14, 0x19, 0x19, 0x17, + 0x15, 0x13, 0x15, 0x1A, 0x1C, 0x1E, 0x23, 0x28, 0x28, 0x24, 0x23, 0x28, 0x2D, 0x2F, 0x2E, 0x2E, + 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x16, 0x0B, 0x02, 0xFF, 0xF9, 0xEB, 0xE0, 0xD6, 0xCC, 0xC3, 0xBA, + 0xB0, 0xA6, 0xA0, 0x99, 0x92, 0x8C, 0x88, 0x88, 0x88, 0x85, 0x83, 0x85, 0x89, 0x8C, 0x91, 0x9A, + 0xA2, 0xAB, 0xB2, 0xBB, 0xC7, 0xD6, 0xE3, 0xF1, 0xFF, 0x0C, 0x17, 0x23, 0x2D, 0x39, 0x45, 0x50, + 0x5A, 0x63, 0x67, 0x6A, 0x6E, 0x72, 0x76, 0x7A, 0x7A, 0x76, 0x73, 0x72, 0x6E, 0x6B, 0x6A, 0x66, + 0x61, 0x5D, 0x53, 0x4B, 0x48, 0x45, 0x40, 0x3C, 0x3A, 0x33, 0x2D, 0x2A, 0x24, 0x20, 0x20, 0x20, + 0x1C, 0x1B, 0x1A, 0x16, 0x13, 0x12, 0x11, 0x12, 0x12, 0x10, 0x0D, 0x0B, 0x0B, 0x09, 0x07, 0x07, + 0x06, 0x05, 0x04, 0x02, 0x01, 0xFE, 0xFC, 0xFC, 0xFF, 0x00, 0xFE, 0xFB, 0xFA, 0xFA, 0xFC, 0xFD, + 0xFC, 0xFD, 0x01, 0x02, 0x00, 0x00, 0x04, 0x08, 0x0C, 0x0E, 0x0D, 0x10, 0x13, 0x16, 0x19, 0x1B, + 0x1D, 0x1E, 0x21, 0x23, 0x23, 0x23, 0x24, 0x26, 0x28, 0x26, 0x23, 0x21, 0x21, 0x23, 0x23, 0x1F, + 0x1C, 0x1C, 0x1B, 0x1A, 0x18, 0x16, 0x15, 0x14, 0x13, 0x11, 0x0F, 0x0E, 0x0C, 0x0A, 0x08, 0x03, + 0xFD, 0xFA, 0xFA, 0xF9, 0xF6, 0xF3, 0xF1, 0xEF, 0xEF, 0xEF, 0xF0, 0xF3, 0xF4, 0xF2, 0xF4, 0xF9, + 0xFD, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x08, 0x05, 0x01, 0xFD, 0xF9, 0xF5, 0xF1, + 0xED, 0xE6, 0xDE, 0xD9, 0xD7, 0xD5, 0xD3, 0xD0, 0xCD, 0xCB, 0xCA, 0xC8, 0xC8, 0xCB, 0xCC, 0xCE, + 0xD1, 0xD4, 0xD4, 0xD6, 0xDD, 0xE4, 0xE9, 0xEB, 0xEC, 0xEF, 0xF6, 0xFC, 0xFD, 0xFB, 0xFB, 0xFC, + 0xFC, 0xFC, 0xF9, 0xF6, 0xF5, 0xF3, 0xEE, 0xEB, 0xE9, 0xE7, 0xE7, 0xE7, 0xE6, 0xE5, 0xE5, 0xE6, + 0xEA, 0xEE, 0xF2, 0xF6, 0xFA, 0xFE, 0x03, 0x0A, 0x10, 0x15, 0x1A, 0x1D, 0x20, 0x23, 0x25, 0x25, + 0x26, 0x26, 0x24, 0x20, 0x1A, 0x15, 0x0F, 0x09, 0x02, 0xF8, 0xEE, 0xE4, 0xD9, 0xCF, 0xC8, 0xC1, + 0xB8, 0xAF, 0xA7, 0xA0, 0x9A, 0x97, 0x94, 0x92, 0x92, 0x92, 0x94, 0x97, 0x99, 0x9D, 0xA5, 0xAD, + 0xB6, 0xBF, 0xC7, 0xD1, 0xDC, 0xE7, 0xF3, 0xFF, 0x0B, 0x16, 0x1F, 0x29, 0x33, 0x3B, 0x44, 0x4D, + 0x55, 0x5A, 0x5E, 0x62, 0x64, 0x66, 0x67, 0x68, 0x68, 0x68, 0x66, 0x63, 0x60, 0x5D, 0x5B, 0x59, + 0x56, 0x52, 0x4F, 0x4B, 0x48, 0x46, 0x44, 0x42, 0x40, 0x3F, 0x3E, 0x3D, 0x3A, 0x39, 0x39, 0x3A, + 0x39, 0x37, 0x36, 0x35, 0x35, 0x35, 0x35, 0x34, 0x32, 0x31, 0x30, 0x2E, 0x2D, 0x2B, 0x2A, 0x29, + 0x27, 0x26, 0x25, 0x24, 0x22, 0x21, 0x20, 0x20, 0x1F, 0x1D, 0x1D, 0x1F, 0x20, 0x1F, 0x1F, 0x1F, + 0x20, 0x23, 0x25, 0x26, 0x26, 0x29, 0x2B, 0x2C, 0x2D, 0x2E, 0x30, 0x32, 0x33, 0x34, 0x34, 0x35, + 0x35, 0x35, 0x36, 0x36, 0x35, 0x34, 0x33, 0x33, 0x32, 0x31, 0x30, 0x2F, 0x2E, 0x2B, 0x29, 0x29, + 0x29, 0x28, 0x27, 0x27, 0x27, 0x26, 0x26, 0x26, 0x28, 0x28, 0x28, 0x27, 0x27, 0x26, 0x24, 0x22, + 0x20, 0x1D, 0x1A, 0x15, 0x0F, 0x0A, 0x05, 0x01, 0xFE, 0xFA, 0xF5, 0xF2, 0xF0, 0xED, 0xEC, 0xEB, + 0xEA, 0xE9, 0xE9, 0xE9, 0xEA, 0xEB, 0xEB, 0xEB, 0xEB, 0xEA, 0xE9, 0xE6, 0xE3, 0xE1, 0xDC, 0xD8, + 0xD4, 0xCE, 0xC8, 0xC3, 0xBF, 0xBA, 0xB6, 0xB1, 0xAE, 0xAB, 0xAA, 0xA8, 0xA7, 0xA6, 0xA6, 0xA7, + 0xA9, 0xAB, 0xAE, 0xAF, 0xB1, 0xB3, 0xB8, 0xBC, 0xC0, 0xC3, 0xC5, 0xC7, 0xCA, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD2, 0xD3, 0xD2, 0xD1, 0xCF, 0xD0, 0xD0, 0xD0, 0xCF, 0xCF, 0xCF, 0xCF, 0xD1, 0xD3, 0xD5, + 0xD8, 0xDB, 0xDF, 0xE3, 0xE7, 0xEB, 0xF0, 0xF6, 0xFB, 0xFF, 0x03, 0x08, 0x0C, 0x0E, 0x11, 0x12, + 0x13, 0x14, 0x13, 0x11, 0x0E, 0x0A, 0x05, 0x00, 0xFA, 0xF4, 0xED, 0xE5, 0xDE, 0xD6, 0xCE, 0xC6, + 0xC0, 0xBA, 0xB4, 0xAF, 0xAA, 0xA7, 0xA5, 0xA4, 0xA4, 0xA4, 0xA6, 0xA9, 0xAE, 0xB3, 0xB8, 0xBF, + 0xC7, 0xCF, 0xD7, 0xDF, 0xE9, 0xF4, 0xFE, 0x08, 0x11, 0x1B, 0x24, 0x2D, 0x35, 0x3D, 0x45, 0x4B, + 0x50, 0x55, 0x58, 0x5B, 0x5E, 0x60, 0x60, 0x60, 0x5F, 0x5E, 0x5D, 0x5B, 0x59, 0x58, 0x57, 0x54, + 0x52, 0x4F, 0x4E, 0x4D, 0x4C, 0x4A, 0x48, 0x47, 0x46, 0x46, 0x46, 0x46, 0x46, 0x45, 0x44, 0x44, + 0x44, 0x45, 0x44, 0x44, 0x43, 0x43, 0x43, 0x43, 0x42, 0x41, 0x41, 0x40, 0x3F, 0x3D, 0x3C, 0x3C, + 0x3B, 0x3A, 0x39, 0x38, 0x36, 0x36, 0x35, 0x34, 0x34, 0x34, 0x33, 0x32, 0x32, 0x33, 0x34, 0x35, + 0x34, 0x34, 0x34, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x36, 0x34, + 0x35, 0x34, 0x33, 0x32, 0x32, 0x32, 0x32, 0x31, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, 0x30, + 0x31, 0x31, 0x32, 0x32, 0x33, 0x34, 0x35, 0x36, 0x36, 0x36, 0x37, 0x38, 0x38, 0x38, 0x37, 0x35, + 0x32, 0x2F, 0x2D, 0x29, 0x24, 0x20, 0x1A, 0x14, 0x0E, 0x08, 0x03, 0xFE, 0xF8, 0xF3, 0xEE, 0xEA, + 0xE6, 0xE2, 0xE0, 0xDE, 0xDB, 0xD9, 0xD8, 0xD6, 0xD5, 0xD3, 0xD1, 0xD0, 0xCD, 0xCA, 0xC7, 0xC4, + 0xC1, 0xBD, 0xBA, 0xB6, 0xB3, 0xB0, 0xAC, 0xA9, 0xA7, 0xA5, 0xA3, 0xA1, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA1, 0xA1, 0xA2, 0xA2, 0xA4, 0xA6, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAC, 0xAD, 0xAE, + 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB5, 0xB7, 0xB9, 0xBB, 0xBE, 0xC0, 0xC4, 0xC8, 0xCC, 0xD1, 0xD5, + 0xDA, 0xDF, 0xE5, 0xEA, 0xEF, 0xF5, 0xFA, 0xFF, 0x04, 0x08, 0x0B, 0x0D, 0x10, 0x12, 0x12, 0x11, + 0x10, 0x0E, 0x0B, 0x08, 0x03, 0xFE, 0xF8, 0xF1, 0xEB, 0xE4, 0xDD, 0xD6, 0xD0, 0xC9, 0xC3, 0xBD, + 0xB8, 0xB4, 0xB1, 0xAE, 0xAC, 0xAB, 0xAA, 0xAB, 0xAD, 0xB0, 0xB3, 0xB8, 0xBD, 0xC3, 0xCA, 0xD2, + 0xD9, 0xE1, 0xE9, 0xF2, 0xFA, 0x02, 0x0B, 0x13, 0x1C, 0x23, 0x2A, 0x31, 0x36, 0x3B, 0x40, 0x45, + 0x48, 0x4B, 0x4D, 0x4F, 0x50, 0x50, 0x50, 0x50, 0x50, 0x4F, 0x4E, 0x4C, 0x4C, 0x4B, 0x4B, 0x4A, + 0x49, 0x49, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x48, 0x49, 0x49, 0x4A, 0x4B, 0x4B, 0x4B, + 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4A, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x44, 0x44, 0x43, 0x41, + 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3B, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x39, 0x3A, 0x3B, 0x3C, + 0x3C, 0x3C, 0x3C, 0x3D, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3E, 0x3E, 0x3E, 0x3E, 0x3D, 0x3D, 0x3C, + 0x3B, 0x39, 0x38, 0x38, 0x37, 0x36, 0x34, 0x33, 0x32, 0x32, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x31, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3A, 0x3B, + 0x3A, 0x3A, 0x38, 0x37, 0x34, 0x31, 0x2E, 0x2B, 0x27, 0x22, 0x1D, 0x18, 0x13, 0x0D, 0x08, 0x01, + 0xFC, 0xF7, 0xF2, 0xED, 0xE9, 0xE4, 0xE0, 0xDC, 0xD8, 0xD4, 0xD0, 0xCB, 0xC7, 0xC3, 0xBF, 0xBA, + 0xB6, 0xB2, 0xAF, 0xAB, 0xA8, 0xA5, 0xA3, 0xA0, 0x9F, 0x9E, 0x9D, 0x9D, 0x9D, 0x9C, 0x9D, 0x9D, + 0x9E, 0x9E, 0x9F, 0x9F, 0xA0, 0xA0, 0xA0, 0xA0, 0xA1, 0xA1, 0xA1, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, + 0xA3, 0xA5, 0xA5, 0xA7, 0xA8, 0xAB, 0xAD, 0xB0, 0xB2, 0xB6, 0xBA, 0xBF, 0xC3, 0xC8, 0xCE, 0xD3, + 0xD9, 0xDF, 0xE5, 0xEB, 0xF1, 0xF6, 0xFB, 0x00, 0x04, 0x08, 0x0B, 0x0D, 0x0E, 0x0E, 0x0E, 0x0C, + 0x0A, 0x08, 0x04, 0x00, 0xFA, 0xF5, 0xEF, 0xE8, 0xE2, 0xDC, 0xD6, 0xCF, 0xC9, 0xC3, 0xBE, 0xBA, + 0xB6, 0xB3, 0xB0, 0xAE, 0xAD, 0xAE, 0xAF, 0xB0, 0xB3, 0xB7, 0xBB, 0xBF, 0xC5, 0xCB, 0xD2, 0xD9, + 0xE1, 0xE8, 0xF0, 0xF9, 0x01, 0x09, 0x11, 0x18, 0x1F, 0x26, 0x2D, 0x32, 0x37, 0x3C, 0x40, 0x43, + 0x46, 0x48, 0x49, 0x4A, 0x4B, 0x4B, 0x4B, 0x4A, 0x4A, 0x49, 0x48, 0x47, 0x47, 0x46, 0x46, 0x45, + 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x46, 0x47, 0x47, 0x47, 0x48, 0x49, + 0x49, 0x49, 0x49, 0x4A, 0x49, 0x49, 0x49, 0x48, 0x48, 0x47, 0x46, 0x45, 0x45, 0x44, 0x43, 0x42, + 0x41, 0x41, 0x40, 0x40, 0x3F, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x3F, 0x3F, 0x3E, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, + 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x31, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x30, 0x30, + 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x3A, 0x3B, 0x3D, 0x3D, 0x3E, 0x3F, + 0x3F, 0x3F, 0x3E, 0x3E, 0x3C, 0x3B, 0x38, 0x36, 0x33, 0x30, 0x2B, 0x27, 0x22, 0x1E, 0x19, 0x14, + 0x0E, 0x09, 0x04, 0xFE, 0xF8, 0xF3, 0xED, 0xE8, 0xE2, 0xDC, 0xD6, 0xD1, 0xCB, 0xC6, 0xC0, 0xBC, + 0xB7, 0xB2, 0xAE, 0xAB, 0xA8, 0xA5, 0xA2, 0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x9B, 0x9A, 0x9A, 0x99, + 0x99, 0x99, 0x98, 0x98, 0x97, 0x97, 0x96, 0x95, 0x95, 0x95, 0x94, 0x94, 0x94, 0x94, 0x94, 0x95, + 0x96, 0x97, 0x99, 0x9B, 0x9E, 0xA0, 0xA4, 0xA8, 0xAD, 0xB2, 0xB7, 0xBD, 0xC3, 0xCA, 0xD1, 0xD7, + 0xDF, 0xE5, 0xEC, 0xF3, 0xF9, 0xFF, 0x04, 0x09, 0x0C, 0x0F, 0x11, 0x12, 0x12, 0x11, 0x10, 0x0D, + 0x09, 0x05, 0x00, 0xFB, 0xF5, 0xEF, 0xE9, 0xE2, 0xDC, 0xD6, 0xD0, 0xC9, 0xC4, 0xBF, 0xBB, 0xB7, + 0xB4, 0xB1, 0xB0, 0xAF, 0xAF, 0xAF, 0xB1, 0xB4, 0xB7, 0xBB, 0xBF, 0xC5, 0xCA, 0xD1, 0xD7, 0xDE, + 0xE5, 0xED, 0xF4, 0xFC, 0x03, 0x0B, 0x12, 0x19, 0x1F, 0x24, 0x29, 0x2E, 0x33, 0x36, 0x39, 0x3C, + 0x3E, 0x40, 0x41, 0x42, 0x42, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43, 0x44, 0x44, 0x44, 0x45, 0x46, 0x47, 0x47, 0x47, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x47, 0x47, 0x46, 0x46, 0x45, 0x44, 0x43, 0x43, 0x42, 0x41, 0x40, + 0x40, 0x3F, 0x3F, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F, 0x3F, 0x40, 0x40, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x40, 0x40, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, + 0x37, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x30, 0x2F, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, + 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x35, 0x36, 0x37, 0x39, 0x3A, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x42, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3C, 0x39, 0x37, 0x34, 0x31, 0x2D, 0x29, 0x24, + 0x20, 0x1B, 0x16, 0x10, 0x0A, 0x05, 0xFE, 0xF8, 0xF2, 0xEC, 0xE6, 0xE0, 0xDA, 0xD4, 0xCE, 0xC9, + 0xC4, 0xBF, 0xBB, 0xB7, 0xB3, 0xB0, 0xAD, 0xAA, 0xA8, 0xA6, 0xA4, 0xA2, 0xA0, 0x9F, 0x9D, 0x9B, + 0x9A, 0x98, 0x96, 0x95, 0x93, 0x91, 0x8F, 0x8E, 0x8C, 0x8B, 0x89, 0x88, 0x88, 0x87, 0x87, 0x87, + 0x88, 0x89, 0x8A, 0x8C, 0x8F, 0x92, 0x96, 0x9B, 0xA0, 0xA6, 0xAC, 0xB3, 0xB9, 0xC1, 0xC8, 0xD0, + 0xD8, 0xDF, 0xE7, 0xEE, 0xF5, 0xFB, 0xFF, 0x04, 0x08, 0x0B, 0x0D, 0x0E, 0x0E, 0x0E, 0x0C, 0x09, + 0x06, 0x03, 0xFE, 0xFA, 0xF4, 0xEF, 0xE9, 0xE3, 0xDD, 0xD8, 0xD2, 0xCD, 0xC8, 0xC4, 0xC0, 0xBC, + 0xBA, 0xB8, 0xB7, 0xB6, 0xB6, 0xB7, 0xB9, 0xBC, 0xBF, 0xC2, 0xC7, 0xCB, 0xD0, 0xD6, 0xDC, 0xE2, + 0xE8, 0xEF, 0xF5, 0xFB, 0x01, 0x07, 0x0D, 0x12, 0x17, 0x1B, 0x1F, 0x23, 0x27, 0x29, 0x2C, 0x2E, + 0x30, 0x32, 0x33, 0x34, 0x35, 0x36, 0x36, 0x37, 0x38, 0x38, 0x39, 0x39, 0x3A, 0x3B, 0x3B, 0x3C, + 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x47, 0x48, 0x48, 0x49, + 0x49, 0x49, 0x49, 0x49, 0x48, 0x48, 0x47, 0x46, 0x46, 0x45, 0x44, 0x44, 0x43, 0x42, 0x42, 0x41, + 0x41, 0x41, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x41, 0x41, 0x40, 0x40, 0x3F, 0x3E, 0x3E, 0x3D, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2F, 0x2E, 0x2E, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2E, 0x2F, + 0x2F, 0x30, 0x31, 0x33, 0x34, 0x35, 0x36, 0x38, 0x39, 0x3B, 0x3C, 0x3D, 0x3F, 0x40, 0x41, 0x42, + 0x43, 0x44, 0x45, 0x45, 0x45, 0x45, 0x44, 0x43, 0x42, 0x40, 0x3E, 0x3C, 0x39, 0x36, 0x32, 0x2E, + 0x2A, 0x26, 0x21, 0x1C, 0x16, 0x10, 0x0A, 0x04, 0xFE, 0xF8, 0xF2, 0xEC, 0xE6, 0xE0, 0xDB, 0xD6, + 0xD1, 0xCC, 0xC8, 0xC4, 0xC0, 0xBD, 0xB9, 0xB6, 0xB3, 0xB1, 0xAE, 0xAB, 0xA8, 0xA5, 0xA3, 0xA0, + 0x9D, 0x9A, 0x98, 0x95, 0x92, 0x8F, 0x8D, 0x8A, 0x88, 0x86, 0x84, 0x83, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x83, 0x84, 0x86, 0x86 +}; + +const uint8_t SfxPlayer::_musicDataSample2[] = { + 0x0D, 0x90, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x22, 0x1E, 0x18, 0x14, 0x10, 0x10, + 0x12, 0x16, 0x18, 0x1E, 0x22, 0x22, 0x1E, 0x20, 0x24, 0x22, 0x28, 0x38, 0x30, 0x36, 0x38, 0x2A, + 0x38, 0x32, 0x48, 0x30, 0x36, 0x58, 0x2E, 0x78, 0x24, 0x1A, 0x60, 0x1A, 0x78, 0xF6, 0x7F, 0x80, + 0x7F, 0x00, 0xFE, 0x7F, 0xB8, 0x7E, 0xE8, 0x0A, 0x7C, 0x28, 0x80, 0x9A, 0x7F, 0x6C, 0x60, 0xE4, + 0x5E, 0x6C, 0x7F, 0x7F, 0x76, 0x7F, 0x7C, 0x7F, 0x7F, 0x42, 0x7E, 0x48, 0x9E, 0x7F, 0xE8, 0x6C, + 0x08, 0x1A, 0x7F, 0x20, 0xEC, 0xFE, 0x7F, 0x32, 0x1C, 0xD8, 0x3E, 0x18, 0xCA, 0x48, 0xE0, 0xD8, + 0x4C, 0x24, 0xDC, 0x80, 0x80, 0x02, 0xA0, 0xCA, 0xD8, 0x94, 0xF2, 0xE6, 0x80, 0xAE, 0xA0, 0x80, + 0xCA, 0xA2, 0x82, 0x88, 0xAE, 0x80, 0x80, 0xB8, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x8E, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x96, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x90, 0x80, 0x8E, 0x9A, 0x84, 0xD6, 0xB8, 0x82, 0x98, 0x80, 0x96, 0x90, 0xFE, 0x18, + 0xE4, 0xFE, 0x50, 0x90, 0xBE, 0x4C, 0x00, 0xE8, 0xFE, 0x18, 0xDA, 0x7F, 0x60, 0x46, 0x60, 0x3C, + 0x50, 0x34, 0x7F, 0x7A, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x70, 0x54, + 0x58, 0x60, 0x3C, 0x3A, 0x40, 0x1C, 0x12, 0x08, 0x00, 0xE4, 0xCC, 0xCA, 0xC0, 0xE2, 0xD6, 0xBA, + 0x96, 0x80, 0x9A, 0x82, 0x80, 0x9C, 0x8E, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x82, + 0x88, 0x90, 0x8E, 0x92, 0x9E, 0xAE, 0xD8, 0xE0, 0xC2, 0xB0, 0xA8, 0xBA, 0xD8, 0xFC, 0x10, 0x02, + 0xF0, 0xEA, 0x0C, 0x3A, 0x48, 0x34, 0x24, 0x16, 0x1E, 0x3E, 0x6C, 0x7F, 0x7F, 0x62, 0x46, 0x3C, + 0x54, 0x76, 0x7E, 0x74, 0x7A, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7A, 0x78, 0x72, 0x66, 0x6E, 0x6E, 0x6C, 0x70, 0x72, 0x66, 0x60, + 0x60, 0x58, 0x52, 0x5C, 0x54, 0x54, 0x50, 0x4A, 0x48, 0x4A, 0x40, 0x42, 0x3A, 0x2A, 0x2E, 0x30, + 0x34, 0x34, 0x28, 0x22, 0x1E, 0x1A, 0x18, 0x16, 0x14, 0x0E, 0x06, 0x0A, 0x0E, 0x0A, 0x00, 0xF4, + 0xF6, 0xF0, 0xF8, 0xF8, 0xF0, 0xE8, 0xD8, 0xD0, 0xCE, 0xD0, 0xD0, 0xCE, 0xCE, 0xCC, 0xCE, 0xC2, + 0xB2, 0xB0, 0xB4, 0xBA, 0xB4, 0xAE, 0xAE, 0xA8, 0xA6, 0xA8, 0x9A, 0x98, 0x94, 0x8E, 0x8E, 0x8E, + 0x8E, 0x88, 0x8C, 0x8A, 0x84, 0x86, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x84, 0x8E, 0x9A, 0x92, 0x90, 0x90, 0x9A, 0x98, 0x9E, 0xB6, 0xBA, 0xC0, 0xC0, 0xA8, 0xB0, 0xC0, + 0xCC, 0xE2, 0xE4, 0xD8, 0xDC, 0xD4, 0xE2, 0xF2, 0xF0, 0x00, 0x06, 0x02, 0x00, 0x06, 0x06, 0x0E, + 0x14, 0x16, 0x22, 0x30, 0x2A, 0x22, 0x28, 0x34, 0x3A, 0x4A, 0x4E, 0x52, 0x54, 0x4A, 0x56, 0x54, + 0x52, 0x5E, 0x5E, 0x64, 0x68, 0x6E, 0x78, 0x7F, 0x7A, 0x7C, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7C, 0x78, 0x76, + 0x72, 0x6E, 0x6C, 0x68, 0x64, 0x60, 0x5C, 0x58, 0x56, 0x52, 0x50, 0x4C, 0x44, 0x46, 0x3E, 0x38, + 0x38, 0x2E, 0x2A, 0x1C, 0x1E, 0x18, 0x0E, 0x16, 0x02, 0xF0, 0xFA, 0xFC, 0xEC, 0xEC, 0xDC, 0xE2, + 0xD4, 0xDA, 0xCC, 0xC8, 0xCC, 0xBE, 0xC6, 0xC0, 0xBA, 0xBC, 0xB6, 0xB0, 0xA2, 0xA6, 0x9E, 0x94, + 0x96, 0x8C, 0x98, 0x80, 0x92, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x86, 0x8E, 0x8C, 0x8C, 0x94, 0x90, + 0x98, 0xA0, 0xA6, 0xB4, 0xBA, 0xB8, 0xC4, 0xC4, 0xD0, 0xCE, 0xD2, 0xD8, 0xDC, 0xE2, 0xE4, 0xEA, + 0xEA, 0xEC, 0xF6, 0xFE, 0xFE, 0x04, 0x0E, 0x06, 0x0E, 0x1E, 0x1E, 0x24, 0x2A, 0x32, 0x30, 0x3C, + 0x42, 0x3E, 0x46, 0x46, 0x48, 0x4C, 0x54, 0x5C, 0x64, 0x66, 0x6C, 0x6E, 0x72, 0x76, 0x72, 0x76, + 0x7A, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7A, 0x78, 0x78, 0x72, 0x72, 0x68, 0x68, + 0x68, 0x68, 0x64, 0x64, 0x60, 0x5A, 0x5E, 0x58, 0x56, 0x58, 0x58, 0x54, 0x56, 0x52, 0x50, 0x52, + 0x4A, 0x4E, 0x4A, 0x48, 0x4C, 0x46, 0x44, 0x3E, 0x3C, 0x34, 0x36, 0x38, 0x34, 0x36, 0x30, 0x34, + 0x2E, 0x30, 0x2C, 0x26, 0x32, 0x26, 0x26, 0x26, 0x24, 0x26, 0x22, 0x22, 0x1E, 0x20, 0x20, 0x22, + 0x1E, 0x1A, 0x18, 0x18, 0x1C, 0x18, 0x18, 0x1A, 0x10, 0x14, 0x12, 0x10, 0x14, 0x14, 0x18, 0x16, + 0x1A, 0x14, 0x14, 0x12, 0x18, 0x16, 0x0E, 0x16, 0x0C, 0x0C, 0x10, 0x04, 0x10, 0x04, 0x0E, 0x00, + 0x06, 0x0E, 0x06, 0x04, 0x04, 0x06, 0x0A, 0x08, 0xFC, 0x06, 0x0E, 0x0A, 0x0C, 0x04, 0x06, 0x08, + 0x10, 0x0A, 0x06, 0x08, 0x04, 0x04, 0x06, 0x02, 0x06, 0x00, 0xFE, 0x06, 0xFE, 0xFC, 0xFA, 0x02, + 0x02, 0x00, 0xF6, 0xF6, 0x00, 0xF6, 0xF8, 0xF4, 0xFA, 0xF8, 0xF2, 0xF6, 0xF0, 0xEC, 0xF4, 0xF0, + 0xE6, 0xEA, 0xEC, 0xF0, 0xF0, 0xE4, 0xEA, 0xEC, 0xEC, 0xF0, 0xE0, 0xE4, 0xE4, 0xDE, 0xE2, 0xE2, + 0xE4, 0xE0, 0xE4, 0xDE, 0xDA, 0xE6, 0xDA, 0xDC, 0xD6, 0xCE, 0xD8, 0xDA, 0xD4, 0xCE, 0xD8, 0xD4, + 0xD8, 0xDA, 0xD0, 0xD2, 0xD0, 0xCE, 0xCC, 0xD0, 0xD2, 0xCE, 0xD4, 0xCC, 0xCA, 0xCC, 0xC6, 0xC8, + 0xC6, 0xC2, 0xC6, 0xCE, 0xC6, 0xCE, 0xCC, 0xC0, 0xCA, 0xC4, 0xCC, 0xCC, 0xCA, 0xCC, 0xCA, 0xCC, + 0xCA, 0xC6, 0xC6, 0xC6, 0xC6, 0xC0, 0xC2, 0xC6, 0xC0, 0xC8, 0xCC, 0xCC, 0xD0, 0xD0, 0xCC, 0xCC, + 0xCA, 0xCE, 0xD8, 0xD2, 0xDC, 0xDC, 0xD8, 0xDC, 0xD4, 0xD2, 0xD2, 0xD4, 0xD8, 0xDA, 0xE0, 0xDA, + 0xE0, 0xEE, 0xEE, 0xF8, 0xF4, 0xEE, 0xF6, 0xFE, 0xF8, 0xFC, 0x00, 0x02, 0x04, 0x00, 0xFE, 0xFE, + 0x06, 0x08, 0x0E, 0x0C, 0x0C, 0x0E, 0x0E, 0x10, 0x18, 0x12, 0x14, 0x18, 0x20, 0x20, 0x24, 0x2A, + 0x2A, 0x2C, 0x28, 0x26, 0x2A, 0x32, 0x34, 0x3A, 0x3A, 0x38, 0x38, 0x38, 0x36, 0x38, 0x42, 0x46, + 0x48, 0x4A, 0x48, 0x4E, 0x50, 0x4C, 0x52, 0x4E, 0x50, 0x58, 0x52, 0x54, 0x54, 0x5A, 0x56, 0x5A, + 0x5A, 0x5C, 0x62, 0x64, 0x62, 0x60, 0x68, 0x64, 0x6A, 0x6C, 0x6E, 0x72, 0x66, 0x6C, 0x68, 0x6C, + 0x72, 0x6E, 0x72, 0x6E, 0x72, 0x78, 0x70, 0x70, 0x72, 0x74, 0x7A, 0x74, 0x74, 0x74, 0x74, 0x76, + 0x7A, 0x7A, 0x7C, 0x7F, 0x78, 0x7C, 0x78, 0x70, 0x78, 0x78, 0x7A, 0x7F, 0x78, 0x7A, 0x7F, 0x78, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7C, 0x7F, 0x7F, 0x7F, 0x7F, 0x7C, 0x7E, + 0x7C, 0x7C, 0x7F, 0x7F, 0x7A, 0x7C, 0x70, 0x72, 0x7C, 0x74, 0x70, 0x6E, 0x6E, 0x6E, 0x6E, 0x68, + 0x6E, 0x6A, 0x64, 0x64, 0x5C, 0x5E, 0x5A, 0x56, 0x50, 0x48, 0x48, 0x4E, 0x4A, 0x44, 0x3A, 0x38, + 0x32, 0x2A, 0x36, 0x34, 0x24, 0x26, 0x20, 0x1C, 0x1E, 0x1E, 0x1C, 0x18, 0x12, 0x0C, 0x06, 0xFC, + 0x02, 0xFA, 0xF6, 0xF8, 0xEE, 0xEE, 0xF0, 0xEE, 0xEA, 0xE0, 0xDE, 0xE0, 0xDE, 0xCE, 0xD6, 0xD0, + 0xC8, 0xD2, 0xC4, 0xBA, 0xC8, 0xBA, 0xB8, 0xC0, 0xAC, 0xB0, 0xB0, 0xA8, 0xB4, 0xAA, 0xA8, 0xA8, + 0xA0, 0x9A, 0xA2, 0xA0, 0x9C, 0x9C, 0x9C, 0x98, 0x94, 0x98, 0x8C, 0x92, 0x94, 0x8A, 0x8A, 0x88, + 0x80, 0x86, 0x84, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x82, 0x82, 0x80, 0x86, 0x80, + 0x82, 0x88, 0x82, 0x8E, 0x88, 0x8A, 0x8E, 0x8E, 0x96, 0x92, 0x96, 0x9A, 0x98, 0x9A, 0x9E, 0x9E, + 0xAA, 0xB0, 0xB0, 0xB0, 0xB8, 0xB2, 0xB8, 0xC4, 0xC2, 0xCC, 0xC6, 0xCC, 0xD6, 0xD0, 0xD0, 0xD6, + 0xDE, 0xE2, 0xE4, 0xF0, 0xEE, 0xE4, 0xF4, 0xF4, 0xF6, 0xFE, 0x00, 0x0A, 0x10, 0x10, 0x14, 0x1E, + 0x1A, 0x22, 0x2A, 0x22, 0x32, 0x36, 0x34, 0x3E, 0x3E, 0x3C, 0x40, 0x46, 0x4A, 0x50, 0x50, 0x56, + 0x54, 0x60, 0x6A, 0x6A, 0x6E, 0x6A, 0x6C, 0x76, 0x78, 0x7A, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7C, 0x78, 0x74, + 0x76, 0x76, 0x6A, 0x72, 0x62, 0x62, 0x68, 0x5C, 0x58, 0x52, 0x50, 0x44, 0x48, 0x4A, 0x42, 0x48, + 0x3A, 0x32, 0x3E, 0x34, 0x30, 0x38, 0x30, 0x2E, 0x2A, 0x2A, 0x26, 0x1E, 0x1A, 0x16, 0x10, 0x0C, + 0x0C, 0x00, 0xF0, 0xF4, 0xFA, 0xF8, 0xF6, 0xF2, 0xF0, 0xF0, 0xF0, 0xEA, 0xDC, 0xE2, 0xDE, 0xDC, + 0xE0, 0xD2, 0xCA, 0xDA, 0xCC, 0xD2, 0xD6, 0xCA, 0xDC, 0xD0, 0xC8, 0xD6, 0xC6, 0xC6, 0xC0, 0xBC, + 0xB8, 0xBA, 0xBA, 0xC0, 0xC2, 0xB8, 0xB8, 0xB4, 0xB0, 0xB4, 0xB0, 0xB2, 0xAE, 0xAC, 0xB2, 0xB2, + 0xAC, 0xA6, 0xAC, 0xAA, 0xAC, 0xAA, 0xAC, 0xA8, 0xA2, 0xA4, 0xA6, 0x9E, 0xA2, 0xA4, 0xA6, 0xA8, + 0x9E, 0xAC, 0xA4, 0xA6, 0xAC, 0xA4, 0xA8, 0xA6, 0xA2, 0xA0, 0xA2, 0xA4, 0xA0, 0xA0, 0x9C, 0x9C, + 0x98, 0x9C, 0x94, 0x9A, 0x9E, 0x9A, 0x9E, 0xA2, 0xA0, 0x9A, 0x98, 0x9A, 0x94, 0x98, 0x96, 0x8C, + 0x9E, 0x98, 0x9E, 0xA4, 0xA8, 0xA4, 0xA6, 0xA4, 0xA2, 0xAA, 0xA6, 0xAA, 0xAA, 0xA6, 0xAE, 0xB2, + 0xB2, 0xBA, 0xB0, 0xAA, 0xB2, 0xB8, 0xB2, 0xB6, 0xC2, 0xC8, 0xCE, 0xC8, 0xC8, 0xCA, 0xCA, 0xCC, + 0xD4, 0xD2, 0xD4, 0xD6, 0xE6, 0xE8, 0xE6, 0xE8, 0xE0, 0xE6, 0xEC, 0xEE, 0xF8, 0xF6, 0xF2, 0xFA, + 0xFC, 0xF6, 0xFE, 0x08, 0x08, 0x10, 0x10, 0x12, 0x18, 0x1C, 0x24, 0x22, 0x24, 0x2E, 0x2A, 0x34, + 0x34, 0x40, 0x42, 0x3E, 0x42, 0x3E, 0x46, 0x42, 0x46, 0x50, 0x4E, 0x56, 0x50, 0x4E, 0x5C, 0x5E, + 0x56, 0x5E, 0x60, 0x68, 0x62, 0x66, 0x60, 0x62, 0x6C, 0x66, 0x6C, 0x66, 0x60, 0x6A, 0x66, 0x6A, + 0x70, 0x68, 0x5E, 0x64, 0x68, 0x62, 0x6C, 0x68, 0x64, 0x68, 0x60, 0x66, 0x60, 0x5A, 0x58, 0x58, + 0x58, 0x50, 0x50, 0x4A, 0x46, 0x42, 0x44, 0x44, 0x48, 0x40, 0x3E, 0x42, 0x38, 0x3C, 0x30, 0x30, + 0x30, 0x2C, 0x34, 0x28, 0x28, 0x26, 0x1C, 0x28, 0x22, 0x1A, 0x16, 0x12, 0x0E, 0x0C, 0x0C, 0x0C, + 0x0C, 0x02, 0x06, 0x06, 0x00, 0x00, 0x00, 0xFA, 0xFA, 0xFC, 0xF2, 0xF6, 0xFA, 0xF6, 0xF4, 0xF0, + 0xF0, 0xE8, 0xE8, 0xF2, 0xF0, 0xF0, 0xE6, 0xE4, 0xE6, 0xEC, 0xEE, 0xEE, 0xE2, 0xE6, 0xEE, 0xE4, + 0xF0, 0xEC, 0xE6, 0xEC, 0xEA, 0xEC, 0xF0, 0xF0, 0xEA, 0xE8, 0xEA, 0xEC, 0xFA, 0xF0, 0xE8, 0xEE, + 0xEA, 0xF4, 0xFC, 0xFE, 0xFA, 0x00, 0xF8, 0xF8, 0xF8, 0xFC, 0x00, 0xFC, 0x02, 0x00, 0x06, 0x0A, + 0x0A, 0x0C, 0x10, 0x0C, 0x0E, 0x08, 0x0C, 0x10, 0x0E, 0x18, 0x14, 0x1E, 0x1C, 0x20, 0x1E, 0x1C, + 0x1E, 0x1E, 0x20, 0x26, 0x22, 0x1E, 0x20, 0x22, 0x28, 0x20, 0x26, 0x2A, 0x26, 0x2C, 0x26, 0x26, + 0x26, 0x28, 0x30, 0x38, 0x2E, 0x2E, 0x30, 0x2A, 0x34, 0x30, 0x32, 0x2E, 0x26, 0x2C, 0x2C, 0x26, + 0x26, 0x2A, 0x28, 0x2A, 0x28, 0x26, 0x2A, 0x24, 0x20, 0x28, 0x26, 0x28, 0x26, 0x22, 0x1E, 0x20, + 0x24, 0x1C, 0x12, 0x1C, 0x0E, 0x14, 0x14, 0x0E, 0x18, 0x12, 0x10, 0x12, 0x0C, 0x0C, 0x04, 0x0C, + 0x0A, 0x0C, 0x08, 0x02, 0x0C, 0x10, 0x0E, 0x0A, 0x02, 0xFE, 0x06, 0x06, 0x06, 0x04, 0xFC, 0x06, + 0x08, 0x02, 0x00, 0xF8, 0xFC, 0xFC, 0xF4, 0xFC, 0x00, 0x00, 0xFE, 0xF8, 0xF0, 0xF6, 0xFC, 0xF6, + 0xF4, 0xF2, 0xF6, 0xFA, 0xF2, 0xF8, 0xF8, 0xFA, 0xF6, 0xFC, 0xFC, 0xF6, 0xFC, 0xF2, 0xFC, 0xFA, + 0xFE, 0xFC, 0xFE, 0x00, 0xFC, 0xFE, 0x00, 0xFE, 0x06, 0x02, 0x04, 0x10, 0x0E, 0x12, 0x0C, 0x0E, + 0x0E, 0x0C, 0x0E, 0x10, 0x10, 0x1A, 0x0E, 0x08, 0x16, 0x1A, 0x20, 0x20, 0x22, 0x2C, 0x2C, 0x30, + 0x30, 0x38, 0x3E, 0x34, 0x36, 0x3E, 0x40, 0x3C, 0x42, 0x3C, 0x44, 0x46, 0x46, 0x4A, 0x4C, 0x4A, + 0x4A, 0x52, 0x50, 0x56, 0x5E, 0x5E, 0x60, 0x60, 0x62, 0x60, 0x62, 0x64, 0x60, 0x64, 0x64, 0x6A, + 0x72, 0x68, 0x66, 0x6C, 0x6E, 0x6E, 0x74, 0x70, 0x6C, 0x6C, 0x66, 0x70, 0x7A, 0x7A, 0x7A, 0x78, + 0x74, 0x72, 0x72, 0x78, 0x72, 0x76, 0x76, 0x74, 0x78, 0x72, 0x76, 0x72, 0x70, 0x74, 0x70, 0x72, + 0x70, 0x76, 0x74, 0x6E, 0x6A, 0x66, 0x68, 0x64, 0x64, 0x60, 0x64, 0x64, 0x64, 0x68, 0x60, 0x5A, + 0x5C, 0x58, 0x56, 0x54, 0x58, 0x4C, 0x50, 0x4E, 0x4A, 0x4A, 0x46, 0x46, 0x42, 0x42, 0x46, 0x46, + 0x42, 0x40, 0x40, 0x3C, 0x3A, 0x3A, 0x3A, 0x36, 0x3A, 0x36, 0x34, 0x30, 0x2E, 0x30, 0x28, 0x24, + 0x26, 0x1E, 0x26, 0x1E, 0x18, 0x1A, 0x14, 0x16, 0x1C, 0x12, 0x08, 0x02, 0x04, 0x04, 0x08, 0x04, + 0x00, 0x00, 0xFA, 0xF8, 0xF2, 0xF2, 0xEC, 0xE8, 0xEA, 0xE4, 0xE2, 0xE0, 0xDA, 0xDE, 0xDC, 0xD6, + 0xD2, 0xD2, 0xCE, 0xCC, 0xC4, 0xC0, 0xC4, 0xBC, 0xC0, 0xC0, 0xB8, 0xAE, 0xAA, 0xAC, 0xAE, 0xA4, + 0xA0, 0x9C, 0x9C, 0xA6, 0x9E, 0xA0, 0x9A, 0x9C, 0x9A, 0x94, 0x98, 0x94, 0x98, 0x96, 0x9C, 0x92, + 0x8E, 0x8E, 0x8E, 0x90, 0x8A, 0x84, 0x82, 0x82, 0x84, 0x80, 0x86, 0x86, 0x86, 0x8A, 0x88, 0x90, + 0x96, 0x94, 0x98, 0x8E, 0x90, 0x98, 0x9A, 0x9A, 0x98, 0x90, 0x9A, 0xA0, 0xA0, 0xAC, 0xA8, 0xAE, + 0xB2, 0xB0, 0xB2, 0xBE, 0xBC, 0xBC, 0xC2, 0xC4, 0xCC, 0xCC, 0xCE, 0xD4, 0xD8, 0xDA, 0xDC, 0xEA, + 0xEA, 0xEC, 0xF2, 0xF4, 0xFC, 0xFA, 0x00, 0x06, 0x0A, 0x12, 0x14, 0x16, 0x16, 0x2A, 0x36, 0x34, + 0x34, 0x3A, 0x3A, 0x46, 0x4C, 0x52, 0x5A, 0x5A, 0x60, 0x5C, 0x5E, 0x68, 0x6A, 0x66, 0x72, 0x76, + 0x78, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7C, + 0x76, 0x76, 0x72, 0x74, 0x70, 0x68, 0x68, 0x60, 0x5E, 0x5E, 0x56, 0x58, 0x56, 0x4C, 0x4C, 0x46, + 0x44, 0x46, 0x3C, 0x3A, 0x30, 0x30, 0x2A, 0x2C, 0x26, 0x20, 0x1E, 0x1E, 0x1E, 0x18, 0x16, 0x14, + 0x0E, 0x10, 0x08, 0x08, 0x06, 0x04, 0x00, 0xFC, 0xFA, 0xF6, 0xEE, 0xF0, 0xEE, 0xEA, 0xE4, 0xE6, + 0xE6, 0xE2, 0xDE, 0xE0, 0xE0, 0xDE, 0xE2, 0xDA, 0xD8, 0xD8, 0xD8, 0xD6, 0xDA, 0xD6, 0xD4, 0xD4, + 0xCE, 0xCA, 0xC8, 0xCA, 0xD0, 0xCE, 0xCA, 0xCC, 0xC6, 0xC2, 0xC6, 0xC8, 0xC8, 0xCE, 0xCA, 0xCA, + 0xC6, 0xCC, 0xC0, 0xC0, 0xC4, 0xC2, 0xC6, 0xC0, 0xBE, 0xC2, 0xC2, 0xBC, 0xB8, 0xBC, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC8, 0xC6, 0xC4, 0xC2, 0xC6, 0xC2, 0xC2, 0xC4, 0xC6, 0xC0, 0xBC, 0xC4, 0xC2, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC4, 0xC0, 0xC6, 0xCE, 0xC6, 0xC8, 0xC8, 0xC6, 0xC0, 0xC2, 0xC8, 0xCC, + 0xCA, 0xCC, 0xCA, 0xC4, 0xCC, 0xCE, 0xC8, 0xCC, 0xC8, 0xC6, 0xC6, 0xC6, 0xD0, 0xCA, 0xC8, 0xC6, + 0xC8, 0xD2, 0xD0, 0xCC, 0xCA, 0xCE, 0xD0, 0xD4, 0xD4, 0xD6, 0xD4, 0xD6, 0xD6, 0xD6, 0xD4, 0xD2, + 0xD4, 0xD8, 0xD2, 0xD6, 0xD8, 0xD6, 0xDA, 0xD4, 0xD4, 0xD2, 0xD8, 0xE0, 0xE0, 0xE0, 0xDC, 0xDE, + 0xDE, 0xE2, 0xE0, 0xDC, 0xE2, 0xE0, 0xE0, 0xE4, 0xE6, 0xE6, 0xE4, 0xE4, 0xE2, 0xE0, 0xE6, 0xEC, + 0xE8, 0xE6, 0xE8, 0xE8, 0xEA, 0xEC, 0xEE, 0xF0, 0xEC, 0xEA, 0xEA, 0xEC, 0xF4, 0xF2, 0xF2, 0xEC, + 0xEE, 0xF0, 0xEE, 0xF2, 0xF2, 0xF2, 0xF6, 0xF8, 0xF4, 0xF6, 0xFA, 0xF8, 0xF8, 0xF8, 0xFC, 0xFC, + 0xF8, 0xF8, 0xFA, 0x00, 0x00, 0x04, 0x08, 0x04, 0x02, 0x02, 0x04, 0x10, 0x14, 0x10, 0x12, 0x0C, + 0x0C, 0x12, 0x12, 0x14, 0x16, 0x16, 0x18, 0x1A, 0x1E, 0x20, 0x20, 0x22, 0x20, 0x1E, 0x22, 0x28, + 0x28, 0x2A, 0x2C, 0x2E, 0x30, 0x32, 0x34, 0x38, 0x36, 0x36, 0x36, 0x36, 0x3E, 0x42, 0x42, 0x42, + 0x42, 0x46, 0x48, 0x48, 0x4E, 0x4A, 0x54, 0x58, 0x58, 0x5A, 0x5A, 0x5C, 0x62, 0x62, 0x5E, 0x68, + 0x66, 0x6A, 0x70, 0x6E, 0x70, 0x72, 0x72, 0x76, 0x7A, 0x76, 0x74, 0x78, 0x78, 0x7C, 0x7F, 0x7A, + 0x7C, 0x7E, 0x7E, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7F, 0x7A, 0x7C, + 0x7C, 0x7C, 0x74, 0x6A, 0x6C, 0x6E, 0x6E, 0x6C, 0x60, 0x60, 0x5E, 0x5E, 0x5C, 0x56, 0x54, 0x56, + 0x54, 0x52, 0x54, 0x4C, 0x46, 0x44, 0x42, 0x40, 0x3C, 0x3C, 0x3C, 0x38, 0x32, 0x32, 0x2C, 0x2C, + 0x26, 0x24, 0x26, 0x20, 0x22, 0x1E, 0x1C, 0x18, 0x10, 0x18, 0x10, 0x10, 0x0C, 0x0C, 0x08, 0x0C, + 0x0C, 0x02, 0x00, 0xFC, 0x00, 0xFC, 0xF8, 0xF2, 0xF2, 0xEA, 0xEA, 0xEE, 0xF0, 0xF2, 0xE6, 0xE4, + 0xE4, 0xE6, 0xE8, 0xEA, 0xE6, 0xE2, 0xE4, 0xE0, 0xE2, 0xE0, 0xDC, 0xD2, 0xD6, 0xD8, 0xDA, 0xDA, + 0xD0, 0xD4, 0xD6, 0xD0, 0xCE, 0xD2, 0xD0, 0xCC, 0xCA, 0xCC, 0xCC, 0xCA, 0xCC, 0xCC, 0xCC, 0xCA, + 0xC6, 0xC6, 0xC4, 0xC4, 0xC4, 0xC4, 0xC0, 0xC6, 0xC2, 0xC6, 0xC8, 0xC2, 0xC2, 0xC2, 0xC0, 0xC6, + 0xC6, 0xC2, 0xC4, 0xC6, 0xC2, 0xC2, 0xC4, 0xC8, 0xC6, 0xC4, 0xC0, 0xC0, 0xBC, 0xBE, 0xBE, 0xC0, + 0xC2, 0xC0, 0xC4, 0xC0, 0xC0, 0xC2, 0xBE, 0xC2, 0xC6, 0xCA, 0xC6, 0xC4, 0xC0, 0xC0, 0xC0, 0xC2, + 0xC6, 0xC8, 0xC6, 0xC8, 0xC8, 0xC6, 0xC6, 0xCA, 0xCA, 0xCC, 0xCE, 0xCC, 0xCC, 0xD6, 0xDA, 0xDC, + 0xDC, 0xDE, 0xDA, 0xDA, 0xE2, 0xE2, 0xE8, 0xE6, 0xE6, 0xE6, 0xEC, 0xF0, 0xF2, 0xF2, 0xF2, 0xF4, + 0xF8, 0xFC, 0xFC, 0x02, 0x04, 0x04, 0x06, 0x0C, 0x0E, 0x10, 0x10, 0x16, 0x1A, 0x1A, 0x1E, 0x20, + 0x24, 0x24, 0x24, 0x26, 0x2A, 0x30, 0x2E, 0x32, 0x36, 0x38, 0x40, 0x3E, 0x3E, 0x3E, 0x42, 0x42, + 0x44, 0x4C, 0x50, 0x54, 0x54, 0x52, 0x50, 0x54, 0x5C, 0x5A, 0x5C, 0x5E, 0x5C, 0x5E, 0x62, 0x64, + 0x66, 0x64, 0x64, 0x66, 0x66, 0x66, 0x68, 0x6C, 0x6E, 0x6E, 0x6C, 0x6A, 0x6C, 0x6A, 0x6E, 0x6A, + 0x6E, 0x6A, 0x70, 0x70, 0x6A, 0x6C, 0x68, 0x6A, 0x6E, 0x6C, 0x6C, 0x64, 0x62, 0x64, 0x66, 0x6C, + 0x68, 0x62, 0x60, 0x5E, 0x64, 0x66, 0x60, 0x5E, 0x5C, 0x5C, 0x5C, 0x58, 0x54, 0x56, 0x50, 0x52, + 0x4C, 0x46, 0x48, 0x42, 0x46, 0x4A, 0x40, 0x3A, 0x38, 0x3A, 0x36, 0x30, 0x2A, 0x26, 0x2C, 0x30, + 0x2A, 0x26, 0x2A, 0x2A, 0x22, 0x1C, 0x18, 0x1C, 0x16, 0x14, 0x16, 0x0E, 0x12, 0x14, 0x0A, 0x06, + 0x08, 0x00, 0x04, 0x02, 0x00, 0xFC, 0xFC, 0xFE, 0xF8, 0xF6, 0xF2, 0xF0, 0xF2, 0xF0, 0xEC, 0xEA, + 0xEA, 0xEA, 0xEE, 0xEA, 0xE6, 0xE8, 0xE2, 0xE6, 0xE8, 0xE6, 0xEA, 0xE4, 0xE2, 0xE0, 0xE0, 0xE0, + 0xDE, 0xE2, 0xE4, 0xE0, 0xE0, 0xE0, 0xE2, 0xE2, 0xE0, 0xE2, 0xE4, 0xE0, 0xE0, 0xE2, 0xE2, 0xE4, + 0xE6, 0xE6, 0xE6, 0xE6, 0xEE, 0xE8, 0xE6, 0xE8, 0xE6, 0xE6, 0xEC, 0xF0, 0xEE, 0xEE, 0xEC, 0xEE, + 0xF2, 0xF4, 0xF8, 0xF4, 0xF8, 0xF8, 0xF8, 0xFA, 0xFE, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, + 0x08, 0x0A, 0x08, 0x0C, 0x0A, 0x0E, 0x0E, 0x0C, 0x0C, 0x10, 0x10, 0x12, 0x16, 0x18, 0x1A, 0x18, + 0x16, 0x18, 0x18, 0x16, 0x1A, 0x1E, 0x1E, 0x1E, 0x18, 0x1C, 0x1E, 0x1E, 0x1C, 0x1A, 0x20, 0x1E, + 0x24, 0x24, 0x24, 0x22, 0x20, 0x22, 0x22, 0x26, 0x22, 0x20, 0x20, 0x26, 0x26, 0x20, 0x1E, 0x1E, + 0x1E, 0x1C, 0x1A, 0x1C, 0x20, 0x20, 0x22, 0x22, 0x24, 0x20, 0x1E, 0x20, 0x22, 0x26, 0x20, 0x22, + 0x24, 0x24, 0x1E, 0x1C, 0x1C, 0x22, 0x22, 0x1C, 0x20, 0x20, 0x1E, 0x1C, 0x1C, 0x1A, 0x1A, 0x1C, + 0x1E, 0x1C, 0x1A, 0x1A, 0x18, 0x1C, 0x1A, 0x18, 0x1E, 0x18, 0x1C, 0x14, 0x12, 0x12, 0x16, 0x10, + 0x0E, 0x16, 0x14, 0x16, 0x10, 0x0E, 0x12, 0x16, 0x16, 0x14, 0x18, 0x10, 0x10, 0x10, 0x12, 0x10, + 0x10, 0x08, 0x08, 0x06, 0x08, 0x08, 0x06, 0x0C, 0x08, 0x08, 0x06, 0x08, 0x08, 0x0A, 0x08, 0x0A, + 0x0C, 0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x04, 0x02, 0x06, 0x06, 0x02, 0x04, 0x04, 0x06, + 0x08, 0x06, 0x04, 0x04, 0x06, 0x0C, 0x0A, 0x02, 0x02 +}; + +const uint8_t SfxPlayer::_musicDataSample3[] = { + 0x11, 0x8C, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x42, 0x50, 0x43, 0x18, 0xF6, 0xEE, + 0xE5, 0xCF, 0xC7, 0xB7, 0xAC, 0xAA, 0xAB, 0xD9, 0x2E, 0x7B, 0x7F, 0x79, 0x27, 0xEC, 0xCD, 0xE6, + 0x03, 0xFC, 0xE9, 0xE1, 0xE2, 0xF5, 0xFF, 0x0E, 0x23, 0x29, 0x13, 0xD5, 0x98, 0x8B, 0xA1, 0xBB, + 0xDF, 0xE9, 0x03, 0x36, 0x65, 0x72, 0x55, 0x23, 0x01, 0xDF, 0xC2, 0xA0, 0x85, 0x90, 0xC3, 0xEF, + 0x18, 0x40, 0x53, 0x55, 0x26, 0xDB, 0x9E, 0x90, 0xC1, 0x0A, 0x3D, 0x59, 0x58, 0x54, 0x62, 0x68, + 0x57, 0x4A, 0x2B, 0xF3, 0xB5, 0x8C, 0x94, 0xC3, 0x02, 0x20, 0x04, 0xCD, 0xAF, 0xAC, 0xD9, 0x03, + 0x0D, 0x0D, 0x0F, 0x01, 0xFA, 0x06, 0x30, 0x5C, 0x75, 0x6F, 0x3A, 0x00, 0xF1, 0xFF, 0xFA, 0xE2, + 0xB2, 0xA3, 0xBC, 0xD8, 0xD7, 0xCD, 0xC5, 0xC6, 0xCA, 0xCE, 0xC7, 0xC1, 0xE8, 0x29, 0x46, 0x47, + 0x58, 0x73, 0x7F, 0x5F, 0x0E, 0xBE, 0xAC, 0xDA, 0x23, 0x50, 0x4F, 0x1F, 0xFE, 0xFB, 0xED, 0xCC, + 0xC6, 0xCB, 0xC0, 0xAB, 0xAB, 0xD6, 0x23, 0x7F, 0x7F, 0x7F, 0x3E, 0xEB, 0xCA, 0xE6, 0xFF, 0xF6, + 0xE8, 0xEB, 0xE7, 0xE5, 0xF6, 0x14, 0x22, 0x24, 0x17, 0xDC, 0x9D, 0x91, 0xB2, 0xDC, 0xED, 0xE2, + 0xEE, 0x21, 0x5A, 0x6E, 0x62, 0x3A, 0xFE, 0xCA, 0xBD, 0xAD, 0x93, 0x9D, 0xC7, 0xE8, 0xFF, 0x24, + 0x50, 0x60, 0x3A, 0xF1, 0xA9, 0x9A, 0xBE, 0x00, 0x48, 0x6D, 0x59, 0x48, 0x58, 0x5C, 0x4A, 0x38, + 0x24, 0xE7, 0x95, 0x84, 0x85, 0xC4, 0x13, 0x36, 0x1F, 0xE2, 0xA4, 0xA2, 0xD8, 0x02, 0x06, 0x01, + 0x0F, 0x15, 0x0E, 0x2E, 0x62, 0x73, 0x6A, 0x53, 0x19, 0xE0, 0xD2, 0xE4, 0xF1, 0xD0, 0xA6, 0xA6, + 0xCF, 0xF7, 0xEB, 0xD2, 0xC4, 0xB1, 0xA9, 0xC6, 0xD4, 0xD3, 0xFB, 0x3A, 0x56, 0x50, 0x4F, 0x6E, + 0x7C, 0x52, 0xFC, 0xA7, 0x9A, 0xC6, 0x0A, 0x44, 0x49, 0x18, 0x00, 0x0F, 0x09, 0xDF, 0xC4, 0xCB, + 0xCE, 0xB9, 0xC2, 0xE8, 0x26, 0x76, 0x7F, 0x7F, 0x3A, 0xD7, 0xBB, 0xE4, 0x01, 0xED, 0xCB, 0xCD, + 0xD8, 0xD9, 0xF2, 0x1C, 0x1F, 0x1B, 0x1E, 0xF2, 0xBF, 0xAC, 0xC6, 0xF6, 0xFD, 0xEC, 0xF0, 0x1B, + 0x58, 0x68, 0x58, 0x3E, 0xFE, 0xC5, 0xBA, 0xAD, 0x90, 0x98, 0xC2, 0xE7, 0xF7, 0x06, 0x39, 0x57, + 0x4A, 0x11, 0xBD, 0xA4, 0xC7, 0x03, 0x59, 0x7E, 0x5A, 0x3B, 0x41, 0x48, 0x37, 0x24, 0x18, 0xEA, + 0x95, 0x84, 0x8E, 0xC9, 0x20, 0x3F, 0x1F, 0xDE, 0x99, 0xAC, 0xFD, 0x3B, 0x42, 0x25, 0x23, 0x1D, + 0xFA, 0x05, 0x3E, 0x54, 0x57, 0x46, 0x0C, 0xDC, 0xD7, 0xF5, 0x11, 0xDA, 0x8A, 0x84, 0x8B, 0xDC, + 0xFB, 0xF1, 0xEF, 0xD7, 0xC5, 0xE5, 0xFB, 0xF2, 0xFA, 0x1F, 0x38, 0x35, 0x33, 0x6C, 0x7F, 0x78, + 0x1F, 0xA6, 0x84, 0x98, 0xD6, 0x23, 0x3B, 0x08, 0xE7, 0x02, 0x1A, 0x02, 0xE2, 0xE3, 0xE4, 0xB9, + 0xB1, 0xDA, 0x22, 0x7B, 0x7F, 0x7F, 0x34, 0xD3, 0xC7, 0x0C, 0x33, 0x0C, 0xC9, 0xB3, 0xC1, 0xC1, + 0xDD, 0x1D, 0x2E, 0x20, 0x14, 0xEF, 0xCB, 0xD0, 0xF7, 0x26, 0x0C, 0xC3, 0xA6, 0xD6, 0x36, 0x67, + 0x68, 0x59, 0x1B, 0xCD, 0xBA, 0xB8, 0x9C, 0x8F, 0xA6, 0xC2, 0xD0, 0xEC, 0x3B, 0x77, 0x6D, 0x29, + 0xC6, 0xA2, 0xC6, 0x07, 0x59, 0x7F, 0x5C, 0x2B, 0x2D, 0x41, 0x35, 0x25, 0x1F, 0xF5, 0x95, 0x84, + 0x8B, 0xD6, 0x2E, 0x43, 0x0E, 0xBC, 0x84, 0x84, 0xED, 0x3B, 0x41, 0x21, 0x22, 0x2A, 0x17, 0x24, + 0x64, 0x73, 0x4F, 0x29, 0xF5, 0xD7, 0xE9, 0x12, 0x29, 0xE5, 0x86, 0x84, 0x84, 0xDE, 0x06, 0xF9, + 0xF1, 0xD5, 0xB0, 0xC7, 0xE4, 0xDF, 0xE0, 0x01, 0x1B, 0x22, 0x32, 0x76, 0x7F, 0x7F, 0x3B, 0xB7, + 0x85, 0x9A, 0xD0, 0x17, 0x32, 0x01, 0xE2, 0xFB, 0x1A, 0x0B, 0xF1, 0xF0, 0xE4, 0xA0, 0x87, 0xAF, + 0xFE, 0x62, 0x7F, 0x79, 0x35, 0xE1, 0xDA, 0x26, 0x4E, 0x2B, 0xE4, 0xC8, 0xC8, 0xBA, 0xC8, 0x0A, + 0x1F, 0x13, 0x0E, 0xFB, 0xEB, 0xF8, 0x1A, 0x3F, 0x11, 0xB7, 0x95, 0xBD, 0x1C, 0x4E, 0x57, 0x53, + 0x21, 0xD8, 0xCB, 0xD1, 0xBA, 0xA7, 0xA8, 0xAC, 0xA7, 0xBA, 0x1E, 0x76, 0x7E, 0x45, 0xDC, 0xAA, + 0xBB, 0xEE, 0x44, 0x78, 0x5B, 0x36, 0x3A, 0x4A, 0x37, 0x27, 0x2D, 0x15, 0xBB, 0x86, 0x92, 0xC7, + 0x0C, 0x27, 0x04, 0xC7, 0x8F, 0x9D, 0xF8, 0x37, 0x2E, 0x05, 0x08, 0x15, 0x0D, 0x1C, 0x58, 0x67, + 0x4C, 0x2E, 0x12, 0x01, 0x0D, 0x2A, 0x35, 0xE7, 0x8A, 0x84, 0x84, 0xDA, 0x08, 0x11, 0x0D, 0xEC, + 0xBC, 0xBE, 0xD5, 0xD4, 0xD3, 0xED, 0xFF, 0x00, 0x13, 0x68, 0x7F, 0x7F, 0x61, 0xE1, 0x90, 0x83, + 0xA4, 0xEC, 0x1F, 0x0D, 0xF6, 0x0C, 0x2B, 0x1F, 0x0F, 0x14, 0x09, 0xC4, 0x98, 0xA9, 0xEC, 0x41, + 0x7C, 0x78, 0x39, 0xE8, 0xD8, 0x16, 0x46, 0x27, 0xE1, 0xC0, 0xAF, 0xA0, 0xB5, 0xFB, 0x23, 0x1F, + 0x16, 0x06, 0xF8, 0x05, 0x2D, 0x4E, 0x27, 0xC9, 0x8E, 0xAD, 0x05, 0x46, 0x68, 0x6A, 0x36, 0xE8, + 0xCA, 0xCA, 0xB8, 0xA4, 0xA5, 0xA4, 0x9A, 0xAE, 0x05, 0x66, 0x7F, 0x55, 0xF0, 0xAE, 0xA6, 0xD4, + 0x2A, 0x66, 0x55, 0x29, 0x2E, 0x49, 0x47, 0x40, 0x3D, 0x18, 0xC2, 0x86, 0x85, 0xBC, 0x06, 0x31, + 0x28, 0xE5, 0x9A, 0x8D, 0xD5, 0x2C, 0x37, 0x15, 0x04, 0x00, 0xFA, 0x18, 0x60, 0x7E, 0x6B, 0x3C, + 0x11, 0xF2, 0xF2, 0x16, 0x2B, 0xF8, 0x99, 0x84, 0x84, 0xC1, 0xFA, 0x10, 0x0D, 0xE7, 0xBC, 0xB6, + 0xD1, 0xDE, 0xDA, 0xE9, 0xFA, 0xFD, 0x15, 0x5A, 0x7F, 0x7F, 0x76, 0x0C, 0xB9, 0x91, 0xA5, 0xE1, + 0x0F, 0x01, 0xDE, 0xE6, 0x09, 0x13, 0x18, 0x25, 0x18, 0xE0, 0xB4, 0xB2, 0xE4, 0x28, 0x5E, 0x70, + 0x47, 0x05, 0xEE, 0x15, 0x46, 0x3A, 0x01, 0xD8, 0xBE, 0xA5, 0xAD, 0xDF, 0x0A, 0x17, 0x09, 0xF8, + 0xEC, 0xF5, 0x21, 0x45, 0x34, 0xEB, 0xA7, 0xB4, 0xF9, 0x34, 0x5E, 0x63, 0x35, 0xEF, 0xC2, 0xBB, + 0xBF, 0xB9, 0xB5, 0xAD, 0x94, 0x99, 0xD0, 0x1D, 0x58, 0x44, 0x03, 0xD5, 0xC5, 0xEA, 0x3A, 0x73, + 0x73, 0x42, 0x30, 0x3A, 0x3C, 0x3B, 0x43, 0x2B, 0xEC, 0xB2, 0x9C, 0xBF, 0xF4, 0x14, 0x14, 0xE0, + 0x9B, 0x89, 0xC1, 0x1E, 0x3F, 0x29, 0x14, 0x03, 0xF8, 0x17, 0x4C, 0x6C, 0x5F, 0x33, 0x0F, 0xFF, + 0xFC, 0x13, 0x1F, 0xFA, 0xB2, 0x84, 0x84, 0xB0, 0xE5, 0x10, 0x1B, 0xF5, 0xC3, 0xA8, 0xC0, 0xE6, + 0xF8, 0x04, 0x09, 0xFC, 0x0C, 0x3F, 0x79, 0x7F, 0x62, 0x08, 0xC2, 0x95, 0x98, 0xCF, 0x04, 0x19, + 0x03, 0xF9, 0x04, 0x0E, 0x1B, 0x30, 0x27, 0xFE, 0xD1, 0xC1, 0xED, 0x24, 0x45, 0x58, 0x3E, 0x0E, + 0xFA, 0x10, 0x3E, 0x3A, 0x0F, 0xE6, 0xBB, 0x94, 0x9A, 0xC0, 0xF3, 0x0B, 0x03, 0xF6, 0xFA, 0x0C, + 0x36, 0x52, 0x38, 0xEF, 0xA2, 0xA3, 0xDC, 0x1A, 0x51, 0x68, 0x3F, 0x03, 0xD3, 0xC8, 0xCD, 0xCE, + 0xC4, 0xB0, 0x8C, 0x86, 0xB6, 0x06, 0x4F, 0x4F, 0x23, 0xF8, 0xDD, 0xEF, 0x2F, 0x5B, 0x5B, 0x31, + 0x1B, 0x1D, 0x22, 0x2D, 0x3F, 0x2C, 0x05, 0xDE, 0xC0, 0xCA, 0xE7, 0xF6, 0xFA, 0xD9, 0xA8, 0xA2, + 0xD1, 0x22, 0x44, 0x38, 0x1F, 0x02, 0xF0, 0x11, 0x38, 0x4D, 0x48, 0x27, 0x0A, 0x03, 0x01, 0x15, + 0x1C, 0xFC, 0xBE, 0x85, 0x84, 0xA8, 0xE0, 0x18, 0x2C, 0x04, 0xD7, 0xC2, 0xD1, 0xED, 0xFF, 0x02, + 0x02, 0xFC, 0x19, 0x44, 0x6B, 0x7F, 0x5D, 0x1B, 0xDD, 0xA8, 0x9B, 0xBB, 0xD9, 0xE5, 0xD8, 0xDA, + 0xEC, 0x08, 0x29, 0x41, 0x2C, 0x08, 0xE9, 0xDB, 0xF9, 0x22, 0x37, 0x41, 0x32, 0x1A, 0x22, 0x3C, + 0x5F, 0x4E, 0x18, 0xDE, 0xA1, 0x84, 0x86, 0xA4, 0xC8, 0xE9, 0xF6, 0xFF, 0x0E, 0x21, 0x42, 0x4E, + 0x35, 0xFF, 0xC1, 0xC0, 0xED, 0x20, 0x55, 0x67, 0x3E, 0x14, 0xED, 0xD9, 0xCC, 0xC2, 0xB5, 0xA9, + 0x94, 0x9C, 0xBA, 0xE7, 0x20, 0x2B, 0x13, 0xF6, 0xDC, 0xF1, 0x32, 0x57, 0x5F, 0x3F, 0x2C, 0x2A, + 0x2A, 0x2A, 0x1F, 0xF7, 0xDE, 0xD8, 0xCD, 0xDC, 0xEF, 0xF7, 0xFB, 0xE1, 0xBC, 0xB7, 0xD7, 0x15, + 0x31, 0x26, 0x0B, 0xEE, 0xF8, 0x35, 0x5F, 0x64, 0x53, 0x33, 0x15, 0x03, 0xF6, 0xF1, 0xE7, 0xD3, + 0xB8, 0x8E, 0x89, 0xA8, 0xDE, 0x26, 0x40, 0x1A, 0xED, 0xCC, 0xC6, 0xD9, 0xEE, 0xFB, 0x01, 0x0B, + 0x2E, 0x4A, 0x58, 0x6C, 0x53, 0x27, 0xF5, 0xBC, 0xA0, 0xAF, 0xC2, 0xD6, 0xDC, 0xEC, 0x05, 0x1D, + 0x3D, 0x42, 0x20, 0x0B, 0xFD, 0xEF, 0xFE, 0x12, 0x1F, 0x22, 0x0F, 0xFB, 0x05, 0x23, 0x4F, 0x55, + 0x31, 0xF6, 0xAF, 0x8C, 0x9B, 0xB1, 0xD0, 0xF2, 0xFF, 0x01, 0x03, 0x1E, 0x4A, 0x66, 0x60, 0x2E, + 0xD5, 0xAB, 0xAE, 0xD9, 0x1F, 0x38, 0x1E, 0x07, 0xF3, 0xE6, 0xDD, 0xD4, 0xCE, 0xBC, 0xAD, 0xAC, + 0xAD, 0xC4, 0x02, 0x26, 0x2E, 0x25, 0x0B, 0x13, 0x38, 0x49, 0x41, 0x25, 0x17, 0x1B, 0x23, 0x2B, + 0x15, 0xE7, 0xDE, 0xEB, 0xEB, 0xF7, 0xFE, 0x01, 0x04, 0xE6, 0xC4, 0xBD, 0xD6, 0x16, 0x36, 0x31, + 0x12, 0xE6, 0xF1, 0x34, 0x5C, 0x55, 0x3A, 0x0F, 0xEF, 0xE1, 0xE6, 0xF8, 0x03, 0x01, 0xEB, 0xB7, + 0xA2, 0xAB, 0xD9, 0x2A, 0x4A, 0x24, 0xF5, 0xDB, 0xD8, 0xE2, 0xEC, 0xF2, 0xE3, 0xE2, 0xFA, 0x09, + 0x15, 0x2F, 0x36, 0x31, 0x19, 0xE5, 0xC7, 0xC3, 0xCA, 0xD2, 0xD8, 0xEB, 0x08, 0x29, 0x55, 0x5F, + 0x3A, 0x23, 0x1B, 0x0B, 0x0B, 0x0A, 0x04, 0xF8, 0xDC, 0xCF, 0xDF, 0x08, 0x3C, 0x47, 0x2F, 0x00, + 0xBA, 0xA5, 0xC7, 0xDE, 0xE0, 0xE3, 0xDE, 0xE0, 0xEF, 0x1B, 0x56, 0x77, 0x76, 0x48, 0xFA, 0xCB, + 0xBD, 0xD0, 0x02, 0x0D, 0xF0, 0xE0, 0xE9, 0xFB, 0x04, 0x01, 0xFE, 0xE6, 0xD3, 0xCD, 0xB8, 0xB3, + 0xD3, 0xF0, 0x0A, 0x13, 0x03, 0x13, 0x3B, 0x50, 0x3F, 0x1C, 0x08, 0x08, 0x12, 0x23, 0x0B, 0xD5, + 0xCF, 0xF1, 0x0A, 0x1F, 0x23, 0x1B, 0x10, 0xEE, 0xCD, 0xC3, 0xDB, 0x0C, 0x29, 0x27, 0x0A, 0xD6, + 0xDB, 0x25, 0x51, 0x4D, 0x32, 0x0A, 0xEE, 0xE6, 0xF4, 0x07, 0x0A, 0x04, 0xEF, 0xC7, 0xB0, 0xAE, + 0xCB, 0x13, 0x39, 0x22, 0x05, 0xF8, 0xF7, 0xFB, 0xFA, 0xEF, 0xD5, 0xD0, 0xF3, 0x08, 0x14, 0x2B, + 0x33, 0x30, 0x24, 0xFC, 0xE0, 0xD5, 0xCA, 0xBD, 0xB8, 0xC9, 0xE9, 0x15, 0x4D, 0x5B, 0x30, 0x1A, + 0x1A, 0x17, 0x1A, 0x18, 0x07, 0xF2, 0xD6, 0xCF, 0xEB, 0x18, 0x44, 0x50, 0x40, 0x1A, 0xD6, 0xB8, + 0xD0, 0xD8, 0xCC, 0xC9, 0xC8, 0xD1, 0xE6, 0x10, 0x47, 0x67, 0x71, 0x4F, 0x09, 0xD3, 0xBA, 0xBF, + 0xEC, 0x04, 0xF2, 0xEA, 0xFB, 0x0A, 0x0E, 0x05, 0xF7, 0xDC, 0xCB, 0xCB, 0xBA, 0xB4, 0xD5, 0xFB, + 0x1C, 0x29, 0x1C, 0x20, 0x3B, 0x48, 0x31, 0x13, 0x01, 0x02, 0x14, 0x2F, 0x22, 0xE9, 0xD4, 0xE6, + 0xF5, 0x01, 0x07, 0x06, 0x00, 0xED, 0xD6, 0xCE, 0xE6, 0x12, 0x2F, 0x31, 0x15, 0xDF, 0xD9, 0x16, + 0x42, 0x3F, 0x2A, 0x0E, 0xF8, 0xED, 0xF5, 0xFF, 0x01, 0x04, 0xF0, 0xC7, 0xA8, 0xA1, 0xC0, 0x09, + 0x37, 0x29, 0x0B, 0x01, 0xFD, 0xFE, 0xFF, 0xF4, 0xD9, 0xD1, 0xE9, 0xFA, 0x07, 0x21, 0x31, 0x34, + 0x29, 0x07, 0xE9, 0xDF, 0xD5, 0xC2, 0xB9, 0xC6, 0xE2, 0x0D, 0x47, 0x5B, 0x3C, 0x28, 0x28, 0x1E, + 0x0F, 0x05, 0xFA, 0xEF, 0xE2, 0xD7, 0xE2, 0x0D, 0x3A, 0x51, 0x4B, 0x24, 0xE0, 0xC0, 0xD6, 0xE0, + 0xCE, 0xC2, 0xC8, 0xDB, 0xF5, 0x19, 0x39, 0x51, 0x60, 0x48, 0x14, 0xDE, 0xBA, 0xBE, 0xE8, 0x01, + 0xEF, 0xE3, 0xF7, 0x0E, 0x17, 0x16, 0x06, 0xE8, 0xD8, 0xD1, 0xBA, 0xAC, 0xBC, 0xE7, 0x12, 0x29, + 0x24, 0x1D, 0x31, 0x3F, 0x2C, 0x11, 0xFF, 0xF5, 0xFC, 0x15, 0x14, 0xF2, 0xEF, 0x0B, 0x1A, 0x14, + 0x03, 0xFB, 0xFB, 0xFC, 0xED, 0xDD, 0xE7, 0xFE, 0x18, 0x28, 0x1D, 0xF6, 0xE3, 0x0D, 0x2E, 0x28, + 0x18, 0x0E, 0x02, 0xFC, 0xFE, 0xFF, 0xFC, 0x01, 0xEE, 0xD0, 0xB3, 0xA8, 0xBF, 0xFC, 0x27, 0x1D, + 0xFF, 0xF3, 0xF1, 0xEA, 0xF0, 0xF6, 0xEB, 0xE8, 0xF2, 0xF3, 0xFD, 0x12, 0x30, 0x40, 0x39, 0x19, + 0xF4, 0xE3, 0xDD, 0xCC, 0xC8, 0xDD, 0xEE, 0x0A, 0x2E, 0x3C, 0x28, 0x20, 0x26, 0x26, 0x11, 0xFA, + 0xF1, 0xEB, 0xEA, 0xEA, 0xF3, 0x19, 0x3A, 0x46, 0x45, 0x23, 0xEC, 0xCC, 0xD6, 0xDE, 0xD1, 0xC6, + 0xD6, 0xE7, 0xF8, 0x10, 0x21, 0x32, 0x46, 0x37, 0x14, 0xE8, 0xC5, 0xC2, 0xE3, 0x01, 0xFD, 0xF5, + 0xFD, 0x0A, 0x04, 0x02, 0xFE, 0xEC, 0xE2, 0xDD, 0xC2, 0xB2, 0xBA, 0xE2, 0x0F, 0x23, 0x20, 0x13, + 0x18, 0x2B, 0x29, 0x1E, 0x18, 0x08, 0x02, 0x0D, 0x0A, 0xF6, 0xFC, 0x13, 0x27, 0x17, 0xFF, 0xF3, + 0xEF, 0xF8, 0xF8, 0xE5, 0xE4, 0xF0, 0xFF, 0x15, 0x13, 0xFB, 0xF1, 0x09, 0x24, 0x28, 0x19, 0x17, + 0x0E, 0x01, 0xFD, 0xF6, 0xF5, 0x06, 0x00, 0xEC, 0xD1, 0xBC, 0xCC, 0xF9, 0x1E, 0x1C, 0xFF, 0xEB, + 0xE6, 0xDE, 0xE9, 0xF3, 0xF1, 0xF0, 0xF5, 0xED, 0xF1, 0x03, 0x27, 0x40, 0x37, 0x16, 0xEE, 0xDE, + 0xE1, 0xDE, 0xD6, 0xDC, 0xE5, 0xFA, 0x1F, 0x30, 0x2A, 0x2B, 0x2F, 0x30, 0x15, 0xF6, 0xEB, 0xEB, + 0xF5, 0xFF, 0xFD, 0x10, 0x2C, 0x3E, 0x43, 0x2A, 0xFA, 0xDA, 0xD8, 0xDD, 0xD1, 0xC1, 0xCD, 0xE1, + 0xF6, 0x12, 0x1F, 0x29, 0x39, 0x32, 0x18, 0xEF, 0xCB, 0xC8, 0xE0, 0xF8, 0xFA, 0xF3, 0xFF, 0x19, + 0x1F, 0x1C, 0x10, 0xF3, 0xE2, 0xD9, 0xBC, 0xA2, 0x9D, 0xBF, 0xF6, 0x1A, 0x29, 0x25, 0x20, 0x26, + 0x24, 0x16, 0x0C, 0xFE, 0xFA, 0x07, 0x0A, 0x01, 0x0C, 0x25, 0x3F, 0x38, 0x1B, 0x02, 0xEA, 0xE6, + 0xEA, 0xE2, 0xE1, 0xED, 0xFD, 0x12, 0x13, 0x04, 0xFE, 0x0A, 0x19, 0x18, 0x05, 0x00, 0xFF, 0xFA, + 0x01, 0xFD, 0xF7, 0x04, 0x0A, 0xFF, 0xE6, 0xCA, 0xCE, 0xE4, 0xFE, 0x09, 0x00, 0xFB, 0x02, 0xFE, + 0xFC, 0xFE, 0xF1, 0xF5, 0xFB, 0xEF, 0xE4, 0xE5, 0x02, 0x27, 0x32, 0x2C, 0x12, 0xF7, 0xEB, 0xE0, + 0xD1, 0xD3, 0xD9, 0xED, 0x0E, 0x1B, 0x1A, 0x21, 0x32, 0x44, 0x38, 0x14, 0xF7, 0xDD, 0xDE, 0xF1, + 0xFD, 0x11, 0x2A, 0x37, 0x3B, 0x23, 0xFF, 0xEF, 0xEF, 0xED, 0xD6, 0xB4, 0xAD, 0xC6, 0xE6, 0x12, + 0x20, 0x1E, 0x2A, 0x32, 0x2B, 0x0C, 0xE3, 0xD6, 0xD8, 0xE2, 0xEF, 0xF2, 0xFE, 0x18, 0x20, 0x1A, + 0x0A, 0xF0, 0xEB, 0xEC, 0xD7, 0xB8, 0xA4, 0xB3, 0xE6, 0x12, 0x30, 0x33, 0x21, 0x1D, 0x19, 0x10, + 0x14, 0x13, 0x0D, 0x0C, 0xFB, 0xEF, 0xF4, 0x0C, 0x2D, 0x31, 0x15, 0xFF, 0xE9, 0xED, 0xFE, 0xFD, + 0xF7, 0xF3, 0xF2, 0xFD, 0x01, 0x00, 0x0A, 0x16, 0x24, 0x25, 0x12, 0x0B, 0x06, 0xFA, 0xF9, 0xE9, + 0xE1, 0xEF, 0xFE, 0x00, 0xF2, 0xDC, 0xE0, 0xEB, 0xF5, 0xFB, 0xF3, 0xF0, 0xFF, 0xFB, 0xF7, 0xF8, + 0xF3, 0x03, 0x0C, 0xFE, 0xEF, 0xE8, 0xF8, 0x1C, 0x23, 0x21, 0x10, 0xFA, 0xF3, 0xE6, 0xCE, 0xD1, + 0xE1, 0xFF, 0x1C, 0x1A, 0x0F, 0x0B, 0x19, 0x34, 0x36, 0x17, 0xFD, 0xE1, 0xE2, 0xF8, 0x05, 0x14, + 0x2B, 0x33, 0x30, 0x14, 0xF7, 0xF3, 0xF9, 0x01, 0xF2, 0xC9, 0xB8, 0xC6, 0xE0, 0x07, 0x11, 0x0C, + 0x14, 0x23, 0x26, 0x18, 0xF9, 0xE8, 0xE0, 0xD9, 0xDA, 0xDB, 0xEE, 0x12, 0x21, 0x1A, 0x0C, 0xFB, + 0xFE, 0x03, 0xF2, 0xD0, 0xAD, 0xAA, 0xD1, 0xFB, 0x20, 0x2E, 0x22, 0x1B, 0x15, 0x08, 0x07, 0x0D, + 0x10, 0x14, 0x02, 0xF5, 0xF5, 0x09, 0x28, 0x32, 0x1C, 0x08, 0xF4, 0xF7, 0x08, 0x08, 0xFA, 0xF6, + 0xF2, 0xF3, 0xF1, 0xED, 0xFC, 0x08, 0x18, 0x1E, 0x0B, 0xFF, 0x00, 0x01, 0x04, 0xF7, 0xEA, 0xEC, + 0xFB, 0x00, 0xF8, 0xEF, 0xF0, 0xF7, 0xF7, 0xF7, 0xEB, 0xEC, 0xFF, 0x0B, 0x04, 0xF8, 0xE9, 0xEE, + 0xF7, 0xF7, 0xEE, 0xEB, 0xF7, 0x10, 0x1D, 0x22, 0x1E, 0x0E, 0x04, 0xF8, 0xDE, 0xD0, 0xE0, 0xFF, + 0x1D, 0x20, 0x17, 0x10, 0x14, 0x28, 0x2F, 0x18, 0xF8, 0xDD, 0xDA, 0xF3, 0x08, 0x0F, 0x1F, 0x26, + 0x1C, 0x07, 0xF6, 0xF8, 0x02, 0x0B, 0x02, 0xDE, 0xC2, 0xC9, 0xE6, 0x08, 0x10, 0x02, 0xFE, 0x0D, + 0x18, 0x17, 0x06, 0xF1, 0xE2, 0xD6, 0xDB, 0xE2, 0xEB, 0x09, 0x25, 0x27, 0x1A, 0x09, 0x03, 0x05, + 0xF9, 0xDD, 0xC1, 0xB7, 0xCC, 0xF1, 0x15, 0x25, 0x15, 0x06, 0x05, 0x00, 0xFB, 0x02, 0x07, 0x07, + 0xFC, 0xF7, 0xFF, 0x0F, 0x24, 0x34, 0x2C, 0x15, 0x04, 0x03, 0x13, 0x17, 0x01, 0xF1, 0xEC, 0xEA, + 0xED, 0xF5, 0x05, 0x0C, 0x12, 0x17, 0x0F, 0xFB, 0xF2, 0xF1, 0xF3, 0xEE, 0xE8, 0xEF, 0x05, 0x10, + 0x0A, 0x02, 0xFA, 0xF4, 0xEC, 0xED, 0xE9, 0xE3, 0xEC, 0x01, 0x0B, 0x08, 0x01, 0xFB, 0xF5, 0xED, + 0xE5, 0xEA, 0xF8, 0x07, 0x16, 0x1B, 0x1B, 0x0E, 0x05, 0x02, 0xED, 0xD5, 0xD6, 0xEF, 0x0D, 0x1A, + 0x1E, 0x1A, 0x15, 0x17, 0x1D, 0x18, 0x04, 0xF1, 0xEC, 0xFA, 0x0B, 0x0B, 0x15, 0x23, 0x1C, 0x08, + 0xF8, 0xF6, 0x00, 0x0A, 0x09, 0xF6, 0xD6, 0xCA, 0xDF, 0xFC, 0x09, 0x04, 0xFB, 0x06, 0x10, 0x10, + 0x0D, 0x02, 0xEE, 0xDB, 0xD5, 0xD7, 0xDE, 0xF6, 0x19, 0x2D, 0x24, 0x12, 0x03, 0xFB, 0xF4, 0xDF, + 0xCB, 0xC3, 0xCA, 0xE9, 0x0C, 0x21, 0x1E, 0x11, 0x10, 0x0B, 0xFE, 0xF9, 0xFF, 0xFF, 0xFB, 0xFF, + 0x06, 0x13, 0x1C, 0x25, 0x2A, 0x1B, 0x0D, 0x09, 0x15, 0x1B, 0x0A, 0xF9, 0xF3, 0xEE, 0xE9, 0xF0, + 0xFC, 0x03, 0x07, 0x0C, 0x0D, 0x04, 0xF3, 0xF4, 0xF6, 0xEF, 0xE6, 0xE2, 0xF3, 0x03, 0x06, 0x0D, + 0x11, 0x0B, 0x00, 0xF6, 0xEE, 0xE9, 0xEB, 0xFB, 0x09, 0x03, 0xFA, 0xF2, 0xEA, 0xE9, 0xE7, 0xEF, + 0xFD, 0xFF, 0x01, 0x03, 0x06, 0x08, 0x07, 0x06, 0xFB, 0xE6, 0xDF, 0xF2, 0x07, 0x17, 0x20, 0x1D, + 0x1B, 0x16, 0x10, 0x0D, 0xFC, 0xEC, 0xED, 0xF9, 0x08, 0x0D, 0x0D, 0x17, 0x18, 0x0E, 0x0B, 0x0E, + 0x12, 0x10, 0x04, 0xF3, 0xE0, 0xD5, 0xE7, 0xFE, 0x08, 0x04, 0xF6, 0xF5, 0xFE, 0x01, 0x03, 0x01, + 0xEF, 0xD9, 0xCE, 0xD1, 0xE7, 0x01, 0x1F, 0x33, 0x2B, 0x16, 0x03, 0xF5, 0xF4, 0xEA, 0xE0, 0xDE, + 0xDD, 0xEC, 0xFE, 0x0D, 0x11, 0x0A, 0x04, 0x03, 0xFB, 0xEE, 0xED, 0xF0, 0xFC, 0x0C, 0x17, 0x1F, + 0x20, 0x1A, 0x1F, 0x19, 0x11, 0x0D, 0x10, 0x17, 0x11, 0xFE, 0xF6, 0xF4, 0xF2, 0xF6, 0xFF, 0xFE, + 0xF9, 0xF5, 0xF9, 0xFF, 0xF5, 0xF4, 0xFA, 0xFC, 0xFE, 0xFB, 0xFF, 0x0B, 0x0C, 0x0A, 0x0B, 0x02, + 0xF5, 0xEC, 0xEB, 0xED, 0xEF, 0xF7, 0x0A, 0x0A, 0xFC, 0xEA, 0xDB, 0xDC, 0xE6, 0xF3, 0x04, 0x08, + 0x07, 0x0B, 0x10, 0x13, 0x11, 0x09, 0x03, 0xF4, 0xE1, 0xE3, 0xF0, 0x07, 0x1E, 0x25, 0x1F, 0x0D, + 0xFB, 0xFC, 0xFA, 0xF3, 0xF6, 0xFC, 0x0A, 0x10, 0x10, 0x10, 0x15, 0x13, 0x15, 0x13, 0x0E, 0x02, + 0xF7, 0xF3, 0xF0, 0xE3, 0xE9, 0xFA, 0x04, 0x02, 0xF5, 0xEF, 0xF5, 0xFF, 0x08, 0x0B, 0xFD, 0xEA, + 0xE1, 0xE2, 0xED, 0xF9, 0x09, 0x23, 0x24, 0x13, 0xFC, 0xE9, 0xE5, 0xE9, 0xEC, 0xEE, 0xE8, 0xE8, + 0xF1, 0xFA, 0x00, 0x00, 0x01, 0x08, 0x0B, 0xFB, 0xF3, 0xF1, 0xFE, 0x15, 0x24, 0x27, 0x1B, 0x0B, + 0x09, 0x06, 0x05, 0x0C, 0x14, 0x18, 0x0F, 0xFA, 0xE9, 0xEA, 0xF3, 0x01, 0x05, 0xFF, 0xF7, 0xF7, + 0x05, 0x0E, 0x05, 0x00, 0x03, 0x03, 0xFE, 0xF3, 0xED, 0xF2, 0x01, 0x0B, 0x11, 0x07, 0xF7, 0xEB, + 0xE5, 0xE4, 0xE3, 0xEA, 0x03, 0x11, 0x07, 0xF1, 0xE0, 0xE0, 0xF4, 0x0B, 0x15, 0x0D, 0x01, 0xFD, + 0x01, 0x06, 0x09, 0x09, 0x09, 0x04, 0xF1, 0xE5, 0xE9, 0xFC, 0x11, 0x19, 0x11, 0xFF, 0xF7, 0x00, + 0x04, 0x02, 0x01, 0x09, 0x17, 0x1F, 0x1B, 0x0A, 0x03, 0x01, 0x07, 0x0A, 0x09, 0x05, 0x01, 0xFF, + 0xF9, 0xE7, 0xE5, 0xF5, 0x01, 0xFD, 0xEF, 0xE3, 0xE5, 0xFD, 0x13, 0x19, 0x0B, 0xF7, 0xEA, 0xE9, + 0xF1, 0xF9, 0x01, 0x15, 0x1E, 0x0F, 0xF9, 0xE9, 0xE8, 0xF3, 0xFB, 0xF4, 0xE8, 0xE5, 0xEE, 0xF8, + 0xFE, 0xFF, 0xFF, 0x06, 0x0D, 0x04, 0xF7, 0xF8, 0x09, 0x1F, 0x29, 0x23, 0x12, 0x09, 0x09, 0x07, + 0xFD, 0xFD, 0x06, 0x10, 0x14, 0x03, 0xE9, 0xE2, 0xEE, 0x00, 0x09, 0x04, 0xFF, 0x00, 0x09, 0x0F, + 0x01, 0xF7, 0xFF, 0x06, 0x05, 0xF9, 0xEB, 0xEC, 0x03, 0x13, 0x13, 0x04, 0xF1, 0xE5, 0xDD, 0xDD, + 0xDD, 0xE7, 0x03, 0x1A, 0x11, 0xF7, 0xE1, 0xE5, 0xFD, 0x15, 0x13, 0x01, 0xF5, 0xF6, 0xFD, 0x05, + 0x0A, 0x08, 0x08, 0x09, 0xF9, 0xE7, 0xEA, 0x01, 0x1A, 0x23, 0x16, 0xFE, 0xF6, 0x00, 0x07, 0x04, + 0x04, 0x0E, 0x1C, 0x27, 0x22, 0x06, 0xF7, 0xF9, 0xFE, 0x02, 0x00, 0xFC, 0xFA, 0xFF, 0xFE, 0xF2, + 0xEB, 0xF9, 0x06, 0x03, 0xF3, 0xE1, 0xDD, 0xF8, 0x12, 0x16, 0x0B, 0xFC, 0xEF, 0xE9, 0xEF, 0xF4, + 0xFD, 0x10, 0x1B, 0x0B, 0xE9, 0xD6, 0xD5, 0xE8, 0xFD, 0xFA, 0xF2, 0xF1, 0xFC, 0x04, 0x09, 0x0B, + 0x05, 0x06, 0x0B, 0x01, 0xED, 0xEE, 0x0B, 0x23, 0x30, 0x27, 0x11, 0x05, 0x04, 0x00, 0xF8, 0xF4, + 0xFE, 0x0C, 0x15, 0x0F, 0xF5, 0xED, 0xFD, 0x0A, 0x0B, 0x04, 0x01, 0x01, 0x0B, 0x0E, 0xFE, 0xEF, + 0xF4, 0x03, 0x07, 0xFE, 0xE8, 0xE1, 0xF8, 0x0F, 0x11, 0x05, 0xF4, 0xE5, 0xDC, 0xDF, 0xE1, 0xEA, + 0x04, 0x1D, 0x18, 0xFC, 0xE7, 0xE6, 0xFC, 0x12, 0x0B, 0xFA, 0xEE, 0xF0, 0xFA, 0x03, 0x09, 0x03, + 0x01, 0x06, 0xFD, 0xE9, 0xEB, 0x05, 0x1D, 0x23, 0x16, 0xFC, 0xF2, 0xF9, 0x07, 0x0D, 0x0D, 0x12, + 0x1B, 0x27, 0x27, 0x0B, 0xF7, 0xF9, 0xF8, 0xF7, 0xF3, 0xF6, 0xF7, 0x01, 0x03, 0xFB, 0xF3, 0xFD, + 0x0B, 0x0A, 0xF8, 0xDF, 0xD4, 0xEE, 0x0C, 0x13, 0x11, 0x07, 0xF9, 0xF1, 0xF3, 0xF7, 0xFF, 0x0D, + 0x1B, 0x06, 0xE1, 0xCD, 0xCF, 0xE6, 0x00, 0x01, 0xF5, 0xF3, 0xFA, 0x03, 0x05, 0x05, 0xFD, 0xF9, + 0x01, 0xFD, 0xEA, 0xF3, 0x12, 0x2C, 0x35, 0x28, 0x10, 0x04, 0x03, 0x06, 0xFF, 0xF7, 0xFA, 0x06, + 0x15, 0x15, 0xFD, 0xEE, 0xFF, 0x09, 0x06, 0x00, 0xFC, 0xFE, 0x08, 0x09, 0xFB, 0xEE, 0xF3, 0x05, + 0x0A, 0x01, 0xEC, 0xE5, 0xFD, 0x13, 0x10, 0x02, 0xF3, 0xE9, 0xE2, 0xE2, 0xE0, 0xE5, 0xFD, 0x1C, + 0x1C, 0xFE, 0xE8, 0xE6, 0xFC, 0x14, 0x11, 0xFD, 0xF4, 0xF3, 0xF9, 0xFB, 0xFD, 0xF8, 0xF9, 0x04, + 0x02, 0xEA, 0xEC, 0x07, 0x1E, 0x25, 0x16, 0xF8, 0xEB, 0xF3, 0x00, 0x0A, 0x11, 0x1E, 0x28, 0x33, + 0x2E, 0x0F, 0xF8, 0xFE, 0x01, 0xF7, 0xEE, 0xEB, 0xF2, 0x03, 0x09, 0x01, 0xF3, 0xF3, 0xFC, 0xFA, + 0xEF, 0xDC, 0xD5, 0xED, 0x0C, 0x10, 0x0D, 0x0A, 0x08, 0x02, 0xFC, 0xF6, 0xF4, 0x03, 0x1B, 0x15, + 0xF0, 0xD7, 0xCE, 0xE2, 0xFE, 0x03, 0xF7, 0xF5, 0xF3, 0xF5, 0xF6, 0xFE, 0x03, 0x08, 0x10, 0x03, + 0xE5, 0xE5, 0x06, 0x27, 0x37, 0x2B, 0x0C, 0xFE, 0xFE, 0x04, 0x09, 0x06, 0x07, 0x08, 0x0B, 0x08, + 0xF4, 0xEB, 0x04, 0x15, 0x0D, 0x01, 0xF9, 0x02, 0x11, 0x14, 0x04, 0xF0, 0xED, 0xFF, 0x07, 0x03, + 0xEE, 0xE2, 0xF6, 0x11, 0x0D, 0x01, 0xF7, 0xED, 0xE1, 0xD8, 0xD5, 0xDD, 0xF9, 0x1C, 0x1F, 0x00, + 0xE7, 0xE1, 0xF9, 0x1B, 0x1E, 0x0B, 0xFC, 0xF4, 0xF0, 0xF1, 0xFA, 0x01, 0x0A, 0x10, 0x06, 0xE5, + 0xDB, 0xF6, 0x14, 0x24, 0x17, 0xF8, 0xE8, 0xED, 0xFD, 0x0D, 0x16, 0x1F, 0x23, 0x26, 0x23, 0x0A, + 0xF7, 0x03, 0x0C, 0xFF, 0xF2, 0xEC, 0xF3, 0x04, 0x10, 0x0B, 0xFD, 0xF7, 0xFE, 0x00, 0xF9, 0xE8, + 0xDA, 0xEA, 0x03, 0x07, 0x04, 0x0B, 0x0D, 0x08, 0xFB, 0xEE, 0xE9, 0xF8, 0x10, 0x11, 0xED, 0xD3, + 0xC9, 0xE0, 0x04, 0x13, 0x0C, 0x03, 0xF8, 0xEC, 0xE7, 0xEE, 0xFC, 0x08, 0x12, 0x09, 0xEA, 0xE2, + 0x02, 0x27, 0x3C, 0x31, 0x11, 0xF9, 0xF2, 0xF8, 0x01, 0x07, 0x10, 0x11, 0x10, 0x09, 0xF7, 0xEF, + 0x05, 0x15, 0x09, 0xFA, 0xF2, 0xF9, 0x07, 0x0F, 0x07, 0xF6, 0xF1, 0x01, 0x0C, 0x0F, 0xFD, 0xEC, + 0xF3, 0x07, 0x0A, 0x03, 0x01, 0xFB, 0xF2, 0xE5, 0xDD, 0xDE, 0xF3, 0x14, 0x1B, 0xFE, 0xE2, 0xD4, + 0xE6, 0x07, 0x17, 0x0E, 0x00, 0xF2, 0xE8, 0xE6, 0xEF, 0x01, 0x11, 0x1B, 0x14, 0xF3, 0xE3, 0xF7, + 0x10, 0x21, 0x1A, 0xFD, 0xE6, 0xE4, 0xF4, 0x09, 0x19, 0x25, 0x28, 0x26, 0x1C, 0x02, 0xF2, 0xFF, + 0x0D, 0x08, 0xFC, 0xF1, 0xF4, 0x05, 0x15, 0x15, 0x04, 0xF6, 0xF7, 0xF7, 0xF6, 0xE9, 0xDE, 0xE3, + 0xF6, 0xFC, 0xFB, 0x03, 0x0A, 0x0D, 0x05, 0xF9, 0xF1, 0xFA, 0x13, 0x18, 0xFC, 0xDF, 0xCD, 0xD4, + 0xF4, 0x0F, 0x13, 0x0B, 0xFB, 0xEA, 0xE2, 0xE4, 0xF4, 0x02, 0x0D, 0x05, 0xE6, 0xDB, 0xF6, 0x1E, + 0x3D, 0x40, 0x26, 0x08, 0xF7, 0xFA, 0x04, 0x0D, 0x11, 0x0E, 0x08, 0x01, 0xF5, 0xF2, 0x07, 0x1A, + 0x14, 0x02, 0xF0, 0xEE, 0xF9, 0x07, 0x04, 0xF5, 0xEE, 0xF7, 0x06, 0x12, 0x0E, 0xFE, 0xFB, 0x02, + 0x04, 0xFD, 0xFB, 0xFA, 0xF3, 0xE9, 0xE2, 0xDE, 0xEF, 0x0D, 0x19, 0x08, 0xEE, 0xDB, 0xE2, 0xFE, + 0x11, 0x13, 0x05, 0xF6, 0xE9, 0xE5, 0xEC, 0xFD, 0x0E, 0x1A, 0x16, 0xF9, 0xE5, 0xEE, 0x02, 0x17, + 0x13, 0xFF, 0xE9, 0xE2, 0xF1, 0x06, 0x19, 0x27, 0x2A, 0x25, 0x1E, 0x0A, 0xFC, 0x04, 0x11, 0x0D, + 0xFD, 0xEF, 0xF1, 0xFE, 0x10, 0x18, 0x0B, 0xFD, 0xF6, 0xF5, 0xF6, 0xEE, 0xE0, 0xDE, 0xE7, 0xEF, + 0xF5, 0x02, 0x12, 0x19, 0x13, 0x09, 0xFB, 0xF8, 0x08, 0x0B, 0xF7, 0xDB, 0xCB, 0xD4, 0xF2, 0x11, + 0x1E, 0x19, 0x0A, 0xF1, 0xE2, 0xDE, 0xE7, 0xF2, 0xFE, 0xFD, 0xEA, 0xE2, 0xF6, 0x1C, 0x37, 0x39, + 0x24, 0x07, 0xF3, 0xF2, 0xF8, 0x05, 0x0D, 0x0C, 0x0B, 0x0E, 0x06, 0x01, 0x0C, 0x1C, 0x18, 0x06, + 0xF6, 0xF2, 0xF5, 0xFB, 0xFE, 0xF4, 0xF1, 0xF9, 0x09, 0x14, 0x13, 0x03, 0xFE, 0xFE, 0xFD, 0xF4, + 0xF1, 0xF1, 0xF2, 0xEB, 0xE7, 0xE6, 0xEF, 0x05, 0x15, 0x0E, 0xF8, 0xE3, 0xE3, 0xF2, 0x02, 0x09, + 0x05, 0xFF, 0xF2, 0xE9, 0xE9, 0xF4, 0x04, 0x13, 0x19, 0x07, 0xF3, 0xEF, 0xFF, 0x10, 0x12, 0x03, + 0xF0, 0xE3, 0xE8, 0xF8, 0x11, 0x27, 0x30, 0x2E, 0x26, 0x12, 0x00, 0x00, 0x09, 0x09, 0xFB, 0xEC, + 0xEB, 0xF9, 0x0C, 0x1B, 0x17, 0x0A, 0xFC, 0xF5, 0xF3, 0xEF, 0xE4, 0xDF, 0xE2, 0xE7, 0xEC, 0xFD, + 0x14, 0x22, 0x1F, 0x10, 0x00, 0xF6, 0xFC, 0x01, 0xF7, 0xDE, 0xCB, 0xCC, 0xE5, 0x04, 0x17, 0x1B, + 0x13, 0xFF, 0xE9, 0xE0, 0xE2, 0xEA, 0xF4, 0xF7, 0xEE, 0xE7, 0xF5, 0x17, 0x37, 0x40, 0x2F, 0x15, + 0xFC, 0xF4, 0xF6, 0x00, 0x06, 0x09, 0x05, 0x06, 0x06, 0x06, 0x10, 0x1C, 0x1E, 0x0E, 0xF9, 0xF0, + 0xF1, 0xF9, 0x01, 0xFE, 0xFA, 0xF9, 0x00, 0x0A, 0x10, 0x08, 0x01, 0xFE, 0xFA, 0xF0, 0xEB, 0xED, + 0xF2, 0xF2, 0xED, 0xE9, 0xE9, 0xFD, 0x0E, 0x13, 0x06, 0xF3, 0xEA, 0xF2, 0xFE, 0x05, 0x01, 0xFB, + 0xF1, 0xEA, 0xE9, 0xF2, 0xFD, 0x0B, 0x13, 0x0B, 0xFA, 0xEE, 0xF2, 0x03, 0x0C, 0x07, 0xF8, 0xE9, + 0xED, 0xFD, 0x18, 0x2A, 0x30, 0x2B, 0x22, 0x16, 0x09, 0x07, 0x0A, 0x0A, 0xFF, 0xEF, 0xEA, 0xF6, + 0x0A, 0x1C, 0x1A, 0x0B, 0xFB, 0xF3, 0xF3, 0xF7, 0xEE, 0xE4, 0xDF, 0xE3, 0xEB, 0xFA, 0x0D, 0x1D, + 0x1E, 0x14, 0x03, 0xF5, 0xF2, 0xF7, 0xFA, 0xEB, 0xD7, 0xD0, 0xDF, 0xFB, 0x14, 0x1B, 0x13, 0x02, + 0xF3, 0xE8, 0xE8, 0xED, 0xF1, 0xF2, 0xEE, 0xE9, 0xF0, 0x0A, 0x26, 0x32, 0x2A, 0x14, 0xFE, 0xF7, + 0xFD, 0x05, 0x07, 0x01, 0xFB, 0xFF, 0x08, 0x12, 0x1A, 0x22, 0x23, 0x17, 0x03, 0xF7, 0xF7, 0xFE, + 0x04, 0xFF, 0xF6, 0xF0, 0xF8, 0x06, 0x10, 0x0E, 0x05, 0xFD, 0xF9, 0xF5, 0xEC, 0xE9, 0xEB, 0xEE, + 0xEE, 0xED, 0xEF, 0xFA, 0x08, 0x12, 0x0D, 0xFD, 0xF0, 0xEF, 0xF8, 0xFE, 0xFA, 0xF3, 0xEB, 0xE9, + 0xEA, 0xF3, 0xFF, 0x06, 0x0D, 0x0A, 0x00, 0xF3, 0xF4, 0x02, 0x0C, 0x0A, 0xFB, 0xEE, 0xF1, 0x03, + 0x19, 0x28, 0x2A, 0x24, 0x19, 0x11, 0x09, 0x06, 0x03, 0x05, 0xFC, 0xED, 0xE7, 0xF4, 0x0B, 0x22, + 0x26, 0x17, 0x00, 0xF3, 0xF6, 0xFD, 0xFF, 0xF0, 0xE3, 0xDE, 0xE7, 0xF6, 0x0B, 0x1B, 0x20, 0x13, + 0xFF, 0xF0, 0xE8, 0xEB, 0xF1, 0xED, 0xDC, 0xD4, 0xDA, 0xF5, 0x10, 0x1F, 0x1B, 0x0D, 0xFA, 0xEE, + 0xEB, 0xEF, 0xF1, 0xF0, 0xEF, 0xF1, 0xF6, 0x09, 0x22, 0x2D, 0x29, 0x12, 0xFB, 0xF1, 0xF4, 0xFC, + 0x03, 0x00, 0xFE, 0xFD, 0x07, 0x17, 0x21, 0x24, 0x24, 0x15, 0xFD, 0xF1, 0xF1, 0xFB, 0x03, 0x02, + 0xF9, 0xF0, 0xF4, 0x04, 0x11, 0x17, 0x0B, 0xFA, 0xF0, 0xEC, 0xEA, 0xF1, 0xF9, 0xFD, 0xF9, 0xF1, + 0xEF, 0xF5, 0x02, 0x14, 0x12, 0xFD, 0xEB, 0xE3, 0xEC, 0xFB, 0x00, 0xFB, 0xF3, 0xE8, 0xE7, 0xEC, + 0xF8, 0x04, 0x08, 0x0B, 0x03, 0xF3, 0xF3, 0x02, 0x10, 0x13, 0x04, 0xF4, 0xF1, 0x00, 0x17, 0x28, + 0x28, 0x1F, 0x12, 0x0B, 0x0D, 0x0B, 0x08, 0x06, 0xF8, 0xE8, 0xE3, 0xEC, 0x07, 0x1F, 0x26, 0x19, + 0xFF, 0xF2, 0xF6, 0xFE, 0x04, 0xF8, 0xE4, 0xDC, 0xE0, 0xF1, 0x0B, 0x1D, 0x23, 0x17, 0x01, 0xF1, + 0xE7, 0xE8, 0xF3, 0xEF, 0xDF, 0xD3, 0xD5, 0xEF, 0x0F, 0x21, 0x1F, 0x0D, 0xF7, 0xEC, 0xEB, 0xF2, + 0xF6, 0xF1, 0xED, 0xEE, 0xF0, 0x01, 0x1B, 0x2A, 0x2B, 0x14, 0xFD, 0xF2, 0xF6, 0x00, 0x07, 0x00, + 0xFB, 0xF7, 0x02, 0x18, 0x28, 0x2D, 0x2A, 0x1A, 0x05, 0xF6, 0xF1, 0xFB, 0x01, 0xFF, 0xF3, 0xE7, + 0xEB, 0x01, 0x14, 0x1F, 0x19, 0x00, 0xEC, 0xE4, 0xE2, 0xEA, 0xF3, 0xF8, 0xF8, 0xF3, 0xF3, 0xFB, + 0x09, 0x1B, 0x1C, 0x07, 0xF1, 0xE0, 0xE2, 0xF2, 0xFA, 0xF8, 0xF1, 0xE8, 0xE7, 0xEE, 0xF9, 0x06, + 0x09, 0x09, 0x06, 0xF7, 0xF1, 0xFD, 0x08, 0x0F, 0x04, 0xF6, 0xF3, 0x03, 0x1A, 0x29, 0x26, 0x19, + 0x09, 0x03, 0x0A, 0x0F, 0x09, 0x04, 0xF8, 0xEB, 0xE8, 0xF2, 0x09, 0x1E, 0x25, 0x17, 0xFB, 0xEB, + 0xF2, 0x01, 0x0C, 0x05, 0xEB, 0xD8, 0xDA, 0xEC, 0x06, 0x1B, 0x1F, 0x13, 0xFF, 0xF1, 0xE7, 0xE7, + 0xF2, 0xF7, 0xE8, 0xDA, 0xD5, 0xE9, 0x0C, 0x23, 0x25, 0x15, 0xFC, 0xF1, 0xED, 0xF1, 0xF4, 0xE8, + 0xE4, 0xE9, 0xEF, 0xFB, 0x12, 0x1F, 0x23, 0x15, 0x02, 0xF7, 0xFC, 0x05, 0x0D, 0x04, 0xF9, 0xF3, + 0xFB, 0x16, 0x2A, 0x30, 0x2A, 0x1B, 0x05, 0xF8, 0xF4, 0xFD, 0x03, 0x02, 0xF5, 0xE7, 0xE3, 0xF8, + 0x11, 0x21, 0x1E, 0x05, 0xED, 0xE4, 0xE3, 0xEC, 0xF6, 0xFD, 0xFC, 0xF4, 0xF3, 0xF3, 0xFB, 0x0E, + 0x18, 0x0B, 0xF5, 0xE4, 0xE5, 0xF5, 0xFF, 0xFB, 0xF0, 0xE5, 0xE6, 0xF1, 0xFF, 0x0A, 0x09, 0x09, + 0x08, 0xFD, 0xF4, 0xFA, 0x05, 0x0A, 0x00, 0xF1, 0xEC, 0xFD, 0x19, 0x2D, 0x2A, 0x18, 0x03, 0xFC, + 0x0A, 0x13, 0x12, 0x0B, 0x02, 0xF6, 0xF0, 0xF5, 0x08, 0x19, 0x21, 0x14, 0xF8, 0xE6, 0xEC, 0x01, + 0x10, 0x0A, 0xEC, 0xD5, 0xD8, 0xE9, 0x03, 0x13, 0x19, 0x11, 0x03, 0xF7, 0xEF, 0xED, 0xF6, 0xFC, + 0xEE, 0xDC, 0xD6, 0xE3, 0x01, 0x1A, 0x1B, 0x0A, 0xF5, 0xED, 0xEE, 0xF2, 0xF4, 0xEA, 0xE7, 0xED, + 0xF5, 0xFF, 0x11, 0x20, 0x25, 0x1B, 0x0A, 0x02, 0x03, 0x0C, 0x10, 0x03, 0xF4, 0xEC, 0xF5, 0x0F, + 0x25, 0x27, 0x21, 0x17, 0x09, 0xFB, 0xF7, 0xFD, 0x01, 0x01, 0xF9, 0xEC, 0xEA, 0xFD, 0x17, 0x26, + 0x22, 0x07, 0xEC, 0xE3, 0xE2, 0xE7, 0xEE, 0xF8, 0xFD, 0xF9, 0xF7, 0xF3, 0xF7, 0x07, 0x15, 0x0D, + 0xF7, 0xE5, 0xE1, 0xEF, 0xFD, 0xFF, 0xF8, 0xF3, 0xF3, 0xF5, 0xF8, 0xFD, 0xFD, 0x00, 0x03, 0xFC, + 0xF1, 0xEF, 0xFD, 0x06, 0x04, 0xF8, 0xF4, 0x01, 0x19, 0x27, 0x25, 0x15, 0x05, 0x01, 0x0F, 0x18, + 0x15, 0x0D, 0x07, 0x02, 0xFA, 0xF9, 0x03, 0x10, 0x19, 0x13, 0xFB, 0xE7, 0xE9, 0xFD, 0x0F, 0x0F, + 0xF4, 0xDC, 0xD7, 0xE6, 0xF9, 0x09, 0x12, 0x13, 0x08, 0xFD, 0xF3, 0xEE, 0xF8, 0x04, 0xFF, 0xEA, + 0xDB, 0xDD, 0xF4, 0x0D, 0x14, 0x0A, 0xFD, 0xF5, 0xF3, 0xF3, 0xF3, 0xEA, 0xE7, 0xEF, 0xF6, 0xF9, + 0x00, 0x0F, 0x19, 0x19, 0x10, 0x06, 0x04, 0x0D, 0x11, 0x06, 0xF6, 0xEF, 0xF4, 0x0D, 0x21, 0x27, + 0x22, 0x1A, 0x11, 0x04, 0xFB, 0xFB, 0x01, 0x02, 0xFB, 0xEC, 0xE5, 0xF3, 0x0D, 0x21, 0x22, 0x0E, + 0xF5, 0xE8, 0xE7, 0xEB, 0xEF, 0xF7, 0xFB, 0xF9, 0xF4, 0xF0, 0xF2, 0x02, 0x13, 0x13, 0xFD, 0xE8, + 0xE0, 0xE8, 0xF6, 0xFD, 0xFA, 0xF7, 0xF8, 0xFB, 0xFE, 0xFF, 0xFE, 0x00, 0x05, 0x02, 0xF4, 0xED, + 0xF5, 0x01, 0x05, 0xFE, 0xF9, 0xFF, 0x0F, 0x1B, 0x19, 0x0B, 0x00, 0x00, 0x0D, 0x1A, 0x1A, 0x13, + 0x0E, 0x09, 0xFF, 0xFB, 0x01, 0x10, 0x1C, 0x1A, 0x04, 0xEB, 0xE8, 0xFB, 0x0C, 0x0E, 0xF8, 0xE0, + 0xD8, 0xE3, 0xF5, 0x05, 0x11, 0x14, 0x0E, 0xFF, 0xF3, 0xE9, 0xF0, 0xFE, 0x03, 0xF3, 0xE3, 0xE1, + 0xF0, 0x03, 0x0E, 0x09, 0xFD, 0xF6, 0xF1, 0xED, 0xEA, 0xE7, 0xE9, 0xF6, 0xFD, 0xFD, 0xFF, 0x0B, + 0x16, 0x18, 0x11, 0x08, 0x08 +}; + +const uint8_t SfxPlayer::_musicDataSample4[] = { + 0x01, 0xF8, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0E, 0x0D, 0xF4, 0x0F, 0xFF, 0x0C, + 0x10, 0xE1, 0xC9, 0xD5, 0xF2, 0x17, 0x2C, 0x05, 0x1B, 0x50, 0x1D, 0x1F, 0x40, 0x1B, 0x09, 0x2B, + 0xFE, 0xE0, 0x0A, 0x27, 0xDF, 0xEB, 0x1F, 0x41, 0x56, 0x2E, 0x06, 0xEC, 0xC0, 0xA7, 0xCF, 0xE5, + 0x24, 0x2C, 0x2B, 0x53, 0x36, 0x2C, 0x15, 0x1F, 0x1E, 0x18, 0x18, 0x15, 0xD9, 0xD6, 0x03, 0xEE, + 0xEF, 0x3F, 0x38, 0x36, 0x36, 0x0F, 0xE8, 0xC9, 0xC6, 0xE0, 0x21, 0xF7, 0x08, 0x3C, 0x45, 0x14, + 0x33, 0x37, 0x2A, 0x17, 0x03, 0x21, 0x10, 0x15, 0xFC, 0xCD, 0xD5, 0xF6, 0x12, 0x46, 0x24, 0xFC, + 0xF3, 0x22, 0x0A, 0xD7, 0xE8, 0x02, 0xF9, 0x0C, 0x3D, 0x46, 0x25, 0x16, 0x30, 0x0C, 0xF2, 0x16, + 0x35, 0xF8, 0xF1, 0x01, 0x03, 0x07, 0xF6, 0x11, 0x08, 0x0E, 0x14, 0x1F, 0x0F, 0xF5, 0xFD, 0x03, + 0x0E, 0xE3, 0x11, 0x2B, 0x26, 0x23, 0x21, 0x18, 0xFF, 0x11, 0x0C, 0x08, 0x07, 0x05, 0x06, 0x0A, + 0x18, 0x0F, 0x0F, 0x0E, 0x0C, 0x05, 0x12, 0x2C, 0x01, 0xFD, 0x05, 0xF6, 0xF6, 0x15, 0x29, 0x1B, + 0x0C, 0x09, 0x2A, 0x12, 0x08, 0x14, 0x00, 0xF8, 0x03, 0x26, 0x14, 0x11, 0x0C, 0x1E, 0x00, 0xFA, + 0x14, 0x15, 0x0A, 0x04, 0x07, 0x05, 0x08, 0x09, 0x18, 0x03, 0x09, 0x1A, 0x1A, 0x21, 0x12, 0x11, + 0x06, 0x01, 0x0C, 0xF3, 0x1D, 0x1F, 0x15, 0x10, 0x11, 0x10, 0x05, 0x06, 0x15, 0x02, 0xF7, 0x0C, + 0x17, 0x16, 0x01, 0xFB, 0x09, 0x01, 0x13, 0x2D, 0x28, 0x0E, 0x07, 0x1C, 0xFB, 0x01, 0x17, 0x19, + 0x02, 0x07, 0x15, 0x14, 0x0D, 0x14, 0xFD, 0xF6, 0x05, 0x16, 0x23, 0x10, 0x0E, 0x08, 0xFD, 0x09, + 0x0B, 0x16, 0x1A, 0x11, 0x13, 0x07, 0x10, 0x18, 0x0B, 0x02, 0x0D, 0x0E, 0x13, 0x1E, 0x23, 0x0C, + 0xF8, 0x00, 0x05, 0x09, 0x06, 0x1A, 0x1B, 0x01, 0x0C, 0x0C, 0x08, 0x0C, 0x17, 0x18, 0x08, 0x0C, + 0x19, 0x13, 0x06, 0x06, 0x04, 0x04, 0x11, 0x23, 0x21, 0x14, 0x0C, 0x09, 0x03, 0x08, 0x0E, 0x12, + 0x08, 0x0A, 0x0A, 0x02, 0x10, 0x15, 0x0C, 0x0A, 0x0F, 0x16, 0x1F, 0x1C, 0x14, 0x05, 0xF5, 0x02, + 0x16, 0x14, 0x17, 0x1C, 0x1B, 0x08, 0x06, 0x0F, 0x0A, 0x03, 0x0C, 0x14, 0x09, 0x0E, 0x1B, 0x09, + 0xFB, 0x05, 0x0F, 0x10, 0x1D, 0x21, 0x1B, 0x09, 0x09, 0x02, 0x06, 0x07, 0x0E, 0x16, 0x10, 0x15, + 0x17, 0x0E, 0x0D, 0x0A, 0x08, 0x02, 0x0F, 0x21, 0x16, 0x0C, 0x09, 0x03, 0xFC, 0x07, 0x19, 0x19, + 0x0F, 0x22, 0x17, 0x06, 0x03, 0x0C, 0x0D, 0xFE, 0x11, 0x1C, 0x13, 0x14, 0x17, 0x0D, 0xFC, 0xFD, + 0x16, 0x16, 0x14, 0x19, 0x10, 0x02, 0x00, 0x0A, 0x0C, 0x0A, 0x17, 0x15, 0x16, 0x11, 0x12, 0x14, + 0x04, 0xFF, 0x0C, 0x10, 0x11, 0x1D, 0x1A, 0x0A, 0x06, 0x0E, 0x00, 0x07, 0x16, 0x12, 0x0F, 0x0F, + 0x12, 0x07, 0x02, 0x13, 0x0A, 0x09, 0x15, 0x1B, 0x19, 0x0D, 0x0C, 0x07, 0x00, 0x07, 0x15, 0x17, + 0x10, 0x14, 0x19, 0x06, 0x02, 0x10, 0x0C, 0x0A, 0x0F, 0x15, 0x11, 0x0C, 0x12, 0x0D, 0x06, 0x06, + 0x0E, 0x17, 0x13, 0x12, 0x16, 0x0A, 0x06, 0x0E, 0x12, 0x0C, 0x13, 0x1C, 0x0C, 0x0C, 0x14, 0x0C, + 0x07, 0x0F, 0x0D, 0x07, 0x0F, 0x19, 0x11, 0x0F, 0x10, 0x0D, 0x09, 0x0B, 0x13, 0x14, 0x10, 0x0E, + 0x11, 0x0A, 0x07, 0x0B, 0x17, 0x0F, 0x0D, 0x17, 0x14, 0x0B, 0x10, 0x11, 0x06, 0x06, 0x10, 0x13, + 0x0F, 0x10, 0x13, 0x0E, 0x07, 0x0E, 0x13, 0x0E, 0x0D, 0x13, 0x0F, 0x0E, 0x15, 0x11, 0x0B, 0x0D, + 0x0F, 0x0A, 0x0E, 0x14, 0x14, 0x0C, 0x0F, 0x0B, 0x0B, 0x11, 0x13, 0x10, 0x0C, 0x0B, 0x0F, 0x10, + 0x10 +}; + +const uint8_t SfxPlayer::_musicDataSample5[] = { + 0x09, 0xE4, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x0C, 0x0C, 0x0C, 0x10, 0x14, 0x28, 0x28, 0x28, + 0x28, 0x2C, 0x28, 0x24, 0x24, 0x1C, 0x1C, 0x1C, 0x10, 0x14, 0x14, 0x10, 0x10, 0x08, 0x08, 0x04, + 0x0C, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x14, 0x04, 0x00, 0x14, 0x1C, 0x0C, 0x00, 0xF4, 0xE4, 0xC4, + 0xB8, 0xB4, 0xB0, 0xA8, 0xA4, 0xA0, 0xA0, 0xA0, 0xA4, 0xB0, 0xC4, 0xCC, 0xD4, 0xDC, 0xE0, 0xE8, + 0xEC, 0xF4, 0xF8, 0xFC, 0x04, 0x04, 0x24, 0x3C, 0x3C, 0x44, 0x50, 0x5C, 0x5C, 0x5C, 0x64, 0x68, + 0x68, 0x5C, 0x64, 0x64, 0x6C, 0x68, 0x6C, 0x78, 0x74, 0x68, 0x64, 0x6C, 0x6C, 0x58, 0x68, 0x58, + 0x34, 0x38, 0x48, 0x58, 0x58, 0x3C, 0x08, 0xDC, 0xC4, 0x9C, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x8C, 0x98, 0x9C, 0xA4, 0xA8, 0xBC, 0xD0, 0xD8, 0xF0, 0x08, 0x0C, + 0x0C, 0x10, 0x18, 0x20, 0x28, 0x48, 0x5C, 0x6C, 0x7C, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7C, 0x7F, + 0x7F, 0x74, 0x68, 0x5C, 0x4C, 0x3C, 0x2C, 0x28, 0x2C, 0x30, 0x34, 0x34, 0x24, 0x1C, 0x14, 0x1C, + 0x20, 0x20, 0x0C, 0x00, 0xF4, 0xE4, 0xCC, 0xBC, 0xB4, 0xB4, 0xA8, 0x94, 0x80, 0x80, 0x80, 0x80, + 0x84, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x84, 0x84, 0x8C, 0xA0, 0xC0, 0xD4, 0xD0, 0xE4, 0xEC, 0xF0, + 0xF8, 0x10, 0x20, 0x4C, 0x64, 0x68, 0x6C, 0x78, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6C, 0x64, 0x58, + 0x34, 0x2C, 0x34, 0x38, 0x2C, 0x14, 0x14, 0x20, 0x2C, 0x38, 0x34, 0x34, 0x3C, 0x3C, 0x3C, 0x2C, + 0x38, 0x54, 0x70, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x74, 0x78, 0x78, 0x7C, 0x6C, 0x74, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x74, 0x4C, 0x4C, 0x4C, 0x30, 0x14, 0x14, 0x04, 0x10, 0x1C, 0xF4, 0xCC, 0xAC, 0x84, 0x88, 0x80, + 0x80, 0x80, 0x84, 0xA8, 0x80, 0x80, 0x80, 0x84, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xAC, + 0x80, 0x80, 0xA4, 0xFC, 0x14, 0x00, 0x00, 0xF8, 0x3C, 0x70, 0x64, 0x30, 0xEC, 0x34, 0x7F, 0x44, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x70, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x70, 0x68, 0x4C, 0x68, 0x7F, 0x7F, 0x7F, 0x48, 0x3C, 0x44, 0x2C, 0x5C, + 0x68, 0x30, 0x18, 0x30, 0xF8, 0x44, 0x4C, 0x54, 0x48, 0x20, 0x14, 0xEC, 0xE0, 0xF4, 0x0C, 0x20, + 0xFC, 0x1C, 0x1C, 0x04, 0x5C, 0x3C, 0x14, 0x40, 0xCC, 0xBC, 0xF4, 0x00, 0x2C, 0xEC, 0xEC, 0x84, + 0x80, 0x9C, 0xCC, 0x90, 0x80, 0x8C, 0x80, 0x80, 0x80, 0xB4, 0xEC, 0x90, 0xC4, 0x38, 0xAC, 0xBC, + 0xAC, 0x80, 0x84, 0xA4, 0x94, 0xCC, 0xCC, 0xD4, 0x10, 0x94, 0xA4, 0xDC, 0xAC, 0xCC, 0x08, 0xF4, + 0xE4, 0x04, 0xEC, 0x4C, 0x0C, 0x04, 0x34, 0x28, 0x24, 0x50, 0x28, 0x18, 0x1C, 0x00, 0x0C, 0x1C, + 0x48, 0x74, 0x54, 0x3C, 0x1C, 0xE0, 0xCC, 0x04, 0xD8, 0xD4, 0xD8, 0xF4, 0x48, 0x44, 0x3C, 0x54, + 0x3C, 0x7F, 0x40, 0x1C, 0x6C, 0x6C, 0x7F, 0x7F, 0x5C, 0x64, 0x48, 0x50, 0x20, 0x00, 0x30, 0x0C, + 0x14, 0x28, 0x2C, 0x50, 0x70, 0x6C, 0x54, 0x54, 0x6C, 0x54, 0x28, 0x5C, 0x3C, 0x7F, 0x74, 0x7F, + 0x7F, 0x5C, 0x7C, 0x58, 0x58, 0x3C, 0xD8, 0x10, 0xCC, 0xCC, 0xA0, 0x88, 0xA4, 0xBC, 0x8C, 0xCC, + 0xF0, 0xC8, 0xB0, 0x8C, 0xBC, 0xD4, 0x80, 0x80, 0x94, 0x94, 0x84, 0xA8, 0x80, 0xF8, 0xD0, 0xE0, + 0xBC, 0x80, 0x80, 0xB4, 0x84, 0xD4, 0x9C, 0xA0, 0xD4, 0xC8, 0x00, 0xCC, 0x14, 0xD4, 0x08, 0xE8, + 0x44, 0x4C, 0xEC, 0x10, 0x1C, 0x04, 0x24, 0x50, 0x2C, 0x54, 0x64, 0x74, 0x3C, 0x24, 0x00, 0x20, + 0x24, 0x50, 0x78, 0x68, 0x24, 0x28, 0x44, 0x5C, 0x58, 0x54, 0x5C, 0x7C, 0x7F, 0x64, 0xFC, 0x2C, + 0x08, 0x58, 0x24, 0x50, 0xD4, 0x04, 0x48, 0x4C, 0x50, 0x4C, 0xE0, 0xDC, 0xDC, 0x4C, 0xD8, 0x28, + 0x60, 0xC8, 0x2C, 0xCC, 0x94, 0xC0, 0x5C, 0x54, 0x44, 0x1C, 0xEC, 0x24, 0xF0, 0xCC, 0x1C, 0xE4, + 0x7F, 0x1C, 0xD4, 0xAC, 0xA0, 0x9C, 0xEC, 0xD8, 0x1C, 0xF8, 0x20, 0x04, 0xD8, 0xD8, 0xE4, 0xC4, + 0x14, 0xCC, 0xD4, 0xD0, 0xA0, 0xDC, 0xB8, 0x80, 0xE8, 0x00, 0x2C, 0xEC, 0xE4, 0x24, 0x7F, 0xE8, + 0x14, 0xD4, 0xDC, 0xF4, 0xEC, 0x44, 0x74, 0x1C, 0xA0, 0x9C, 0xCC, 0xCC, 0x04, 0xC4, 0x14, 0x6C, + 0x7F, 0x10, 0xA0, 0x1C, 0x7F, 0x58, 0x44, 0x58, 0x4C, 0x1C, 0x08, 0x34, 0xF4, 0xCC, 0x10, 0xE4, + 0xF8, 0x50, 0x18, 0x10, 0x3C, 0x0C, 0x30, 0x44, 0xCC, 0xD4, 0x48, 0x70, 0xC8, 0x20, 0x54, 0x0C, + 0xD0, 0xF8, 0x60, 0xAC, 0xE4, 0xE8, 0x38, 0xE8, 0xFC, 0xF4, 0xD4, 0x34, 0x54, 0x0C, 0x14, 0x74, + 0x44, 0x14, 0x0C, 0x00, 0x0C, 0xC8, 0x34, 0x54, 0x6C, 0x7F, 0x30, 0xE8, 0x18, 0xD0, 0xB0, 0x08, + 0x20, 0xD0, 0x38, 0x34, 0xCC, 0x7F, 0x1C, 0x14, 0x2C, 0x30, 0xDC, 0xE0, 0xF4, 0x34, 0x28, 0xC8, + 0xAC, 0xA8, 0x14, 0xAC, 0x90, 0xBC, 0xCC, 0xD4, 0xD4, 0xD4, 0xE4, 0x0C, 0x14, 0xFC, 0xD0, 0xEC, + 0x1C, 0x24, 0x0C, 0x08, 0xEC, 0x14, 0x70, 0x2C, 0xC4, 0x84, 0xCC, 0xA4, 0x2C, 0x24, 0xA0, 0x0C, + 0x74, 0x04, 0xE4, 0x0C, 0x04, 0xDC, 0x1C, 0xF4, 0xD4, 0xFC, 0xCC, 0x94, 0xD4, 0x54, 0x24, 0x08, + 0xCC, 0xD4, 0xF4, 0x44, 0x54, 0x0C, 0x18, 0x28, 0xF0, 0x18, 0x68, 0x28, 0x60, 0x6C, 0x44, 0xC4, + 0x14, 0x64, 0x74, 0x7C, 0x5C, 0x7F, 0x7F, 0x7F, 0x20, 0x58, 0x7F, 0x28, 0x7F, 0x58, 0x68, 0x18, + 0x54, 0x04, 0x08, 0xE4, 0x14, 0x34, 0x08, 0xDC, 0xE4, 0x08, 0x3C, 0x24, 0xAC, 0xEC, 0xF4, 0xCC, + 0xF4, 0x1C, 0xE4, 0x0C, 0xF4, 0xD0, 0xE8, 0xD0, 0xDC, 0xBC, 0xA0, 0xEC, 0xB4, 0xB4, 0x28, 0xD8, + 0xF4, 0xDC, 0xBC, 0x28, 0x44, 0xF0, 0xF8, 0xE0, 0xFC, 0xC8, 0x1C, 0x4C, 0xEC, 0x00, 0xF8, 0x00, + 0xC8, 0xCC, 0xDC, 0xBC, 0xD0, 0xAC, 0xE0, 0xCC, 0xF4, 0xF8, 0xF0, 0x08, 0x10, 0x1C, 0xEC, 0x30, + 0x28, 0x44, 0x34, 0x90, 0x34, 0x3C, 0xC4, 0xE0, 0xCC, 0x00, 0x34, 0xF8, 0x34, 0xB4, 0x34, 0x3C, + 0x34, 0xEC, 0xFC, 0x7C, 0x34, 0xCC, 0x0C, 0x4C, 0x10, 0x44, 0x20, 0x14, 0x3C, 0x78, 0x64, 0x50, + 0x20, 0x4C, 0x7F, 0x20, 0x24, 0x34, 0x0C, 0x1C, 0x28, 0x04, 0x48, 0x04, 0x5C, 0x60, 0x10, 0x1C, + 0x18, 0x10, 0xEC, 0x20, 0x10, 0xAC, 0xE0, 0x10, 0x0C, 0xD0, 0xCC, 0x24, 0xE4, 0xBC, 0xE8, 0x58, + 0x00, 0xBC, 0x00, 0x4C, 0xF4, 0xBC, 0xF4, 0x28, 0xDC, 0xB4, 0xEC, 0x24, 0xF0, 0x04, 0xE4, 0xB0, + 0xF0, 0xB0, 0xC8, 0x3C, 0x2C, 0xB8, 0xB8, 0xDC, 0xF0, 0x10, 0xD8, 0xEC, 0x2C, 0x08, 0xF8, 0xC8, + 0xF4, 0x2C, 0x0C, 0x0C, 0x10, 0xE0, 0xDC, 0x28, 0x1C, 0x20, 0x38, 0xFC, 0x34, 0xF4, 0x08, 0x3C, + 0x64, 0x2C, 0xC4, 0xE4, 0xE4, 0xCC, 0x08, 0x7F, 0x3C, 0xEC, 0x14, 0xD8, 0x14, 0x48, 0x1C, 0x74, + 0x1C, 0x18, 0x74, 0x34, 0xF4, 0xE0, 0x44, 0x44, 0x58, 0x4C, 0x50, 0x28, 0x4C, 0x48, 0x08, 0x08, + 0x40, 0x64, 0x3C, 0x2C, 0x14, 0x4C, 0x40, 0x5C, 0x10, 0xFC, 0x3C, 0x28, 0xF4, 0xF4, 0x08, 0xEC, + 0x00, 0x34, 0x28, 0x80, 0xF0, 0xDC, 0xF4, 0xFC, 0xD4, 0xF0, 0x34, 0xE8, 0xEC, 0xBC, 0x90, 0x88, + 0x34, 0xF4, 0x9C, 0xAC, 0xC4, 0xDC, 0xD4, 0xCC, 0xF4, 0xE4, 0xE4, 0x2C, 0xD4, 0x08, 0xEC, 0x3C, + 0x10, 0x14, 0x24, 0x00, 0x44, 0x34, 0x2C, 0xF8, 0x0C, 0x1C, 0x44, 0x5C, 0xFC, 0x24, 0x14, 0xD4, + 0x24, 0x7F, 0xF0, 0x34, 0xE4, 0xC8, 0xE8, 0xF0, 0x2C, 0xDC, 0x0C, 0x28, 0xA4, 0xBC, 0x14, 0x60, + 0xF4, 0x2C, 0xF4, 0xE8, 0x14, 0xE8, 0x1C, 0x04, 0x28, 0x60, 0x0C, 0x0C, 0x28, 0x44, 0x3C, 0x18, + 0x4C, 0x4C, 0x68, 0x04, 0xE8, 0x28, 0x0C, 0x2C, 0x7C, 0x58, 0x5C, 0x4C, 0x68, 0x7F, 0x60, 0x6C, + 0x30, 0xEC, 0x0C, 0xFC, 0xE0, 0x30, 0x34, 0x00, 0x08, 0x1C, 0xF8, 0xAC, 0xCC, 0x0C, 0x08, 0x2C, + 0xE8, 0x08, 0x0C, 0xB4, 0xD4, 0xC4, 0x00, 0xEC, 0xCC, 0xE4, 0x10, 0xE4, 0xF8, 0xA0, 0xAC, 0xD0, + 0xF4, 0x14, 0x04, 0xC4, 0xE8, 0xDC, 0x00, 0x08, 0xF0, 0xD0, 0xD8, 0xD4, 0x10, 0xE0, 0x08, 0x1C, + 0xF8, 0xCC, 0xF4, 0xF8, 0x14, 0x04, 0x1C, 0x20, 0x04, 0xD8, 0xEC, 0x00, 0x14, 0x14, 0xEC, 0x24, + 0xF4, 0x10, 0x04, 0xC4, 0x14, 0x30, 0x28, 0x3C, 0xCC, 0x30, 0x44, 0x44, 0x10, 0x3C, 0x4C, 0x0C, + 0x4C, 0x2C, 0x48, 0x50, 0x5C, 0x2C, 0x24, 0x7F, 0x48, 0x4C, 0x24, 0x30, 0x18, 0x40, 0x24, 0x0C, + 0xF4, 0x44, 0x30, 0x48, 0x28, 0x18, 0xFC, 0xDC, 0xDC, 0x34, 0xFC, 0xE8, 0xEC, 0x4C, 0x50, 0xF4, + 0xE8, 0x20, 0x18, 0x0C, 0x20, 0x20, 0x2C, 0xE8, 0xEC, 0x10, 0xE0, 0xFC, 0x1C, 0x3C, 0x24, 0x1C, + 0x3C, 0x1C, 0x0C, 0x1C, 0xBC, 0xAC, 0x04, 0x50, 0x14, 0xE4, 0xF8, 0xEC, 0xCC, 0xE4, 0xD4, 0xE0, + 0xD8, 0xF4, 0xF4, 0xD4, 0xB4, 0xBC, 0xC8, 0xFC, 0xCC, 0xD0, 0xEC, 0xE4, 0xF0, 0xEC, 0xCC, 0xD0, + 0xE0, 0x94, 0xB8, 0xE8, 0x24, 0x04, 0xCC, 0x0C, 0xE4, 0xEC, 0xD4, 0x00, 0xE4, 0x08, 0x18, 0x00, + 0xEC, 0xEC, 0xEC, 0x28, 0xD4, 0xEC, 0x2C, 0x44, 0x44, 0x2C, 0x30, 0x54, 0x78, 0x70, 0x3C, 0x34, + 0x7C, 0x7F, 0x44, 0x2C, 0x5C, 0x54, 0x4C, 0x44, 0x5C, 0x20, 0x14, 0x1C, 0x5C, 0x78, 0x34, 0x3C, + 0x34, 0x40, 0x40, 0x54, 0x3C, 0x04, 0x14, 0x14, 0x2C, 0x2C, 0x2C, 0x2C, 0x0C, 0xD4, 0x34, 0x08, + 0xE4, 0x00, 0x14, 0x14, 0x04, 0x0C, 0xDC, 0xE4, 0xF4, 0x24, 0xEC, 0xC8, 0xB4, 0xCC, 0xD8, 0xBC, + 0xD0, 0xE0, 0xEC, 0xC4, 0xF8, 0xC4, 0xE4, 0xD4, 0xC4, 0x14, 0xF4, 0xDC, 0xDC, 0xB0, 0xA0, 0xE4, + 0x0C, 0xF8, 0x0C, 0xEC, 0xB4, 0xAC, 0xEC, 0x0C, 0xD8, 0x1C, 0x30, 0x3C, 0x0C, 0xD4, 0x0C, 0xF8, + 0xF4, 0xFC, 0x28, 0x3C, 0x28, 0x30, 0x3C, 0x38, 0x04, 0x04, 0xF4, 0x18, 0x50, 0x0C, 0xF8, 0x24, + 0xF0, 0x34, 0x20, 0x0C, 0x08, 0xF4, 0x18, 0xD8, 0xDC, 0x14, 0x24, 0xEC, 0x04, 0x2C, 0xF8, 0x30, + 0x1C, 0x2C, 0x0C, 0x0C, 0x1C, 0x18, 0x24, 0x34, 0x3C, 0x2C, 0x38, 0x3C, 0x1C, 0x38, 0x3C, 0x28, + 0x58, 0x54, 0x24, 0x24, 0x44, 0x30, 0x10, 0xEC, 0x2C, 0x1C, 0x1C, 0x14, 0xF8, 0x0C, 0x08, 0x00, + 0x04, 0xF8, 0xE8, 0x00, 0x14, 0xDC, 0xF4, 0xE4, 0xDC, 0xF0, 0xF4, 0xEC, 0xE4, 0x20, 0x1C, 0xE4, + 0x00, 0xDC, 0xF4, 0xF4, 0xE8, 0xF8, 0x28, 0x14, 0x00, 0x04, 0x5C, 0x1C, 0xE0, 0x04, 0xF0, 0xF4, + 0x0C, 0x24, 0xE4, 0xF0, 0xDC, 0xF4, 0xF8, 0xE0, 0x0C, 0xEC, 0xEC, 0xF8, 0xE4, 0xD4, 0x08, 0x04, + 0xE4, 0xF0, 0x14, 0xF4, 0xF4, 0xF0, 0x08, 0x08, 0x04, 0x04, 0xE4, 0xE8, 0xFC, 0x14, 0x14, 0x0C, + 0x24, 0x2C, 0x34, 0x14, 0x0C, 0x0C, 0x2C, 0x14, 0xF8, 0x1C, 0x10, 0x0C, 0x14, 0x14, 0x1C, 0x44, + 0x30, 0x14, 0x1C, 0x04, 0x24, 0x44, 0x18, 0x24, 0x1C, 0xFC, 0xF0, 0xEC, 0xFC, 0xEC, 0x0C, 0xF8, + 0x04, 0xFC, 0xF0, 0xE8, 0x0C, 0x2C, 0x20, 0xE4, 0xFC, 0x18, 0xF4, 0xFC, 0x0C, 0x18, 0x08, 0xF0, + 0x04, 0x0C, 0x00, 0x0C, 0x0C, 0x28, 0x1C, 0xF4, 0x08, 0x0C, 0x10, 0x14, 0x1C, 0x28, 0x2C, 0xFC, + 0x1C, 0x18, 0x10, 0x04, 0x0C, 0x24, 0x34, 0x14, 0x0C, 0x1C, 0x1C, 0x00, 0xE4, 0xFC, 0x0C, 0x28, + 0xF0, 0xEC, 0xE8, 0xFC, 0x00, 0xE4, 0x00, 0xF4, 0x24, 0x18, 0xE0, 0x0C, 0xFC, 0xF0, 0x14, 0x04, + 0x14, 0xE8, 0xEC, 0x0C, 0x08, 0x10, 0x00, 0xF0, 0xEC, 0x04, 0x14, 0xEC, 0x1C, 0x10, 0x0C, 0x14, + 0xE0, 0xF4, 0x00, 0x18, 0x04, 0xFC, 0xE4, 0xE4, 0xE0, 0x00, 0x04, 0xF0, 0xF0, 0x10, 0x00, 0x04, + 0x10, 0x0C, 0x1C, 0x08, 0x00, 0x10, 0x04, 0x0C, 0xF8, 0x04, 0x14, 0x04, 0xFC, 0x20, 0x24, 0x14, + 0x1C, 0x2C, 0x1C, 0xF0, 0x28, 0x44, 0x0C, 0x14, 0x40, 0x34, 0x1C, 0x08, 0x0C, 0x28, 0x20, 0x20, + 0x14, 0x0C, 0x04, 0x0C, 0x2C, 0x1C, 0x0C, 0x04, 0x10, 0x18, 0x14, 0x10, 0x2C, 0x2C, 0x1C, 0x04, + 0x00, 0xFC, 0x18, 0x10, 0x1C, 0x24, 0x0C, 0x28, 0x14, 0x04, 0xF8, 0x1C, 0x0C, 0x18, 0x18, 0xF8, + 0xFC, 0x08, 0xD4, 0xFC, 0xEC, 0xE4, 0xE0, 0xF4, 0x0C, 0xE8, 0xE8, 0xE8, 0xBC, 0xEC, 0x04, 0xEC, + 0xEC, 0xE0, 0xE4, 0x04, 0x10, 0x0C, 0xF8, 0xF8, 0xEC, 0xDC, 0xF4, 0x0C, 0x0C, 0xF4, 0x0C, 0x04, + 0xF0, 0xFC, 0x0C, 0x20, 0x14, 0x1C, 0x28, 0x34, 0x28, 0x18, 0x20, 0x54, 0x3C, 0x1C, 0x24, 0x24, + 0x28, 0x3C, 0x28, 0x1C, 0x18, 0x1C, 0x14, 0x00, 0x0C, 0x14, 0xF0, 0xFC, 0x24, 0x0C, 0x00, 0xF4, + 0x04, 0x24, 0x1C, 0xF4, 0x08, 0xEC, 0xF4, 0x0C, 0xF8, 0xEC, 0xF4, 0x0C, 0xF4, 0xEC, 0xEC, 0x18, + 0x18, 0x08, 0xE0, 0xF4, 0x0C, 0x20, 0x0C, 0x00, 0x00, 0x10, 0x1C, 0x00, 0xEC, 0x0C, 0x10, 0x14, + 0x10, 0x0C, 0xF8, 0xF8, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x04, 0x1C, 0x30, 0x24, 0x0C, 0xE4, 0xF4, + 0x08, 0x14, 0x0C, 0x00, 0x00, 0x0C, 0x08, 0x00, 0xEC, 0x04, 0x1C, 0x14, 0x08, 0x1C, 0x24, 0x2C, + 0x18, 0x10, 0x20, 0x0C, 0x20, 0x3C, 0x24, 0x20, 0x20, 0x38, 0x38, 0x18, 0x14, 0x1C, 0x18, 0x24, + 0x2C, 0x0C, 0x14, 0x24, 0x00, 0xEC, 0xF4, 0xEC, 0xD8, 0xD8, 0xE8, 0xE0, 0xB4, 0xC4, 0xF0, 0xEC, + 0xD0, 0xD4, 0xE0, 0xE4, 0xE0, 0xE4, 0xDC, 0x0C, 0x0C, 0x00, 0x00, 0x10, 0x20, 0x14, 0x14, 0x18, + 0x14, 0x14, 0x14, 0x10, 0x08, 0x24, 0x2C, 0x28, 0x24, 0x34, 0x30, 0x30, 0x34, 0x34, 0x38, 0x2C, + 0x1C, 0x1C, 0x34, 0x18, 0x04, 0x14, 0x10, 0x14, 0x14, 0x00, 0xE4, 0xEC, 0xE4, 0xFC, 0x10, 0x0C, + 0x0C, 0x14, 0x20, 0x04, 0x0C, 0x2C, 0x20, 0x14, 0x04, 0x08, 0x10, 0x2C, 0x2C, 0x14, 0x24, 0x00, + 0xEC, 0xFC, 0x10, 0x0C, 0x00, 0x10, 0x08, 0xF4, 0x00, 0xF4, 0x00, 0xFC, 0x08, 0x18, 0xF4, 0x00, + 0x0C, 0x0C, 0xF8, 0xF8, 0x10, 0x0C, 0x10, 0xE4, 0xE8, 0xFC, 0x04, 0x18, 0x0C, 0x0C, 0x04, 0x18, + 0x18, 0x14, 0x04, 0x0C, 0x10, 0x20, 0x0C, 0x10, 0x28, 0x34, 0x30, 0x34, 0x2C, 0x20, 0x1C, 0x1C, + 0x2C, 0x40, 0x3C, 0x24, 0x24, 0x1C, 0x18, 0x14, 0x24, 0x14, 0xEC, 0xFC, 0x04, 0xF8, 0xF4, 0xE4, + 0xE4, 0xFC, 0x04, 0xF8, 0xEC, 0xF8, 0xF8, 0xF4, 0x00, 0xF0, 0x00, 0xF4, 0xEC, 0x10, 0x04, 0xFC, + 0x08, 0x04, 0x00, 0xEC, 0x00, 0x00, 0x00, 0x14, 0x10, 0x0C, 0x04, 0x20, 0x1C, 0x24, 0x14, 0xF8, + 0x08, 0x28, 0x14, 0x0C, 0x24, 0x2C, 0x18, 0x0C, 0x24, 0x34, 0x04, 0xF8, 0xEC, 0x0C, 0x1C, 0x18, + 0x00, 0x04, 0x28, 0x1C, 0x14, 0x24, 0x18, 0x14, 0x20, 0x10, 0x10, 0x24, 0x1C, 0x04, 0x0C, 0x14, + 0x1C, 0x1C, 0x1C, 0x28, 0x24, 0x20, 0x2C, 0x24, 0x14, 0x04, 0x1C, 0x2C, 0x24, 0x24, 0x00, 0xF8, + 0xFC, 0x18, 0xF4, 0xEC, 0xFC, 0x04, 0xE4, 0xE4, 0xF4, 0xF0, 0xF8, 0x1C, 0x14, 0x14, 0x04, 0x04, + 0x00, 0x04, 0x1C, 0x1C, 0x08, 0xF4, 0xF0, 0xF8, 0x14, 0xFC, 0xF4, 0x10, 0x10, 0x18, 0x20, 0x24, + 0x14, 0x1C, 0x38, 0x28, 0x24, 0x14, 0x34, 0x44, 0x20, 0x24, 0x14, 0x10, 0x28, 0x24, 0x0C, 0x18, + 0x04, 0xF4, 0xF8, 0x14, 0xF8, 0xDC, 0xE4, 0xEC, 0xE4, 0x04, 0xFC, 0xEC, 0xF4, 0xFC, 0xFC, 0xFC, + 0xE4, 0xE4, 0xF0, 0xE0, 0xD4, 0xE8, 0xE4, 0xE4, 0xF8, 0xF0, 0xE4, 0xEC, 0xE4, 0xE4, 0xF4, 0xF8, + 0xFC, 0x04, 0x14, 0x04, 0x00, 0xF8, 0x14, 0x10, 0x14, 0x20, 0x20, 0x14, 0x08, 0x04, 0x20, 0x2C, + 0x1C, 0x0C, 0x1C, 0x1C, 0x0C, 0x1C, 0x1C, 0x00, 0x04, 0xF8, 0x20, 0x24, 0x2C, 0x3C, 0x1C, 0x28, + 0x34, 0x20, 0x2C, 0x20, 0x30, 0x2C, 0x28, 0x28, 0x24, 0x24, 0x3C, 0x3C, 0x34, 0x34, 0x34, 0x3C, + 0x24, 0x3C, 0x3C, 0x3C, 0x34, 0x34, 0x2C, 0x24, 0x18, 0x0C, 0x1C, 0x1C, 0x14, 0xF4, 0xFC, 0x0C, + 0x0C, 0x00, 0xF8, 0xFC, 0x04, 0x0C, 0x00, 0xF8, 0xF8, 0xEC, 0xEC, 0xE8, 0xF0, 0xDC, 0xE4, 0xF4, + 0xF0, 0xF0, 0xF4, 0x04, 0xDC, 0xEC, 0xEC, 0xDC, 0xE0, 0xEC, 0xEC, 0xF4, 0xEC, 0xE8, 0xF0, 0xE4, + 0xDC, 0xC4, 0xC4, 0xE4, 0xF4, 0x04, 0xF4, 0xF0, 0x08, 0x24, 0x14, 0x1C, 0x1C, 0x14, 0x30, 0x2C, + 0x08, 0x08, 0x1C, 0x14, 0x0C, 0x00, 0x08, 0x18, 0x10, 0x04, 0x04, 0x08, 0x14, 0x04, 0x10, 0x0C, + 0x00, 0x2C, 0x34, 0x1C, 0x0C, 0x1C, 0x20, 0x2C, 0x1C, 0x2C, 0x38, 0x44, 0x2C, 0x1C, 0x20, 0x44, + 0x48, 0x1C, 0x18, 0x1C, 0x24, 0x3C, 0x28, 0x24, 0x38, 0x28, 0x18, 0x1C, 0x1C, 0x1C, 0x2C, 0x14, + 0x04, 0x10, 0x24, 0x18, 0xF4, 0xFC, 0x24, 0x24, 0x14, 0xFC, 0x04, 0xF0, 0xF4, 0xF8, 0xEC, 0xE4, + 0xEC, 0xF8, 0xF4, 0xEC, 0xE4, 0x04, 0xF4, 0xEC, 0xE8, 0xFC, 0xF4, 0xF4, 0x0C, 0x0C, 0x04, 0x04, + 0x00, 0x00, 0x0C, 0x00, 0xFC, 0x00, 0x04, 0xEC, 0xEC, 0xEC, 0xF4, 0x04, 0x14, 0x0C, 0x04, 0xE0, + 0xE4, 0xF4, 0xDC, 0xE8, 0x08, 0xEC, 0xF4, 0xEC, 0xE4, 0xF4, 0x08, 0x0C, 0x08, 0xFC, 0xF0, 0xF0, + 0x00, 0xF8, 0xFC, 0xFC, 0xF8, 0xF8, 0x08, 0x0C, 0xFC, 0xF8, 0x04, 0x14, 0x18, 0x0C, 0x0C, 0x20, + 0x28, 0x34, 0x24, 0x24, 0x1C, 0x28, 0x34, 0x38, 0x2C, 0x28, 0x20, 0x1C, 0x1C, 0x1C, 0x20, 0x20, + 0x24, 0x18, 0x0C, 0x20, 0x28, 0x24, 0x0C, 0x0C, 0x2C, 0x1C, 0x14, 0x04, 0x08, 0x1C, 0x24, 0x10, + 0x04, 0x18, 0x18, 0x08, 0x04, 0x18, 0x24, 0x14, 0x04, 0xF8, 0xE4, 0x00, 0x00, 0x04, 0x08, 0xFC, + 0xF4, 0xFC, 0xF0, 0xF0, 0x00, 0x08, 0xF4, 0xE4, 0xF4, 0xEC, 0xEC, 0xEC, 0xE8, 0xF4, 0xE8, 0xD8, + 0xDC, 0xE4, 0xF0, 0xEC, 0xF0, 0x04, 0xF4, 0xE8, 0xFC, 0xFC, 0xE4, 0xE8, 0xF4, 0xF4, 0x04, 0xEC, + 0xF0, 0xE4, 0xE8, 0x10, 0x0C, 0xF4, 0xEC, 0x00, 0x14, 0x0C, 0x0C, 0x04, 0x04 +}; + +const uint8_t SfxPlayer::_musicDataSample6[] = { + 0x09, 0x2E, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x03, 0x03, 0x03, 0x06, 0x06, 0x0A, + 0x00, 0x10, 0x05, 0x0C, 0x04, 0x07, 0x08, 0xEF, 0xF4, 0xEB, 0xFC, 0xE3, 0x21, 0x10, 0x10, 0x08, + 0x22, 0x0E, 0x27, 0x3A, 0x35, 0x38, 0x2D, 0x38, 0x19, 0x0B, 0xCE, 0xDA, 0xCA, 0xD2, 0xCE, 0xEB, + 0x0B, 0x16, 0x14, 0x05, 0x04, 0xED, 0xF1, 0xB8, 0xCD, 0xCB, 0xD5, 0xE9, 0xF3, 0x22, 0x29, 0x2A, + 0x13, 0x1A, 0x3A, 0x32, 0x1F, 0x3B, 0x42, 0x4F, 0x3C, 0x2E, 0x08, 0x14, 0xFF, 0xE7, 0xF0, 0xF6, + 0x0D, 0xF5, 0x0E, 0xFE, 0x08, 0x05, 0xDD, 0xC4, 0xC9, 0xB1, 0xB7, 0xCC, 0xE6, 0xF8, 0x0D, 0x20, + 0xFF, 0x3A, 0x40, 0x4F, 0x2F, 0x57, 0x4C, 0x4A, 0x39, 0xF6, 0xF4, 0xDA, 0xD1, 0xBF, 0xD4, 0xE8, + 0x02, 0xFE, 0x0B, 0xF8, 0x06, 0xF0, 0xC6, 0xB8, 0xCA, 0xB3, 0xCF, 0xDF, 0x09, 0x27, 0x2D, 0x21, + 0x1F, 0x46, 0x59, 0x40, 0x5F, 0x67, 0x6C, 0x62, 0x3A, 0x0E, 0x08, 0xE9, 0xCF, 0xCC, 0xCE, 0xED, + 0xE4, 0xF3, 0xF0, 0xF3, 0x00, 0xE5, 0xB9, 0xDD, 0xB0, 0xBF, 0xC3, 0xDF, 0x01, 0x13, 0x2D, 0x06, + 0x3C, 0x49, 0x58, 0x37, 0x65, 0x5A, 0x5F, 0x50, 0x0C, 0xFE, 0xDF, 0xC5, 0xB9, 0xB5, 0xCB, 0xE4, + 0xE2, 0x0B, 0xE7, 0x17, 0x02, 0xDA, 0xD2, 0xD8, 0xC2, 0xD7, 0xE2, 0x0D, 0x24, 0x3F, 0x2E, 0x2D, + 0x3B, 0x58, 0x36, 0x4E, 0x60, 0x56, 0x6A, 0x31, 0x15, 0xF8, 0xE0, 0xCA, 0xBC, 0xC1, 0xD8, 0xD1, + 0xF5, 0xE1, 0xF3, 0x04, 0xED, 0xC7, 0xDE, 0xC2, 0xC9, 0xC9, 0xE3, 0x09, 0x1F, 0x39, 0x1C, 0x31, + 0x4E, 0x46, 0x3A, 0x55, 0x54, 0x66, 0x5C, 0x2D, 0x14, 0xF6, 0xDA, 0xC4, 0xBF, 0xC5, 0xD2, 0xDB, + 0xF4, 0xE3, 0x0C, 0x0F, 0xE6, 0xD9, 0xD4, 0xCA, 0xCB, 0xD9, 0x03, 0x0E, 0x3F, 0x2C, 0x29, 0x33, + 0x43, 0x36, 0x39, 0x55, 0x4E, 0x6B, 0x45, 0x24, 0x04, 0xE6, 0xCC, 0xBB, 0xB9, 0xCA, 0xC7, 0xE7, + 0xDE, 0xE9, 0x03, 0x00, 0xDC, 0xE2, 0xD8, 0xCC, 0xCF, 0xEB, 0xF9, 0x25, 0x2C, 0x2B, 0x1E, 0x3B, + 0x3B, 0x2E, 0x43, 0x4C, 0x5B, 0x6A, 0x44, 0x2A, 0x0C, 0xE8, 0xD1, 0xC0, 0xC9, 0xC9, 0xD7, 0xE7, + 0xE6, 0xF8, 0x1B, 0xF0, 0xE7, 0xE0, 0xCC, 0xC6, 0xCF, 0xEC, 0xFF, 0x25, 0x2D, 0x20, 0x23, 0x37, + 0x2D, 0x2A, 0x46, 0x42, 0x66, 0x5A, 0x38, 0x25, 0x00, 0xE3, 0xCA, 0xC0, 0xCD, 0xC7, 0xDE, 0xE4, + 0xDA, 0x07, 0x04, 0xEA, 0xE9, 0xD4, 0xD1, 0xBF, 0xE2, 0xEB, 0x19, 0x27, 0x35, 0x1C, 0x39, 0x3A, + 0x2D, 0x3F, 0x43, 0x53, 0x6B, 0x4C, 0x3A, 0x20, 0xF8, 0xE8, 0xC3, 0xD3, 0xC6, 0xD1, 0xDE, 0xDC, + 0xE5, 0x0E, 0xF1, 0xEF, 0xDA, 0xD7, 0xBC, 0xC9, 0xD7, 0xF3, 0x13, 0x31, 0x1C, 0x21, 0x32, 0x28, + 0x29, 0x38, 0x3E, 0x5D, 0x62, 0x45, 0x3B, 0x10, 0xFE, 0xD4, 0xCF, 0xD0, 0xCD, 0xD7, 0xE7, 0xD6, + 0xFB, 0x04, 0xF2, 0xF0, 0xDA, 0xD8, 0xBF, 0xDB, 0xE1, 0x06, 0x23, 0x36, 0x24, 0x32, 0x39, 0x2C, + 0x35, 0x38, 0x47, 0x5D, 0x58, 0x42, 0x2E, 0x08, 0xF3, 0xCF, 0xD4, 0xC9, 0xCA, 0xD8, 0xDB, 0xD6, + 0xFF, 0xF3, 0xF5, 0xDC, 0xE0, 0xC2, 0xCB, 0xD2, 0xED, 0x07, 0x2D, 0x2A, 0x22, 0x32, 0x2C, 0x26, + 0x31, 0x37, 0x49, 0x63, 0x4A, 0x48, 0x21, 0x0C, 0xE6, 0xD8, 0xD3, 0xD0, 0xCF, 0xE7, 0xD3, 0xEB, + 0x00, 0xFB, 0xEE, 0xE4, 0xD8, 0xC5, 0xD0, 0xDD, 0xF7, 0x17, 0x33, 0x28, 0x29, 0x3C, 0x28, 0x33, + 0x34, 0x3A, 0x57, 0x57, 0x4C, 0x38, 0x17, 0x00, 0xE0, 0xD5, 0xD2, 0xC4, 0xD5, 0xDC, 0xCB, 0xF4, + 0xF7, 0xF8, 0xE6, 0xE2, 0xC9, 0xC5, 0xC9, 0xE1, 0xF6, 0x22, 0x2D, 0x1E, 0x33, 0x2A, 0x27, 0x2E, + 0x30, 0x3F, 0x59, 0x54, 0x51, 0x30, 0x19, 0xF8, 0xDE, 0xDD, 0xD2, 0xCB, 0xEB, 0xD0, 0xE7, 0xF6, + 0x03, 0xF5, 0xF1, 0xE0, 0xCE, 0xC4, 0xD7, 0xE0, 0x03, 0x25, 0x26, 0x1F, 0x34, 0x26, 0x2C, 0x32, + 0x2C, 0x4B, 0x50, 0x58, 0x42, 0x2C, 0x11, 0xF1, 0xDE, 0xDB, 0xC6, 0xDA, 0xDA, 0xD5, 0xE4, 0xF7, + 0xFB, 0xF1, 0xEA, 0xD6, 0xC6, 0xC6, 0xD4, 0xE3, 0x0B, 0x27, 0x1B, 0x2D, 0x2C, 0x26, 0x32, 0x2A, + 0x3A, 0x4B, 0x5B, 0x55, 0x41, 0x28, 0x0A, 0xEA, 0xDE, 0xD8, 0xC7, 0xE8, 0xD7, 0xE2, 0xED, 0x03, + 0xF6, 0xF8, 0xE3, 0xD6, 0xC1, 0xD1, 0xD2, 0xEF, 0x15, 0x21, 0x1B, 0x2A, 0x24, 0x23, 0x30, 0x22, + 0x3F, 0x49, 0x5A, 0x4E, 0x3A, 0x22, 0x06, 0xE4, 0xEA, 0xC4, 0xDB, 0xDA, 0xDC, 0xDB, 0xF6, 0xFC, + 0xFA, 0xF2, 0xE2, 0xCC, 0xC7, 0xCE, 0xD9, 0xF7, 0x22, 0x1E, 0x25, 0x31, 0x20, 0x35, 0x24, 0x33, + 0x3F, 0x55, 0x5B, 0x4B, 0x36, 0x1D, 0xF8, 0xEB, 0xDC, 0xC9, 0xDE, 0xDB, 0xDA, 0xE3, 0xFB, 0xF8, + 0xFB, 0xE8, 0xE0, 0xC5, 0xCC, 0xCF, 0xD9, 0x07, 0x1C, 0x1B, 0x27, 0x24, 0x24, 0x2C, 0x23, 0x33, + 0x43, 0x57, 0x58, 0x48, 0x31, 0x1C, 0xF0, 0xF6, 0xCA, 0xD7, 0xDB, 0xDD, 0xD5, 0xEA, 0xF7, 0xFB, + 0xF2, 0xEC, 0xD0, 0xCA, 0xC9, 0xCC, 0xDF, 0x0F, 0x1B, 0x1C, 0x30, 0x1F, 0x34, 0x28, 0x2B, 0x38, + 0x47, 0x5D, 0x54, 0x41, 0x34, 0x04, 0xFB, 0xE2, 0xCF, 0xD7, 0xDF, 0xD7, 0xDB, 0xF1, 0xF8, 0xF9, + 0xF2, 0xE2, 0xD0, 0xC7, 0xCF, 0xC9, 0xF3, 0x12, 0x13, 0x25, 0x20, 0x28, 0x2A, 0x28, 0x2C, 0x3A, + 0x51, 0x5B, 0x51, 0x40, 0x2C, 0x02, 0x00, 0xDB, 0xD5, 0xDF, 0xE0, 0xD5, 0xE3, 0xF1, 0xFD, 0xF4, + 0xF2, 0xDA, 0xCC, 0xCB, 0xC5, 0xCF, 0xFD, 0x12, 0x17, 0x26, 0x21, 0x2A, 0x2C, 0x24, 0x2F, 0x3D, + 0x53, 0x5C, 0x44, 0x46, 0x12, 0x0A, 0xEE, 0xD7, 0xD4, 0xDF, 0xD8, 0xD6, 0xE3, 0xF8, 0xF4, 0xFA, + 0xE8, 0xDB, 0xC9, 0xD0, 0xC3, 0xDB, 0x09, 0x0B, 0x23, 0x1E, 0x27, 0x2C, 0x29, 0x29, 0x32, 0x44, + 0x5D, 0x52, 0x4F, 0x38, 0x17, 0x04, 0xEE, 0xD6, 0xDE, 0xE3, 0xD6, 0xDD, 0xE9, 0xF8, 0xF6, 0xF4, + 0xE8, 0xD0, 0xCF, 0xC6, 0xC0, 0xEB, 0x01, 0x15, 0x1C, 0x22, 0x26, 0x2C, 0x26, 0x27, 0x35, 0x46, + 0x5E, 0x49, 0x52, 0x28, 0x16, 0x00, 0xE2, 0xD4, 0xE1, 0xD8, 0xD8, 0xD8, 0xF3, 0xF0, 0xF9, 0xF0, + 0xE0, 0xD0, 0xCF, 0xC4, 0xC7, 0xF9, 0x05, 0x1B, 0x1F, 0x23, 0x2D, 0x2C, 0x26, 0x2E, 0x33, 0x59, + 0x4D, 0x57, 0x44, 0x28, 0x12, 0xFC, 0xDE, 0xDC, 0xE3, 0xDB, 0xD6, 0xE5, 0xF1, 0xF7, 0xF5, 0xF2, + 0xD9, 0xD2, 0xD0, 0xB6, 0xDD, 0xF1, 0x0D, 0x16, 0x1D, 0x25, 0x29, 0x28, 0x24, 0x2A, 0x3D, 0x54, + 0x4D, 0x53, 0x3C, 0x20, 0x0E, 0xF4, 0xD8, 0xE2, 0xDD, 0xDB, 0xD6, 0xEA, 0xF3, 0xF4, 0xF9, 0xE8, + 0xD8, 0xD5, 0xC4, 0xBF, 0xE3, 0xFD, 0x11, 0x1C, 0x21, 0x29, 0x2E, 0x24, 0x2E, 0x27, 0x4F, 0x4B, + 0x56, 0x50, 0x34, 0x1E, 0x0A, 0xE8, 0xDD, 0xDE, 0xE0, 0xD1, 0xDE, 0xE8, 0xF3, 0xF5, 0xF6, 0xE6, + 0xD4, 0xD8, 0xB9, 0xCB, 0xE5, 0xFE, 0x12, 0x18, 0x22, 0x29, 0x26, 0x2A, 0x20, 0x37, 0x47, 0x4E, + 0x53, 0x49, 0x2C, 0x1B, 0x02, 0xE2, 0xE0, 0xE3, 0xDB, 0xD7, 0xDF, 0xF2, 0xEF, 0xF9, 0xF4, 0xDA, + 0xDE, 0xC8, 0xBF, 0xD1, 0xED, 0x05, 0x15, 0x1E, 0x25, 0x2D, 0x27, 0x2C, 0x23, 0x3F, 0x4A, 0x51, + 0x57, 0x42, 0x28, 0x1A, 0xF5, 0xE4, 0xDD, 0xE4, 0xD4, 0xD8, 0xE4, 0xED, 0xF1, 0xF9, 0xEC, 0xDB, + 0xDB, 0xC2, 0xC0, 0xD7, 0xEF, 0x07, 0x16, 0x19, 0x2C, 0x21, 0x32, 0x1E, 0x2F, 0x3F, 0x4A, 0x53, + 0x54, 0x38, 0x29, 0x10, 0xF3, 0xDE, 0xE6, 0xDC, 0xD9, 0xDB, 0xEB, 0xEF, 0xF4, 0xFE, 0xE0, 0xE5, + 0xD2, 0xC1, 0xC7, 0xDD, 0xF7, 0x0D, 0x13, 0x23, 0x24, 0x2B, 0x28, 0x21, 0x34, 0x44, 0x4B, 0x58, + 0x4E, 0x33, 0x28, 0x07, 0xEE, 0xE1, 0xE4, 0xDC, 0xD6, 0xDF, 0xEB, 0xEB, 0xFD, 0xF2, 0xE3, 0xE0, + 0xCE, 0xBF, 0xCB, 0xE2, 0xFA, 0x12, 0x13, 0x29, 0x20, 0x31, 0x21, 0x26, 0x37, 0x42, 0x4D, 0x59, + 0x42, 0x37, 0x1D, 0x06, 0xE5, 0xE5, 0xE2, 0xD8, 0xD8, 0xE1, 0xEB, 0xEF, 0x00, 0xEB, 0xE7, 0xE0, + 0xC9, 0xC3, 0xD2, 0xE6, 0x06, 0x0A, 0x1F, 0x1F, 0x29, 0x2B, 0x21, 0x29, 0x3A, 0x43, 0x54, 0x54, + 0x3F, 0x30, 0x1C, 0xFA, 0xE7, 0xE5, 0xE1, 0xD8, 0xD9, 0xE9, 0xE4, 0xFA, 0xF8, 0xE9, 0xE7, 0xD8, + 0xC6, 0xC5, 0xD5, 0xEF, 0x06, 0x0F, 0x20, 0x1E, 0x2C, 0x26, 0x20, 0x2D, 0x3A, 0x43, 0x58, 0x49, + 0x3E, 0x2B, 0x16, 0xF3, 0xE6, 0xE6, 0xDD, 0xD5, 0xDE, 0xE4, 0xE9, 0xFC, 0xF2, 0xE9, 0xE6, 0xD4, + 0xC3, 0xCB, 0xD7, 0xFB, 0x02, 0x18, 0x1A, 0x23, 0x2C, 0x23, 0x23, 0x34, 0x39, 0x4F, 0x54, 0x4B, + 0x38, 0x2C, 0x0C, 0xF0, 0xE8, 0xE6, 0xDD, 0xD8, 0xE6, 0xE2, 0xF3, 0xFC, 0xEE, 0xEA, 0xE4, 0xCD, + 0xC7, 0xC8, 0xE1, 0xF8, 0x07, 0x16, 0x19, 0x25, 0x2A, 0x1E, 0x27, 0x31, 0x3D, 0x51, 0x51, 0x44, + 0x38, 0x26, 0x04, 0xEE, 0xE8, 0xE6, 0xD8, 0xDF, 0xE2, 0xE6, 0xF9, 0xF8, 0xEE, 0xEC, 0xE0, 0xCB, + 0xC7, 0xCA, 0xE9, 0xF8, 0x0D, 0x13, 0x1B, 0x27, 0x25, 0x1C, 0x2D, 0x2F, 0x46, 0x51, 0x50, 0x40, + 0x38, 0x20, 0xFE, 0xEC, 0xEA, 0xE1, 0xD8, 0xE2, 0xDF, 0xED, 0xFB, 0xF6, 0xED, 0xEE, 0xD8, 0xCE, + 0xC1, 0xD6, 0xE9, 0xFF, 0x0D, 0x14, 0x1D, 0x2B, 0x1E, 0x24, 0x2A, 0x35, 0x48, 0x52, 0x4A, 0x3E, + 0x34, 0x14, 0xFA, 0xEB, 0xED, 0xDB, 0xDF, 0xE0, 0xE1, 0xF1, 0xFB, 0xEF, 0xF0, 0xE6, 0xD6, 0xC8, + 0xC5, 0xDC, 0xED, 0x05, 0x0E, 0x14, 0x23, 0x27, 0x1D, 0x28, 0x2B, 0x3B, 0x4B, 0x53, 0x45, 0x40, + 0x2C, 0x10, 0xF2, 0xEF, 0xE8, 0xDB, 0xE3, 0xDE, 0xE6, 0xF6, 0xF8, 0xEE, 0xF2, 0xE0, 0xD7, 0xC2, + 0xCD, 0xDD, 0xF4, 0x06, 0x0F, 0x17, 0x2A, 0x21, 0x22, 0x27, 0x2E, 0x3E, 0x4F, 0x4E, 0x44, 0x3D, + 0x26, 0x06, 0xF0, 0xF0, 0xE0, 0xDD, 0xDF, 0xDE, 0xE9, 0xFA, 0xF1, 0xF3, 0xEC, 0xE1, 0xCE, 0xC2, + 0xD1, 0xE1, 0xF9, 0x09, 0x0E, 0x1F, 0x27, 0x21, 0x24, 0x27, 0x32, 0x43, 0x51, 0x49, 0x45, 0x39, + 0x20, 0x00, 0xF2, 0xEE, 0xDE, 0xE1, 0xDF, 0xDF, 0xF2, 0xF8, 0xF3, 0xF4, 0xEA, 0xE0, 0xC8, 0xC7, + 0xD2, 0xE5, 0xFC, 0x08, 0x0F, 0x23, 0x24, 0x21, 0x24, 0x29, 0x33, 0x47, 0x4C, 0x47, 0x41, 0x34, + 0x16, 0xF8, 0xF5, 0xE8, 0xE0, 0xE1, 0xDE, 0xE3, 0xF7, 0xF4, 0xF6, 0xF2, 0xEB, 0xD9, 0xC7, 0xC8, + 0xD7, 0xE9, 0x03, 0x04, 0x17, 0x24, 0x22, 0x22, 0x25, 0x2A, 0x39, 0x4A, 0x4B, 0x46, 0x40, 0x2E, + 0x0C, 0xF9, 0xF3, 0xE5, 0xE0, 0xE4, 0xDA, 0xED, 0xF5, 0xF6, 0xF7, 0xF1, 0xEA, 0xD4, 0xC7, 0xCC, + 0xD7, 0xF2, 0x00, 0x06, 0x19, 0x21, 0x21, 0x20, 0x26, 0x28, 0x3E, 0x47, 0x49, 0x44, 0x3E, 0x28, + 0x06, 0xFB, 0xF0, 0xE4, 0xE5, 0xE0, 0xDF, 0xF1, 0xF4, 0xF8, 0xF4, 0xF3, 0xE4, 0xD2, 0xC6, 0xD0, + 0xDB, 0xF9, 0xFD, 0x0B, 0x1B, 0x20, 0x1F, 0x23, 0x23, 0x2F, 0x40, 0x4A, 0x48, 0x43, 0x3E, 0x20, + 0x06, 0xF9, 0xF0, 0xE4, 0xE9, 0xDC, 0xE7, 0xF2, 0xF6, 0xF8, 0xF5, 0xF1, 0xE0, 0xCA, 0xCB, 0xCC, + 0xE5, 0xF9, 0xFD, 0x0F, 0x1A, 0x1F, 0x1D, 0x24, 0x21, 0x32, 0x43, 0x49, 0x44, 0x44, 0x38, 0x16, + 0x02, 0xFA, 0xE8, 0xEA, 0xE4, 0xDF, 0xED, 0xF2, 0xFB, 0xF5, 0xF8, 0xEE, 0xDA, 0xCB, 0xCA, 0xCF, + 0xEC, 0xF7, 0x02, 0x12, 0x1D, 0x1C, 0x22, 0x1F, 0x25, 0x36, 0x45, 0x49, 0x43, 0x47, 0x2D, 0x13, + 0x01, 0xF6, 0xE7, 0xEB, 0xDF, 0xE2, 0xED, 0xF6, 0xF8, 0xF8, 0xF5, 0xED, 0xD3, 0xCD, 0xC7, 0xD7, + 0xEF, 0xF6, 0x05, 0x13, 0x1C, 0x1D, 0x20, 0x1F, 0x28, 0x3B, 0x48, 0x46, 0x47, 0x42, 0x2A, 0x0D, + 0x03, 0xF0, 0xEB, 0xE8, 0xDD, 0xE7, 0xED, 0xF8, 0xF7, 0xF7, 0xF6, 0xE4, 0xD3, 0xCA, 0xC7, 0xDD, + 0xEE, 0xF8, 0x06, 0x17, 0x19, 0x20, 0x1F, 0x20, 0x2E, 0x3F, 0x4A, 0x45, 0x4C, 0x40, 0x20, 0x0F, + 0xFE, 0xEE, 0xED, 0xE3, 0xE1, 0xE7, 0xF3, 0xF6, 0xF8, 0xF6, 0xF4, 0xDD, 0xD1, 0xC5, 0xC9, 0xE3, + 0xEF, 0xF9, 0x0C, 0x16, 0x1C, 0x1F, 0x1F, 0x22, 0x31, 0x46, 0x46, 0x49, 0x4B, 0x3A, 0x1C, 0x0D, + 0xF8, 0xEE, 0xEC, 0xE0, 0xE2, 0xEB, 0xF3, 0xF9, 0xF5, 0xFB, 0xEC, 0xDC, 0xCE, 0xC2, 0xD2, 0xE5, + 0xEF, 0xFD, 0x0F, 0x16, 0x1D, 0x20, 0x1D, 0x24, 0x37, 0x46, 0x46, 0x49, 0x4C, 0x2E, 0x1C, 0x07, + 0xF4, 0xF0, 0xE7, 0xE2, 0xE3, 0xEE, 0xF6, 0xF6, 0xF9, 0xF8, 0xE8, 0xDA, 0xC8, 0xC6, 0xD7, 0xE9, + 0xEF, 0x05, 0x0F, 0x19, 0x1E, 0x1E, 0x1E, 0x25, 0x3E, 0x43, 0x45, 0x4E, 0x45, 0x2B, 0x19, 0x01, + 0xF4, 0xEE, 0xE7, 0xDE, 0xE7, 0xEE, 0xF9, 0xF5, 0xFD, 0xF5, 0xE6, 0xD9, 0xC5, 0xC9, 0xDC, 0xE8, + 0xF5, 0x05, 0x11, 0x19, 0x1E, 0x1F, 0x1B, 0x2D, 0x3C, 0x44, 0x43, 0x4E, 0x3B, 0x27, 0x13, 0xFB, + 0xF4, 0xEC, 0xE3, 0xE1, 0xE7, 0xF4, 0xF6, 0xF9, 0xFE, 0xF1, 0xE8, 0xD2, 0xC7, 0xCD, 0xE1, 0xE9, + 0xFA, 0x09, 0x14, 0x1D, 0x20, 0x1D, 0x1F, 0x31, 0x3F, 0x3E, 0x48, 0x4A, 0x34, 0x24, 0x0A, 0xFA, + 0xF0, 0xEB, 0xDF, 0xE2, 0xE9, 0xF5, 0xF6, 0xFC, 0xFC, 0xF0, 0xE4, 0xCE, 0xC6, 0xD3, 0xE1, 0xED, + 0xFE, 0x0B, 0x17, 0x1C, 0x22, 0x19, 0x24, 0x35, 0x3F, 0x3F, 0x4C, 0x45, 0x32, 0x20, 0x06, 0xF8, + 0xF1, 0xE5, 0xE1, 0xE1, 0xEF, 0xF5, 0xF7, 0xFF, 0xF8, 0xF2, 0xE0, 0xCC, 0xC8, 0xD7, 0xE3, 0xEF, + 0xFF, 0x0D, 0x17, 0x1F, 0x1D, 0x1B, 0x25, 0x3A, 0x3B, 0x43, 0x4D, 0x3E, 0x30, 0x19, 0x04, 0xF6, + 0xEE, 0xE5, 0xE0, 0xE5, 0xF2, 0xF5, 0xFB, 0xFE, 0xF9, 0xEE, 0xDC, 0xC9, 0xCC, 0xDA, 0xE4, 0xF3, + 0x01, 0x0F, 0x17, 0x1F, 0x1B, 0x1A, 0x2B, 0x39, 0x3B, 0x47, 0x4A, 0x3E, 0x2C, 0x16, 0x00, 0xF7, + 0xEB, 0xE5, 0xDF, 0xE9, 0xF4, 0xF6, 0xFE, 0xFD, 0xF8, 0xEC, 0xD5, 0xC8, 0xCF, 0xDC, 0xE7, 0xF5, + 0x06, 0x0E, 0x1B, 0x1C, 0x18, 0x1B, 0x30, 0x37, 0x3D, 0x4B, 0x48, 0x3B, 0x2A, 0x10, 0x00, 0xF4, + 0xEB, 0xE0, 0xDF, 0xED, 0xF2, 0xF8, 0xFD, 0xFD, 0xF6, 0xE8, 0xD0, 0xC8, 0xD2, 0xDC, 0xE7, 0xF9, + 0x05, 0x12, 0x1B, 0x1D, 0x16, 0x22, 0x33, 0x36, 0x41, 0x4B, 0x46, 0x38, 0x26, 0x0C, 0xFF, 0xF2, + 0xEA, 0xDF, 0xE5, 0xEF, 0xF3, 0xF9, 0xFF, 0xFB, 0xF6, 0xE1, 0xCC, 0xCB, 0xD4, 0xDF, 0xEB, 0xFD, + 0x06, 0x15, 0x1C, 0x1A, 0x16, 0x27, 0x32, 0x37, 0x45, 0x4C, 0x42, 0x38, 0x20, 0x0B, 0xFC, 0xF2, + 0xE6, 0xDE, 0xE8, 0xEE, 0xF4, 0xFB, 0xFD, 0xFB, 0xF2, 0xDC, 0xCB, 0xCD, 0xD7, 0xDF, 0xEF, 0xFC, + 0x09, 0x15, 0x1D, 0x16, 0x1A, 0x2C, 0x32, 0x3B, 0x48, 0x4A, 0x42, 0x34, 0x1A, 0x08, 0xF9, 0xF1, + 0xE2, 0xE3, 0xE9, 0xF0, 0xF6, 0xFD, 0xFC, 0xFB, 0xEE, 0xD5, 0xCB, 0xCE, 0xD8, 0xE3, 0xF3, 0xFF, + 0x0C, 0x19, 0x1B, 0x14, 0x1F, 0x2C, 0x32, 0x3D, 0x49, 0x47, 0x40, 0x2C, 0x16, 0x03, 0xF8, 0xEC, + 0xE1, 0xE4, 0xEB, 0xF1, 0xF9, 0xFC, 0xFD, 0xFA, 0xE8, 0xD2, 0xCA, 0xD1, 0xD7, 0xE7, 0xF5, 0x01, + 0x0F, 0x1B, 0x18, 0x15, 0x23, 0x2D, 0x33, 0x43, 0x49, 0x49, 0x3E, 0x29, 0x13, 0x01, 0xF7, 0xE8, + 0xE1, 0xE5, 0xEB, 0xF2, 0xF9, 0xFC, 0xFD, 0xF8, 0xE2, 0xCF, 0xCD, 0xD1, 0xDC, 0xEA, 0xF7, 0x04, + 0x13, 0x1C, 0x15, 0x18, 0x27, 0x2D, 0x37, 0x45, 0x49, 0x48, 0x39, 0x24, 0x0D, 0x00, 0xF4, 0xE6, + 0xE1, 0xE7, 0xEC, 0xF4, 0xF9, 0xFB, 0xFE, 0xF3, 0xDD, 0xCE, 0xCF, 0xD2, 0xDF, 0xEC, 0xFA, 0x06, + 0x17, 0x1A, 0x15, 0x1C, 0x29, 0x2D, 0x3B, 0x46, 0x4B, 0x45, 0x36, 0x20, 0x0B, 0xFE, 0xF1, 0xE4, + 0xE4, 0xE8, 0xED, 0xF5, 0xF9, 0xFD, 0xFB, 0xEE, 0xD6, 0xCF, 0xCD, 0xD5, 0xE1, 0xEF, 0xFB, 0x0A, + 0x18, 0x18, 0x15, 0x1F, 0x27, 0x2F, 0x3F, 0x47, 0x4B, 0x42, 0x33, 0x1A, 0x0A, 0xFC, 0xEE, 0xE4, + 0xE6, 0xE9, 0xF0, 0xF6, 0xFA, 0xFD, 0xFA, 0xE8, 0xD4, 0xCE, 0xCE, 0xD7, 0xE3, 0xF2, 0xFD, 0x0E, + 0x19, 0x15, 0x16, 0x21, 0x26, 0x33, 0x3F, 0x48, 0x49, 0x41, 0x2E, 0x18, 0x08, 0xFA, 0xEB, 0xE4, + 0xE7, 0xEA, 0xF2, 0xF7, 0xFB, 0xFD, 0xF8, 0xE1, 0xD3, 0xCB, 0xD0, 0xD7, 0xE7, 0xF2, 0xFF, 0x12, + 0x19, 0x13, 0x1A, 0x21, 0x28, 0x36, 0x40, 0x49, 0x47, 0x3D, 0x29, 0x14, 0x06, 0xF8, 0xE9, 0xE6, + 0xE7, 0xED, 0xF3, 0xF8, 0xFB, 0xFE, 0xF2, 0xDF, 0xD2, 0xCD, 0xD1, 0xDB, 0xE9, 0xF3, 0x02, 0x14, + 0x16, 0x13, 0x1D, 0x21, 0x2C, 0x37, 0x44, 0x49, 0x47, 0x3A, 0x25, 0x12, 0x04, 0xF4, 0xE9, 0xE7, + 0xE8, 0xEE, 0xF5, 0xF8, 0xFC, 0xFD, 0xEE, 0xDC, 0xD0, 0xCE, 0xD2, 0xDF, 0xEB, 0xF6, 0x07, 0x16, + 0x13, 0x17, 0x1D, 0x23, 0x2E, 0x3B, 0x45, 0x4A, 0x45, 0x36, 0x21, 0x10, 0x01, 0xF0, 0xEA, 0xE6, + 0xEB, 0xEF, 0xF7, 0xF8, 0xFF, 0xFA, 0xEA, 0xD8, 0xD0, 0xCD, 0xD4, 0xE0, 0xEC, 0xF7, 0x0C, 0x15, + 0x12, 0x19, 0x1D, 0x26, 0x30, 0x3E, 0x47, 0x49, 0x44, 0x32, 0x1E, 0x0F, 0xFE, 0xF0, 0xE8, 0xE7, + 0xEA, 0xF2, 0xF5, 0xFA, 0xFF, 0xF8, 0xE6, 0xD6, 0xCF, 0xCD, 0xD5, 0xE3, 0xEB, 0xFB, 0x0F, 0x12, + 0x15, 0x19, 0x1F, 0x27, 0x34, 0x3F, 0x3F +}; + +const uint8_t SfxPlayer::_musicDataSample7[] = { + 0x03, 0x46, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0F, 0x0A, 0x0F, 0x08, 0x15, 0x0D, + 0x11, 0x16, 0x08, 0x0B, 0x17, 0xFA, 0x0E, 0x17, 0x06, 0x0F, 0x0F, 0x13, 0x11, 0xFA, 0x28, 0xFF, + 0x0E, 0x23, 0xFD, 0x14, 0x1F, 0xF2, 0x1C, 0x0F, 0x00, 0x37, 0xF7, 0x04, 0x1B, 0xF3, 0x1C, 0x0F, + 0x06, 0x0F, 0x12, 0xFF, 0x14, 0x0D, 0x10, 0x0B, 0xF4, 0x4F, 0xCF, 0x28, 0xEA, 0x2B, 0xFF, 0x10, + 0x2F, 0xE4, 0x13, 0xFF, 0x12, 0x0F, 0x16, 0x07, 0x2F, 0xD4, 0x24, 0xFF, 0x00, 0x18, 0x11, 0x00, + 0x17, 0x02, 0x11, 0xFA, 0x2F, 0xEA, 0x18, 0xFF, 0x0C, 0x04, 0x30, 0xFF, 0x24, 0xE3, 0x30, 0xFF, + 0x00, 0x3F, 0xEF, 0x1C, 0xFC, 0x17, 0xEF, 0x28, 0xF7, 0x2B, 0x03, 0x07, 0x10, 0x22, 0xEF, 0x18, + 0x2F, 0xD9, 0x21, 0x08, 0x1F, 0xEC, 0x2C, 0xFC, 0x05, 0x0C, 0x2C, 0xF0, 0x1F, 0x0A, 0x02, 0x17, + 0x0C, 0xF2, 0x34, 0xFF, 0xF8, 0x19, 0x13, 0x09, 0xFC, 0x55, 0xAF, 0x10, 0x37, 0xD2, 0x31, 0x08, + 0x07, 0x09, 0x0C, 0x17, 0x04, 0xFE, 0x24, 0x00, 0x1D, 0x10, 0x10, 0x07, 0x19, 0x03, 0x05, 0x06, + 0x07, 0x0F, 0x18, 0x17, 0x00, 0x24, 0xDF, 0x20, 0x07, 0xF8, 0x1F, 0x00, 0x3F, 0xD2, 0x2A, 0x07, + 0x0C, 0x05, 0x20, 0x0F, 0xE8, 0x27, 0x0D, 0x0C, 0x0F, 0x1D, 0xEF, 0x1C, 0x00, 0x13, 0x0E, 0x00, + 0x2B, 0xF5, 0x08, 0x1F, 0xD0, 0x50, 0xFB, 0xE8, 0x3F, 0xE0, 0x20, 0x05, 0x1C, 0xEE, 0x1C, 0x02, + 0x2B, 0xE3, 0x20, 0x17, 0xE0, 0x58, 0xDF, 0x20, 0x11, 0xEF, 0x1C, 0x06, 0x27, 0xFA, 0x07, 0x1F, + 0xE1, 0x2C, 0xFF, 0x0A, 0x1F, 0x06, 0xFF, 0x00, 0x2F, 0xEB, 0x1A, 0x08, 0x2B, 0xDB, 0x20, 0x1B, + 0xE8, 0x30, 0xF7, 0x08, 0x23, 0xEF, 0x20, 0xFF, 0x27, 0xFB, 0x12, 0x0A, 0x15, 0xFE, 0x0E, 0x17, + 0x11, 0xF7, 0x11, 0x09, 0x15, 0xFF, 0x10, 0x1F, 0xEA, 0x1A, 0x0C, 0xFF, 0x19, 0x1C, 0xFF, 0x15, + 0x06, 0x05, 0x11, 0x19, 0xFA, 0x12, 0x0B, 0x04, 0x1B, 0x0E, 0x04, 0x13, 0x15, 0xFF, 0x04, 0x27, + 0xEC, 0x24, 0xFF, 0x00, 0x2B, 0xE6, 0x20, 0x08, 0x06, 0x0B, 0x08, 0x1B, 0x00, 0x1C, 0x0B, 0x04, + 0x09, 0x0C, 0x0F, 0x06, 0x0C, 0x13, 0x07, 0x03, 0x1F, 0xF3, 0x20, 0x0D, 0xF8, 0x20, 0x0B, 0xF8, + 0x26, 0xFF, 0x14, 0x0F, 0x09, 0x09, 0x0E, 0x1B, 0xE4, 0x40, 0xF7, 0x00, 0x22, 0xFF, 0x11, 0x00, + 0x2B, 0xFA, 0x0A, 0x11, 0x16, 0x03, 0x0C, 0x1B, 0xFC, 0x07, 0x08, 0x1F, 0xE2, 0x40, 0xFB, 0x00, + 0x23, 0xFB, 0x10, 0x16, 0x05, 0x12, 0x06, 0x06, 0x2C, 0xEF, 0x10, 0x17, 0xF8, 0x20, 0xFF, 0x10, + 0x0A, 0x0B, 0x12, 0x05, 0x17, 0x0C, 0x0D, 0x08, 0x0E, 0x12, 0x08, 0x17, 0x05, 0x0C, 0x0F, 0x04, + 0x10, 0x15, 0x04, 0x1D, 0xEF, 0x2C, 0xFF, 0x00, 0x1F, 0x03, 0x12, 0x08, 0x09, 0x18, 0x0B, 0x00, + 0x1E, 0xFF, 0x08, 0xFF, 0x2C, 0xFD, 0x08, 0x1F, 0xF2, 0x14, 0x17, 0xF4, 0x2D, 0xFF, 0x02, 0x2F, + 0xF0, 0x07, 0x10, 0x17, 0xFD, 0x20, 0xFF, 0x0C, 0x0E, 0x06, 0x08, 0x19, 0xFB, 0x12, 0x17, 0xF8, + 0x18, 0x0B, 0x17, 0xF8, 0x16, 0x07, 0x0C, 0x13, 0x08, 0x07, 0x04, 0x0F, 0x09, 0x10, 0x08, 0x1F, + 0xEC, 0x18, 0x17, 0xF8, 0x1F, 0x05, 0x04, 0x17, 0xFF, 0x18, 0x0F, 0x08, 0x0C, 0x08, 0x10, 0x04, + 0x16, 0x09, 0x16, 0x02, 0x0E, 0x12, 0x0F, 0xF6, 0x32, 0xEF, 0x10, 0x1F, 0xF7, 0x16, 0x0C, 0x0E, + 0x16, 0xFB, 0x13, 0x04, 0x11, 0x11, 0x06, 0x1F, 0xFB, 0x12, 0x0F, 0x04, 0x14, 0x07, 0x04, 0x1F, + 0xF3, 0x18, 0x09, 0x16, 0x06, 0x0A, 0x13, 0xFC, 0x1A, 0x07, 0x0C, 0x1C, 0xEF, 0x14, 0x15, 0xF1, + 0x30, 0xFF, 0x08, 0x1C, 0xEF, 0x18, 0x08, 0x13, 0x09, 0x0C, 0x17, 0xF0, 0x28, 0x07, 0x08, 0x1D, + 0xFD, 0x10, 0x15, 0xFD, 0x28, 0xFF, 0x04, 0x1C, 0xF7, 0x18, 0x07, 0x1E, 0x07, 0x08, 0x17, 0xF4, + 0x1C, 0x07, 0x0B, 0x0C, 0x1A, 0x06, 0x06, 0x19, 0x04, 0x10, 0x04, 0x14, 0x07, 0x0A, 0x1F, 0xEE, + 0x28, 0xFF, 0x09, 0x0F, 0x10, 0x07, 0x08, 0x18, 0x02, 0x14, 0x00, 0x1C, 0x05, 0x0B, 0x06, 0x1F, + 0xEF, 0x18, 0x0F, 0x0C, 0x0E, 0x06, 0x13, 0x02, 0x0D, 0x14, 0x04, 0x13, 0x0B, 0x0F, 0x04, 0x1B, + 0xFF, 0x0C, 0x13, 0x06, 0x0E, 0x0E, 0x0F, 0x09, 0x0B, 0x0E, 0x06, 0x12, 0x0B, 0x0A, 0x11, 0x0B, + 0x09, 0x0C, 0x0E, 0x07, 0x11, 0x08, 0x11, 0x0F, 0x09, 0x0C, 0x17, 0xFA, 0x1A, 0x07, 0x16, 0xFF, + 0x18, 0x0F, 0x02, 0x17, 0x05, 0x10, 0x04, 0x19, 0x06, 0x11, 0x02, 0x1D, 0xFF, 0x08, 0x1B, 0xFE, + 0x18, 0x0A, 0x11, 0x07, 0x14, 0x0E, 0x0C, 0x0D, 0x0D, 0x0E, 0x03, 0x16, 0x09, 0x10, 0x03, 0x1A, + 0x06, 0x08, 0x1B, 0xFF, 0x11, 0x0B, 0x0A, 0x0E, 0x0A, 0x0F, 0x06, 0x16, 0x06, 0x06, 0x15, 0x05, + 0x14, 0x0B, 0x07, 0x12, 0x0A, 0x11, 0x02, 0x1C, 0x09, 0x07, 0x1E, 0x00, 0x10, 0x0D, 0x0C, 0x12, + 0x0A, 0x0E, 0x0D, 0x12, 0x07, 0x08, 0x0F, 0x0E, 0x11, 0x08, 0x17, 0x06, 0x0E, 0x0D, 0x0F, 0x10, + 0x07, 0x10, 0x10, 0x08, 0x0E, 0x09, 0x10, 0x0B, 0x10, 0x0A, 0x14, 0x06, 0x10, 0x0F, 0x0D, 0x09, + 0x0E, 0x0B, 0x12, 0x07, 0x0E, 0x13, 0x05, 0x15, 0x08, 0x0D, 0x0D, 0x0E, 0x0B, 0x12, 0x09, 0x0B, + 0x10, 0x0E, 0x0B, 0x0B, 0x10, 0x08, 0x17, 0x03, 0x13, 0x0A, 0x15, 0x03, 0x10, 0x0F, 0x05, 0x14, + 0x0D, 0x0E, 0x0B, 0x13, 0x0A, 0x0E, 0x10, 0x07, 0x10, 0x17, 0xFC, 0x1C, 0x0D, 0x02, 0x1A, 0x0B, + 0x0B, 0x0F, 0x0F, 0x0C, 0x0E, 0x0A, 0x11, 0x0A, 0x11, 0x09, 0x10, 0x0F, 0x0B, 0x17, 0x0B, 0x0C, + 0x0E, 0x0F, 0x0A, 0x11, 0x0B, 0x0E, 0x0C, 0x10, 0x0E, 0x08, 0x14, 0x0B, 0x0E, 0x14, 0x04, 0x16, + 0x0A, 0x10, 0x0E, 0x0C, 0x0F, 0x02, 0x1B, 0x07, 0x10, 0x13, 0x08, 0x14, 0x07, 0x12, 0x07, 0x10, + 0x0F, 0x08, 0x14, 0x0B, 0x0E, 0x0F, 0x0E, 0x10, 0x0B, 0x11, 0x10, 0x0E, 0x0D, 0x08, 0x14, 0x0B, + 0x0E, 0x0F, 0x10, 0x0D, 0x0C, 0x13, 0x0C, 0x10, 0x0F, 0x0C, 0x0E, 0x0E, 0x0F, 0x00, 0x00 +}; + +const uint8_t SfxPlayer::_musicDataSample8[] = { + 0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 +}; + +const SfxPlayer::Module SfxPlayer::_module68 = { + { _musicDataSample1, _musicDataSample8, _musicDataSample3, _musicDataSample4, _musicDataSample8 }, + _musicData68 +}; + +const SfxPlayer::Module SfxPlayer::_module70 = { + { _musicDataSample1, _musicDataSample2, _musicDataSample3, _musicDataSample3, _musicDataSample8 }, + _musicData70 +}; + +const SfxPlayer::Module SfxPlayer::_module72 = { + { _musicDataSample1, _musicDataSample2, _musicDataSample5, _musicDataSample4, _musicDataSample8 }, + _musicData72 +}; + +const SfxPlayer::Module SfxPlayer::_module73 = { + { _musicDataSample1, _musicDataSample2, _musicDataSample4, _musicDataSample3, _musicDataSample8 }, + _musicData73 +}; + +const SfxPlayer::Module SfxPlayer::_module74 = { + { _musicDataSample1, _musicDataSample2, _musicDataSample5, _musicDataSample6, _musicDataSample7 }, + _musicData74 +}; + +const SfxPlayer::Module SfxPlayer::_module75 = { + { _musicDataSample1, _musicDataSample2, _musicDataSample5, _musicDataSample6, _musicDataSample7 }, + _musicData75 +}; + +const uint16_t SfxPlayer::_periodTable[] = { + 0x434, 0x3F8, 0x3C0, 0x38A, 0x358, 0x328, 0x2FA, 0x2D0, 0x2A6, 0x280, + 0x25C, 0x23A, 0x21A, 0x1FC, 0x1E0, 0x1C5, 0x1AC, 0x194, 0x17D, 0x168, + 0x153, 0x140, 0x12E, 0x11D, 0x10D, 0x0FE, 0x0F0, 0x0E2, 0x0D6, 0x0CA, + 0x0BE, 0x0B4, 0x0AA, 0x0A0, 0x097, 0x08F, 0x087, 0x07F, 0x078, 0x071 +}; diff --git a/systemstub.h b/systemstub.h new file mode 100644 index 0000000..d1560d5 --- /dev/null +++ b/systemstub.h @@ -0,0 +1,100 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SYSTEMSTUB_H__ +#define SYSTEMSTUB_H__ + +#include "intern.h" + +struct PlayerInput { + enum { + DIR_UP = 1 << 0, + DIR_DOWN = 1 << 1, + DIR_LEFT = 1 << 2, + DIR_RIGHT = 1 << 3 + }; + enum { + DF_FASTMODE = 1 << 0, + DF_DBLOCKS = 1 << 1, + DF_SETLIFE = 1 << 2 + }; + + uint8_t dirMask; + bool enter; + bool space; + bool shift; + bool backspace; + bool escape; + + char lastChar; + + bool save; + bool load; + int stateSlot; + + bool inpRecord; + bool inpReplay; + + bool mirrorMode; + + uint8_t dbgMask; + bool quit; +}; + +struct SystemStub { + typedef void (*AudioCallback)(void *param, int8_t *stream, int len); + + PlayerInput _pi; + + virtual ~SystemStub() {} + + virtual void init(const char *title, int w, int h) = 0; + virtual void destroy() = 0; + + virtual void setPalette(const uint8_t *pal, int n) = 0; + virtual void setPaletteEntry(int i, const Color *c) = 0; + virtual void getPaletteEntry(int i, Color *c) = 0; + virtual void setOverscanColor(int i) = 0; + virtual void copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch) = 0; + virtual void fadeScreen() = 0; + virtual void updateScreen(int shakeOffset) = 0; + + virtual void processEvents() = 0; + virtual void sleep(int duration) = 0; + virtual uint32_t getTimeStamp() = 0; + + virtual void startAudio(AudioCallback callback, void *param) = 0; + virtual void stopAudio() = 0; + virtual uint32_t getOutputSampleRate() = 0; + virtual void lockAudio() = 0; + virtual void unlockAudio() = 0; +}; + +struct LockAudioStack { + LockAudioStack(SystemStub *stub) + : _stub(stub) { + _stub->lockAudio(); + } + ~LockAudioStack() { + _stub->unlockAudio(); + } + SystemStub *_stub; +}; + +extern SystemStub *SystemStub_SDL_create(); + +#endif // SYSTEMSTUB_H__ diff --git a/systemstub_sdl.cpp b/systemstub_sdl.cpp new file mode 100644 index 0000000..2e78613 --- /dev/null +++ b/systemstub_sdl.cpp @@ -0,0 +1,619 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "scaler.h" +#include "systemstub.h" + + +struct SystemStub_SDL : SystemStub { + enum { + MAX_BLIT_RECTS = 200, + SOUND_SAMPLE_RATE = 22050, + JOYSTICK_COMMIT_VALUE = 3200 + }; + + uint16_t *_screenBuffer; + uint16_t *_fadeScreenBuffer; + SDL_Surface *_screenSurface; + bool _fullscreen; + int _currentScaler; + uint8_t _overscanColor; + uint16_t _pal[256]; + int _screenW, _screenH; + SDL_Joystick *_joystick; + SDL_Rect _blitRects[MAX_BLIT_RECTS]; + int _numBlitRects; + bool _fadeOnUpdateScreen; + void (*_audioCbProc)(void *, int8_t *, int); + void *_audioCbData; + + virtual ~SystemStub_SDL() {} + virtual void init(const char *title, int w, int h); + virtual void destroy(); + virtual void setPalette(const uint8_t *pal, int n); + virtual void setPaletteEntry(int i, const Color *c); + virtual void getPaletteEntry(int i, Color *c); + virtual void setOverscanColor(int i); + virtual void copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch); + virtual void fadeScreen(); + virtual void updateScreen(int shakeOffset); + virtual void processEvents(); + virtual void sleep(int duration); + virtual uint32_t getTimeStamp(); + virtual void startAudio(AudioCallback callback, void *param); + virtual void stopAudio(); + virtual uint32_t getOutputSampleRate(); + virtual void lockAudio(); + virtual void unlockAudio(); + + void processEvent(const SDL_Event &ev, bool &paused); + void updateScreen_GL(int shakeOffset); + void updateScreen_SW(int shakeOffset); + void prepareGfxMode(); + void cleanupGfxMode(); + void switchGfxMode(bool fullscreen, uint8_t scaler); + void flipGfx(); + void forceGfxRedraw(); + void drawRect(SDL_Rect *rect, uint8_t color, uint16_t *dst, uint16_t dstPitch); +}; + +SystemStub *SystemStub_SDL_create() { + return new SystemStub_SDL(); +} + +void SystemStub_SDL::init(const char *title, int w, int h) { + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK); + SDL_ShowCursor(SDL_DISABLE); + SDL_WM_SetCaption(title, NULL); + memset(&_pi, 0, sizeof(_pi)); + _screenW = w; + _screenH = h; + // allocate some extra bytes for the scaling routines + const int screenBufferSize = (w + 2) * (h + 2) * sizeof(uint16_t); + _screenBuffer = (uint16_t *)malloc(screenBufferSize); + if (!_screenBuffer) { + error("SystemStub_SDL::init() Unable to allocate offscreen buffer"); + } + memset(_screenBuffer, 0, screenBufferSize); + _fadeScreenBuffer = 0; + _fadeOnUpdateScreen = false; + _fullscreen = false; + _currentScaler = SCALER_SCALE_3X; + memset(_pal, 0, sizeof(_pal)); + prepareGfxMode(); + _joystick = NULL; + if (SDL_NumJoysticks() > 0) { + _joystick = SDL_JoystickOpen(0); + } +} + +void SystemStub_SDL::destroy() { + cleanupGfxMode(); + if (SDL_JoystickOpened(0)) { + SDL_JoystickClose(_joystick); + } + SDL_Quit(); +} + +void SystemStub_SDL::setPalette(const uint8_t *pal, int n) { + assert(n <= 256); + for (int i = 0; i < n; ++i) { + uint8_t r = pal[i * 3 + 0]; + uint8_t g = pal[i * 3 + 1]; + uint8_t b = pal[i * 3 + 2]; + _pal[i] = SDL_MapRGB(_screenSurface->format, r, g, b); + } +} + +void SystemStub_SDL::setPaletteEntry(int i, const Color *c) { + uint8_t r = (c->r << 2) | (c->r & 3); + uint8_t g = (c->g << 2) | (c->g & 3); + uint8_t b = (c->b << 2) | (c->b & 3); + _pal[i] = SDL_MapRGB(_screenSurface->format, r, g, b); +} + +void SystemStub_SDL::getPaletteEntry(int i, Color *c) { + SDL_GetRGB(_pal[i], _screenSurface->format, &c->r, &c->g, &c->b); + c->r >>= 2; + c->g >>= 2; + c->b >>= 2; +} + +void SystemStub_SDL::setOverscanColor(int i) { + _overscanColor = i; +} + +void SystemStub_SDL::copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch) { + if (_numBlitRects >= MAX_BLIT_RECTS) { + warning("SystemStub_SDL::copyRect() Too many blit rects, you may experience graphical glitches"); + } else { + // extend the dirty region by 1 pixel for scalers accessing 'outer' pixels + --x; + --y; + w += 2; + h += 2; + + if (x < 0) { + x = 0; + } else if (x >= _screenW) { + return; + } + if (y < 0) { + y = 0; + } else if (y >= _screenH) { + return; + } + if (x + w > _screenW) { + w = _screenW - x; + } + if (y + h > _screenH) { + h = _screenH - y; + } + SDL_Rect *br = &_blitRects[_numBlitRects]; + + br->x = _pi.mirrorMode ? _screenW - (x + w) : x; + br->y = y; + br->w = w; + br->h = h; + ++_numBlitRects; + + uint16_t *p = _screenBuffer + (br->y + 1) * _screenW + (br->x + 1); + buf += y * pitch + x; + + if (_pi.mirrorMode) { + while (h--) { + for (int i = 0; i < w; ++i) { + p[i] = _pal[buf[w - 1 - i]]; + } + p += _screenW; + buf += pitch; + } + } else { + while (h--) { + for (int i = 0; i < w; ++i) { + p[i] = _pal[buf[i]]; + } + p += _screenW; + buf += pitch; + } + } + if (_pi.dbgMask & PlayerInput::DF_DBLOCKS) { + drawRect(br, 0xE7, _screenBuffer + _screenW + 1, _screenW * 2); + } + } +} + +void SystemStub_SDL::fadeScreen() { + const int fadeScreenBufferSize = _screenH * _screenW * sizeof(uint16_t); + if (!_fadeScreenBuffer) { + _fadeScreenBuffer = (uint16_t *)malloc(fadeScreenBufferSize); + assert(_fadeScreenBuffer); + } + _fadeOnUpdateScreen = true; + memcpy(_fadeScreenBuffer, _screenBuffer + _screenW + 1, fadeScreenBufferSize); +} + +static uint16_t blendPixel16(uint16_t colorSrc, uint16_t colorDst, uint32_t mask, int step) { + const uint32_t pSrc = (colorSrc | (colorSrc << 16)) & mask; + const uint32_t pDst = (colorDst | (colorDst << 16)) & mask; + const uint32_t pRes = ((pDst - pSrc) * step / 16 + pSrc) & mask; + return pRes | (pRes >> 16); +} + +void SystemStub_SDL::updateScreen(int shakeOffset) { + const int mul = _scalers[_currentScaler].factor; + if (_fadeOnUpdateScreen) { + const int tempScreenBufferSize = (_screenH + 2) * (_screenW + 2) * sizeof(uint16_t); + uint16_t *tempScreenBuffer = (uint16_t *)calloc(tempScreenBufferSize, 1); + assert(tempScreenBuffer); + const SDL_PixelFormat *pf = _screenSurface->format; + const uint32_t colorMask = (pf->Gmask << 16) | (pf->Rmask | pf->Bmask); + const uint16_t *screenBuffer = _screenBuffer + _screenW + 1; + for (int i = 1; i <= 16; ++i) { + for (int x = 0; x < _screenH * _screenW; ++x) { + tempScreenBuffer[_screenW + 1 + x] = blendPixel16(_fadeScreenBuffer[x], screenBuffer[x], colorMask, i); + } + SDL_LockSurface(_screenSurface); + uint16_t *dst = (uint16_t *)_screenSurface->pixels; + const uint16_t *src = tempScreenBuffer + _screenW + 1; + (*_scalers[_currentScaler].proc)(dst, _screenSurface->pitch, src, _screenW, _screenW, _screenH); + SDL_UnlockSurface(_screenSurface); + SDL_UpdateRect(_screenSurface, 0, 0, _screenW * mul, _screenH * mul); + SDL_Delay(30); + } + free(tempScreenBuffer); + _fadeOnUpdateScreen = false; + return; + } + if (shakeOffset == 0) { + for (int i = 0; i < _numBlitRects; ++i) { + SDL_Rect *br = &_blitRects[i]; + int dx = br->x * mul; + int dy = br->y * mul; + SDL_LockSurface(_screenSurface); + uint16_t *dst = (uint16_t *)_screenSurface->pixels + dy * _screenSurface->pitch / 2 + dx; + const uint16_t *src = _screenBuffer + (br->y + 1) * _screenW + (br->x + 1); + (*_scalers[_currentScaler].proc)(dst, _screenSurface->pitch, src, _screenW, br->w, br->h); + SDL_UnlockSurface(_screenSurface); + br->x *= mul; + br->y *= mul; + br->w *= mul; + br->h *= mul; + } + SDL_UpdateRects(_screenSurface, _numBlitRects, _blitRects); + } else { + SDL_LockSurface(_screenSurface); + int w = _screenW; + int h = _screenH - shakeOffset; + uint16_t *dst = (uint16_t *)_screenSurface->pixels + shakeOffset * mul * _screenSurface->pitch / 2; + const uint16_t *src = _screenBuffer + _screenW + 1; + (*_scalers[_currentScaler].proc)(dst, _screenSurface->pitch, src, _screenW, w, h); + SDL_UnlockSurface(_screenSurface); + + SDL_Rect r; + r.x = 0; + r.y = 0; + r.w = _screenW * mul; + r.h = shakeOffset * mul; + SDL_FillRect(_screenSurface, &r, _pal[_overscanColor]); + + SDL_UpdateRect(_screenSurface, 0, 0, _screenW * mul, _screenH * mul); + } + _numBlitRects = 0; +} + +void SystemStub_SDL::processEvents() { + while (true) { + bool paused = false; + SDL_Event ev; + while (SDL_PollEvent(&ev)) { + processEvent(ev, paused); + if (_pi.quit) { + return; + } + } + if (!paused) { + break; + } + SDL_Delay(100); + } +} + +void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) { + switch (ev.type) { + case SDL_QUIT: + _pi.quit = true; + break; + case SDL_ACTIVEEVENT: + if (ev.active.state & SDL_APPINPUTFOCUS) { + paused = ev.active.gain == 0; + SDL_PauseAudio(paused ? 1 : 0); + } + break; + case SDL_JOYHATMOTION: + _pi.dirMask = 0; + if (ev.jhat.value & SDL_HAT_UP) { + _pi.dirMask |= PlayerInput::DIR_UP; + } + if (ev.jhat.value & SDL_HAT_DOWN) { + _pi.dirMask |= PlayerInput::DIR_DOWN; + } + if (ev.jhat.value & SDL_HAT_LEFT) { + _pi.dirMask |= PlayerInput::DIR_LEFT; + } + if (ev.jhat.value & SDL_HAT_RIGHT) { + _pi.dirMask |= PlayerInput::DIR_RIGHT; + } + break; + case SDL_JOYAXISMOTION: + switch (ev.jaxis.axis) { + case 0: + if (ev.jaxis.value > JOYSTICK_COMMIT_VALUE) { + _pi.dirMask |= PlayerInput::DIR_RIGHT; + if (_pi.dirMask & PlayerInput::DIR_LEFT) { + _pi.dirMask &= ~PlayerInput::DIR_LEFT; + } + } else if (ev.jaxis.value < -JOYSTICK_COMMIT_VALUE) { + _pi.dirMask |= PlayerInput::DIR_LEFT; + if (_pi.dirMask & PlayerInput::DIR_RIGHT) { + _pi.dirMask &= ~PlayerInput::DIR_RIGHT; + } + } else { + _pi.dirMask &= ~(PlayerInput::DIR_RIGHT | PlayerInput::DIR_LEFT); + } + break; + case 1: + if (ev.jaxis.value > JOYSTICK_COMMIT_VALUE) { + _pi.dirMask |= PlayerInput::DIR_DOWN; + if (_pi.dirMask & PlayerInput::DIR_UP) { + _pi.dirMask &= ~PlayerInput::DIR_UP; + } + } else if (ev.jaxis.value < -JOYSTICK_COMMIT_VALUE) { + _pi.dirMask |= PlayerInput::DIR_UP; + if (_pi.dirMask & PlayerInput::DIR_DOWN) { + _pi.dirMask &= ~PlayerInput::DIR_DOWN; + } + } else { + _pi.dirMask &= ~(PlayerInput::DIR_UP | PlayerInput::DIR_DOWN); + } + break; + } + break; + case SDL_JOYBUTTONDOWN: + switch (ev.jbutton.button) { + case 0: + _pi.space = true; + break; + case 1: + _pi.shift = true; + break; + case 2: + _pi.enter = true; + break; + case 3: + _pi.backspace = true; + break; + } + break; + case SDL_JOYBUTTONUP: + switch (ev.jbutton.button) { + case 0: + _pi.space = false; + break; + case 1: + _pi.shift = false; + break; + case 2: + _pi.enter = false; + break; + case 3: + _pi.backspace = false; + break; + } + break; + case SDL_KEYUP: + switch (ev.key.keysym.sym) { + case SDLK_LEFT: + _pi.dirMask &= ~PlayerInput::DIR_LEFT; + break; + case SDLK_RIGHT: + _pi.dirMask &= ~PlayerInput::DIR_RIGHT; + break; + case SDLK_UP: + _pi.dirMask &= ~PlayerInput::DIR_UP; + break; + case SDLK_DOWN: + _pi.dirMask &= ~PlayerInput::DIR_DOWN; + break; + case SDLK_SPACE: + _pi.space = false; + break; + case SDLK_RSHIFT: + case SDLK_LSHIFT: + _pi.shift = false; + break; + case SDLK_RETURN: + _pi.enter = false; + break; + case SDLK_ESCAPE: + _pi.escape = false; + break; + default: + break; + } + break; + case SDL_KEYDOWN: + if (ev.key.keysym.mod & KMOD_ALT) { + if (ev.key.keysym.sym == SDLK_RETURN) { + switchGfxMode(!_fullscreen, _currentScaler); + } else if (ev.key.keysym.sym == SDLK_KP_PLUS || ev.key.keysym.sym == SDLK_PAGEUP) { + uint8_t s = _currentScaler + 1; + if (s < NUM_SCALERS) { + switchGfxMode(_fullscreen, s); + } + } else if (ev.key.keysym.sym == SDLK_KP_MINUS || ev.key.keysym.sym == SDLK_PAGEDOWN) { + int8_t s = _currentScaler - 1; + if (_currentScaler > 0) { + switchGfxMode(_fullscreen, s); + } + } + break; + } else if (ev.key.keysym.mod & KMOD_CTRL) { + if (ev.key.keysym.sym == SDLK_f) { + _pi.dbgMask ^= PlayerInput::DF_FASTMODE; + } else if (ev.key.keysym.sym == SDLK_b) { + _pi.dbgMask ^= PlayerInput::DF_DBLOCKS; + } else if (ev.key.keysym.sym == SDLK_i) { + _pi.dbgMask ^= PlayerInput::DF_SETLIFE; + } else if (ev.key.keysym.sym == SDLK_m) { + _pi.mirrorMode = !_pi.mirrorMode; + flipGfx(); + } else if (ev.key.keysym.sym == SDLK_s) { + _pi.save = true; + } else if (ev.key.keysym.sym == SDLK_l) { + _pi.load = true; + } else if (ev.key.keysym.sym == SDLK_KP_PLUS || ev.key.keysym.sym == SDLK_PAGEUP) { + _pi.stateSlot = 1; + } else if (ev.key.keysym.sym == SDLK_KP_MINUS || ev.key.keysym.sym == SDLK_PAGEDOWN) { + _pi.stateSlot = -1; + } else if (ev.key.keysym.sym == SDLK_r) { + _pi.inpRecord = true; + } else if (ev.key.keysym.sym == SDLK_p) { + _pi.inpReplay = true; + } + } + _pi.lastChar = ev.key.keysym.sym; + switch (ev.key.keysym.sym) { + case SDLK_LEFT: + _pi.dirMask |= PlayerInput::DIR_LEFT; + break; + case SDLK_RIGHT: + _pi.dirMask |= PlayerInput::DIR_RIGHT; + break; + case SDLK_UP: + _pi.dirMask |= PlayerInput::DIR_UP; + break; + case SDLK_DOWN: + _pi.dirMask |= PlayerInput::DIR_DOWN; + break; + case SDLK_BACKSPACE: + case SDLK_TAB: + _pi.backspace = true; + break; + case SDLK_SPACE: + _pi.space = true; + break; + case SDLK_RSHIFT: + case SDLK_LSHIFT: + _pi.shift = true; + break; + case SDLK_RETURN: + _pi.enter = true; + break; + case SDLK_ESCAPE: + _pi.escape = true; + break; + default: + break; + } + break; + default: + break; + } +} + +void SystemStub_SDL::sleep(int duration) { + SDL_Delay(duration); +} + +uint32_t SystemStub_SDL::getTimeStamp() { + return SDL_GetTicks(); +} + +static void mixAudioS8ToU8(void *param, uint8_t *buf, int len) { + SystemStub_SDL *stub = (SystemStub_SDL *)param; + stub->_audioCbProc(stub->_audioCbData, (int8_t *)buf, len); + for (int i = 0; i < len; ++i) { + buf[i] ^= 0x80; + } +} + +void SystemStub_SDL::startAudio(AudioCallback callback, void *param) { + SDL_AudioSpec desired, obtained; + memset(&desired, 0, sizeof(desired)); + desired.freq = SOUND_SAMPLE_RATE; + desired.format = AUDIO_U8; + desired.channels = 1; + desired.samples = 2048; + desired.callback = mixAudioS8ToU8; + desired.userdata = this; + if (SDL_OpenAudio(&desired, &obtained) == 0) { + _audioCbProc = callback; + _audioCbData = param; + SDL_PauseAudio(0); + } else { + error("SystemStub_SDL::startAudio() Unable to open sound device"); + } +} + +void SystemStub_SDL::stopAudio() { + SDL_CloseAudio(); +} + +uint32_t SystemStub_SDL::getOutputSampleRate() { + return SOUND_SAMPLE_RATE; +} + +void SystemStub_SDL::lockAudio() { + SDL_LockAudio(); +} + +void SystemStub_SDL::unlockAudio() { + SDL_UnlockAudio(); +} + +void SystemStub_SDL::prepareGfxMode() { + int w = _screenW * _scalers[_currentScaler].factor; + int h = _screenH * _scalers[_currentScaler].factor; + _screenSurface = SDL_SetVideoMode(w, h, 16, _fullscreen ? (SDL_FULLSCREEN | SDL_HWSURFACE) : SDL_HWSURFACE); + if (!_screenSurface) { + error("SystemStub_SDL::prepareGfxMode() Unable to allocate _screen buffer"); + } + forceGfxRedraw(); +} + +void SystemStub_SDL::cleanupGfxMode() { + if (_screenBuffer) { + free(_screenBuffer); + _screenBuffer = 0; + } + if (_fadeScreenBuffer) { + free(_fadeScreenBuffer); + _fadeScreenBuffer = 0; + } + if (_screenSurface) { + // freed by SDL_Quit() + _screenSurface = 0; + } +} + +void SystemStub_SDL::switchGfxMode(bool fullscreen, uint8_t scaler) { + SDL_FreeSurface(_screenSurface); + _fullscreen = fullscreen; + _currentScaler = scaler; + prepareGfxMode(); + forceGfxRedraw(); +} + +void SystemStub_SDL::flipGfx() { + uint16_t scanline[256]; + assert(_screenW <= 256); + uint16_t *p = _screenBuffer + _screenW + 1; + for (int y = 0; y < _screenH; ++y) { + p += _screenW; + for (int x = 0; x < _screenW; ++x) { + scanline[x] = *--p; + } + memcpy(p, scanline, _screenW * sizeof(uint16_t)); + p += _screenW; + } + forceGfxRedraw(); +} + +void SystemStub_SDL::forceGfxRedraw() { + _numBlitRects = 1; + _blitRects[0].x = 0; + _blitRects[0].y = 0; + _blitRects[0].w = _screenW; + _blitRects[0].h = _screenH; +} + +void SystemStub_SDL::drawRect(SDL_Rect *rect, uint8_t color, uint16_t *dst, uint16_t dstPitch) { + dstPitch >>= 1; + int x1 = rect->x; + int y1 = rect->y; + int x2 = rect->x + rect->w - 1; + int y2 = rect->y + rect->h - 1; + assert(x1 >= 0 && x2 < _screenW && y1 >= 0 && y2 < _screenH); + for (int i = x1; i <= x2; ++i) { + *(dst + y1 * dstPitch + i) = *(dst + y2 * dstPitch + i) = _pal[color]; + } + for (int j = y1; j <= y2; ++j) { + *(dst + j * dstPitch + x1) = *(dst + j * dstPitch + x2) = _pal[color]; + } +} diff --git a/unpack.cpp b/unpack.cpp new file mode 100644 index 0000000..e9444dc --- /dev/null +++ b/unpack.cpp @@ -0,0 +1,108 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "unpack.h" + +struct UnpackCtx { + int size, datasize; + uint32_t crc; + uint32_t bits; + uint8_t *dst; + const uint8_t *src; +}; + +static int shiftBit(UnpackCtx *uc, int CF) { + int rCF = (uc->bits & 1); + uc->bits >>= 1; + if (CF) { + uc->bits |= 0x80000000; + } + return rCF; +} + +static int nextBit(UnpackCtx *uc) { + int CF = shiftBit(uc, 0); + if (uc->bits == 0) { + uc->bits = READ_BE_UINT32(uc->src); uc->src -= 4; + uc->crc ^= uc->bits; + CF = shiftBit(uc, 1); + } + return CF; +} + +static uint16_t getBits(UnpackCtx *uc, uint8_t num_bits) { + uint16_t c = 0; + while (num_bits--) { + c <<= 1; + if (nextBit(uc)) { + c |= 1; + } + } + return c; +} + +static void unpackHelper1(UnpackCtx *uc, uint8_t num_bits, uint8_t add_count) { + uint16_t count = getBits(uc, num_bits) + add_count + 1; + uc->datasize -= count; + while (count--) { + *uc->dst = (uint8_t)getBits(uc, 8); + --uc->dst; + } +} + +static void unpackHelper2(UnpackCtx *uc, uint8_t num_bits) { + uint16_t i = getBits(uc, num_bits); + uint16_t count = uc->size + 1; + uc->datasize -= count; + while (count--) { + *uc->dst = *(uc->dst + i); + --uc->dst; + } +} + +bool delphine_unpack(uint8_t *dst, const uint8_t *src, int len) { + UnpackCtx uc; + uc.src = src + len - 4; + uc.datasize = READ_BE_UINT32(uc.src); uc.src -= 4; + uc.dst = dst + uc.datasize - 1; + uc.size = 0; + uc.crc = READ_BE_UINT32(uc.src); uc.src -= 4; + uc.bits = READ_BE_UINT32(uc.src); uc.src -= 4; + uc.crc ^= uc.bits; + do { + if (!nextBit(&uc)) { + uc.size = 1; + if (!nextBit(&uc)) { + unpackHelper1(&uc, 3, 0); + } else { + unpackHelper2(&uc, 8); + } + } else { + uint16_t c = getBits(&uc, 2); + if (c == 3) { + unpackHelper1(&uc, 8, 8); + } else if (c < 2) { + uc.size = c + 2; + unpackHelper2(&uc, c + 9); + } else { + uc.size = getBits(&uc, 8); + unpackHelper2(&uc, 12); + } + } + } while (uc.datasize > 0); + return uc.crc == 0; +} diff --git a/unpack.h b/unpack.h new file mode 100644 index 0000000..b0e06a1 --- /dev/null +++ b/unpack.h @@ -0,0 +1,25 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef UNPACK_H__ +#define UNPACK_H__ + +#include "intern.h" + +extern bool delphine_unpack(uint8_t *dst, const uint8_t *src, int len); + +#endif // UNPACK_H__ diff --git a/util.cpp b/util.cpp new file mode 100644 index 0000000..195a69b --- /dev/null +++ b/util.cpp @@ -0,0 +1,61 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif +#include +#include "util.h" + + +uint16_t g_debugMask; + +void debug(uint16_t cm, const char *msg, ...) { + char buf[1024]; + if (cm & g_debugMask) { + va_list va; + va_start(va, msg); + vsprintf(buf, msg, va); + va_end(va); + printf("%s\n", buf); + fflush(stdout); + } +} + +void error(const char *msg, ...) { + char buf[1024]; + va_list va; + va_start(va, msg); + vsnprintf(buf, sizeof(buf), msg, va); + va_end(va); + fprintf(stderr, "ERROR: %s!\n", buf); +#ifdef _WIN32 + MessageBox(0, buf, g_caption, MB_ICONERROR); +#endif + exit(-1); +} + +void warning(const char *msg, ...) { + char buf[1024]; + va_list va; + va_start(va, msg); + vsnprintf(buf, sizeof(buf), msg, va); + va_end(va); + fprintf(stderr, "WARNING: %s!\n", buf); +} + diff --git a/util.h b/util.h new file mode 100644 index 0000000..b4e7d16 --- /dev/null +++ b/util.h @@ -0,0 +1,45 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef UTIL_H__ +#define UTIL_H__ + +#include "intern.h" + +enum { + DBG_INFO = 1 << 0, + DBG_RES = 1 << 1, + DBG_MENU = 1 << 2, + DBG_UNPACK = 1 << 3, + DBG_PGE = 1 << 4, + DBG_VIDEO = 1 << 5, + DBG_GAME = 1 << 6, + DBG_COL = 1 << 7, + DBG_SND = 1 << 8, + DBG_CUT = 1 << 9, + DBG_MOD = 1 << 10, + DBG_SFX = 1 << 11, + DBG_FILE = 1 << 12 +}; + +extern uint16_t g_debugMask; + +extern void debug(uint16_t cm, const char *msg, ...); +extern void error(const char *msg, ...); +extern void warning(const char *msg, ...); + +#endif // UTIL_H__ diff --git a/video.cpp b/video.cpp new file mode 100644 index 0000000..8bbb9bf --- /dev/null +++ b/video.cpp @@ -0,0 +1,831 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "resource.h" +#include "systemstub.h" +#include "unpack.h" +#include "video.h" + + +Video::Video(Resource *res, SystemStub *stub) + : _res(res), _stub(stub) { + _frontLayer = (uint8_t *)malloc(GAMESCREEN_W * GAMESCREEN_H); + memset(_frontLayer, 0, GAMESCREEN_W * GAMESCREEN_H); + _backLayer = (uint8_t *)malloc(GAMESCREEN_W * GAMESCREEN_H); + memset(_backLayer, 0, GAMESCREEN_W * GAMESCREEN_H); + _tempLayer = (uint8_t *)malloc(GAMESCREEN_W * GAMESCREEN_H); + memset(_tempLayer, 0, GAMESCREEN_W * GAMESCREEN_H); + _tempLayer2 = (uint8_t *)malloc(GAMESCREEN_W * GAMESCREEN_H); + memset(_tempLayer2, 0, GAMESCREEN_W * GAMESCREEN_H); + _screenBlocks = (uint8_t *)malloc((GAMESCREEN_W / SCREENBLOCK_W) * (GAMESCREEN_H / SCREENBLOCK_H)); + memset(_screenBlocks, 0, (GAMESCREEN_W / SCREENBLOCK_W) * (GAMESCREEN_H / SCREENBLOCK_H)); + _fullRefresh = true; + _shakeOffset = 0; + _charFrontColor = 0; + _charTransparentColor = 0; + _charShadowColor = 0; +} + +Video::~Video() { + free(_frontLayer); + free(_backLayer); + free(_tempLayer); + free(_tempLayer2); + free(_screenBlocks); +} + +void Video::markBlockAsDirty(int16_t x, int16_t y, uint16_t w, uint16_t h) { + debug(DBG_VIDEO, "Video::markBlockAsDirty(%d, %d, %d, %d)", x, y, w, h); + assert(x >= 0 && x + w <= GAMESCREEN_W && y >= 0 && y + h <= GAMESCREEN_H); + int bx1 = x / SCREENBLOCK_W; + int by1 = y / SCREENBLOCK_H; + int bx2 = (x + w - 1) / SCREENBLOCK_W; + int by2 = (y + h - 1) / SCREENBLOCK_H; + assert(bx2 < GAMESCREEN_W / SCREENBLOCK_W && by2 < GAMESCREEN_H / SCREENBLOCK_H); + for (; by1 <= by2; ++by1) { + for (int i = bx1; i <= bx2; ++i) { + _screenBlocks[by1 * (GAMESCREEN_W / SCREENBLOCK_W) + i] = 2; + } + } +} + +void Video::updateScreen() { + debug(DBG_VIDEO, "Video::updateScreen()"); +// _fullRefresh = true; + if (_fullRefresh) { + _stub->copyRect(0, 0, Video::GAMESCREEN_W, Video::GAMESCREEN_H, _frontLayer, 256); + _stub->updateScreen(_shakeOffset); + _fullRefresh = false; + } else { + int i, j; + int count = 0; + uint8_t *p = _screenBlocks; + for (j = 0; j < GAMESCREEN_H / SCREENBLOCK_H; ++j) { + uint16_t nh = 0; + for (i = 0; i < GAMESCREEN_W / SCREENBLOCK_W; ++i) { + if (p[i] != 0) { + --p[i]; + ++nh; + } else if (nh != 0) { + int16_t x = (i - nh) * SCREENBLOCK_W; + _stub->copyRect(x, j * SCREENBLOCK_H, nh * SCREENBLOCK_W, SCREENBLOCK_H, _frontLayer, 256); + nh = 0; + ++count; + } + } + if (nh != 0) { + int16_t x = (i - nh) * SCREENBLOCK_W; + _stub->copyRect(x, j * SCREENBLOCK_H, nh * SCREENBLOCK_W, SCREENBLOCK_H, _frontLayer, 256); + ++count; + } + p += GAMESCREEN_W / SCREENBLOCK_W; + } + if (count != 0) { + _stub->updateScreen(_shakeOffset); + } + } + if (_shakeOffset != 0) { + _shakeOffset = 0; + _fullRefresh = true; + } +} + +void Video::fullRefresh() { + debug(DBG_VIDEO, "Video::fullRefresh()"); + _fullRefresh = true; + memset(_screenBlocks, 0, (GAMESCREEN_W / SCREENBLOCK_W) * (GAMESCREEN_H / SCREENBLOCK_H)); +} + +void Video::fadeOut() { + debug(DBG_VIDEO, "Video::fadeOut()"); + _stub->fadeScreen(); +// fadeOutPalette(); +} + +void Video::fadeOutPalette() { + for (int step = 16; step >= 0; --step) { + for (int c = 0; c < 256; ++c) { + Color col; + _stub->getPaletteEntry(c, &col); + col.r = col.r * step >> 4; + col.g = col.g * step >> 4; + col.b = col.b * step >> 4; + _stub->setPaletteEntry(c, &col); + } + fullRefresh(); + updateScreen(); + _stub->sleep(50); + } +} + +void Video::setPaletteColorBE(int num, int offset) { + const int color = READ_BE_UINT16(_res->_pal + offset * 2); + Color c; + c.r = (color & 0x00F) << 2; + c.g = (color & 0x0F0) >> 2; + c.b = (color & 0xF00) >> 6; + if (color != 0) { + c.r |= 3; + c.g |= 3; + c.b |= 3; + } + _stub->setPaletteEntry(num, &c); +} + +void Video::setPaletteSlotBE(int palSlot, int palNum) { + debug(DBG_VIDEO, "Video::setPaletteSlotBE()"); + const uint8_t *p = _res->_pal + palNum * 0x20; + for (int i = 0; i < 16; ++i) { + const int color = READ_BE_UINT16(p); p += 2; + Color c; + c.r = (color & 0x00F) << 2; + c.g = (color & 0x0F0) >> 2; + c.b = (color & 0xF00) >> 6; + if (color != 0) { + c.r |= 3; + c.g |= 3; + c.b |= 3; + } + _stub->setPaletteEntry(palSlot * 0x10 + i, &c); + } +} + +void Video::setPaletteSlotLE(int palSlot, const uint8_t *palData) { + debug(DBG_VIDEO, "Video::setPaletteSlotLE()"); + for (int i = 0; i < 16; ++i) { + uint16_t color = READ_LE_UINT16(palData); palData += 2; + Color c; + c.b = (color & 0x00F) << 2; + c.g = (color & 0x0F0) >> 2; + c.r = (color & 0xF00) >> 6; + _stub->setPaletteEntry(palSlot * 0x10 + i, &c); + } +} + +void Video::setTextPalette() { + debug(DBG_VIDEO, "Video::setTextPalette()"); + setPaletteSlotLE(0xE, _textPal); +} + +void Video::setPalette0xF() { + debug(DBG_VIDEO, "Video::setPalette0xF()"); + const uint8_t *p = _palSlot0xF; + for (int i = 0; i < 16; ++i) { + Color c; + c.r = *p++ >> 2; + c.g = *p++ >> 2; + c.b = *p++ >> 2; + _stub->setPaletteEntry(0xF0 + i, &c); + } +} + +static void PC_decodeMapHelper(int sz, const uint8_t *src, uint8_t *dst) { + const uint8_t *end = src + sz; + while (src < end) { + int16_t code = (int8_t)*src++; + if (code < 0) { + const int len = 1 - code; + memset(dst, *src++, len); + dst += len; + } else { + ++code; + memcpy(dst, src, code); + src += code; + dst += code; + } + } +} + +void Video::PC_decodeMap(int level, int room) { + debug(DBG_VIDEO, "Video::PC_decodeMap(%d)", room); + assert(room < 0x40); + int32_t off = READ_LE_UINT32(_res->_map + room * 6); + if (off == 0) { + error("Invalid room %d", room); + } + bool packed = true; + if (off < 0) { + off = -off; + packed = false; + } + const uint8_t *p = _res->_map + off; + _mapPalSlot1 = *p++; + _mapPalSlot2 = *p++; + _mapPalSlot3 = *p++; + _mapPalSlot4 = *p++; + if (level == 4 && room == 60) { + // workaround for wrong palette colors (fire) + _mapPalSlot4 = 5; + } + if (packed) { + uint8_t *vid = _frontLayer; + for (int i = 0; i < 4; ++i) { + const int sz = READ_LE_UINT16(p); p += 2; + PC_decodeMapHelper(sz, p, _res->_memBuf); p += sz; + memcpy(vid, _res->_memBuf, 256 * 56); + vid += 256 * 56; + } + } else { + for (int i = 0; i < 4; ++i) { + for (int y = 0; y < 224; ++y) { + for (int x = 0; x < 64; ++x) { + _frontLayer[i + x * 4 + 256 * y] = p[256 * 56 * i + x + 64 * y]; + } + } + } + } + memcpy(_backLayer, _frontLayer, Video::GAMESCREEN_W * Video::GAMESCREEN_H); +} + +void Video::PC_setLevelPalettes() { + debug(DBG_VIDEO, "Video::PC_setLevelPalettes()"); + if (_unkPalSlot2 == 0) { + _unkPalSlot2 = _mapPalSlot3; + } + if (_unkPalSlot1 == 0) { + _unkPalSlot1 = _mapPalSlot3; + } + setPaletteSlotBE(0x0, _mapPalSlot1); + setPaletteSlotBE(0x1, _mapPalSlot2); + setPaletteSlotBE(0x2, _mapPalSlot3); + setPaletteSlotBE(0x3, _mapPalSlot4); + if (_unkPalSlot1 == _mapPalSlot3) { + setPaletteSlotLE(4, _conradPal1); + } else { + setPaletteSlotLE(4, _conradPal2); + } + // slot 5 is monster palette + setPaletteSlotBE(0x8, _mapPalSlot1); + setPaletteSlotBE(0x9, _mapPalSlot2); + setPaletteSlotBE(0xA, _unkPalSlot2); + setPaletteSlotBE(0xB, _mapPalSlot4); + // slots 0xC and 0xD are cutscene palettes + setTextPalette(); +} + +void Video::PC_decodeIcn(const uint8_t *src, int num, uint8_t *dst) { + const int offset = READ_LE_UINT16(src + num * 2); + const uint8_t *p = src + offset + 2; + for (int i = 0; i < 16 * 16 / 2; ++i) { + *dst++ = p[i] >> 4; + *dst++ = p[i] & 15; + } +} + +void Video::PC_decodeSpc(const uint8_t *src, int w, int h, uint8_t *dst) { + const int size = w * h / 2; + for (int i = 0; i < size; ++i) { + *dst++ = src[i] >> 4; + *dst++ = src[i] & 15; + } +} + +static void AMIGA_blit3pNxN(uint8_t *dst, int pitch, int w, int h, const uint8_t *src) { + const int planarSize = w * 2 * h; + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w; ++x) { + for (int i = 0; i < 16; ++i) { + int color = 0; + const int mask = 1 << (15 - i); + for (int bit = 0; bit < 3; ++bit) { + if (READ_BE_UINT16(src + bit * planarSize) & mask) { + color |= 1 << bit; + } + } + dst[x * 16 + i] = color; + } + src += 2; + } + dst += pitch; + } +} + +static void AMIGA_blit4p16xN(uint8_t *dst, int w, int h, const uint8_t *src) { + const int planarSize = w * 2 * h; + assert(w == 1); + for (int y = 0; y < h; ++y) { + for (int i = 0; i < 16; ++i) { + int color = 0; + const int mask = 1 << (15 - i); + for (int bit = 0; bit < 4; ++bit) { + if (READ_BE_UINT16(src + bit * planarSize) & mask) { + color |= 1 << bit; + } + } + dst[i] = color; + } + src += 2; + dst += 16; + } +} + +static void AMIGA_blit4p8xN(uint8_t *dst, int w, int h, const uint8_t *src) { + assert(w == 8); + for (int y = 0; y < h; ++y) { + for (int i = 0; i < 8; ++i) { + int color = 0; + const int mask = 1 << (7 - i); + for (int bit = 0; bit < 4; ++bit) { + if (src[bit] & mask) { + color |= 1 << bit; + } + } + dst[i] = color; + } + src += 4; + dst += w; + } +} + +static void AMIGA_blit4pNxN(uint8_t *dst, int w, int h, const uint8_t *src) { + const int planarSize = w / 8 * h; + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w / 8; ++x) { + for (int i = 0; i < 8; ++i) { + int color = 0; + const int mask = 1 << (7 - i); + for (int bit = 0; bit < 4; ++bit) { + if (src[bit * planarSize] & mask) { + color |= 1 << bit; + } + } + dst[x * 8 + i] = color; + } + ++src; + } + dst += w; + } +} + +static void AMIGA_blit4pNxN_mask(uint8_t *dst, int x0, int y0, int w, int h, uint8_t *src, uint8_t *mask, int size) { + dst += y0 * 256 + x0; + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w * 2; ++x) { + for (int i = 0; i < 8; ++i) { + const int c_mask = 1 << (7 - i); + int color = 0; + for (int j = 0; j < 4; ++j) { + if (mask[j * size] & c_mask) { + color |= 1 << j; + } + } + if (*src & c_mask) { + const int px = x0 + 8 * x + i; + const int py = y0 + y; + if (px >= 0 && px < 256 && py >= 0 && py < 224) { + dst[8 * x + i] = color; + } + } + } + ++src; + ++mask; + } + dst += 256; + } +} + +static void AMIGA_decodeRLE(uint8_t *dst, const uint8_t *src) { + int code = READ_BE_UINT16(src) & 0x7FFF; src += 2; + const uint8_t *end = src + code; + do { + code = *src++; + if ((code & 0x80) == 0) { + ++code; + memcpy(dst, src, code); + src += code; + } else { + code = 1 - ((int8_t)code); + memset(dst, *src, code); + ++src; + } + dst += code; + } while (src < end); + assert(src == end); +} + +static void AMIGA_decodeSgd(uint8_t *dst, const uint8_t *src, const uint8_t *data) { + int num = -1; + uint8_t buf[256 * 32]; + int count = READ_BE_UINT16(src) - 1; src += 2; + do { + int d2 = READ_BE_UINT16(src); src += 2; + int d0 = READ_BE_UINT16(src); src += 2; + int d1 = READ_BE_UINT16(src); src += 2; + if (d2 != 0xFFFF) { + d2 &= ~(1 << 15); + const int offset = READ_BE_UINT32(data + d2 * 4); + if (offset < 0) { + const uint8_t *ptr = data - offset; + const int size = READ_BE_UINT16(ptr); ptr += 2; + if (num != d2) { + num = d2; + assert(size <= (int)sizeof(buf)); + memcpy(buf, ptr, size); + } + } else { + if (num != d2) { + num = d2; + const int size = READ_BE_UINT16(data + offset) & 0x7FFF; + assert(size <= (int)sizeof(buf)); + AMIGA_decodeRLE(buf, data + offset); + } + } + } + const int w = (buf[0] + 1) >> 1; + const int h = buf[1] + 1; + const int planarSize = READ_BE_UINT16(buf + 2); + AMIGA_blit4pNxN_mask(dst, (int16_t)d0, (int16_t)d1, w, h, buf + 4, buf + 4 + planarSize, planarSize); + } while (--count >= 0); +} + +static const uint8_t *AMIGA_mirrorY(const uint8_t *a2) { + static uint8_t buf[32]; + + a2 += 24; + for (int j = 0; j < 4; ++j) { + for (int i = 0; i < 8; ++i) { + buf[31 - j * 8 - i] = *a2++; + } + a2 -= 16; + } + return buf; +} + +static const uint8_t *AMIGA_mirrorX(const uint8_t *a2) { + static uint8_t buf[32]; + + for (int i = 0; i < 32; ++i) { + uint8_t mask = 0; + for (int bit = 0; bit < 8; ++bit) { + if (a2[i] & (1 << bit)) { + mask |= 1 << (7 - bit); + } + } + buf[i] = mask; + } + return buf; +} + +static void AMIGA_blit4p8x8(uint8_t *dst, int pitch, const uint8_t *src, int pal, int colorKey = -1) { + for (int y = 0; y < 8; ++y) { + for (int i = 0; i < 8; ++i) { + const int mask = 1 << (7 - i); + int color = 0; + for (int bit = 0; bit < 4; ++bit) { + if (src[8 * bit] & mask) { + color |= 1 << bit; + } + } + if (color != colorKey) { + dst[i] = pal + color; + } + } + ++src; + dst += pitch; + } +} + +static void AMIGA_decodeLevHelper(uint8_t *dst, const uint8_t *src, int offset10, int offset12, const uint8_t *a5, bool sgdBuf) { + if (offset10 != 0) { + const uint8_t *a0 = src + offset10; + for (int y = 0; y < 224; y += 8) { + for (int x = 0; x < 256; x += 8) { + const int d3 = READ_BE_UINT16(a0); a0 += 2; + const int d0 = d3 & 0x7FF; + if (d0 != 0) { + const uint8_t *a2 = a5 + d0 * 32; + if ((d3 & (1 << 12)) != 0) { + a2 = AMIGA_mirrorY(a2); + } + if ((d3 & (1 << 11)) != 0) { + a2 = AMIGA_mirrorX(a2); + } + int mask = 0; + if ((d3 < (1 << 15)) == 0) { + mask = 0x80; + } + AMIGA_blit4p8x8(dst + y * 256 + x, 256, a2, mask); + } + } + } + } + if (offset12 != 0) { + const uint8_t *a0 = src + offset12; + for (int y = 0; y < 224; y += 8) { + for (int x = 0; x < 256; x += 8) { + int d3 = READ_BE_UINT16(a0); a0 += 2; + int d0 = d3 & 0x7FF; + if (d0 != 0 && sgdBuf) { + d0 -= 896; + } + if (d0 != 0) { + const uint8_t *a2 = a5 + d0 * 32; + if ((d3 & (1 << 12)) != 0) { + a2 = AMIGA_mirrorY(a2); + } + if ((d3 & (1 << 11)) != 0) { + a2 = AMIGA_mirrorX(a2); + } + int mask = 0; + if ((d3 & 0x6000) != 0 && sgdBuf) { + mask = 0x10; + } else if ((d3 < (1 << 15)) == 0) { + mask = 0x80; + } + AMIGA_blit4p8x8(dst + y * 256 + x, 256, a2, mask, 0); + } + } + } + } +} + +void Video::AMIGA_decodeLev(int level, int room) { + uint8_t *tmp = _res->_memBuf; + const int offset = READ_BE_UINT32(_res->_lev + room * 4); + if (!delphine_unpack(tmp, _res->_lev, offset)) { + error("Bad CRC for level %d room %d", level, room); + } + uint16_t offset10 = READ_BE_UINT16(tmp + 10); + const uint16_t offset12 = READ_BE_UINT16(tmp + 12); + const uint16_t offset14 = READ_BE_UINT16(tmp + 14); + static const int kTempMbkSize = 1024; + uint8_t *buf = (uint8_t *)malloc(kTempMbkSize * 32); + if (!buf) { + error("Unable to allocate mbk temporary buffer"); + } + int sz = 0; + memset(buf, 0, 32); + sz += 32; + const uint8_t *a1 = tmp + offset14; + for (bool loop = true; loop;) { + int d0 = READ_BE_UINT16(a1); a1 += 2; + if (d0 & 0x8000) { + d0 &= ~0x8000; + loop = false; + } + const int d1 = _res->getBankDataSize(d0); + const uint8_t *a6 = _res->findBankData(d0); + if (!a6) { + a6 = _res->loadBankData(d0); + } + const int d3 = *a1++; + if (d3 == 255) { + assert(sz + d1 < kTempMbkSize * 32); + memcpy(buf + sz, a6, d1); + sz += d1; + } else { + for (int i = 0; i < d3 + 1; ++i) { + const int d4 = *a1++; + assert(sz + 32 < kTempMbkSize * 32); + memcpy(buf + sz, a6 + d4 * 32, 32); + sz += 32; + } + } + } + memset(_frontLayer, 0, Video::GAMESCREEN_W * Video::GAMESCREEN_H); + if (tmp[1] != 0) { + assert(_res->_sgd); + AMIGA_decodeSgd(_frontLayer, tmp + offset10, _res->_sgd); + offset10 = 0; + } + AMIGA_decodeLevHelper(_frontLayer, tmp, offset10, offset12, buf, tmp[1] != 0); + memcpy(_backLayer, _frontLayer, Video::GAMESCREEN_W * Video::GAMESCREEN_H); + uint16_t num[4]; + for (int i = 0; i < 4; ++i) { + num[i] = READ_BE_UINT16(tmp + 2 + i * 2); + } + _mapPalSlot1 = num[1]; + _mapPalSlot2 = num[2]; + setPaletteSlotBE(0x0, num[0]); + for (int i = 1; i < 5; ++i) { + setPaletteSlotBE(i, _mapPalSlot2); + } + setPaletteSlotBE(0x6, _mapPalSlot2); + setPaletteSlotBE(0x8, num[0]); + setPaletteSlotBE(0xA, _mapPalSlot2); +} + +void Video::AMIGA_decodeSpm(const uint8_t *src, uint8_t *dst) { + uint8_t buf[256 * 32]; + const int size = READ_BE_UINT16(src + 3) & 0x7FFF; + assert(size <= (int)sizeof(buf)); + AMIGA_decodeRLE(buf, src + 3); + const int w = (src[2] >> 7) + 1; + const int h = src[2] & 0x7F; + AMIGA_blit3pNxN(dst, w * 16, w, h, buf); +} + +void Video::AMIGA_decodeIcn(const uint8_t *src, int num, uint8_t *dst) { + for (int i = 0; i < num; ++i) { + const int h = 1 + *src++; + const int w = 1 + *src++; + const int size = w * h * 8; + src += 4 + size; + } + const int h = 1 + *src++; + const int w = 1 + *src++; + AMIGA_blit4p16xN(dst, w, h, src + 4); +} + +void Video::AMIGA_decodeSpc(const uint8_t *src, int w, int h, uint8_t *dst) { + switch (w) { + case 8: + AMIGA_blit4p8xN(dst, w, h, src); + break; + default: + AMIGA_blit4pNxN(dst, w, h, src); + break; + } +} + +void Video::drawSpriteSub1(const uint8_t *src, uint8_t *dst, int pitch, int h, int w, uint8_t colMask) { + debug(DBG_VIDEO, "Video::drawSpriteSub1(0x%X, 0x%X, 0x%X, 0x%X)", pitch, w, h, colMask); + while (h--) { + for (int i = 0; i < w; ++i) { + if (src[i] != 0) { + dst[i] = src[i] | colMask; + } + } + src += pitch; + dst += 256; + } +} + +void Video::drawSpriteSub2(const uint8_t *src, uint8_t *dst, int pitch, int h, int w, uint8_t colMask) { + debug(DBG_VIDEO, "Video::drawSpriteSub2(0x%X, 0x%X, 0x%X, 0x%X)", pitch, w, h, colMask); + while (h--) { + for (int i = 0; i < w; ++i) { + if (src[-i] != 0) { + dst[i] = src[-i] | colMask; + } + } + src += pitch; + dst += 256; + } +} + +void Video::drawSpriteSub3(const uint8_t *src, uint8_t *dst, int pitch, int h, int w, uint8_t colMask) { + debug(DBG_VIDEO, "Video::drawSpriteSub3(0x%X, 0x%X, 0x%X, 0x%X)", pitch, w, h, colMask); + while (h--) { + for (int i = 0; i < w; ++i) { + if (src[i] != 0 && !(dst[i] & 0x80)) { + dst[i] = src[i] | colMask; + } + } + src += pitch; + dst += 256; + } +} + +void Video::drawSpriteSub4(const uint8_t *src, uint8_t *dst, int pitch, int h, int w, uint8_t colMask) { + debug(DBG_VIDEO, "Video::drawSpriteSub4(0x%X, 0x%X, 0x%X, 0x%X)", pitch, w, h, colMask); + while (h--) { + for (int i = 0; i < w; ++i) { + if (src[-i] != 0 && !(dst[i] & 0x80)) { + dst[i] = src[-i] | colMask; + } + } + src += pitch; + dst += 256; + } +} + +void Video::drawSpriteSub5(const uint8_t *src, uint8_t *dst, int pitch, int h, int w, uint8_t colMask) { + debug(DBG_VIDEO, "Video::drawSpriteSub5(0x%X, 0x%X, 0x%X, 0x%X)", pitch, w, h, colMask); + while (h--) { + for (int i = 0; i < w; ++i) { + if (src[i * pitch] != 0 && !(dst[i] & 0x80)) { + dst[i] = src[i * pitch] | colMask; + } + } + ++src; + dst += 256; + } +} + +void Video::drawSpriteSub6(const uint8_t *src, uint8_t *dst, int pitch, int h, int w, uint8_t colMask) { + debug(DBG_VIDEO, "Video::drawSpriteSub6(0x%X, 0x%X, 0x%X, 0x%X)", pitch, w, h, colMask); + while (h--) { + for (int i = 0; i < w; ++i) { + if (src[-i * pitch] != 0 && !(dst[i] & 0x80)) { + dst[i] = src[-i * pitch] | colMask; + } + } + ++src; + dst += 256; + } +} + +void Video::PC_drawChar(uint8_t c, int16_t y, int16_t x) { + debug(DBG_VIDEO, "Video::PC_drawChar(0x%X, %d, %d)", c, y, x); + y *= 8; + x *= 8; + const uint8_t *src = _res->_fnt + (c - 32) * 32; + uint8_t *dst = _frontLayer + x + 256 * y; + for (int h = 0; h < 8; ++h) { + for (int i = 0; i < 4; ++i) { + uint8_t c1 = (*src & 0xF0) >> 4; + uint8_t c2 = (*src & 0x0F) >> 0; + ++src; + + if (c1 != 0) { + if (c1 != 2) { + *dst = _charFrontColor; + } else { + *dst = _charShadowColor; + } + } else if (_charTransparentColor != 0xFF) { + *dst = _charTransparentColor; + } + ++dst; + + if (c2 != 0) { + if (c2 != 2) { + *dst = _charFrontColor; + } else { + *dst = _charShadowColor; + } + } else if (_charTransparentColor != 0xFF) { + *dst = _charTransparentColor; + } + ++dst; + } + dst += 256 - 8; + } +} + +void Video::AMIGA_drawStringChar(uint8_t *dst, int pitch, const uint8_t *src, uint8_t color, uint8_t chr) { + assert(chr >= 32); + AMIGA_decodeIcn(src, chr - 32, _res->_memBuf); + src = _res->_memBuf; + for (int y = 0; y < 8; ++y) { + for (int x = 0; x < 8; ++x) { + if (src[x] != 0) { + dst[x] = 0x1D; + } + } + src += 16; + dst += pitch; + } +} + +void Video::PC_drawStringChar(uint8_t *dst, int pitch, const uint8_t *src, uint8_t color, uint8_t chr) { + assert(chr >= 32); + src += (chr - 32) * 8 * 4; + for (int y = 0; y < 8; ++y) { + for (int x = 0; x < 4; ++x) { + const uint8_t c1 = src[x] >> 4; + if (c1 != 0) { + *dst = (c1 == 15) ? color : (0xE0 + c1); + } + ++dst; + const uint8_t c2 = src[x] & 15; + if (c2 != 0) { + *dst = (c2 == 15) ? color : (0xE0 + c2); + } + ++dst; + } + src += 4; + dst += pitch - CHAR_W; + } +} + +const char *Video::drawString(const char *str, int16_t x, int16_t y, uint8_t col) { + debug(DBG_VIDEO, "Video::drawString('%s', %d, %d, 0x%X)", str, x, y, col); + void (Video::*drawCharFunc)(uint8_t *, int, const uint8_t *, uint8_t, uint8_t) = 0; + switch (_res->_type) { + case kResourceTypeAmiga: + drawCharFunc = &Video::AMIGA_drawStringChar; + break; + case kResourceTypePC: + drawCharFunc = &Video::PC_drawStringChar; + break; + } + int len = 0; + uint8_t *dst = _frontLayer + y * 256 + x; + while (1) { + const uint8_t c = *str++; + if (c == 0 || c == 0xB || c == 0xA) { + break; + } + (this->*drawCharFunc)(dst, 256, _res->_fnt, col, c); + dst += CHAR_W; + ++len; + } + markBlockAsDirty(x, y, len * 8, 8); + return str - 1; +} diff --git a/video.h b/video.h new file mode 100644 index 0000000..c232e95 --- /dev/null +++ b/video.h @@ -0,0 +1,90 @@ +/* REminiscence - Flashback interpreter + * Copyright (C) 2005-2015 Gregory Montoir + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef VIDEO_H__ +#define VIDEO_H__ + +#include "intern.h" + +struct Resource; +struct SystemStub; + +struct Video { + enum { + GAMESCREEN_W = 256, + GAMESCREEN_H = 224, + SCREENBLOCK_W = 8, + SCREENBLOCK_H = 8, + CHAR_W = 8, + CHAR_H = 8 + }; + + static const uint8_t _conradPal1[]; + static const uint8_t _conradPal2[]; + static const uint8_t _textPal[]; + static const uint8_t _palSlot0xF[]; + + Resource *_res; + SystemStub *_stub; + + uint8_t *_frontLayer; + uint8_t *_backLayer; + uint8_t *_tempLayer; + uint8_t *_tempLayer2; + uint8_t _unkPalSlot1, _unkPalSlot2; + uint8_t _mapPalSlot1, _mapPalSlot2, _mapPalSlot3, _mapPalSlot4; + uint8_t _charFrontColor; + uint8_t _charTransparentColor; + uint8_t _charShadowColor; + uint8_t *_screenBlocks; + bool _fullRefresh; + uint8_t _shakeOffset; + + Video(Resource *res, SystemStub *stub); + ~Video(); + + void markBlockAsDirty(int16_t x, int16_t y, uint16_t w, uint16_t h); + void updateScreen(); + void fullRefresh(); + void fadeOut(); + void fadeOutPalette(); + void setPaletteColorBE(int num, int offset); + void setPaletteSlotBE(int palSlot, int palNum); + void setPaletteSlotLE(int palSlot, const uint8_t *palData); + void setTextPalette(); + void setPalette0xF(); + void PC_decodeMap(int level, int room); + void PC_setLevelPalettes(); + void PC_decodeIcn(const uint8_t *src, int num, uint8_t *dst); + void PC_decodeSpc(const uint8_t *src, int w, int h, uint8_t *dst); + void AMIGA_decodeLev(int level, int room); + void AMIGA_decodeSpm(const uint8_t *src, uint8_t *dst); + void AMIGA_decodeIcn(const uint8_t *src, int num, uint8_t *dst); + void AMIGA_decodeSpc(const uint8_t *src, int w, int h, uint8_t *dst); + void drawSpriteSub1(const uint8_t *src, uint8_t *dst, int pitch, int h, int w, uint8_t colMask); + void drawSpriteSub2(const uint8_t *src, uint8_t *dst, int pitch, int h, int w, uint8_t colMask); + void drawSpriteSub3(const uint8_t *src, uint8_t *dst, int pitch, int h, int w, uint8_t colMask); + void drawSpriteSub4(const uint8_t *src, uint8_t *dst, int pitch, int h, int w, uint8_t colMask); + void drawSpriteSub5(const uint8_t *src, uint8_t *dst, int pitch, int h, int w, uint8_t colMask); + void drawSpriteSub6(const uint8_t *src, uint8_t *dst, int pitch, int h, int w, uint8_t colMask); + void PC_drawChar(uint8_t c, int16_t y, int16_t x); + void PC_drawStringChar(uint8_t *dst, int pitch, const uint8_t *src, uint8_t color, uint8_t chr); + void AMIGA_drawStringChar(uint8_t *dst, int pitch, const uint8_t *src, uint8_t color, uint8_t chr); + const char *drawString(const char *str, int16_t x, int16_t y, uint8_t col); +}; + +#endif // VIDEO_H__