Import 0.3.1
This commit is contained in:
parent
cb9e469636
commit
577fec920a
6
Makefile
6
Makefile
|
@ -1,12 +1,12 @@
|
||||||
|
|
||||||
SDL_CFLAGS = `sdl-config --cflags`
|
SDL_CFLAGS = `sdl-config --cflags`
|
||||||
SDL_LIBS = `sdl-config --libs`
|
SDL_LIBS = `sdl-config --libs`
|
||||||
VORBIS_LIBS = -lvorbisidec
|
|
||||||
MODPLUG_LIBS = -lmodplug
|
MODPLUG_LIBS = -lmodplug
|
||||||
|
# TREMOR_LIBS = -lvorbisidec -logg
|
||||||
ZLIB_LIBS = -lz
|
ZLIB_LIBS = -lz
|
||||||
|
|
||||||
CXX := clang++
|
CXX := clang++
|
||||||
CXXFLAGS := -Wall -MMD $(SDL_CFLAGS) -DUSE_ZLIB # -DUSE_MODPLUG
|
CXXFLAGS := -Wall -MMD $(SDL_CFLAGS) -DUSE_MODPLUG -DUSE_ZLIB # -DUSE_TREMOR
|
||||||
|
|
||||||
SRCS = collision.cpp cutscene.cpp file.cpp fs.cpp game.cpp graphics.cpp main.cpp menu.cpp \
|
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 resource_aba.cpp \
|
mixer.cpp mod_player.cpp ogg_player.cpp piege.cpp resource.cpp resource_aba.cpp \
|
||||||
|
@ -16,7 +16,7 @@ SRCS = collision.cpp cutscene.cpp file.cpp fs.cpp game.cpp graphics.cpp main.cpp
|
||||||
OBJS = $(SRCS:.cpp=.o)
|
OBJS = $(SRCS:.cpp=.o)
|
||||||
DEPS = $(SRCS:.cpp=.d)
|
DEPS = $(SRCS:.cpp=.d)
|
||||||
|
|
||||||
LIBS = $(SDL_LIBS) $(VORBIS_LIBS) $(MODPLUG_LIBS) $(ZLIB_LIBS)
|
LIBS = $(SDL_LIBS) $(MODPLUG_LIBS) $(TREMOR_LIBS) $(ZLIB_LIBS)
|
||||||
|
|
||||||
rs: $(OBJS)
|
rs: $(OBJS)
|
||||||
$(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
$(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
REminiscence README
|
REminiscence README
|
||||||
Release version: 0.3.0 ($date)
|
Release version: 0.3.1
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,8 @@ game can be found at [1], [2] and [3].
|
||||||
Compiling:
|
Compiling:
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Update the defines in the Makefile if needed. The SDL and zlib libraries are required.
|
Update the defines in the Makefile if needed. The SDL, zlib and modplug
|
||||||
|
libraries are required.
|
||||||
|
|
||||||
|
|
||||||
Data Files:
|
Data Files:
|
||||||
|
@ -64,6 +65,10 @@ directory. These paths can be changed using command line switches :
|
||||||
Usage: rs [OPTIONS]...
|
Usage: rs [OPTIONS]...
|
||||||
--datapath=PATH Path to data files (default 'DATA')
|
--datapath=PATH Path to data files (default 'DATA')
|
||||||
--savepath=PATH Path to save files (default '.')
|
--savepath=PATH Path to save files (default '.')
|
||||||
|
--levelnum=NUM Level to start from (default '0')
|
||||||
|
--fullscreen Fullscreen display
|
||||||
|
--scaler=INDEX Graphics scaler
|
||||||
|
--language=LANG Language (fr,en,de,sp,it)
|
||||||
|
|
||||||
In-game hotkeys :
|
In-game hotkeys :
|
||||||
|
|
130
cutscene.cpp
130
cutscene.cpp
|
@ -18,13 +18,16 @@ Cutscene::Cutscene(Resource *res, SystemStub *stub, Video *vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cutscene::sync() {
|
void Cutscene::sync() {
|
||||||
// XXX input handling
|
if (_stub->_pi.quit) {
|
||||||
if (!(_stub->_pi.dbgMask & PlayerInput::DF_FASTMODE)) {
|
return;
|
||||||
int32_t delay = _stub->getTimeStamp() - _tstamp;
|
}
|
||||||
int32_t pause = _frameDelay * TIMER_SLICE - delay;
|
if (_stub->_pi.dbgMask & PlayerInput::DF_FASTMODE) {
|
||||||
if (pause > 0) {
|
return;
|
||||||
_stub->sleep(pause);
|
}
|
||||||
}
|
const int32_t delay = _stub->getTimeStamp() - _tstamp;
|
||||||
|
const int32_t pause = _frameDelay * TIMER_SLICE - delay;
|
||||||
|
if (pause > 0) {
|
||||||
|
_stub->sleep(pause);
|
||||||
}
|
}
|
||||||
_tstamp = _stub->getTimeStamp();
|
_tstamp = _stub->getTimeStamp();
|
||||||
}
|
}
|
||||||
|
@ -90,7 +93,7 @@ uint16_t Cutscene::findTextSeparators(const uint8_t *p) {
|
||||||
uint8_t *q = _textSep;
|
uint8_t *q = _textSep;
|
||||||
uint16_t ret = 0;
|
uint16_t ret = 0;
|
||||||
uint16_t pos = 0;
|
uint16_t pos = 0;
|
||||||
for (; *p != 0xA; ++p) {
|
for (; *p != 0xA && *p; ++p) {
|
||||||
if (*p == 0x7C) {
|
if (*p == 0x7C) {
|
||||||
*q++ = pos;
|
*q++ = pos;
|
||||||
if (pos > ret) {
|
if (pos > ret) {
|
||||||
|
@ -111,6 +114,7 @@ uint16_t Cutscene::findTextSeparators(const uint8_t *p) {
|
||||||
|
|
||||||
void Cutscene::drawText(int16_t x, int16_t y, const uint8_t *p, uint16_t color, uint8_t *page, uint8_t n) {
|
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);
|
debug(DBG_CUT, "Cutscene::drawText(x=%d, y=%d, c=%d)", x, y, color);
|
||||||
|
Video::drawCharFunc dcf = _vid->_drawChar;
|
||||||
uint16_t last_sep = 0;
|
uint16_t last_sep = 0;
|
||||||
if (n != 0) {
|
if (n != 0) {
|
||||||
last_sep = findTextSeparators(p);
|
last_sep = findTextSeparators(p);
|
||||||
|
@ -126,7 +130,7 @@ void Cutscene::drawText(int16_t x, int16_t y, const uint8_t *p, uint16_t color,
|
||||||
if (n != 0) {
|
if (n != 0) {
|
||||||
xx += ((last_sep - *sep++) & 0xFE) * 4;
|
xx += ((last_sep - *sep++) & 0xFE) * 4;
|
||||||
}
|
}
|
||||||
for (; *p != 0xA; ++p) {
|
for (; *p != 0xA && *p; ++p) {
|
||||||
if (*p == 0x7C) {
|
if (*p == 0x7C) {
|
||||||
yy += 8;
|
yy += 8;
|
||||||
xx = x;
|
xx = x;
|
||||||
|
@ -135,25 +139,11 @@ void Cutscene::drawText(int16_t x, int16_t y, const uint8_t *p, uint16_t color,
|
||||||
}
|
}
|
||||||
} else if (*p == 0x20) {
|
} else if (*p == 0x20) {
|
||||||
xx += 8;
|
xx += 8;
|
||||||
|
} else if (*p == 0x9) {
|
||||||
|
// ignore tab
|
||||||
} else {
|
} else {
|
||||||
uint8_t *dst_char = page + 256 * yy + xx;
|
uint8_t *dst = page + 256 * yy + xx;
|
||||||
const uint8_t *src = _res->_fnt + (*p - 32) * 32;
|
(_vid->*dcf)(dst, 256, _res->_fnt, color, *p);
|
||||||
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;
|
xx += 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,11 +166,10 @@ void Cutscene::drawCreditsText() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_creditsTextCounter <= 0) { // XXX
|
if (_creditsTextCounter <= 0) {
|
||||||
uint8_t code = *_textCurPtr;
|
uint8_t code = *_textCurPtr;
|
||||||
if (code == 0xFF) {
|
if (code == 0xFF) {
|
||||||
_textBuf[0] = 0xA;
|
_textBuf[0] = 0xA;
|
||||||
// _cut_status = 0;
|
|
||||||
} else if (code == 0xFE) {
|
} else if (code == 0xFE) {
|
||||||
++_textCurPtr;
|
++_textCurPtr;
|
||||||
code = *_textCurPtr++;
|
code = *_textCurPtr++;
|
||||||
|
@ -198,10 +187,11 @@ void Cutscene::drawCreditsText() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*_textCurBuf++ = code;
|
*_textCurBuf++ = code;
|
||||||
*_textCurBuf++ = 0xA;
|
*_textCurBuf = 0xA;
|
||||||
|
++_textCurPtr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_creditsTextCounter -= 10; // XXX adjust
|
_creditsTextCounter -= 10;
|
||||||
}
|
}
|
||||||
drawText((_creditsTextPosX - 1) * 8, _creditsTextPosY * 8, _textBuf, 0xEF, _page1, 0);
|
drawText((_creditsTextPosX - 1) * 8, _creditsTextPosY * 8, _textBuf, 0xEF, _page1, 0);
|
||||||
}
|
}
|
||||||
|
@ -270,7 +260,7 @@ void Cutscene::op_waitForSync() {
|
||||||
_varText = 0xFF;
|
_varText = 0xFF;
|
||||||
_frameDelay = 3;
|
_frameDelay = 3;
|
||||||
if (_textBuf == _textCurBuf) {
|
if (_textBuf == _textCurBuf) {
|
||||||
_creditsTextCounter = 20;
|
_creditsTextCounter = _res->isAmiga() ? 60 : 20;
|
||||||
}
|
}
|
||||||
memcpy(_page1, _page0, _vid->_layerSize);
|
memcpy(_page1, _page0, _vid->_layerSize);
|
||||||
drawCreditsText();
|
drawCreditsText();
|
||||||
|
@ -385,6 +375,16 @@ void Cutscene::op_drawStringAtBottom() {
|
||||||
debug(DBG_CUT, "Cutscene::op_drawStringAtBottom()");
|
debug(DBG_CUT, "Cutscene::op_drawStringAtBottom()");
|
||||||
uint16_t strId = fetchNextCmdWord();
|
uint16_t strId = fetchNextCmdWord();
|
||||||
if (!_creditsSequence) {
|
if (!_creditsSequence) {
|
||||||
|
|
||||||
|
// 'espions' - ignore last call, allows caption to be displayed longer on the screen
|
||||||
|
if (_id == 0x39 && strId == 0xFFFF) {
|
||||||
|
if ((_res->isDOS() && (_cmdPtr - _cmdPtrBak) == 0x10) || (_res->isAmiga() && (_cmdPtr - _res->_cmd) == 0x9F3)) {
|
||||||
|
_frameDelay = 100;
|
||||||
|
setPalette();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memset(_pageC + 179 * 256, 0xC0, 45 * 256);
|
memset(_pageC + 179 * 256, 0xC0, 45 * 256);
|
||||||
memset(_page1 + 179 * 256, 0xC0, 45 * 256);
|
memset(_page1 + 179 * 256, 0xC0, 45 * 256);
|
||||||
memset(_page0 + 179 * 256, 0xC0, 45 * 256);
|
memset(_page0 + 179 * 256, 0xC0, 45 * 256);
|
||||||
|
@ -839,7 +839,7 @@ void Cutscene::op_drawStringAtPos() {
|
||||||
uint8_t color = 0xD0 + (strId >> 0xC);
|
uint8_t color = 0xD0 + (strId >> 0xC);
|
||||||
drawText(x, y, str, color, _page1, 2);
|
drawText(x, y, str, color, _page1, 2);
|
||||||
}
|
}
|
||||||
// workaround for buggy cutscene script
|
// 'voyage' - cutscene script redraws the string to refresh the screen
|
||||||
if (_id == 0x34 && (strId & 0xFFF) == 0x45) {
|
if (_id == 0x34 && (strId & 0xFFF) == 0x45) {
|
||||||
if ((_cmdPtr - _cmdPtrBak) == 0xA) {
|
if ((_cmdPtr - _cmdPtrBak) == 0xA) {
|
||||||
_stub->copyRect(0, 0, _vid->_w, _vid->_h, _page1, 256);
|
_stub->copyRect(0, 0, _vid->_w, _vid->_h, _page1, 256);
|
||||||
|
@ -964,13 +964,30 @@ void Cutscene::load(uint16_t cutName) {
|
||||||
name = "INTRO";
|
name = "INTRO";
|
||||||
}
|
}
|
||||||
_res->load(name, Resource::OT_CMP);
|
_res->load(name, Resource::OT_CMP);
|
||||||
|
if (_id == 0x39 && _res->_lang != LANG_FR) {
|
||||||
|
//
|
||||||
|
// 'espions' - '... the power which we need' caption is missing in Amiga English.
|
||||||
|
// fixed in DOS version, opcodes order is wrong
|
||||||
|
//
|
||||||
|
// opcode 0 pos 0x323
|
||||||
|
// opcode 6 pos 0x324
|
||||||
|
// str 0x3a
|
||||||
|
//
|
||||||
|
uint8_t *p = _res->_cmd + 0x322;
|
||||||
|
if (memcmp(p, "\x00\x18\x00\x3a", 4) == 0) {
|
||||||
|
p[0] = 0x06 << 2; // op_drawStringAtBottom
|
||||||
|
p[1] = 0x00;
|
||||||
|
p[2] = 0x3a;
|
||||||
|
p[3] = 0x00; // op_markCurPos
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case kResourceTypeDOS:
|
case kResourceTypeDOS:
|
||||||
_res->load(name, Resource::OT_CMD);
|
_res->load(name, Resource::OT_CMD);
|
||||||
_res->load(name, Resource::OT_POL);
|
_res->load(name, Resource::OT_POL);
|
||||||
_res->load_CINE();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
_res->load_CINE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cutscene::prepare() {
|
void Cutscene::prepare() {
|
||||||
|
@ -986,12 +1003,11 @@ void Cutscene::prepare() {
|
||||||
_gfx.setClippingRect(8, 50, 240, 128);
|
_gfx.setClippingRect(8, 50, 240, 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cutscene::startCredits() {
|
void Cutscene::playCredits() {
|
||||||
_textCurPtr = _creditsData;
|
_textCurPtr = _res->isAmiga() ? _creditsDataAmiga : _creditsDataDOS;
|
||||||
_textBuf[0] = 0xA;
|
_textBuf[0] = 0xA;
|
||||||
_textCurBuf = _textBuf;
|
_textCurBuf = _textBuf;
|
||||||
_creditsSequence = true;
|
_creditsSequence = true;
|
||||||
// _cut_status = 1;
|
|
||||||
_varText = 0;
|
_varText = 0;
|
||||||
_textUnk2 = 0;
|
_textUnk2 = 0;
|
||||||
_creditsTextCounter = 0;
|
_creditsTextCounter = 0;
|
||||||
|
@ -1011,6 +1027,37 @@ void Cutscene::startCredits() {
|
||||||
_creditsSequence = false;
|
_creditsSequence = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Cutscene::playText(const char *str) {
|
||||||
|
Color c;
|
||||||
|
// background
|
||||||
|
c.r = c.g = c.b = 0;
|
||||||
|
_stub->setPaletteEntry(0xC0, &c);
|
||||||
|
// text
|
||||||
|
c.r = c.g = c.b = 255;
|
||||||
|
_stub->setPaletteEntry(0xC1, &c);
|
||||||
|
|
||||||
|
int lines = 0;
|
||||||
|
for (int i = 0; str[i]; ++i) {
|
||||||
|
if (str[i] == '|') {
|
||||||
|
++lines;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const int y = (128 - lines * 8) / 2;
|
||||||
|
memset(_page1, 0xC0, _vid->_layerSize);
|
||||||
|
drawText(0, y, (const uint8_t *)str, 0xC1, _page1, 1);
|
||||||
|
_stub->copyRect(0, 0, _vid->_w, _vid->_h, _page1, 256);
|
||||||
|
_stub->updateScreen(0);
|
||||||
|
|
||||||
|
while (!_stub->_pi.quit) {
|
||||||
|
_stub->processEvents();
|
||||||
|
if (_stub->_pi.backspace) {
|
||||||
|
_stub->_pi.backspace = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_stub->sleep(TIMER_SLICE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Cutscene::play() {
|
void Cutscene::play() {
|
||||||
if (_id != 0xFFFF) {
|
if (_id != 0xFFFF) {
|
||||||
_textCurBuf = NULL;
|
_textCurBuf = NULL;
|
||||||
|
@ -1044,7 +1091,14 @@ void Cutscene::play() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cutName != 0xFFFF) {
|
if (g_options.use_text_cutscenes && _res->_lang == LANG_FR) {
|
||||||
|
for (int i = 0; _frTextsTable[i].str; ++i) {
|
||||||
|
if (_id == _frTextsTable[i].num) {
|
||||||
|
playText(_frTextsTable[i].str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (cutName != 0xFFFF) {
|
||||||
load(cutName);
|
load(cutName);
|
||||||
mainLoop(cutOff);
|
mainLoop(cutOff);
|
||||||
}
|
}
|
||||||
|
|
12
cutscene.h
12
cutscene.h
|
@ -22,16 +22,23 @@ struct Cutscene {
|
||||||
TIMER_SLICE = 15
|
TIMER_SLICE = 15
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Text {
|
||||||
|
int num;
|
||||||
|
const char *str;
|
||||||
|
};
|
||||||
|
|
||||||
static const OpcodeStub _opcodeTable[];
|
static const OpcodeStub _opcodeTable[];
|
||||||
static const char *_namesTable[];
|
static const char *_namesTable[];
|
||||||
static const uint16_t _offsetsTable[];
|
static const uint16_t _offsetsTable[];
|
||||||
static const uint8_t _amigaDemoOffsetsTable[];
|
static const uint8_t _amigaDemoOffsetsTable[];
|
||||||
static const uint16_t _cosTable[];
|
static const uint16_t _cosTable[];
|
||||||
static const uint16_t _sinTable[];
|
static const uint16_t _sinTable[];
|
||||||
static const uint8_t _creditsData[];
|
static const uint8_t _creditsDataDOS[];
|
||||||
|
static const uint8_t _creditsDataAmiga[];
|
||||||
static const uint16_t _creditsCutSeq[];
|
static const uint16_t _creditsCutSeq[];
|
||||||
static const uint8_t _musicTable[];
|
static const uint8_t _musicTable[];
|
||||||
static const uint8_t _protectionShapeData[];
|
static const uint8_t _protectionShapeData[];
|
||||||
|
static const Text _frTextsTable[];
|
||||||
|
|
||||||
Graphics _gfx;
|
Graphics _gfx;
|
||||||
Resource *_res;
|
Resource *_res;
|
||||||
|
@ -118,7 +125,8 @@ struct Cutscene {
|
||||||
void mainLoop(uint16_t offset);
|
void mainLoop(uint16_t offset);
|
||||||
void load(uint16_t cutName);
|
void load(uint16_t cutName);
|
||||||
void prepare();
|
void prepare();
|
||||||
void startCredits();
|
void playCredits();
|
||||||
|
void playText(const char *str);
|
||||||
void play();
|
void play();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
14
file.cpp
14
file.cpp
|
@ -24,9 +24,9 @@ struct File_impl {
|
||||||
virtual uint32_t write(void *ptr, uint32_t len) = 0;
|
virtual uint32_t write(void *ptr, uint32_t len) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct stdFile : File_impl {
|
struct StdioFile : File_impl {
|
||||||
FILE *_fp;
|
FILE *_fp;
|
||||||
stdFile() : _fp(0) {}
|
StdioFile() : _fp(0) {}
|
||||||
bool open(const char *path, const char *mode) {
|
bool open(const char *path, const char *mode) {
|
||||||
_ioErr = false;
|
_ioErr = false;
|
||||||
_fp = fopen(path, mode);
|
_fp = fopen(path, mode);
|
||||||
|
@ -76,9 +76,9 @@ struct stdFile : File_impl {
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef USE_ZLIB
|
#ifdef USE_ZLIB
|
||||||
struct zlibFile : File_impl {
|
struct GzipFile : File_impl {
|
||||||
gzFile _fp;
|
gzFile _fp;
|
||||||
zlibFile() : _fp(0) {}
|
GzipFile() : _fp(0) {}
|
||||||
bool open(const char *path, const char *mode) {
|
bool open(const char *path, const char *mode) {
|
||||||
_ioErr = false;
|
_ioErr = false;
|
||||||
_fp = gzopen(path, mode);
|
_fp = gzopen(path, mode);
|
||||||
|
@ -147,7 +147,7 @@ bool File::open(const char *filename, const char *mode, FileSystem *fs) {
|
||||||
_impl = 0;
|
_impl = 0;
|
||||||
}
|
}
|
||||||
assert(mode[0] != 'z');
|
assert(mode[0] != 'z');
|
||||||
_impl = new stdFile;
|
_impl = new StdioFile;
|
||||||
char *path = fs->findPath(filename);
|
char *path = fs->findPath(filename);
|
||||||
if (path) {
|
if (path) {
|
||||||
debug(DBG_FILE, "Open file name '%s' mode '%s' path '%s'", filename, mode, path);
|
debug(DBG_FILE, "Open file name '%s' mode '%s' path '%s'", filename, mode, path);
|
||||||
|
@ -166,12 +166,12 @@ bool File::open(const char *filename, const char *mode, const char *directory) {
|
||||||
}
|
}
|
||||||
#ifdef USE_ZLIB
|
#ifdef USE_ZLIB
|
||||||
if (mode[0] == 'z') {
|
if (mode[0] == 'z') {
|
||||||
_impl = new zlibFile;
|
_impl = new GzipFile;
|
||||||
++mode;
|
++mode;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!_impl) {
|
if (!_impl) {
|
||||||
_impl = new stdFile;
|
_impl = new StdioFile;
|
||||||
}
|
}
|
||||||
char path[MAXPATHLEN];
|
char path[MAXPATHLEN];
|
||||||
snprintf(path, sizeof(path), "%s/%s", directory, filename);
|
snprintf(path, sizeof(path), "%s/%s", directory, filename);
|
||||||
|
|
21
game.cpp
21
game.cpp
|
@ -69,21 +69,26 @@ void Game::run() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_res.isAmiga()) {
|
|
||||||
displayTitleScreenAmiga();
|
|
||||||
_stub->setScreenSize(Video::GAMESCREEN_W, Video::GAMESCREEN_H);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!_stub->_pi.quit) {
|
while (!_stub->_pi.quit) {
|
||||||
if (_res.isDOS()) {
|
switch (_res._type) {
|
||||||
|
case kResourceTypeDOS:
|
||||||
_mix.playMusic(1);
|
_mix.playMusic(1);
|
||||||
_menu.handleTitleScreen();
|
_menu.handleTitleScreen();
|
||||||
if (_menu._selectedOption == Menu::MENU_OPTION_ITEM_QUIT) {
|
if (_menu._selectedOption == Menu::MENU_OPTION_ITEM_QUIT || _stub->_pi.quit) {
|
||||||
|
_stub->_pi.quit = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_skillLevel = _menu._skill;
|
_skillLevel = _menu._skill;
|
||||||
_currentLevel = _menu._level;
|
_currentLevel = _menu._level;
|
||||||
_mix.stopMusic();
|
_mix.stopMusic();
|
||||||
|
break;
|
||||||
|
case kResourceTypeAmiga:
|
||||||
|
displayTitleScreenAmiga();
|
||||||
|
_stub->setScreenSize(Video::GAMESCREEN_W, Video::GAMESCREEN_H);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (_stub->_pi.quit) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (_currentLevel == 7) {
|
if (_currentLevel == 7) {
|
||||||
_vid.fadeOut();
|
_vid.fadeOut();
|
||||||
|
@ -328,7 +333,7 @@ void Game::playCutscene(int id) {
|
||||||
_cut.play();
|
_cut.play();
|
||||||
}
|
}
|
||||||
if (id == 0x3D) {
|
if (id == 0x3D) {
|
||||||
_cut.startCredits();
|
_cut.playCredits();
|
||||||
}
|
}
|
||||||
_mix.stopMusic();
|
_mix.stopMusic();
|
||||||
}
|
}
|
||||||
|
|
21
intern.h
21
intern.h
|
@ -46,6 +46,26 @@ inline uint32_t READ_LE_UINT32(const void *ptr) {
|
||||||
return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
|
return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int8_t ADDC_S8(int a, int b) {
|
||||||
|
a += b;
|
||||||
|
if (a < -128) {
|
||||||
|
a = -128;
|
||||||
|
} else if (a > 127) {
|
||||||
|
a = 127;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int16_t ADDC_S16(int a, int b) {
|
||||||
|
a += b;
|
||||||
|
if (a < -32768) {
|
||||||
|
a = -32768;
|
||||||
|
} else if (a > 32767) {
|
||||||
|
a = 32767;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void SWAP(T &a, T &b) {
|
inline void SWAP(T &a, T &b) {
|
||||||
T tmp = a;
|
T tmp = a;
|
||||||
|
@ -72,6 +92,7 @@ struct Options {
|
||||||
bool enable_password_menu;
|
bool enable_password_menu;
|
||||||
bool fade_out_palette;
|
bool fade_out_palette;
|
||||||
bool use_tiledata;
|
bool use_tiledata;
|
||||||
|
bool use_text_cutscenes;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Color {
|
struct Color {
|
||||||
|
|
31
main.cpp
31
main.cpp
|
@ -19,9 +19,10 @@ static const char *USAGE =
|
||||||
"Usage: %s [OPTIONS]...\n"
|
"Usage: %s [OPTIONS]...\n"
|
||||||
" --datapath=PATH Path to data files (default 'DATA')\n"
|
" --datapath=PATH Path to data files (default 'DATA')\n"
|
||||||
" --savepath=PATH Path to save files (default '.')\n"
|
" --savepath=PATH Path to save files (default '.')\n"
|
||||||
" --levelnum=NUM Start level (default '0')\n"
|
" --levelnum=NUM Level to start from (default '0')\n"
|
||||||
" --fullscreen Start fullscreen\n"
|
" --fullscreen Fullscreen display\n"
|
||||||
" --scaler=INDEX Graphics scaler\n"
|
" --scaler=INDEX Graphics scaler\n"
|
||||||
|
" --language=LANG Language (fr,en,de,sp,it)\n"
|
||||||
;
|
;
|
||||||
|
|
||||||
static int detectVersion(FileSystem *fs) {
|
static int detectVersion(FileSystem *fs) {
|
||||||
|
@ -80,6 +81,7 @@ static void initOptions() {
|
||||||
g_options.play_disabled_cutscenes = false;
|
g_options.play_disabled_cutscenes = false;
|
||||||
g_options.enable_password_menu = false;
|
g_options.enable_password_menu = false;
|
||||||
g_options.fade_out_palette = true;
|
g_options.fade_out_palette = true;
|
||||||
|
g_options.use_text_cutscenes = false;
|
||||||
// read configuration file
|
// read configuration file
|
||||||
struct {
|
struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -90,6 +92,7 @@ static void initOptions() {
|
||||||
{ "enable_password_menu", &g_options.enable_password_menu },
|
{ "enable_password_menu", &g_options.enable_password_menu },
|
||||||
{ "fade_out_palette", &g_options.fade_out_palette },
|
{ "fade_out_palette", &g_options.fade_out_palette },
|
||||||
{ "use_tiledata", &g_options.use_tiledata },
|
{ "use_tiledata", &g_options.use_tiledata },
|
||||||
|
{ "use_text_cutscenes", &g_options.use_text_cutscenes },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
static const char *filename = "rs.cfg";
|
static const char *filename = "rs.cfg";
|
||||||
|
@ -130,6 +133,7 @@ int main(int argc, char *argv[]) {
|
||||||
int levelNum = 0;
|
int levelNum = 0;
|
||||||
int scaler = DEFAULT_SCALER;
|
int scaler = DEFAULT_SCALER;
|
||||||
bool fullscreen = false;
|
bool fullscreen = false;
|
||||||
|
int forcedLanguage = -1;
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
// data path as the only command line argument
|
// data path as the only command line argument
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
@ -144,6 +148,7 @@ int main(int argc, char *argv[]) {
|
||||||
{ "levelnum", required_argument, 0, 3 },
|
{ "levelnum", required_argument, 0, 3 },
|
||||||
{ "fullscreen", no_argument, 0, 4 },
|
{ "fullscreen", no_argument, 0, 4 },
|
||||||
{ "scaler", required_argument, 0, 5 },
|
{ "scaler", required_argument, 0, 5 },
|
||||||
|
{ "language", required_argument, 0, 6 },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
int index;
|
int index;
|
||||||
|
@ -170,6 +175,26 @@ int main(int argc, char *argv[]) {
|
||||||
scaler = DEFAULT_SCALER;
|
scaler = DEFAULT_SCALER;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 6: {
|
||||||
|
static const struct {
|
||||||
|
int lang;
|
||||||
|
const char *str;
|
||||||
|
} languages[] = {
|
||||||
|
{ LANG_FR, "FR" },
|
||||||
|
{ LANG_EN, "EN" },
|
||||||
|
{ LANG_DE, "DE" },
|
||||||
|
{ LANG_SP, "SP" },
|
||||||
|
{ LANG_IT, "IT" },
|
||||||
|
{ -1, 0 }
|
||||||
|
};
|
||||||
|
for (int i = 0; languages[i].str; ++i) {
|
||||||
|
if (strcasecmp(languages[i].str, optarg) == 0) {
|
||||||
|
forcedLanguage = languages[i].lang;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf(USAGE, argv[0]);
|
printf(USAGE, argv[0]);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -183,7 +208,7 @@ int main(int argc, char *argv[]) {
|
||||||
error("Unable to find data files, check that all required files are present");
|
error("Unable to find data files, check that all required files are present");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
Language language = detectLanguage(&fs);
|
const Language language = (forcedLanguage == -1) ? detectLanguage(&fs) : (Language)forcedLanguage;
|
||||||
SystemStub *stub = SystemStub_SDL_create();
|
SystemStub *stub = SystemStub_SDL_create();
|
||||||
Game *g = new Game(stub, &fs, savePath, levelNum, (ResourceType)version, language);
|
Game *g = new Game(stub, &fs, savePath, levelNum, (ResourceType)version, language);
|
||||||
stub->init(g_caption, Video::GAMESCREEN_W, Video::GAMESCREEN_H, scaler, fullscreen);
|
stub->init(g_caption, Video::GAMESCREEN_W, Video::GAMESCREEN_H, scaler, fullscreen);
|
||||||
|
|
44
mixer.cpp
44
mixer.cpp
|
@ -101,12 +101,19 @@ void Mixer::playMusic(int num) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (_musicType == MT_OGG && isMusicSfx(num)) { // do not play level action music with background music
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isMusicSfx(num)) { // level action sequence
|
if (isMusicSfx(num)) { // level action sequence
|
||||||
_sfx.play(num);
|
_sfx.play(num);
|
||||||
_musicType = MT_SFX;
|
if (_sfx._playing) {
|
||||||
|
_musicType = MT_SFX;
|
||||||
|
}
|
||||||
} else { // cutscene
|
} else { // cutscene
|
||||||
_mod.play(num);
|
_mod.play(num);
|
||||||
_musicType = MT_MOD;
|
if (_mod._playing) {
|
||||||
|
_musicType = MT_MOD;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,8 +126,7 @@ void Mixer::stopMusic() {
|
||||||
_mod.stop();
|
_mod.stop();
|
||||||
break;
|
break;
|
||||||
case MT_OGG:
|
case MT_OGG:
|
||||||
_ogg.stopTrack();
|
_ogg.pauseTrack();
|
||||||
_musicTrack = -1;
|
|
||||||
break;
|
break;
|
||||||
case MT_SFX:
|
case MT_SFX:
|
||||||
_sfx.stop();
|
_sfx.stop();
|
||||||
|
@ -133,20 +139,9 @@ void Mixer::stopMusic() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nr(const int8_t *in, int len, int8_t *out) {
|
void Mixer::mix(int16_t *out, int len) {
|
||||||
static int prev = 0;
|
|
||||||
for (int i = 0; i < len; ++i) {
|
|
||||||
const int vnr = in[i] >> 1;
|
|
||||||
out[i] = vnr + prev;
|
|
||||||
prev = vnr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mixer::mix(int8_t *out, int len) {
|
|
||||||
int8_t buf[len];
|
|
||||||
memset(buf, 0, len);
|
|
||||||
if (_premixHook) {
|
if (_premixHook) {
|
||||||
if (!_premixHook(_premixHookData, buf, len)) {
|
if (!_premixHook(_premixHookData, out, len)) {
|
||||||
_premixHook = 0;
|
_premixHook = 0;
|
||||||
_premixHookData = 0;
|
_premixHookData = 0;
|
||||||
}
|
}
|
||||||
|
@ -160,24 +155,13 @@ void Mixer::mix(int8_t *out, int len) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const int sample = ch->chunk.getPCM(ch->chunkPos >> FRAC_BITS);
|
const int sample = ch->chunk.getPCM(ch->chunkPos >> FRAC_BITS);
|
||||||
addclamp(buf[pos], sample * ch->volume / Mixer::MAX_VOLUME);
|
out[pos] = ADDC_S16(out[pos], (sample * ch->volume / Mixer::MAX_VOLUME) << 8);
|
||||||
ch->chunkPos += ch->chunkInc;
|
ch->chunkPos += ch->chunkInc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nr(buf, len, out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mixer::addclamp(int8_t& a, int b) {
|
void Mixer::mixCallback(void *param, int16_t *buf, int len) {
|
||||||
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);
|
((Mixer *)param)->mix(buf, len);
|
||||||
}
|
}
|
||||||
|
|
7
mixer.h
7
mixer.h
|
@ -42,7 +42,7 @@ struct FileSystem;
|
||||||
struct SystemStub;
|
struct SystemStub;
|
||||||
|
|
||||||
struct Mixer {
|
struct Mixer {
|
||||||
typedef bool (*PremixHook)(void *userData, int8_t *buf, int len);
|
typedef bool (*PremixHook)(void *userData, int16_t *buf, int len);
|
||||||
|
|
||||||
enum MusicType {
|
enum MusicType {
|
||||||
MT_NONE,
|
MT_NONE,
|
||||||
|
@ -79,10 +79,9 @@ struct Mixer {
|
||||||
void stopAll();
|
void stopAll();
|
||||||
void playMusic(int num);
|
void playMusic(int num);
|
||||||
void stopMusic();
|
void stopMusic();
|
||||||
void mix(int8_t *buf, int len);
|
void mix(int16_t *buf, int len);
|
||||||
|
|
||||||
static void addclamp(int8_t &a, int b);
|
static void mixCallback(void *param, int16_t *buf, int len);
|
||||||
static void mixCallback(void *param, int8_t *buf, int len);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MIXER_H__
|
#endif // MIXER_H__
|
||||||
|
|
|
@ -27,7 +27,7 @@ struct ModPlayer_impl {
|
||||||
ModPlug_GetSettings(&_settings);
|
ModPlug_GetSettings(&_settings);
|
||||||
_settings.mFlags = MODPLUG_ENABLE_OVERSAMPLING | MODPLUG_ENABLE_NOISE_REDUCTION;
|
_settings.mFlags = MODPLUG_ENABLE_OVERSAMPLING | MODPLUG_ENABLE_NOISE_REDUCTION;
|
||||||
_settings.mChannels = 1;
|
_settings.mChannels = 1;
|
||||||
_settings.mBits = 8;
|
_settings.mBits = 16;
|
||||||
_settings.mFrequency = rate;
|
_settings.mFrequency = rate;
|
||||||
_settings.mResamplingMode = MODPLUG_RESAMPLE_FIR;
|
_settings.mResamplingMode = MODPLUG_RESAMPLE_FIR;
|
||||||
ModPlug_SetSettings(&_settings);
|
ModPlug_SetSettings(&_settings);
|
||||||
|
@ -50,18 +50,14 @@ struct ModPlayer_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mix(int8_t *buf, int len) {
|
bool mix(int16_t *buf, int len) {
|
||||||
memset(buf, 0, len);
|
|
||||||
if (_mf) {
|
if (_mf) {
|
||||||
const int order = ModPlug_GetCurrentOrder(_mf);
|
const int order = ModPlug_GetCurrentOrder(_mf);
|
||||||
if (order == 3 && _repeatIntro) {
|
if (order == 3 && _repeatIntro) {
|
||||||
ModPlug_SeekOrder(_mf, 1);
|
ModPlug_SeekOrder(_mf, 1);
|
||||||
_repeatIntro = false;
|
_repeatIntro = false;
|
||||||
}
|
}
|
||||||
const int count = ModPlug_Read(_mf, buf, len);
|
const int count = ModPlug_Read(_mf, buf, len * sizeof(int16_t));
|
||||||
for (int i = 0; i < count; ++i) {
|
|
||||||
buf[i] ^= 0x80;
|
|
||||||
}
|
|
||||||
return count > 0;
|
return count > 0;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -152,7 +148,8 @@ struct ModPlayer_impl {
|
||||||
void applyPortamento(int trackNum);
|
void applyPortamento(int trackNum);
|
||||||
void handleEffect(int trackNum, bool tick);
|
void handleEffect(int trackNum, bool tick);
|
||||||
void mixSamples(int8_t *buf, int len);
|
void mixSamples(int8_t *buf, int len);
|
||||||
bool mix(int8_t *buf, int len);
|
bool mixS8(int8_t *buf, int len);
|
||||||
|
bool mix(int16_t *buf, int len);
|
||||||
};
|
};
|
||||||
|
|
||||||
ModPlayer_impl::ModPlayer_impl()
|
ModPlayer_impl::ModPlayer_impl()
|
||||||
|
@ -607,7 +604,8 @@ void ModPlayer_impl::mixSamples(int8_t *buf, int samplesLen) {
|
||||||
}
|
}
|
||||||
while (count--) {
|
while (count--) {
|
||||||
const int out = si->getPCM(pos >> FRAC_BITS);
|
const int out = si->getPCM(pos >> FRAC_BITS);
|
||||||
Mixer::addclamp(*mixbuf++, out * tk->volume / 64);
|
*mixbuf = ADDC_S8(*mixbuf, out * tk->volume / 64);
|
||||||
|
++mixbuf;
|
||||||
pos += deltaPos;
|
pos += deltaPos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -616,9 +614,8 @@ void ModPlayer_impl::mixSamples(int8_t *buf, int samplesLen) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModPlayer_impl::mix(int8_t *buf, int len) {
|
bool ModPlayer_impl::mixS8(int8_t *buf, int len) {
|
||||||
if (_playing) {
|
if (_playing) {
|
||||||
memset(buf, 0, len);
|
|
||||||
const int samplesPerTick = _mixingRate / (50 * _songTempo / 125);
|
const int samplesPerTick = _mixingRate / (50 * _songTempo / 125);
|
||||||
while (len != 0) {
|
while (len != 0) {
|
||||||
if (_samplesLeft == 0) {
|
if (_samplesLeft == 0) {
|
||||||
|
@ -637,6 +634,16 @@ bool ModPlayer_impl::mix(int8_t *buf, int len) {
|
||||||
}
|
}
|
||||||
return _playing;
|
return _playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ModPlayer_impl::mix(int16_t *samples, int len) {
|
||||||
|
int8_t buf[len];
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
const bool ret = mixS8(buf, len);
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
samples[i] = buf[i] << 8;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ModPlayer::ModPlayer(Mixer *mixer, FileSystem *fs)
|
ModPlayer::ModPlayer(Mixer *mixer, FileSystem *fs)
|
||||||
|
@ -673,6 +680,6 @@ void ModPlayer::stop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModPlayer::mixCallback(void *param, int8_t *buf, int len) {
|
bool ModPlayer::mixCallback(void *param, int16_t *buf, int len) {
|
||||||
return ((ModPlayer_impl *)param)->mix(buf, len);
|
return ((ModPlayer_impl *)param)->mix(buf, len);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ struct ModPlayer {
|
||||||
void play(int num);
|
void play(int num);
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
static bool mixCallback(void *param, int8_t *buf, int len);
|
static bool mixCallback(void *param, int16_t *buf, int len);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MOD_PLAYER_H__
|
#endif // MOD_PLAYER_H__
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "mixer.h"
|
#include "mixer.h"
|
||||||
#include "ogg_player.h"
|
#include "ogg_player.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#ifdef USE_TREMOR
|
#ifdef USE_TREMOR
|
||||||
struct VorbisFile: File {
|
struct VorbisFile: File {
|
||||||
|
@ -85,7 +86,7 @@ struct OggDecoder_impl {
|
||||||
_channels = vi->channels;
|
_channels = vi->channels;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
int read(int8_t *dst, int samples) {
|
int read(int16_t *dst, int samples) {
|
||||||
int size = samples * _channels * sizeof(int16_t);
|
int size = samples * _channels * sizeof(int16_t);
|
||||||
if (size > _readBufSize) {
|
if (size > _readBufSize) {
|
||||||
_readBufSize = size;
|
_readBufSize = size;
|
||||||
|
@ -100,22 +101,26 @@ struct OggDecoder_impl {
|
||||||
const int len = ov_read(&_ovf, (char *)_readBuf, size, 0);
|
const int len = ov_read(&_ovf, (char *)_readBuf, size, 0);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
// error in decoder
|
// error in decoder
|
||||||
return 0;
|
return count;
|
||||||
} else if (len == 0) {
|
} else if (len == 0) {
|
||||||
// loop
|
// loop
|
||||||
ov_raw_seek(&_ovf, 0);
|
ov_raw_seek(&_ovf, 0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
assert((len & 1) == 0);
|
||||||
switch (_channels) {
|
switch (_channels) {
|
||||||
case 2:
|
case 2:
|
||||||
assert((len & 1) == 0);
|
assert((len & 3) == 0);
|
||||||
for (int i = 0; i < len / 2; i += 2) {
|
for (int i = 0; i < len / 2; i += 2) {
|
||||||
Mixer::addclamp(*dst++, ((_readBuf[i] + _readBuf[i + 1]) / 2) >> 8);
|
const int16_t s16 = (_readBuf[i] + _readBuf[i + 1]) / 2;
|
||||||
|
*dst = ADDC_S16(*dst, s16);
|
||||||
|
++dst;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
for (int i = 0; i < len / 2; ++i) {
|
for (int i = 0; i < len / 2; ++i) {
|
||||||
Mixer::addclamp(*dst++, _readBuf[i] >> 8);
|
*dst = ADDC_S16(*dst, _readBuf[i]);
|
||||||
|
++dst;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -188,7 +193,7 @@ void OggPlayer::resumeTrack() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OggPlayer::mix(int8_t *buf, int len) {
|
bool OggPlayer::mix(int16_t *buf, int len) {
|
||||||
#ifdef USE_TREMOR
|
#ifdef USE_TREMOR
|
||||||
if (_impl) {
|
if (_impl) {
|
||||||
return _impl->read(buf, len) != 0;
|
return _impl->read(buf, len) != 0;
|
||||||
|
@ -197,7 +202,7 @@ bool OggPlayer::mix(int8_t *buf, int len) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OggPlayer::mixCallback(void *param, int8_t *buf, int len) {
|
bool OggPlayer::mixCallback(void *param, int16_t *buf, int len) {
|
||||||
return ((OggPlayer *)param)->mix(buf, len);
|
return ((OggPlayer *)param)->mix(buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,8 @@ struct OggPlayer {
|
||||||
void pauseTrack();
|
void pauseTrack();
|
||||||
void resumeTrack();
|
void resumeTrack();
|
||||||
bool isPlaying() const { return _impl != 0; }
|
bool isPlaying() const { return _impl != 0; }
|
||||||
bool mix(int8_t *buf, int len);
|
bool mix(int16_t *buf, int len);
|
||||||
static bool mixCallback(void *param, int8_t *buf, int len);
|
static bool mixCallback(void *param, int16_t *buf, int len);
|
||||||
|
|
||||||
Mixer *_mix;
|
Mixer *_mix;
|
||||||
FileSystem *_fs;
|
FileSystem *_fs;
|
||||||
|
|
71
resource.cpp
71
resource.cpp
|
@ -269,28 +269,65 @@ void Resource::load_SPR_OFF(const char *fileName, uint8_t *sprData) {
|
||||||
error("Cannot load '%s'", _entryName);
|
error("Cannot load '%s'", _entryName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Resource::load_CINE() {
|
static const char *getCineName(Language lang, ResourceType type) {
|
||||||
const char *baseName = 0;
|
switch (lang) {
|
||||||
switch (_lang) {
|
|
||||||
case LANG_FR:
|
case LANG_FR:
|
||||||
baseName = "FR_CINE";
|
if (type == kResourceTypeAmiga) {
|
||||||
break;
|
return "FR";
|
||||||
case LANG_EN:
|
}
|
||||||
baseName = "ENGCINE";
|
return "FR_";
|
||||||
break;
|
|
||||||
case LANG_DE:
|
case LANG_DE:
|
||||||
baseName = "GERCINE";
|
return "GER";
|
||||||
break;
|
|
||||||
case LANG_SP:
|
case LANG_SP:
|
||||||
baseName = "SPACINE";
|
return "SPA";
|
||||||
break;
|
|
||||||
case LANG_IT:
|
case LANG_IT:
|
||||||
baseName = "ITACINE";
|
return "ITA";
|
||||||
break;
|
case LANG_EN:
|
||||||
|
default:
|
||||||
|
return "ENG";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resource::load_CINE() {
|
||||||
|
const char *prefix = getCineName(_lang, _type);
|
||||||
|
debug(DBG_RES, "Resource::load_CINE('%s')", prefix);
|
||||||
|
if (_type == kResourceTypeAmiga) {
|
||||||
|
if (_isDemo) {
|
||||||
|
// file not present in demo data files
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_cine_txt == 0) {
|
||||||
|
snprintf(_entryName, sizeof(_entryName), "%sCINE.TXT", prefix);
|
||||||
|
File f;
|
||||||
|
if (f.open(_entryName, "rb", _fs)) {
|
||||||
|
const int len = f.size();
|
||||||
|
_cine_txt = (uint8_t *)malloc(len + 1);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
_cine_txt[len] = 0;
|
||||||
|
uint8_t *p = _cine_txt;
|
||||||
|
for (int i = 0; i < NUM_CUTSCENE_TEXTS; ++i) {
|
||||||
|
_cineStrings[i] = p;
|
||||||
|
uint8_t *sep = (uint8_t *)memchr(p, '\n', &_cine_txt[len] - p);
|
||||||
|
if (!sep) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p = sep + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!_cine_txt) {
|
||||||
|
error("Cannot load '%s'", _entryName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
debug(DBG_RES, "Resource::load_CINE('%s')", baseName);
|
|
||||||
if (_cine_off == 0) {
|
if (_cine_off == 0) {
|
||||||
snprintf(_entryName, sizeof(_entryName), "%s.BIN", baseName);
|
snprintf(_entryName, sizeof(_entryName), "%sCINE.BIN", prefix);
|
||||||
File f;
|
File f;
|
||||||
if (f.open(_entryName, "rb", _fs)) {
|
if (f.open(_entryName, "rb", _fs)) {
|
||||||
int len = f.size();
|
int len = f.size();
|
||||||
|
@ -310,7 +347,7 @@ void Resource::load_CINE() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_cine_txt == 0) {
|
if (_cine_txt == 0) {
|
||||||
snprintf(_entryName, sizeof(_entryName), "%s.TXT", baseName);
|
snprintf(_entryName, sizeof(_entryName), "%sCINE.TXT", prefix);
|
||||||
File f;
|
File f;
|
||||||
if (f.open(_entryName, "rb", _fs)) {
|
if (f.open(_entryName, "rb", _fs)) {
|
||||||
int len = f.size();
|
int len = f.size();
|
||||||
|
|
|
@ -90,6 +90,7 @@ struct Resource {
|
||||||
enum {
|
enum {
|
||||||
NUM_SFXS = 66,
|
NUM_SFXS = 66,
|
||||||
NUM_BANK_BUFFERS = 50,
|
NUM_BANK_BUFFERS = 50,
|
||||||
|
NUM_CUTSCENE_TEXTS = 117,
|
||||||
NUM_SPRITES = 1287
|
NUM_SPRITES = 1287
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -135,6 +136,7 @@ struct Resource {
|
||||||
uint8_t _numSfx;
|
uint8_t _numSfx;
|
||||||
uint8_t *_cmd;
|
uint8_t *_cmd;
|
||||||
uint8_t *_pol;
|
uint8_t *_pol;
|
||||||
|
uint8_t *_cineStrings[NUM_CUTSCENE_TEXTS];
|
||||||
uint8_t *_cine_off;
|
uint8_t *_cine_off;
|
||||||
uint8_t *_cine_txt;
|
uint8_t *_cine_txt;
|
||||||
char **_extTextsTable;
|
char **_extTextsTable;
|
||||||
|
@ -209,7 +211,7 @@ struct Resource {
|
||||||
const int offset = READ_BE_UINT16(_cine_off + num * 2);
|
const int offset = READ_BE_UINT16(_cine_off + num * 2);
|
||||||
return _cine_txt + offset;
|
return _cine_txt + offset;
|
||||||
}
|
}
|
||||||
return 0;
|
return (num >= 0 && num < NUM_CUTSCENE_TEXTS) ? _cineStrings[num] : 0;
|
||||||
}
|
}
|
||||||
const char *getMenuString(int num) {
|
const char *getMenuString(int num) {
|
||||||
return (num >= 0 && num < LocaleData::LI_NUM) ? _textsTable[num] : "";
|
return (num >= 0 && num < LocaleData::LI_NUM) ? _textsTable[num] : "";
|
||||||
|
|
3
rs.cfg
3
rs.cfg
|
@ -12,3 +12,6 @@ fade_out_palette=true
|
||||||
|
|
||||||
# use .BNQ & .LEV datafiles (tile based rendering) for backgrounds (instead of .MAP)
|
# use .BNQ & .LEV datafiles (tile based rendering) for backgrounds (instead of .MAP)
|
||||||
use_tiledata=false
|
use_tiledata=false
|
||||||
|
|
||||||
|
# display text instead of playing the polygon cutscenes (french only)
|
||||||
|
use_text_cutscenes=false
|
||||||
|
|
|
@ -102,10 +102,10 @@ void SeqDemuxer::readPalette(uint8_t *dst) {
|
||||||
_f->read(dst, 256 * 3);
|
_f->read(dst, 256 * 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SeqDemuxer::readAudioS8(uint8_t *dst) {
|
void SeqDemuxer::readAudio(int16_t *dst) {
|
||||||
_f->seek(_frameOffset + _audioDataOffset);
|
_f->seek(_frameOffset + _audioDataOffset);
|
||||||
for (int i = 0; i < kAudioBufferSize; ++i) {
|
for (int i = 0; i < kAudioBufferSize; ++i) {
|
||||||
dst[i] = _f->readUint16BE() >> 8;
|
dst[i] = _f->readUint16BE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,9 +246,9 @@ void SeqPlayer::play(File *f) {
|
||||||
if (_demux._audioDataSize != 0) {
|
if (_demux._audioDataSize != 0) {
|
||||||
SoundBufferQueue *sbq = (SoundBufferQueue *)malloc(sizeof(SoundBufferQueue));
|
SoundBufferQueue *sbq = (SoundBufferQueue *)malloc(sizeof(SoundBufferQueue));
|
||||||
if (sbq) {
|
if (sbq) {
|
||||||
sbq->data = (uint8_t *)malloc(SeqDemuxer::kAudioBufferSize);
|
sbq->data = (int16_t *)calloc(SeqDemuxer::kAudioBufferSize, sizeof(int16_t));
|
||||||
if (sbq->data) {
|
if (sbq->data) {
|
||||||
_demux.readAudioS8(sbq->data);
|
_demux.readAudio(sbq->data);
|
||||||
sbq->size = SeqDemuxer::kAudioBufferSize;
|
sbq->size = SeqDemuxer::kAudioBufferSize;
|
||||||
sbq->read = 0;
|
sbq->read = 0;
|
||||||
sbq->next = 0;
|
sbq->next = 0;
|
||||||
|
@ -332,7 +332,7 @@ void SeqPlayer::play(File *f) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SeqPlayer::mix(int8_t *buf, int samples) {
|
bool SeqPlayer::mix(int16_t *buf, int samples) {
|
||||||
if (_soundQueuePreloadSize < kSoundPreloadSize) {
|
if (_soundQueuePreloadSize < kSoundPreloadSize) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -350,7 +350,7 @@ bool SeqPlayer::mix(int8_t *buf, int samples) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SeqPlayer::mixCallback(void *param, int8_t *buf, int len) {
|
bool SeqPlayer::mixCallback(void *param, int16_t *buf, int len) {
|
||||||
return ((SeqPlayer *)param)->mix(buf, len);
|
return ((SeqPlayer *)param)->mix(buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ struct SeqDemuxer {
|
||||||
void fillBuffer(int num, int offset, int size);
|
void fillBuffer(int num, int offset, int size);
|
||||||
void clearBuffer(int num);
|
void clearBuffer(int num);
|
||||||
void readPalette(uint8_t *dst);
|
void readPalette(uint8_t *dst);
|
||||||
void readAudioS8(uint8_t *dst);
|
void readAudio(int16_t *dst);
|
||||||
|
|
||||||
int _frameOffset;
|
int _frameOffset;
|
||||||
int _audioDataOffset;
|
int _audioDataOffset;
|
||||||
|
@ -55,7 +55,7 @@ struct SeqPlayer {
|
||||||
static const char *_namesTable[];
|
static const char *_namesTable[];
|
||||||
|
|
||||||
struct SoundBufferQueue {
|
struct SoundBufferQueue {
|
||||||
uint8_t *data;
|
int16_t *data;
|
||||||
int size;
|
int size;
|
||||||
int read;
|
int read;
|
||||||
SoundBufferQueue *next;
|
SoundBufferQueue *next;
|
||||||
|
@ -66,8 +66,8 @@ struct SeqPlayer {
|
||||||
|
|
||||||
void setBackBuffer(uint8_t *buf) { _buf = buf; }
|
void setBackBuffer(uint8_t *buf) { _buf = buf; }
|
||||||
void play(File *f);
|
void play(File *f);
|
||||||
bool mix(int8_t *buf, int len);
|
bool mix(int16_t *buf, int len);
|
||||||
static bool mixCallback(void *param, int8_t *buf, int len);
|
static bool mixCallback(void *param, int16_t *buf, int len);
|
||||||
|
|
||||||
SystemStub *_stub;
|
SystemStub *_stub;
|
||||||
uint8_t *_buf;
|
uint8_t *_buf;
|
||||||
|
|
|
@ -127,7 +127,8 @@ void SfxPlayer::mixSamples(int8_t *buf, int samplesLen) {
|
||||||
}
|
}
|
||||||
while (count--) {
|
while (count--) {
|
||||||
const int out = si->getPCM(pos >> FRAC_BITS);
|
const int out = si->getPCM(pos >> FRAC_BITS);
|
||||||
Mixer::addclamp(*mixbuf++, out * si->vol / 64);
|
*mixbuf = ADDC_S8(*mixbuf, out * si->vol / 64);
|
||||||
|
++mixbuf;
|
||||||
pos += deltaPos;
|
pos += deltaPos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +139,6 @@ void SfxPlayer::mixSamples(int8_t *buf, int samplesLen) {
|
||||||
|
|
||||||
bool SfxPlayer::mix(int8_t *buf, int len) {
|
bool SfxPlayer::mix(int8_t *buf, int len) {
|
||||||
if (_playing) {
|
if (_playing) {
|
||||||
memset(buf, 0, len);
|
|
||||||
const int samplesPerTick = _mix->getSampleRate() / 50;
|
const int samplesPerTick = _mix->getSampleRate() / 50;
|
||||||
while (len != 0) {
|
while (len != 0) {
|
||||||
if (_samplesLeft == 0) {
|
if (_samplesLeft == 0) {
|
||||||
|
@ -158,6 +158,12 @@ bool SfxPlayer::mix(int8_t *buf, int len) {
|
||||||
return _playing;
|
return _playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SfxPlayer::mixCallback(void *param, int8_t *buf, int len) {
|
bool SfxPlayer::mixCallback(void *param, int16_t *samples, int len) {
|
||||||
return ((SfxPlayer *)param)->mix(buf, len);
|
int8_t buf[len];
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
const bool ret = ((SfxPlayer *)param)->mix(buf, len);
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
samples[i] = buf[i] << 8;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,10 +81,10 @@ struct SfxPlayer {
|
||||||
void stop();
|
void stop();
|
||||||
void playSample(int channel, const uint8_t *sampleData, uint16_t period);
|
void playSample(int channel, const uint8_t *sampleData, uint16_t period);
|
||||||
void handleTick();
|
void handleTick();
|
||||||
bool mix(int8_t *buf, int len);
|
void mixSamples(int8_t *samples, int samplesLen);
|
||||||
void mixSamples(int8_t *buf, int samplesLen);
|
|
||||||
|
|
||||||
static bool mixCallback(void *param, int8_t *buf, int len);
|
bool mix(int8_t *buf, int len);
|
||||||
|
static bool mixCallback(void *param, int16_t *buf, int len);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SFX_PLAYER_H__
|
#endif // SFX_PLAYER_H__
|
||||||
|
|
183
staticres.cpp
183
staticres.cpp
|
@ -188,7 +188,7 @@ const uint16_t Cutscene::_sinTable[] = {
|
||||||
0xFFDD, 0xFFE1, 0xFFE6, 0xFFEA, 0xFFEF, 0xFFF3, 0xFFF8, 0xFFFC
|
0xFFDD, 0xFFE1, 0xFFE6, 0xFFEA, 0xFFEF, 0xFFF3, 0xFFF8, 0xFFFC
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint8_t Cutscene::_creditsData[] = {
|
const uint8_t Cutscene::_creditsDataDOS[] = {
|
||||||
0xFE, 0x14, 0x00, 0x01, 0x00, 0x04, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x46, 0x6C, 0x61, 0x73,
|
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,
|
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,
|
0xFE, 0x32, 0xFE, 0x14, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x05, 0x20, 0x20, 0x49, 0x6E,
|
||||||
|
@ -356,6 +356,164 @@ const uint8_t Cutscene::_creditsData[] = {
|
||||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x50, 0xFE, 0xFF, 0x00, 0xFF
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x50, 0xFE, 0xFF, 0x00, 0xFF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const uint8_t Cutscene::_creditsDataAmiga[] = {
|
||||||
|
0xFE, 0x14, 0x00, 0x01, 0x00, 0x08, 0x20, 0x20, 0x20, 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, 0x00, 0x01, 0x00, 0x08, 0x20, 0x20, 0x41, 0x6D, 0x69, 0x67, 0x61,
|
||||||
|
0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x7C, 0xFE, 0x14, 0x7C, 0x7C, 0xFE, 0x14,
|
||||||
|
0x20, 0x20, 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, 0x7C,
|
||||||
|
0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0xFE, 0x14, 0x00, 0x01, 0x00, 0x07, 0x00, 0x01,
|
||||||
|
0x00, 0x09, 0x20, 0x20, 0x50, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x6D, 0x65, 0x72, 0x73, 0x3A,
|
||||||
|
0x7C, 0x7C, 0xFE, 0x14, 0x20, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 0x20,
|
||||||
|
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, 0x7C, 0xFE, 0x14,
|
||||||
|
0xFE, 0x14, 0x00, 0x01, 0x00, 0x07, 0x20, 0x20, 0x47, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x20,
|
||||||
|
0x41, 0x72, 0x74, 0x69, 0x73, 0x74, 0x73, 0x3A, 0x7C, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20,
|
||||||
|
0x20, 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, 0x7C,
|
||||||
|
0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0xFE, 0x14,
|
||||||
|
0x00, 0x01, 0x00, 0x07, 0x20, 0x20, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x20, 0x45,
|
||||||
|
0x6E, 0x67, 0x69, 0x6E, 0x65, 0x65, 0x72, 0x3A, 0x7C, 0x7C, 0xFE, 0x14, 0x20, 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, 0x14, 0x00,
|
||||||
|
0x01, 0x00, 0x07, 0x20, 0x20, 0x53, 0x74, 0x6F, 0x72, 0x79, 0x3A, 0x7C, 0x7C, 0xFE, 0x14, 0x20,
|
||||||
|
0x20, 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, 0x7C,
|
||||||
|
0xFE, 0x14, 0x00, 0x01, 0x00, 0x08, 0x20, 0x20, 0x4C, 0x65, 0x76, 0x65, 0x6C, 0x20, 0x44, 0x65,
|
||||||
|
0x73, 0x69, 0x67, 0x6E, 0x3A, 0x7C, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20,
|
||||||
|
0x20, 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, 0x7C,
|
||||||
|
0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0xFE, 0x14, 0x00, 0x01, 0x00, 0x08, 0x20, 0x20,
|
||||||
|
0x4D, 0x75, 0x73, 0x69, 0x63, 0x3A, 0x7C, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x61, 0x70, 0x68,
|
||||||
|
0x61, 0x65, 0x6C, 0x20, 0x47, 0x65, 0x73, 0x71, 0x75, 0x61, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x14,
|
||||||
|
0x20, 0x20, 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,
|
||||||
|
0x7C, 0xFE, 0x14, 0xFE, 0x14, 0x00, 0x01, 0x00, 0x08, 0x20, 0x20, 0x53, 0x6F, 0x75, 0x6E, 0x64,
|
||||||
|
0x20, 0x66, 0x78, 0x3A, 0x7C, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20,
|
||||||
|
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, 0x7C, 0xFE,
|
||||||
|
0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0xFE, 0x14, 0x00, 0x01, 0x00, 0x06, 0x20, 0x20, 0x41, 0x63, 0x74, 0x6F,
|
||||||
|
0x72, 0x73, 0x3A, 0x7C, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20,
|
||||||
|
0x20, 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, 0x7C,
|
||||||
|
0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0xFE, 0x14, 0x00, 0x01, 0x00,
|
||||||
|
0x0A, 0x20, 0x20, 0x56, 0x69, 0x64, 0x65, 0x6F, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6F,
|
||||||
|
0x72, 0x73, 0x3A, 0x7C, 0x7C, 0xFE, 0x14, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x09, 0x20, 0x20, 0x20, 0x50, 0x61, 0x74, 0x72, 0x69, 0x63, 0x6B, 0x20, 0x44,
|
||||||
|
0x61, 0x68, 0x65, 0x72, 0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20,
|
||||||
|
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, 0x7C, 0xFE,
|
||||||
|
0x14, 0xFE, 0x14, 0x00, 0x01, 0x00, 0x0A, 0x20, 0x20, 0x56, 0x69, 0x64, 0x65, 0x6F, 0x20, 0x43,
|
||||||
|
0x6F, 0x2D, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x3A, 0x7C, 0x7C, 0xFE, 0x14,
|
||||||
|
0x20, 0x20, 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,
|
||||||
|
0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0xFE, 0x14, 0x00, 0x01, 0x00, 0x0A, 0x20,
|
||||||
|
0x20, 0x56, 0x69, 0x64, 0x65, 0x6F, 0x20, 0x73, 0x66, 0x78, 0x3A, 0x7C, 0x7C, 0xFE, 0x14, 0x20,
|
||||||
|
0x20, 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, 0x7C,
|
||||||
|
0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0x20, 0x20, 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, 0x7C, 0xFE, 0x14, 0xFE, 0x14, 0x00, 0x01, 0x00, 0x07, 0x20, 0x20,
|
||||||
|
0x54, 0x65, 0x73, 0x74, 0x65, 0x72, 0x73, 0x3A, 0x7C, 0x7C, 0xFE, 0x14, 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, 0x20, 0x7C, 0xFE, 0x14, 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, 0x20, 0x7C,
|
||||||
|
0xFE, 0x14, 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, 0x20, 0x7C, 0xFE, 0x14, 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, 0x20, 0x7C, 0xFE, 0x14, 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, 0x20, 0x7C, 0xFE, 0x14, 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, 0x20, 0x7C, 0xFE, 0x14, 0xFE, 0x14,
|
||||||
|
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, 0x14, 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, 0x20, 0x7C, 0xFE, 0x14, 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, 0x20, 0x7C, 0xFE,
|
||||||
|
0x14, 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,
|
||||||
|
0x20, 0x7C, 0xFE, 0x14, 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, 0x20, 0x7C, 0xFE, 0x14, 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, 0x20, 0x7C, 0xFE, 0x14, 0xFE, 0x14, 0x00, 0x01, 0x00, 0x05,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x44, 0x69, 0x72, 0x65, 0x63,
|
||||||
|
0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x7C, 0x7C, 0xFE, 0x14, 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, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x7C, 0xFE, 0x14, 0xFE, 0x14, 0x00, 0x01, 0x00, 0x05, 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, 0x20, 0x7C, 0x7C, 0xFE,
|
||||||
|
0x14, 0x20, 0x20, 0x20, 0x44, 0x65, 0x6C, 0x70, 0x68, 0x69, 0x6E, 0x65, 0x20, 0x53, 0x6F, 0x66,
|
||||||
|
0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x2F, 0x20, 0x55, 0x53, 0x20, 0x47, 0x4F, 0x4C, 0x44, 0x20,
|
||||||
|
0x20, 0x7C, 0xFE, 0x14, 0x20, 0x7C, 0x20, 0x7C, 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, 0x20, 0x7C, 0xFE, 0x14, 0xFE, 0x28, 0x00, 0xFF
|
||||||
|
};
|
||||||
|
|
||||||
const uint16_t Cutscene::_creditsCutSeq[] = {
|
const uint16_t Cutscene::_creditsCutSeq[] = {
|
||||||
0x00, 0x05, 0x2F, 0x32, 0x36, 0x3E, 0x30, 0x39, 0x3F, 0x14, 0x34, 0xFFFF
|
0x00, 0x05, 0x2F, 0x32, 0x36, 0x3E, 0x30, 0x39, 0x3F, 0x14, 0x34, 0xFFFF
|
||||||
};
|
};
|
||||||
|
@ -649,6 +807,29 @@ const uint8_t Cutscene::_protectionShapeData[] = {
|
||||||
0x03, 0xFD, 0x06, 0xFC, 0x00, 0x19
|
0x03, 0xFD, 0x06, 0xFC, 0x00, 0x19
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Cutscene::Text Cutscene::_frTextsTable[] = {
|
||||||
|
{ 1, "VOUS RAMASSEZ L'HOLOCUBE" },
|
||||||
|
{ 2, "VOUS RAMASSEZ LA CLE" },
|
||||||
|
{ 4, "VOUS RAMASSEZ LE PISTOLET" },
|
||||||
|
{ 5, "VOTRE BOUCLIER EST RECHARGE" },
|
||||||
|
{ 10, "VOUS RAMASSEZ||LA CARTE DE CREDITS" },
|
||||||
|
{ 14, "LA PILE EST RECHARGEE" },
|
||||||
|
{ 15, "VOUS RAMASSEZ LA PILE" },
|
||||||
|
{ 16, "VOUS RAMASSEZ LE TELEPORTEUR" },
|
||||||
|
{ 18, "VOUS RAMASSEZ LA CARTE ID" },
|
||||||
|
{ 21, "VOUS LUI DONNEZ LE TELEPORTEUR" },
|
||||||
|
{ 32, "LA RECEPTIONNISTE VOUS DONNE||UN PAQUET" },
|
||||||
|
{ 33, "VOUS DONNEZ LE COLIS" },
|
||||||
|
{ 34, "LE GOUVERNEUR VOUS DONNE||LA CARTE DE TRAVAIL" },
|
||||||
|
{ 35, "LE FAUSSAIRE VOUS DONNE||LA FAUSSE CARTE ID" },
|
||||||
|
{ 36, "VOUS RAMASSEZ LE FUSIBLE" },
|
||||||
|
{ 43, "VOUS LUI TENDEZ||VOS PAPIERS" },
|
||||||
|
{ 44, "VOUS LUI DONNEZ L'ARGENT" },
|
||||||
|
{ 49, "IL VOUS DONNE||UNE CEINTURE ANTI-G" },
|
||||||
|
{ 60, "VOUS RAMASSEZ LE TELE RECEPTEUR" },
|
||||||
|
{ -1, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
const Level Game::_gameLevels[] = {
|
const Level Game::_gameLevels[] = {
|
||||||
{ "level1", "level1", "level1", 0x00, 1, 3 },
|
{ "level1", "level1", "level1", 0x00, 1, 3 },
|
||||||
{ "level2", "level2", "level2", 0x2F, 1, 4 },
|
{ "level2", "level2", "level2", 0x2F, 1, 4 },
|
||||||
|
|
|
@ -45,7 +45,7 @@ struct PlayerInput {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SystemStub {
|
struct SystemStub {
|
||||||
typedef void (*AudioCallback)(void *param, int8_t *stream, int len);
|
typedef void (*AudioCallback)(void *param, int16_t *stream, int len);
|
||||||
|
|
||||||
PlayerInput _pi;
|
PlayerInput _pi;
|
||||||
|
|
||||||
|
|
|
@ -9,26 +9,31 @@
|
||||||
#include "systemstub.h"
|
#include "systemstub.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
struct SystemStub_SDL : SystemStub {
|
static const int kAudioHz = 22050;
|
||||||
enum {
|
static const int kJoystickCommitValue = 3200;
|
||||||
MAX_BLIT_RECTS = 200,
|
|
||||||
SOUND_SAMPLE_RATE = 22050,
|
|
||||||
JOYSTICK_COMMIT_VALUE = 3200
|
|
||||||
};
|
|
||||||
|
|
||||||
|
struct SystemStub_SDL : SystemStub {
|
||||||
|
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||||
|
SDL_Window *_window;
|
||||||
|
SDL_Renderer *_renderer;
|
||||||
|
SDL_Texture *_texture;
|
||||||
|
#else
|
||||||
|
SDL_Surface *_surface;
|
||||||
|
#endif
|
||||||
|
SDL_PixelFormat *_fmt;
|
||||||
|
const char *_caption;
|
||||||
uint16_t *_screenBuffer;
|
uint16_t *_screenBuffer;
|
||||||
uint16_t *_fadeScreenBuffer;
|
uint16_t *_fadeScreenBuffer;
|
||||||
SDL_Surface *_screenSurface;
|
|
||||||
bool _fullscreen;
|
bool _fullscreen;
|
||||||
int _currentScaler;
|
int _scaler;
|
||||||
uint8_t _overscanColor;
|
uint8_t _overscanColor;
|
||||||
uint16_t _pal[256];
|
uint16_t _pal[256];
|
||||||
int _screenW, _screenH;
|
int _screenW, _screenH;
|
||||||
SDL_Joystick *_joystick;
|
SDL_Joystick *_joystick;
|
||||||
SDL_Rect _blitRects[MAX_BLIT_RECTS];
|
SDL_Rect _blitRects[200];
|
||||||
int _numBlitRects;
|
int _numBlitRects;
|
||||||
bool _fadeOnUpdateScreen;
|
bool _fadeOnUpdateScreen;
|
||||||
void (*_audioCbProc)(void *, int8_t *, int);
|
void (*_audioCbProc)(void *, int16_t *, int);
|
||||||
void *_audioCbData;
|
void *_audioCbData;
|
||||||
int _screenshot;
|
int _screenshot;
|
||||||
|
|
||||||
|
@ -53,11 +58,11 @@ struct SystemStub_SDL : SystemStub {
|
||||||
virtual void unlockAudio();
|
virtual void unlockAudio();
|
||||||
|
|
||||||
void processEvent(const SDL_Event &ev, bool &paused);
|
void processEvent(const SDL_Event &ev, bool &paused);
|
||||||
void prepareGfxMode();
|
void prepareGraphics();
|
||||||
void cleanupGfxMode();
|
void cleanupGraphics();
|
||||||
void switchGfxMode(bool fullscreen, uint8_t scaler);
|
void changeGraphics(bool fullscreen, uint8_t scaler);
|
||||||
void flipGfx();
|
void flipGraphics();
|
||||||
void forceGfxRedraw();
|
void forceGraphicsRedraw();
|
||||||
void drawRect(SDL_Rect *rect, uint8_t color, uint16_t *dst, uint16_t dstPitch);
|
void drawRect(SDL_Rect *rect, uint8_t color, uint16_t *dst, uint16_t dstPitch);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -68,14 +73,15 @@ SystemStub *SystemStub_SDL_create() {
|
||||||
void SystemStub_SDL::init(const char *title, int w, int h, int scaler, bool fullscreen) {
|
void SystemStub_SDL::init(const char *title, int w, int h, int scaler, bool fullscreen) {
|
||||||
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK);
|
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK);
|
||||||
SDL_ShowCursor(SDL_DISABLE);
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
SDL_WM_SetCaption(title, NULL);
|
_caption = title;
|
||||||
memset(&_pi, 0, sizeof(_pi));
|
memset(&_pi, 0, sizeof(_pi));
|
||||||
_screenBuffer = 0;
|
_screenBuffer = 0;
|
||||||
_fadeScreenBuffer = 0;
|
_fadeScreenBuffer = 0;
|
||||||
_fadeOnUpdateScreen = false;
|
_fadeOnUpdateScreen = false;
|
||||||
_fullscreen = fullscreen;
|
_fullscreen = fullscreen;
|
||||||
_currentScaler = scaler;
|
_scaler = scaler;
|
||||||
memset(_pal, 0, sizeof(_pal));
|
memset(_pal, 0, sizeof(_pal));
|
||||||
|
_screenW = _screenH = 0;
|
||||||
setScreenSize(w, h);
|
setScreenSize(w, h);
|
||||||
_joystick = NULL;
|
_joystick = NULL;
|
||||||
if (SDL_NumJoysticks() > 0) {
|
if (SDL_NumJoysticks() > 0) {
|
||||||
|
@ -85,9 +91,10 @@ void SystemStub_SDL::init(const char *title, int w, int h, int scaler, bool full
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStub_SDL::destroy() {
|
void SystemStub_SDL::destroy() {
|
||||||
cleanupGfxMode();
|
cleanupGraphics();
|
||||||
if (SDL_JoystickOpened(0)) {
|
if (_joystick) {
|
||||||
SDL_JoystickClose(_joystick);
|
SDL_JoystickClose(_joystick);
|
||||||
|
_joystick = 0;
|
||||||
}
|
}
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
|
@ -108,7 +115,7 @@ void SystemStub_SDL::setScreenSize(int w, int h) {
|
||||||
}
|
}
|
||||||
_screenW = w;
|
_screenW = w;
|
||||||
_screenH = h;
|
_screenH = h;
|
||||||
prepareGfxMode();
|
prepareGraphics();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStub_SDL::setPalette(const uint8_t *pal, int n) {
|
void SystemStub_SDL::setPalette(const uint8_t *pal, int n) {
|
||||||
|
@ -117,16 +124,16 @@ void SystemStub_SDL::setPalette(const uint8_t *pal, int n) {
|
||||||
uint8_t r = pal[i * 3 + 0];
|
uint8_t r = pal[i * 3 + 0];
|
||||||
uint8_t g = pal[i * 3 + 1];
|
uint8_t g = pal[i * 3 + 1];
|
||||||
uint8_t b = pal[i * 3 + 2];
|
uint8_t b = pal[i * 3 + 2];
|
||||||
_pal[i] = SDL_MapRGB(_screenSurface->format, r, g, b);
|
_pal[i] = SDL_MapRGB(_fmt, r, g, b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStub_SDL::setPaletteEntry(int i, const Color *c) {
|
void SystemStub_SDL::setPaletteEntry(int i, const Color *c) {
|
||||||
_pal[i] = SDL_MapRGB(_screenSurface->format, c->r, c->g, c->b);
|
_pal[i] = SDL_MapRGB(_fmt, c->r, c->g, c->b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStub_SDL::getPaletteEntry(int i, Color *c) {
|
void SystemStub_SDL::getPaletteEntry(int i, Color *c) {
|
||||||
SDL_GetRGB(_pal[i], _screenSurface->format, &c->r, &c->g, &c->b);
|
SDL_GetRGB(_pal[i], _fmt, &c->r, &c->g, &c->b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStub_SDL::setOverscanColor(int i) {
|
void SystemStub_SDL::setOverscanColor(int i) {
|
||||||
|
@ -134,7 +141,7 @@ void SystemStub_SDL::setOverscanColor(int i) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStub_SDL::copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch) {
|
void SystemStub_SDL::copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch) {
|
||||||
if (_numBlitRects >= MAX_BLIT_RECTS) {
|
if (_numBlitRects >= ARRAYSIZE(_blitRects)) {
|
||||||
warning("SystemStub_SDL::copyRect() Too many blit rects, you may experience graphical glitches");
|
warning("SystemStub_SDL::copyRect() Too many blit rects, you may experience graphical glitches");
|
||||||
} else {
|
} else {
|
||||||
// extend the dirty region by 1 pixel for scalers accessing 'outer' pixels
|
// extend the dirty region by 1 pixel for scalers accessing 'outer' pixels
|
||||||
|
@ -211,24 +218,39 @@ static uint16_t blendPixel16(uint16_t colorSrc, uint16_t colorDst, uint32_t mask
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStub_SDL::updateScreen(int shakeOffset) {
|
void SystemStub_SDL::updateScreen(int shakeOffset) {
|
||||||
const int mul = _scalers[_currentScaler].factor;
|
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||||
|
// _fadeOnUpdateScreen
|
||||||
|
SDL_UpdateTexture(_texture, 0, _screenBuffer + _screenW + 1, _screenW * sizeof(uint16_t));
|
||||||
|
SDL_RenderClear(_renderer);
|
||||||
|
if (shakeOffset != 0) {
|
||||||
|
SDL_Rect r;
|
||||||
|
r.x = 0;
|
||||||
|
r.y = shakeOffset * _scalers[_scaler].factor;
|
||||||
|
SDL_GetRendererOutputSize(_renderer, &r.w, &r.h);
|
||||||
|
r.h -= r.y;
|
||||||
|
SDL_RenderCopy(_renderer, _texture, 0, &r);
|
||||||
|
} else {
|
||||||
|
SDL_RenderCopy(_renderer, _texture, 0, 0);
|
||||||
|
}
|
||||||
|
SDL_RenderPresent(_renderer);
|
||||||
|
#else
|
||||||
|
const int mul = _scalers[_scaler].factor;
|
||||||
if (_fadeOnUpdateScreen) {
|
if (_fadeOnUpdateScreen) {
|
||||||
const int tempScreenBufferSize = (_screenH + 2) * (_screenW + 2) * sizeof(uint16_t);
|
const int tempScreenBufferSize = (_screenH + 2) * (_screenW + 2) * sizeof(uint16_t);
|
||||||
uint16_t *tempScreenBuffer = (uint16_t *)calloc(tempScreenBufferSize, 1);
|
uint16_t *tempScreenBuffer = (uint16_t *)calloc(tempScreenBufferSize, 1);
|
||||||
assert(tempScreenBuffer);
|
assert(tempScreenBuffer);
|
||||||
const SDL_PixelFormat *pf = _screenSurface->format;
|
const uint32_t colorMask = (_fmt->Gmask << 16) | (_fmt->Rmask | _fmt->Bmask);
|
||||||
const uint32_t colorMask = (pf->Gmask << 16) | (pf->Rmask | pf->Bmask);
|
|
||||||
const uint16_t *screenBuffer = _screenBuffer + _screenW + 1;
|
const uint16_t *screenBuffer = _screenBuffer + _screenW + 1;
|
||||||
for (int i = 1; i <= 16; ++i) {
|
for (int i = 1; i <= 16; ++i) {
|
||||||
for (int x = 0; x < _screenH * _screenW; ++x) {
|
for (int x = 0; x < _screenH * _screenW; ++x) {
|
||||||
tempScreenBuffer[_screenW + 1 + x] = blendPixel16(_fadeScreenBuffer[x], screenBuffer[x], colorMask, i);
|
tempScreenBuffer[_screenW + 1 + x] = blendPixel16(_fadeScreenBuffer[x], screenBuffer[x], colorMask, i);
|
||||||
}
|
}
|
||||||
SDL_LockSurface(_screenSurface);
|
SDL_LockSurface(_surface);
|
||||||
uint16_t *dst = (uint16_t *)_screenSurface->pixels;
|
uint16_t *dst = (uint16_t *)_surface->pixels;
|
||||||
const uint16_t *src = tempScreenBuffer + _screenW + 1;
|
const uint16_t *src = tempScreenBuffer + _screenW + 1;
|
||||||
(*_scalers[_currentScaler].proc)(dst, _screenSurface->pitch, src, _screenW, _screenW, _screenH);
|
(*_scalers[_scaler].proc)(dst, _surface->pitch, src, _screenW, _screenW, _screenH);
|
||||||
SDL_UnlockSurface(_screenSurface);
|
SDL_UnlockSurface(_surface);
|
||||||
SDL_UpdateRect(_screenSurface, 0, 0, _screenW * mul, _screenH * mul);
|
SDL_UpdateRect(_surface, 0, 0, _screenW * mul, _screenH * mul);
|
||||||
SDL_Delay(30);
|
SDL_Delay(30);
|
||||||
}
|
}
|
||||||
free(tempScreenBuffer);
|
free(tempScreenBuffer);
|
||||||
|
@ -240,35 +262,36 @@ void SystemStub_SDL::updateScreen(int shakeOffset) {
|
||||||
SDL_Rect *br = &_blitRects[i];
|
SDL_Rect *br = &_blitRects[i];
|
||||||
int dx = br->x * mul;
|
int dx = br->x * mul;
|
||||||
int dy = br->y * mul;
|
int dy = br->y * mul;
|
||||||
SDL_LockSurface(_screenSurface);
|
SDL_LockSurface(_surface);
|
||||||
uint16_t *dst = (uint16_t *)_screenSurface->pixels + dy * _screenSurface->pitch / 2 + dx;
|
uint16_t *dst = (uint16_t *)_surface->pixels + dy * _surface->pitch / 2 + dx;
|
||||||
const uint16_t *src = _screenBuffer + (br->y + 1) * _screenW + (br->x + 1);
|
const uint16_t *src = _screenBuffer + (br->y + 1) * _screenW + (br->x + 1);
|
||||||
(*_scalers[_currentScaler].proc)(dst, _screenSurface->pitch, src, _screenW, br->w, br->h);
|
(*_scalers[_scaler].proc)(dst, _surface->pitch, src, _screenW, br->w, br->h);
|
||||||
SDL_UnlockSurface(_screenSurface);
|
SDL_UnlockSurface(_surface);
|
||||||
br->x *= mul;
|
br->x *= mul;
|
||||||
br->y *= mul;
|
br->y *= mul;
|
||||||
br->w *= mul;
|
br->w *= mul;
|
||||||
br->h *= mul;
|
br->h *= mul;
|
||||||
}
|
}
|
||||||
SDL_UpdateRects(_screenSurface, _numBlitRects, _blitRects);
|
SDL_UpdateRects(_surface, _numBlitRects, _blitRects);
|
||||||
} else {
|
} else {
|
||||||
SDL_LockSurface(_screenSurface);
|
SDL_LockSurface(_surface);
|
||||||
int w = _screenW;
|
int w = _screenW;
|
||||||
int h = _screenH - shakeOffset;
|
int h = _screenH - shakeOffset;
|
||||||
uint16_t *dst = (uint16_t *)_screenSurface->pixels + shakeOffset * mul * _screenSurface->pitch / 2;
|
uint16_t *dst = (uint16_t *)_surface->pixels + shakeOffset * mul * _surface->pitch / 2;
|
||||||
const uint16_t *src = _screenBuffer + _screenW + 1;
|
const uint16_t *src = _screenBuffer + _screenW + 1;
|
||||||
(*_scalers[_currentScaler].proc)(dst, _screenSurface->pitch, src, _screenW, w, h);
|
(*_scalers[_scaler].proc)(dst, _surface->pitch, src, _screenW, w, h);
|
||||||
SDL_UnlockSurface(_screenSurface);
|
SDL_UnlockSurface(_surface);
|
||||||
|
|
||||||
SDL_Rect r;
|
SDL_Rect r;
|
||||||
r.x = 0;
|
r.x = 0;
|
||||||
r.y = 0;
|
r.y = 0;
|
||||||
r.w = _screenW * mul;
|
r.w = _screenW * mul;
|
||||||
r.h = shakeOffset * mul;
|
r.h = shakeOffset * mul;
|
||||||
SDL_FillRect(_screenSurface, &r, _pal[_overscanColor]);
|
SDL_FillRect(_surface, &r, _pal[_overscanColor]);
|
||||||
|
|
||||||
SDL_UpdateRect(_screenSurface, 0, 0, _screenW * mul, _screenH * mul);
|
SDL_UpdateRect(_surface, 0, 0, _screenW * mul, _screenH * mul);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
_numBlitRects = 0;
|
_numBlitRects = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,13 +317,26 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
_pi.quit = true;
|
_pi.quit = true;
|
||||||
break;
|
break;
|
||||||
|
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||||
|
case SDL_WINDOWEVENT:
|
||||||
|
switch (ev.window.event) {
|
||||||
|
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||||
|
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||||
|
paused = (ev.window.event == SDL_WINDOWEVENT_FOCUS_LOST);
|
||||||
|
SDL_PauseAudio(paused);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#else
|
||||||
case SDL_ACTIVEEVENT:
|
case SDL_ACTIVEEVENT:
|
||||||
if (ev.active.state & SDL_APPINPUTFOCUS) {
|
if (ev.active.state & SDL_APPINPUTFOCUS) {
|
||||||
paused = ev.active.gain == 0;
|
paused = ev.active.gain == 0;
|
||||||
SDL_PauseAudio(paused ? 1 : 0);
|
SDL_PauseAudio(paused ? 1 : 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDL_JOYHATMOTION:
|
#endif
|
||||||
|
case SDL_JOYHATMOTION:
|
||||||
|
if (_joystick) {
|
||||||
_pi.dirMask = 0;
|
_pi.dirMask = 0;
|
||||||
if (ev.jhat.value & SDL_HAT_UP) {
|
if (ev.jhat.value & SDL_HAT_UP) {
|
||||||
_pi.dirMask |= PlayerInput::DIR_UP;
|
_pi.dirMask |= PlayerInput::DIR_UP;
|
||||||
|
@ -314,42 +350,32 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
|
||||||
if (ev.jhat.value & SDL_HAT_RIGHT) {
|
if (ev.jhat.value & SDL_HAT_RIGHT) {
|
||||||
_pi.dirMask |= PlayerInput::DIR_RIGHT;
|
_pi.dirMask |= PlayerInput::DIR_RIGHT;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case SDL_JOYAXISMOTION:
|
break;
|
||||||
|
case SDL_JOYAXISMOTION:
|
||||||
|
if (_joystick) {
|
||||||
switch (ev.jaxis.axis) {
|
switch (ev.jaxis.axis) {
|
||||||
case 0:
|
case 0:
|
||||||
if (ev.jaxis.value > JOYSTICK_COMMIT_VALUE) {
|
_pi.dirMask &= ~(PlayerInput::DIR_RIGHT | PlayerInput::DIR_LEFT);
|
||||||
|
if (ev.jaxis.value > kJoystickCommitValue) {
|
||||||
_pi.dirMask |= PlayerInput::DIR_RIGHT;
|
_pi.dirMask |= PlayerInput::DIR_RIGHT;
|
||||||
if (_pi.dirMask & PlayerInput::DIR_LEFT) {
|
} else if (ev.jaxis.value < -kJoystickCommitValue) {
|
||||||
_pi.dirMask &= ~PlayerInput::DIR_LEFT;
|
|
||||||
}
|
|
||||||
} else if (ev.jaxis.value < -JOYSTICK_COMMIT_VALUE) {
|
|
||||||
_pi.dirMask |= PlayerInput::DIR_LEFT;
|
_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;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (ev.jaxis.value > JOYSTICK_COMMIT_VALUE) {
|
_pi.dirMask &= ~(PlayerInput::DIR_UP | PlayerInput::DIR_DOWN);
|
||||||
|
if (ev.jaxis.value > kJoystickCommitValue) {
|
||||||
_pi.dirMask |= PlayerInput::DIR_DOWN;
|
_pi.dirMask |= PlayerInput::DIR_DOWN;
|
||||||
if (_pi.dirMask & PlayerInput::DIR_UP) {
|
} else if (ev.jaxis.value < -kJoystickCommitValue) {
|
||||||
_pi.dirMask &= ~PlayerInput::DIR_UP;
|
|
||||||
}
|
|
||||||
} else if (ev.jaxis.value < -JOYSTICK_COMMIT_VALUE) {
|
|
||||||
_pi.dirMask |= PlayerInput::DIR_UP;
|
_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;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case SDL_JOYBUTTONDOWN:
|
break;
|
||||||
|
case SDL_JOYBUTTONDOWN:
|
||||||
|
if (_joystick) {
|
||||||
switch (ev.jbutton.button) {
|
switch (ev.jbutton.button) {
|
||||||
case 0:
|
case 0:
|
||||||
_pi.space = true;
|
_pi.space = true;
|
||||||
|
@ -364,8 +390,10 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
|
||||||
_pi.backspace = true;
|
_pi.backspace = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case SDL_JOYBUTTONUP:
|
break;
|
||||||
|
case SDL_JOYBUTTONUP:
|
||||||
|
if (_joystick) {
|
||||||
switch (ev.jbutton.button) {
|
switch (ev.jbutton.button) {
|
||||||
case 0:
|
case 0:
|
||||||
_pi.space = false;
|
_pi.space = false;
|
||||||
|
@ -380,7 +408,8 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
|
||||||
_pi.backspace = false;
|
_pi.backspace = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
case SDL_KEYUP:
|
case SDL_KEYUP:
|
||||||
switch (ev.key.keysym.sym) {
|
switch (ev.key.keysym.sym) {
|
||||||
case SDLK_LEFT:
|
case SDLK_LEFT:
|
||||||
|
@ -415,23 +444,26 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
if (ev.key.keysym.mod & KMOD_ALT) {
|
if (ev.key.keysym.mod & KMOD_ALT) {
|
||||||
if (ev.key.keysym.sym == SDLK_RETURN) {
|
if (ev.key.keysym.sym == SDLK_RETURN) {
|
||||||
switchGfxMode(!_fullscreen, _currentScaler);
|
changeGraphics(!_fullscreen, _scaler);
|
||||||
} else if (ev.key.keysym.sym == SDLK_KP_PLUS || ev.key.keysym.sym == SDLK_PAGEUP) {
|
} else if (ev.key.keysym.sym == SDLK_KP_PLUS || ev.key.keysym.sym == SDLK_PAGEUP) {
|
||||||
uint8_t s = _currentScaler + 1;
|
uint8_t s = _scaler + 1;
|
||||||
if (s < NUM_SCALERS) {
|
if (s < NUM_SCALERS) {
|
||||||
switchGfxMode(_fullscreen, s);
|
changeGraphics(_fullscreen, s);
|
||||||
}
|
}
|
||||||
} else if (ev.key.keysym.sym == SDLK_KP_MINUS || ev.key.keysym.sym == SDLK_PAGEDOWN) {
|
} else if (ev.key.keysym.sym == SDLK_KP_MINUS || ev.key.keysym.sym == SDLK_PAGEDOWN) {
|
||||||
int8_t s = _currentScaler - 1;
|
int8_t s = _scaler - 1;
|
||||||
if (_currentScaler > 0) {
|
if (_scaler > 0) {
|
||||||
switchGfxMode(_fullscreen, s);
|
changeGraphics(_fullscreen, s);
|
||||||
}
|
}
|
||||||
} else if (ev.key.keysym.sym == SDLK_s) {
|
} else if (ev.key.keysym.sym == SDLK_s) {
|
||||||
|
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||||
|
#else
|
||||||
char name[32];
|
char name[32];
|
||||||
snprintf(name, sizeof(name), "screenshot-%03d.bmp", _screenshot);
|
snprintf(name, sizeof(name), "screenshot-%03d.bmp", _screenshot);
|
||||||
SDL_SaveBMP(_screenSurface, name);
|
SDL_SaveBMP(_surface, name);
|
||||||
++_screenshot;
|
++_screenshot;
|
||||||
debug(DBG_INFO, "Written '%s'", name);
|
debug(DBG_INFO, "Written '%s'", name);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else if (ev.key.keysym.mod & KMOD_CTRL) {
|
} else if (ev.key.keysym.mod & KMOD_CTRL) {
|
||||||
|
@ -443,7 +475,7 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
|
||||||
_pi.dbgMask ^= PlayerInput::DF_SETLIFE;
|
_pi.dbgMask ^= PlayerInput::DF_SETLIFE;
|
||||||
} else if (ev.key.keysym.sym == SDLK_m) {
|
} else if (ev.key.keysym.sym == SDLK_m) {
|
||||||
_pi.mirrorMode = !_pi.mirrorMode;
|
_pi.mirrorMode = !_pi.mirrorMode;
|
||||||
flipGfx();
|
flipGraphics();
|
||||||
} else if (ev.key.keysym.sym == SDLK_s) {
|
} else if (ev.key.keysym.sym == SDLK_s) {
|
||||||
_pi.save = true;
|
_pi.save = true;
|
||||||
} else if (ev.key.keysym.sym == SDLK_l) {
|
} else if (ev.key.keysym.sym == SDLK_l) {
|
||||||
|
@ -506,22 +538,20 @@ uint32_t SystemStub_SDL::getTimeStamp() {
|
||||||
return SDL_GetTicks();
|
return SDL_GetTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mixAudioS8ToU8(void *param, uint8_t *buf, int len) {
|
static void mixAudioS16(void *param, uint8_t *buf, int len) {
|
||||||
SystemStub_SDL *stub = (SystemStub_SDL *)param;
|
SystemStub_SDL *stub = (SystemStub_SDL *)param;
|
||||||
stub->_audioCbProc(stub->_audioCbData, (int8_t *)buf, len);
|
memset(buf, 0, len);
|
||||||
for (int i = 0; i < len; ++i) {
|
stub->_audioCbProc(stub->_audioCbData, (int16_t *)buf, len / 2);
|
||||||
buf[i] ^= 0x80;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStub_SDL::startAudio(AudioCallback callback, void *param) {
|
void SystemStub_SDL::startAudio(AudioCallback callback, void *param) {
|
||||||
SDL_AudioSpec desired, obtained;
|
SDL_AudioSpec desired, obtained;
|
||||||
memset(&desired, 0, sizeof(desired));
|
memset(&desired, 0, sizeof(desired));
|
||||||
desired.freq = SOUND_SAMPLE_RATE;
|
desired.freq = kAudioHz;
|
||||||
desired.format = AUDIO_U8;
|
desired.format = AUDIO_S16SYS;
|
||||||
desired.channels = 1;
|
desired.channels = 1;
|
||||||
desired.samples = 2048;
|
desired.samples = 2048;
|
||||||
desired.callback = mixAudioS8ToU8;
|
desired.callback = mixAudioS16;
|
||||||
desired.userdata = this;
|
desired.userdata = this;
|
||||||
if (SDL_OpenAudio(&desired, &obtained) == 0) {
|
if (SDL_OpenAudio(&desired, &obtained) == 0) {
|
||||||
_audioCbProc = callback;
|
_audioCbProc = callback;
|
||||||
|
@ -537,7 +567,7 @@ void SystemStub_SDL::stopAudio() {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t SystemStub_SDL::getOutputSampleRate() {
|
uint32_t SystemStub_SDL::getOutputSampleRate() {
|
||||||
return SOUND_SAMPLE_RATE;
|
return kAudioHz;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStub_SDL::lockAudio() {
|
void SystemStub_SDL::lockAudio() {
|
||||||
|
@ -548,17 +578,49 @@ void SystemStub_SDL::unlockAudio() {
|
||||||
SDL_UnlockAudio();
|
SDL_UnlockAudio();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStub_SDL::prepareGfxMode() {
|
void SystemStub_SDL::prepareGraphics() {
|
||||||
int w = _screenW * _scalers[_currentScaler].factor;
|
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||||
int h = _screenH * _scalers[_currentScaler].factor;
|
switch (_scaler) {
|
||||||
_screenSurface = SDL_SetVideoMode(w, h, 16, _fullscreen ? (SDL_FULLSCREEN | SDL_HWSURFACE) : SDL_HWSURFACE);
|
case SCALER_SCALE_2X:
|
||||||
if (!_screenSurface) {
|
case SCALER_SCALE_3X:
|
||||||
error("SystemStub_SDL::prepareGfxMode() Unable to allocate _screen buffer");
|
case SCALER_SCALE_4X:
|
||||||
|
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); // nearest pixel sampling
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
forceGfxRedraw();
|
const int windowW = _screenW * _scalers[_scaler].factor;
|
||||||
|
const int windowH = _screenH * _scalers[_scaler].factor;
|
||||||
|
int flags = 0;
|
||||||
|
if (_fullscreen) {
|
||||||
|
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||||
|
}
|
||||||
|
_window = SDL_CreateWindow(_caption, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowW, windowH, flags);
|
||||||
|
_renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED);
|
||||||
|
SDL_RenderSetLogicalSize(_renderer, windowW, windowH);
|
||||||
|
static const uint32_t kPixelFormat = SDL_PIXELFORMAT_RGB565;
|
||||||
|
_texture = SDL_CreateTexture(_renderer, kPixelFormat, SDL_TEXTUREACCESS_STREAMING, _screenW, _screenH);
|
||||||
|
_fmt = SDL_AllocFormat(kPixelFormat);
|
||||||
|
#else
|
||||||
|
SDL_WM_SetCaption(_caption, NULL);
|
||||||
|
const int w = _screenW * _scalers[_scaler].factor;
|
||||||
|
const int h = _screenH * _scalers[_scaler].factor;
|
||||||
|
int flags = SDL_HWSURFACE;
|
||||||
|
if (_fullscreen) {
|
||||||
|
flags |= SDL_FULLSCREEN;
|
||||||
|
}
|
||||||
|
static const int kBitDepth = 16;
|
||||||
|
_surface = SDL_SetVideoMode(w, h, kBitDepth, flags);
|
||||||
|
if (!_surface) {
|
||||||
|
error("SystemStub_SDL::prepareGraphics() Unable to allocate _screen buffer");
|
||||||
|
}
|
||||||
|
_fmt = _surface->format;
|
||||||
|
#endif
|
||||||
|
forceGraphicsRedraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStub_SDL::cleanupGfxMode() {
|
void SystemStub_SDL::cleanupGraphics() {
|
||||||
if (_screenBuffer) {
|
if (_screenBuffer) {
|
||||||
free(_screenBuffer);
|
free(_screenBuffer);
|
||||||
_screenBuffer = 0;
|
_screenBuffer = 0;
|
||||||
|
@ -567,21 +629,56 @@ void SystemStub_SDL::cleanupGfxMode() {
|
||||||
free(_fadeScreenBuffer);
|
free(_fadeScreenBuffer);
|
||||||
_fadeScreenBuffer = 0;
|
_fadeScreenBuffer = 0;
|
||||||
}
|
}
|
||||||
if (_screenSurface) {
|
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||||
// freed by SDL_Quit()
|
if (_window) {
|
||||||
_screenSurface = 0;
|
SDL_DestroyWindow(_window);
|
||||||
|
_window = 0;
|
||||||
}
|
}
|
||||||
|
if (_renderer) {
|
||||||
|
SDL_DestroyRenderer(_renderer);
|
||||||
|
_renderer = 0;
|
||||||
|
}
|
||||||
|
if (_fmt) {
|
||||||
|
SDL_FreeFormat(_fmt);
|
||||||
|
_fmt = 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (_surface) {
|
||||||
|
// freed by SDL_Quit()
|
||||||
|
_surface = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStub_SDL::switchGfxMode(bool fullscreen, uint8_t scaler) {
|
void SystemStub_SDL::changeGraphics(bool fullscreen, uint8_t scaler) {
|
||||||
SDL_FreeSurface(_screenSurface);
|
if (_fadeScreenBuffer) {
|
||||||
|
free(_fadeScreenBuffer);
|
||||||
|
_fadeScreenBuffer = 0;
|
||||||
|
}
|
||||||
|
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||||
|
if (_window) {
|
||||||
|
SDL_DestroyWindow(_window);
|
||||||
|
_window = 0;
|
||||||
|
}
|
||||||
|
if (_renderer) {
|
||||||
|
SDL_DestroyRenderer(_renderer);
|
||||||
|
_renderer = 0;
|
||||||
|
}
|
||||||
|
if (_fmt) {
|
||||||
|
SDL_FreeFormat(_fmt);
|
||||||
|
_fmt = 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
SDL_FreeSurface(_surface);
|
||||||
|
_surface = 0;
|
||||||
|
#endif
|
||||||
_fullscreen = fullscreen;
|
_fullscreen = fullscreen;
|
||||||
_currentScaler = scaler;
|
_scaler = scaler;
|
||||||
prepareGfxMode();
|
prepareGraphics();
|
||||||
forceGfxRedraw();
|
forceGraphicsRedraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStub_SDL::flipGfx() {
|
void SystemStub_SDL::flipGraphics() {
|
||||||
uint16_t scanline[256];
|
uint16_t scanline[256];
|
||||||
assert(_screenW <= 256);
|
assert(_screenW <= 256);
|
||||||
uint16_t *p = _screenBuffer + _screenW + 1;
|
uint16_t *p = _screenBuffer + _screenW + 1;
|
||||||
|
@ -593,10 +690,10 @@ void SystemStub_SDL::flipGfx() {
|
||||||
memcpy(p, scanline, _screenW * sizeof(uint16_t));
|
memcpy(p, scanline, _screenW * sizeof(uint16_t));
|
||||||
p += _screenW;
|
p += _screenW;
|
||||||
}
|
}
|
||||||
forceGfxRedraw();
|
forceGraphicsRedraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStub_SDL::forceGfxRedraw() {
|
void SystemStub_SDL::forceGraphicsRedraw() {
|
||||||
_numBlitRects = 1;
|
_numBlitRects = 1;
|
||||||
_blitRects[0].x = 0;
|
_blitRects[0].x = 0;
|
||||||
_blitRects[0].y = 0;
|
_blitRects[0].y = 0;
|
||||||
|
|
95
video.cpp
95
video.cpp
|
@ -25,6 +25,15 @@ Video::Video(Resource *res, SystemStub *stub)
|
||||||
_charFrontColor = 0;
|
_charFrontColor = 0;
|
||||||
_charTransparentColor = 0;
|
_charTransparentColor = 0;
|
||||||
_charShadowColor = 0;
|
_charShadowColor = 0;
|
||||||
|
_drawChar = 0;
|
||||||
|
switch (_res->_type) {
|
||||||
|
case kResourceTypeAmiga:
|
||||||
|
_drawChar = &Video::AMIGA_drawStringChar;
|
||||||
|
break;
|
||||||
|
case kResourceTypeDOS:
|
||||||
|
_drawChar = &Video::PC_drawStringChar;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Video::~Video() {
|
Video::~Video() {
|
||||||
|
@ -150,6 +159,12 @@ void Video::setPaletteSlotLE(int palSlot, const uint8_t *palData) {
|
||||||
void Video::setTextPalette() {
|
void Video::setTextPalette() {
|
||||||
debug(DBG_VIDEO, "Video::setTextPalette()");
|
debug(DBG_VIDEO, "Video::setTextPalette()");
|
||||||
setPaletteSlotLE(0xE, _textPal);
|
setPaletteSlotLE(0xE, _textPal);
|
||||||
|
if (_res->isAmiga()) {
|
||||||
|
Color c;
|
||||||
|
c.r = c.g = 0xEE;
|
||||||
|
c.b = 0;
|
||||||
|
_stub->setPaletteEntry(0xE7, &c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Video::setPalette0xF() {
|
void Video::setPalette0xF() {
|
||||||
|
@ -313,6 +328,35 @@ static void AMIGA_planar8(uint8_t *dst, int w, int h, const uint8_t *src) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AMIGA_planar24(uint8_t *dst, int w, int h, const uint8_t *src) {
|
||||||
|
assert(w == 24);
|
||||||
|
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 * 2) & mask) {
|
||||||
|
color |= 1 << bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst[i] = color;
|
||||||
|
}
|
||||||
|
src += 8;
|
||||||
|
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[16 + i] = color;
|
||||||
|
}
|
||||||
|
src += 4;
|
||||||
|
dst += w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void AMIGA_planar_mask(uint8_t *dst, int x0, int y0, int w, int h, uint8_t *src, uint8_t *mask, int size) {
|
static void AMIGA_planar_mask(uint8_t *dst, int x0, int y0, int w, int h, uint8_t *src, uint8_t *mask, int size) {
|
||||||
dst += y0 * 256 + x0;
|
dst += y0 * 256 + x0;
|
||||||
for (int y = 0; y < h; ++y) {
|
for (int y = 0; y < h; ++y) {
|
||||||
|
@ -341,22 +385,23 @@ static void AMIGA_planar_mask(uint8_t *dst, int x0, int y0, int w, int h, uint8_
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AMIGA_decodeRle(uint8_t *dst, const uint8_t *src) {
|
static void AMIGA_decodeRle(uint8_t *dst, const uint8_t *src) {
|
||||||
int code = READ_BE_UINT16(src) & 0x7FFF; src += 2;
|
const int size = READ_BE_UINT16(src) & 0x7FFF; src += 2;
|
||||||
const uint8_t *end = src + code;
|
for (int i = 0; i < size; ) {
|
||||||
do {
|
int code = src[i++];
|
||||||
code = *src++;
|
|
||||||
if ((code & 0x80) == 0) {
|
if ((code & 0x80) == 0) {
|
||||||
++code;
|
++code;
|
||||||
memcpy(dst, src, code);
|
if (i + code > size) {
|
||||||
src += code;
|
code = size - i;
|
||||||
|
}
|
||||||
|
memcpy(dst, &src[i], code);
|
||||||
|
i += code;
|
||||||
} else {
|
} else {
|
||||||
code = 1 - ((int8_t)code);
|
code = 1 - ((int8_t)code);
|
||||||
memset(dst, *src, code);
|
memset(dst, src[i], code);
|
||||||
++src;
|
++i;
|
||||||
}
|
}
|
||||||
dst += code;
|
dst += code;
|
||||||
} while (src < end);
|
}
|
||||||
assert(src == end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PC_drawTileMask(uint8_t *dst, int x0, int y0, int w, int h, uint8_t *m, uint8_t *p, int size) {
|
static void PC_drawTileMask(uint8_t *dst, int x0, int y0, int w, int h, uint8_t *m, uint8_t *p, int size) {
|
||||||
|
@ -615,12 +660,17 @@ void Video::AMIGA_decodeLev(int level, int room) {
|
||||||
// done in ::PC_setLevelPalettes
|
// done in ::PC_setLevelPalettes
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// background
|
||||||
setPaletteSlotBE(0x0, _mapPalSlot1);
|
setPaletteSlotBE(0x0, _mapPalSlot1);
|
||||||
for (int i = 1; i < 5; ++i) {
|
// objects
|
||||||
setPaletteSlotBE(i, _mapPalSlot3);
|
setPaletteSlotBE(0x1, (level == 0 || level == 1) ? _mapPalSlot3 : _mapPalSlot2);
|
||||||
}
|
setPaletteSlotBE(0x2, _mapPalSlot3);
|
||||||
setPaletteSlotBE(0x6, _mapPalSlot3);
|
setPaletteSlotBE(0x3, _mapPalSlot3);
|
||||||
|
// conrad
|
||||||
|
setPaletteSlotBE(0x4, _mapPalSlot3);
|
||||||
|
// foreground
|
||||||
setPaletteSlotBE(0x8, _mapPalSlot1);
|
setPaletteSlotBE(0x8, _mapPalSlot1);
|
||||||
|
// inventory
|
||||||
setPaletteSlotBE(0xA, _mapPalSlot3);
|
setPaletteSlotBE(0xA, _mapPalSlot3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,6 +705,9 @@ void Video::AMIGA_decodeSpc(const uint8_t *src, int w, int h, uint8_t *dst) {
|
||||||
case 32:
|
case 32:
|
||||||
AMIGA_planar16(dst, w / 16, h, 4, src);
|
AMIGA_planar16(dst, w / 16, h, 4, src);
|
||||||
break;
|
break;
|
||||||
|
case 24:
|
||||||
|
AMIGA_planar24(dst, w, h, src);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
warning("AMIGA_decodeSpc w=%d unimplemented", w);
|
warning("AMIGA_decodeSpc w=%d unimplemented", w);
|
||||||
break;
|
break;
|
||||||
|
@ -788,7 +841,7 @@ void Video::AMIGA_drawStringChar(uint8_t *dst, int pitch, const uint8_t *src, ui
|
||||||
for (int y = 0; y < 8; ++y) {
|
for (int y = 0; y < 8; ++y) {
|
||||||
for (int x = 0; x < 8; ++x) {
|
for (int x = 0; x < 8; ++x) {
|
||||||
if (src[x] != 0) {
|
if (src[x] != 0) {
|
||||||
dst[x] = 0x1D;
|
dst[x] = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
src += 16;
|
src += 16;
|
||||||
|
@ -819,15 +872,7 @@ void Video::PC_drawStringChar(uint8_t *dst, int pitch, const uint8_t *src, uint8
|
||||||
|
|
||||||
const char *Video::drawString(const char *str, int16_t x, int16_t y, uint8_t col) {
|
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);
|
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;
|
drawCharFunc dcf = _drawChar;
|
||||||
switch (_res->_type) {
|
|
||||||
case kResourceTypeAmiga:
|
|
||||||
drawCharFunc = &Video::AMIGA_drawStringChar;
|
|
||||||
break;
|
|
||||||
case kResourceTypeDOS:
|
|
||||||
drawCharFunc = &Video::PC_drawStringChar;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
uint8_t *dst = _frontLayer + y * 256 + x;
|
uint8_t *dst = _frontLayer + y * 256 + x;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -835,7 +880,7 @@ const char *Video::drawString(const char *str, int16_t x, int16_t y, uint8_t col
|
||||||
if (c == 0 || c == 0xB || c == 0xA) {
|
if (c == 0 || c == 0xB || c == 0xA) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
(this->*drawCharFunc)(dst, 256, _res->_fnt, col, c);
|
(this->*dcf)(dst, 256, _res->_fnt, col, c);
|
||||||
dst += CHAR_W;
|
dst += CHAR_W;
|
||||||
++len;
|
++len;
|
||||||
}
|
}
|
||||||
|
|
3
video.h
3
video.h
|
@ -13,6 +13,8 @@ struct Resource;
|
||||||
struct SystemStub;
|
struct SystemStub;
|
||||||
|
|
||||||
struct Video {
|
struct Video {
|
||||||
|
typedef void (Video::*drawCharFunc)(uint8_t *, int, const uint8_t *, uint8_t, uint8_t);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
GAMESCREEN_W = 256,
|
GAMESCREEN_W = 256,
|
||||||
GAMESCREEN_H = 224,
|
GAMESCREEN_H = 224,
|
||||||
|
@ -44,6 +46,7 @@ struct Video {
|
||||||
uint8_t *_screenBlocks;
|
uint8_t *_screenBlocks;
|
||||||
bool _fullRefresh;
|
bool _fullRefresh;
|
||||||
uint8_t _shakeOffset;
|
uint8_t _shakeOffset;
|
||||||
|
drawCharFunc _drawChar;
|
||||||
|
|
||||||
Video(Resource *res, SystemStub *stub);
|
Video(Resource *res, SystemStub *stub);
|
||||||
~Video();
|
~Video();
|
||||||
|
|
Loading…
Reference in New Issue