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_LIBS = `sdl-config --libs`
|
||||
VORBIS_LIBS = -lvorbisidec
|
||||
MODPLUG_LIBS = -lmodplug
|
||||
# TREMOR_LIBS = -lvorbisidec -logg
|
||||
ZLIB_LIBS = -lz
|
||||
|
||||
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 \
|
||||
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)
|
||||
DEPS = $(SRCS:.cpp=.d)
|
||||
|
||||
LIBS = $(SDL_LIBS) $(VORBIS_LIBS) $(MODPLUG_LIBS) $(ZLIB_LIBS)
|
||||
LIBS = $(SDL_LIBS) $(MODPLUG_LIBS) $(TREMOR_LIBS) $(ZLIB_LIBS)
|
||||
|
||||
rs: $(OBJS)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
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:
|
||||
----------
|
||||
|
||||
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:
|
||||
|
@ -64,6 +65,10 @@ directory. These paths can be changed using command line switches :
|
|||
Usage: rs [OPTIONS]...
|
||||
--datapath=PATH Path to data files (default 'DATA')
|
||||
--savepath=PATH Path to save files (default '.')
|
||||
--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 :
|
||||
|
126
cutscene.cpp
126
cutscene.cpp
|
@ -18,14 +18,17 @@ Cutscene::Cutscene(Resource *res, SystemStub *stub, Video *vid)
|
|||
}
|
||||
|
||||
void Cutscene::sync() {
|
||||
// XXX input handling
|
||||
if (!(_stub->_pi.dbgMask & PlayerInput::DF_FASTMODE)) {
|
||||
int32_t delay = _stub->getTimeStamp() - _tstamp;
|
||||
int32_t pause = _frameDelay * TIMER_SLICE - delay;
|
||||
if (_stub->_pi.quit) {
|
||||
return;
|
||||
}
|
||||
if (_stub->_pi.dbgMask & PlayerInput::DF_FASTMODE) {
|
||||
return;
|
||||
}
|
||||
const int32_t delay = _stub->getTimeStamp() - _tstamp;
|
||||
const int32_t pause = _frameDelay * TIMER_SLICE - delay;
|
||||
if (pause > 0) {
|
||||
_stub->sleep(pause);
|
||||
}
|
||||
}
|
||||
_tstamp = _stub->getTimeStamp();
|
||||
}
|
||||
|
||||
|
@ -90,7 +93,7 @@ uint16_t Cutscene::findTextSeparators(const uint8_t *p) {
|
|||
uint8_t *q = _textSep;
|
||||
uint16_t ret = 0;
|
||||
uint16_t pos = 0;
|
||||
for (; *p != 0xA; ++p) {
|
||||
for (; *p != 0xA && *p; ++p) {
|
||||
if (*p == 0x7C) {
|
||||
*q++ = pos;
|
||||
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) {
|
||||
debug(DBG_CUT, "Cutscene::drawText(x=%d, y=%d, c=%d)", x, y, color);
|
||||
Video::drawCharFunc dcf = _vid->_drawChar;
|
||||
uint16_t last_sep = 0;
|
||||
if (n != 0) {
|
||||
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) {
|
||||
xx += ((last_sep - *sep++) & 0xFE) * 4;
|
||||
}
|
||||
for (; *p != 0xA; ++p) {
|
||||
for (; *p != 0xA && *p; ++p) {
|
||||
if (*p == 0x7C) {
|
||||
yy += 8;
|
||||
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) {
|
||||
xx += 8;
|
||||
} else if (*p == 0x9) {
|
||||
// ignore tab
|
||||
} else {
|
||||
uint8_t *dst_char = page + 256 * yy + xx;
|
||||
const uint8_t *src = _res->_fnt + (*p - 32) * 32;
|
||||
for (int h = 0; h < 8; ++h) {
|
||||
for (int w = 0; w < 4; ++w) {
|
||||
uint8_t c1 = (*src & 0xF0) >> 4;
|
||||
uint8_t c2 = (*src & 0x0F) >> 0;
|
||||
++src;
|
||||
if (c1 != 0) {
|
||||
*dst_char = (c1 == 0xF) ? color : (0xE0 + c1);
|
||||
}
|
||||
++dst_char;
|
||||
if (c2 != 0) {
|
||||
*dst_char = (c2 == 0xF) ? color : (0xE0 + c2);
|
||||
}
|
||||
++dst_char;
|
||||
}
|
||||
dst_char += 256 - 8;
|
||||
}
|
||||
uint8_t *dst = page + 256 * yy + xx;
|
||||
(_vid->*dcf)(dst, 256, _res->_fnt, color, *p);
|
||||
xx += 8;
|
||||
}
|
||||
}
|
||||
|
@ -176,11 +166,10 @@ void Cutscene::drawCreditsText() {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (_creditsTextCounter <= 0) { // XXX
|
||||
if (_creditsTextCounter <= 0) {
|
||||
uint8_t code = *_textCurPtr;
|
||||
if (code == 0xFF) {
|
||||
_textBuf[0] = 0xA;
|
||||
// _cut_status = 0;
|
||||
} else if (code == 0xFE) {
|
||||
++_textCurPtr;
|
||||
code = *_textCurPtr++;
|
||||
|
@ -198,10 +187,11 @@ void Cutscene::drawCreditsText() {
|
|||
}
|
||||
} else {
|
||||
*_textCurBuf++ = code;
|
||||
*_textCurBuf++ = 0xA;
|
||||
*_textCurBuf = 0xA;
|
||||
++_textCurPtr;
|
||||
}
|
||||
} else {
|
||||
_creditsTextCounter -= 10; // XXX adjust
|
||||
_creditsTextCounter -= 10;
|
||||
}
|
||||
drawText((_creditsTextPosX - 1) * 8, _creditsTextPosY * 8, _textBuf, 0xEF, _page1, 0);
|
||||
}
|
||||
|
@ -270,7 +260,7 @@ void Cutscene::op_waitForSync() {
|
|||
_varText = 0xFF;
|
||||
_frameDelay = 3;
|
||||
if (_textBuf == _textCurBuf) {
|
||||
_creditsTextCounter = 20;
|
||||
_creditsTextCounter = _res->isAmiga() ? 60 : 20;
|
||||
}
|
||||
memcpy(_page1, _page0, _vid->_layerSize);
|
||||
drawCreditsText();
|
||||
|
@ -385,6 +375,16 @@ void Cutscene::op_drawStringAtBottom() {
|
|||
debug(DBG_CUT, "Cutscene::op_drawStringAtBottom()");
|
||||
uint16_t strId = fetchNextCmdWord();
|
||||
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(_page1 + 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);
|
||||
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 ((_cmdPtr - _cmdPtrBak) == 0xA) {
|
||||
_stub->copyRect(0, 0, _vid->_w, _vid->_h, _page1, 256);
|
||||
|
@ -964,13 +964,30 @@ void Cutscene::load(uint16_t cutName) {
|
|||
name = "INTRO";
|
||||
}
|
||||
_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;
|
||||
case kResourceTypeDOS:
|
||||
_res->load(name, Resource::OT_CMD);
|
||||
_res->load(name, Resource::OT_POL);
|
||||
_res->load_CINE();
|
||||
break;
|
||||
}
|
||||
_res->load_CINE();
|
||||
}
|
||||
|
||||
void Cutscene::prepare() {
|
||||
|
@ -986,12 +1003,11 @@ void Cutscene::prepare() {
|
|||
_gfx.setClippingRect(8, 50, 240, 128);
|
||||
}
|
||||
|
||||
void Cutscene::startCredits() {
|
||||
_textCurPtr = _creditsData;
|
||||
void Cutscene::playCredits() {
|
||||
_textCurPtr = _res->isAmiga() ? _creditsDataAmiga : _creditsDataDOS;
|
||||
_textBuf[0] = 0xA;
|
||||
_textCurBuf = _textBuf;
|
||||
_creditsSequence = true;
|
||||
// _cut_status = 1;
|
||||
_varText = 0;
|
||||
_textUnk2 = 0;
|
||||
_creditsTextCounter = 0;
|
||||
|
@ -1011,6 +1027,37 @@ void Cutscene::startCredits() {
|
|||
_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() {
|
||||
if (_id != 0xFFFF) {
|
||||
_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);
|
||||
mainLoop(cutOff);
|
||||
}
|
||||
|
|
12
cutscene.h
12
cutscene.h
|
@ -22,16 +22,23 @@ struct Cutscene {
|
|||
TIMER_SLICE = 15
|
||||
};
|
||||
|
||||
struct Text {
|
||||
int num;
|
||||
const char *str;
|
||||
};
|
||||
|
||||
static const OpcodeStub _opcodeTable[];
|
||||
static const char *_namesTable[];
|
||||
static const uint16_t _offsetsTable[];
|
||||
static const uint8_t _amigaDemoOffsetsTable[];
|
||||
static const uint16_t _cosTable[];
|
||||
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 uint8_t _musicTable[];
|
||||
static const uint8_t _protectionShapeData[];
|
||||
static const Text _frTextsTable[];
|
||||
|
||||
Graphics _gfx;
|
||||
Resource *_res;
|
||||
|
@ -118,7 +125,8 @@ struct Cutscene {
|
|||
void mainLoop(uint16_t offset);
|
||||
void load(uint16_t cutName);
|
||||
void prepare();
|
||||
void startCredits();
|
||||
void playCredits();
|
||||
void playText(const char *str);
|
||||
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;
|
||||
};
|
||||
|
||||
struct stdFile : File_impl {
|
||||
struct StdioFile : File_impl {
|
||||
FILE *_fp;
|
||||
stdFile() : _fp(0) {}
|
||||
StdioFile() : _fp(0) {}
|
||||
bool open(const char *path, const char *mode) {
|
||||
_ioErr = false;
|
||||
_fp = fopen(path, mode);
|
||||
|
@ -76,9 +76,9 @@ struct stdFile : File_impl {
|
|||
};
|
||||
|
||||
#ifdef USE_ZLIB
|
||||
struct zlibFile : File_impl {
|
||||
struct GzipFile : File_impl {
|
||||
gzFile _fp;
|
||||
zlibFile() : _fp(0) {}
|
||||
GzipFile() : _fp(0) {}
|
||||
bool open(const char *path, const char *mode) {
|
||||
_ioErr = false;
|
||||
_fp = gzopen(path, mode);
|
||||
|
@ -147,7 +147,7 @@ bool File::open(const char *filename, const char *mode, FileSystem *fs) {
|
|||
_impl = 0;
|
||||
}
|
||||
assert(mode[0] != 'z');
|
||||
_impl = new stdFile;
|
||||
_impl = new StdioFile;
|
||||
char *path = fs->findPath(filename);
|
||||
if (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
|
||||
if (mode[0] == 'z') {
|
||||
_impl = new zlibFile;
|
||||
_impl = new GzipFile;
|
||||
++mode;
|
||||
}
|
||||
#endif
|
||||
if (!_impl) {
|
||||
_impl = new stdFile;
|
||||
_impl = new StdioFile;
|
||||
}
|
||||
char path[MAXPATHLEN];
|
||||
snprintf(path, sizeof(path), "%s/%s", directory, filename);
|
||||
|
|
21
game.cpp
21
game.cpp
|
@ -69,21 +69,26 @@ void Game::run() {
|
|||
break;
|
||||
}
|
||||
|
||||
if (_res.isAmiga()) {
|
||||
displayTitleScreenAmiga();
|
||||
_stub->setScreenSize(Video::GAMESCREEN_W, Video::GAMESCREEN_H);
|
||||
}
|
||||
|
||||
while (!_stub->_pi.quit) {
|
||||
if (_res.isDOS()) {
|
||||
switch (_res._type) {
|
||||
case kResourceTypeDOS:
|
||||
_mix.playMusic(1);
|
||||
_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;
|
||||
}
|
||||
_skillLevel = _menu._skill;
|
||||
_currentLevel = _menu._level;
|
||||
_mix.stopMusic();
|
||||
break;
|
||||
case kResourceTypeAmiga:
|
||||
displayTitleScreenAmiga();
|
||||
_stub->setScreenSize(Video::GAMESCREEN_W, Video::GAMESCREEN_H);
|
||||
break;
|
||||
}
|
||||
if (_stub->_pi.quit) {
|
||||
break;
|
||||
}
|
||||
if (_currentLevel == 7) {
|
||||
_vid.fadeOut();
|
||||
|
@ -328,7 +333,7 @@ void Game::playCutscene(int id) {
|
|||
_cut.play();
|
||||
}
|
||||
if (id == 0x3D) {
|
||||
_cut.startCredits();
|
||||
_cut.playCredits();
|
||||
}
|
||||
_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];
|
||||
}
|
||||
|
||||
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>
|
||||
inline void SWAP(T &a, T &b) {
|
||||
T tmp = a;
|
||||
|
@ -72,6 +92,7 @@ struct Options {
|
|||
bool enable_password_menu;
|
||||
bool fade_out_palette;
|
||||
bool use_tiledata;
|
||||
bool use_text_cutscenes;
|
||||
};
|
||||
|
||||
struct Color {
|
||||
|
|
31
main.cpp
31
main.cpp
|
@ -19,9 +19,10 @@ static const char *USAGE =
|
|||
"Usage: %s [OPTIONS]...\n"
|
||||
" --datapath=PATH Path to data files (default 'DATA')\n"
|
||||
" --savepath=PATH Path to save files (default '.')\n"
|
||||
" --levelnum=NUM Start level (default '0')\n"
|
||||
" --fullscreen Start fullscreen\n"
|
||||
" --levelnum=NUM Level to start from (default '0')\n"
|
||||
" --fullscreen Fullscreen display\n"
|
||||
" --scaler=INDEX Graphics scaler\n"
|
||||
" --language=LANG Language (fr,en,de,sp,it)\n"
|
||||
;
|
||||
|
||||
static int detectVersion(FileSystem *fs) {
|
||||
|
@ -80,6 +81,7 @@ static void initOptions() {
|
|||
g_options.play_disabled_cutscenes = false;
|
||||
g_options.enable_password_menu = false;
|
||||
g_options.fade_out_palette = true;
|
||||
g_options.use_text_cutscenes = false;
|
||||
// read configuration file
|
||||
struct {
|
||||
const char *name;
|
||||
|
@ -90,6 +92,7 @@ static void initOptions() {
|
|||
{ "enable_password_menu", &g_options.enable_password_menu },
|
||||
{ "fade_out_palette", &g_options.fade_out_palette },
|
||||
{ "use_tiledata", &g_options.use_tiledata },
|
||||
{ "use_text_cutscenes", &g_options.use_text_cutscenes },
|
||||
{ 0, 0 }
|
||||
};
|
||||
static const char *filename = "rs.cfg";
|
||||
|
@ -130,6 +133,7 @@ int main(int argc, char *argv[]) {
|
|||
int levelNum = 0;
|
||||
int scaler = DEFAULT_SCALER;
|
||||
bool fullscreen = false;
|
||||
int forcedLanguage = -1;
|
||||
if (argc == 2) {
|
||||
// data path as the only command line argument
|
||||
struct stat st;
|
||||
|
@ -144,6 +148,7 @@ int main(int argc, char *argv[]) {
|
|||
{ "levelnum", required_argument, 0, 3 },
|
||||
{ "fullscreen", no_argument, 0, 4 },
|
||||
{ "scaler", required_argument, 0, 5 },
|
||||
{ "language", required_argument, 0, 6 },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
int index;
|
||||
|
@ -170,6 +175,26 @@ int main(int argc, char *argv[]) {
|
|||
scaler = DEFAULT_SCALER;
|
||||
}
|
||||
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:
|
||||
printf(USAGE, argv[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");
|
||||
return -1;
|
||||
}
|
||||
Language language = detectLanguage(&fs);
|
||||
const Language language = (forcedLanguage == -1) ? detectLanguage(&fs) : (Language)forcedLanguage;
|
||||
SystemStub *stub = SystemStub_SDL_create();
|
||||
Game *g = new Game(stub, &fs, savePath, levelNum, (ResourceType)version, language);
|
||||
stub->init(g_caption, Video::GAMESCREEN_W, Video::GAMESCREEN_H, scaler, fullscreen);
|
||||
|
|
40
mixer.cpp
40
mixer.cpp
|
@ -101,13 +101,20 @@ void Mixer::playMusic(int num) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (_musicType == MT_OGG && isMusicSfx(num)) { // do not play level action music with background music
|
||||
return;
|
||||
}
|
||||
if (isMusicSfx(num)) { // level action sequence
|
||||
_sfx.play(num);
|
||||
if (_sfx._playing) {
|
||||
_musicType = MT_SFX;
|
||||
}
|
||||
} else { // cutscene
|
||||
_mod.play(num);
|
||||
if (_mod._playing) {
|
||||
_musicType = MT_MOD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mixer::stopMusic() {
|
||||
|
@ -119,8 +126,7 @@ void Mixer::stopMusic() {
|
|||
_mod.stop();
|
||||
break;
|
||||
case MT_OGG:
|
||||
_ogg.stopTrack();
|
||||
_musicTrack = -1;
|
||||
_ogg.pauseTrack();
|
||||
break;
|
||||
case MT_SFX:
|
||||
_sfx.stop();
|
||||
|
@ -133,20 +139,9 @@ void Mixer::stopMusic() {
|
|||
}
|
||||
}
|
||||
|
||||
static void nr(const int8_t *in, int len, int8_t *out) {
|
||||
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);
|
||||
void Mixer::mix(int16_t *out, int len) {
|
||||
if (_premixHook) {
|
||||
if (!_premixHook(_premixHookData, buf, len)) {
|
||||
if (!_premixHook(_premixHookData, out, len)) {
|
||||
_premixHook = 0;
|
||||
_premixHookData = 0;
|
||||
}
|
||||
|
@ -160,24 +155,13 @@ void Mixer::mix(int8_t *out, int len) {
|
|||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
nr(buf, len, out);
|
||||
}
|
||||
|
||||
void Mixer::addclamp(int8_t& a, int b) {
|
||||
int add = a + b;
|
||||
if (add < -128) {
|
||||
add = -128;
|
||||
} else if (add > 127) {
|
||||
add = 127;
|
||||
}
|
||||
a = add;
|
||||
}
|
||||
|
||||
void Mixer::mixCallback(void *param, int8_t *buf, int len) {
|
||||
void Mixer::mixCallback(void *param, int16_t *buf, int len) {
|
||||
((Mixer *)param)->mix(buf, len);
|
||||
}
|
||||
|
|
7
mixer.h
7
mixer.h
|
@ -42,7 +42,7 @@ struct FileSystem;
|
|||
struct SystemStub;
|
||||
|
||||
struct Mixer {
|
||||
typedef bool (*PremixHook)(void *userData, int8_t *buf, int len);
|
||||
typedef bool (*PremixHook)(void *userData, int16_t *buf, int len);
|
||||
|
||||
enum MusicType {
|
||||
MT_NONE,
|
||||
|
@ -79,10 +79,9 @@ struct Mixer {
|
|||
void stopAll();
|
||||
void playMusic(int num);
|
||||
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, int8_t *buf, int len);
|
||||
static void mixCallback(void *param, int16_t *buf, int len);
|
||||
};
|
||||
|
||||
#endif // MIXER_H__
|
||||
|
|
|
@ -27,7 +27,7 @@ struct ModPlayer_impl {
|
|||
ModPlug_GetSettings(&_settings);
|
||||
_settings.mFlags = MODPLUG_ENABLE_OVERSAMPLING | MODPLUG_ENABLE_NOISE_REDUCTION;
|
||||
_settings.mChannels = 1;
|
||||
_settings.mBits = 8;
|
||||
_settings.mBits = 16;
|
||||
_settings.mFrequency = rate;
|
||||
_settings.mResamplingMode = MODPLUG_RESAMPLE_FIR;
|
||||
ModPlug_SetSettings(&_settings);
|
||||
|
@ -50,18 +50,14 @@ struct ModPlayer_impl {
|
|||
}
|
||||
}
|
||||
|
||||
bool mix(int8_t *buf, int len) {
|
||||
memset(buf, 0, len);
|
||||
bool mix(int16_t *buf, int len) {
|
||||
if (_mf) {
|
||||
const int order = ModPlug_GetCurrentOrder(_mf);
|
||||
if (order == 3 && _repeatIntro) {
|
||||
ModPlug_SeekOrder(_mf, 1);
|
||||
_repeatIntro = false;
|
||||
}
|
||||
const int count = ModPlug_Read(_mf, buf, len);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
buf[i] ^= 0x80;
|
||||
}
|
||||
const int count = ModPlug_Read(_mf, buf, len * sizeof(int16_t));
|
||||
return count > 0;
|
||||
}
|
||||
return false;
|
||||
|
@ -152,7 +148,8 @@ struct ModPlayer_impl {
|
|||
void applyPortamento(int trackNum);
|
||||
void handleEffect(int trackNum, bool tick);
|
||||
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()
|
||||
|
@ -607,7 +604,8 @@ void ModPlayer_impl::mixSamples(int8_t *buf, int samplesLen) {
|
|||
}
|
||||
while (count--) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
memset(buf, 0, len);
|
||||
const int samplesPerTick = _mixingRate / (50 * _songTempo / 125);
|
||||
while (len != 0) {
|
||||
if (_samplesLeft == 0) {
|
||||
|
@ -637,6 +634,16 @@ bool ModPlayer_impl::mix(int8_t *buf, int len) {
|
|||
}
|
||||
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
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ struct ModPlayer {
|
|||
void play(int num);
|
||||
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__
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "file.h"
|
||||
#include "mixer.h"
|
||||
#include "ogg_player.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef USE_TREMOR
|
||||
struct VorbisFile: File {
|
||||
|
@ -85,7 +86,7 @@ struct OggDecoder_impl {
|
|||
_channels = vi->channels;
|
||||
return true;
|
||||
}
|
||||
int read(int8_t *dst, int samples) {
|
||||
int read(int16_t *dst, int samples) {
|
||||
int size = samples * _channels * sizeof(int16_t);
|
||||
if (size > _readBufSize) {
|
||||
_readBufSize = size;
|
||||
|
@ -100,22 +101,26 @@ struct OggDecoder_impl {
|
|||
const int len = ov_read(&_ovf, (char *)_readBuf, size, 0);
|
||||
if (len < 0) {
|
||||
// error in decoder
|
||||
return 0;
|
||||
return count;
|
||||
} else if (len == 0) {
|
||||
// loop
|
||||
ov_raw_seek(&_ovf, 0);
|
||||
continue;
|
||||
}
|
||||
assert((len & 1) == 0);
|
||||
switch (_channels) {
|
||||
case 2:
|
||||
assert((len & 1) == 0);
|
||||
assert((len & 3) == 0);
|
||||
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;
|
||||
case 1:
|
||||
for (int i = 0; i < len / 2; ++i) {
|
||||
Mixer::addclamp(*dst++, _readBuf[i] >> 8);
|
||||
*dst = ADDC_S16(*dst, _readBuf[i]);
|
||||
++dst;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -188,7 +193,7 @@ void OggPlayer::resumeTrack() {
|
|||
#endif
|
||||
}
|
||||
|
||||
bool OggPlayer::mix(int8_t *buf, int len) {
|
||||
bool OggPlayer::mix(int16_t *buf, int len) {
|
||||
#ifdef USE_TREMOR
|
||||
if (_impl) {
|
||||
return _impl->read(buf, len) != 0;
|
||||
|
@ -197,7 +202,7 @@ bool OggPlayer::mix(int8_t *buf, int len) {
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@ struct OggPlayer {
|
|||
void pauseTrack();
|
||||
void resumeTrack();
|
||||
bool isPlaying() const { return _impl != 0; }
|
||||
bool mix(int8_t *buf, int len);
|
||||
static bool mixCallback(void *param, int8_t *buf, int len);
|
||||
bool mix(int16_t *buf, int len);
|
||||
static bool mixCallback(void *param, int16_t *buf, int len);
|
||||
|
||||
Mixer *_mix;
|
||||
FileSystem *_fs;
|
||||
|
|
69
resource.cpp
69
resource.cpp
|
@ -269,28 +269,65 @@ void Resource::load_SPR_OFF(const char *fileName, uint8_t *sprData) {
|
|||
error("Cannot load '%s'", _entryName);
|
||||
}
|
||||
|
||||
void Resource::load_CINE() {
|
||||
const char *baseName = 0;
|
||||
switch (_lang) {
|
||||
static const char *getCineName(Language lang, ResourceType type) {
|
||||
switch (lang) {
|
||||
case LANG_FR:
|
||||
baseName = "FR_CINE";
|
||||
break;
|
||||
case LANG_EN:
|
||||
baseName = "ENGCINE";
|
||||
break;
|
||||
if (type == kResourceTypeAmiga) {
|
||||
return "FR";
|
||||
}
|
||||
return "FR_";
|
||||
case LANG_DE:
|
||||
baseName = "GERCINE";
|
||||
break;
|
||||
return "GER";
|
||||
case LANG_SP:
|
||||
baseName = "SPACINE";
|
||||
break;
|
||||
return "SPA";
|
||||
case LANG_IT:
|
||||
baseName = "ITACINE";
|
||||
return "ITA";
|
||||
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;
|
||||
}
|
||||
debug(DBG_RES, "Resource::load_CINE('%s')", baseName);
|
||||
p = sep + 1;
|
||||
}
|
||||
}
|
||||
if (!_cine_txt) {
|
||||
error("Cannot load '%s'", _entryName);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (_cine_off == 0) {
|
||||
snprintf(_entryName, sizeof(_entryName), "%s.BIN", baseName);
|
||||
snprintf(_entryName, sizeof(_entryName), "%sCINE.BIN", prefix);
|
||||
File f;
|
||||
if (f.open(_entryName, "rb", _fs)) {
|
||||
int len = f.size();
|
||||
|
@ -310,7 +347,7 @@ void Resource::load_CINE() {
|
|||
}
|
||||
}
|
||||
if (_cine_txt == 0) {
|
||||
snprintf(_entryName, sizeof(_entryName), "%s.TXT", baseName);
|
||||
snprintf(_entryName, sizeof(_entryName), "%sCINE.TXT", prefix);
|
||||
File f;
|
||||
if (f.open(_entryName, "rb", _fs)) {
|
||||
int len = f.size();
|
||||
|
|
|
@ -90,6 +90,7 @@ struct Resource {
|
|||
enum {
|
||||
NUM_SFXS = 66,
|
||||
NUM_BANK_BUFFERS = 50,
|
||||
NUM_CUTSCENE_TEXTS = 117,
|
||||
NUM_SPRITES = 1287
|
||||
};
|
||||
|
||||
|
@ -135,6 +136,7 @@ struct Resource {
|
|||
uint8_t _numSfx;
|
||||
uint8_t *_cmd;
|
||||
uint8_t *_pol;
|
||||
uint8_t *_cineStrings[NUM_CUTSCENE_TEXTS];
|
||||
uint8_t *_cine_off;
|
||||
uint8_t *_cine_txt;
|
||||
char **_extTextsTable;
|
||||
|
@ -209,7 +211,7 @@ struct Resource {
|
|||
const int offset = READ_BE_UINT16(_cine_off + num * 2);
|
||||
return _cine_txt + offset;
|
||||
}
|
||||
return 0;
|
||||
return (num >= 0 && num < NUM_CUTSCENE_TEXTS) ? _cineStrings[num] : 0;
|
||||
}
|
||||
const char *getMenuString(int 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_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);
|
||||
}
|
||||
|
||||
void SeqDemuxer::readAudioS8(uint8_t *dst) {
|
||||
void SeqDemuxer::readAudio(int16_t *dst) {
|
||||
_f->seek(_frameOffset + _audioDataOffset);
|
||||
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) {
|
||||
SoundBufferQueue *sbq = (SoundBufferQueue *)malloc(sizeof(SoundBufferQueue));
|
||||
if (sbq) {
|
||||
sbq->data = (uint8_t *)malloc(SeqDemuxer::kAudioBufferSize);
|
||||
sbq->data = (int16_t *)calloc(SeqDemuxer::kAudioBufferSize, sizeof(int16_t));
|
||||
if (sbq->data) {
|
||||
_demux.readAudioS8(sbq->data);
|
||||
_demux.readAudio(sbq->data);
|
||||
sbq->size = SeqDemuxer::kAudioBufferSize;
|
||||
sbq->read = 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) {
|
||||
return true;
|
||||
}
|
||||
|
@ -350,7 +350,7 @@ bool SeqPlayer::mix(int8_t *buf, int samples) {
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ struct SeqDemuxer {
|
|||
void fillBuffer(int num, int offset, int size);
|
||||
void clearBuffer(int num);
|
||||
void readPalette(uint8_t *dst);
|
||||
void readAudioS8(uint8_t *dst);
|
||||
void readAudio(int16_t *dst);
|
||||
|
||||
int _frameOffset;
|
||||
int _audioDataOffset;
|
||||
|
@ -55,7 +55,7 @@ struct SeqPlayer {
|
|||
static const char *_namesTable[];
|
||||
|
||||
struct SoundBufferQueue {
|
||||
uint8_t *data;
|
||||
int16_t *data;
|
||||
int size;
|
||||
int read;
|
||||
SoundBufferQueue *next;
|
||||
|
@ -66,8 +66,8 @@ struct SeqPlayer {
|
|||
|
||||
void setBackBuffer(uint8_t *buf) { _buf = buf; }
|
||||
void play(File *f);
|
||||
bool mix(int8_t *buf, int len);
|
||||
static bool mixCallback(void *param, int8_t *buf, int len);
|
||||
bool mix(int16_t *buf, int len);
|
||||
static bool mixCallback(void *param, int16_t *buf, int len);
|
||||
|
||||
SystemStub *_stub;
|
||||
uint8_t *_buf;
|
||||
|
|
|
@ -127,7 +127,8 @@ void SfxPlayer::mixSamples(int8_t *buf, int samplesLen) {
|
|||
}
|
||||
while (count--) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -138,7 +139,6 @@ void SfxPlayer::mixSamples(int8_t *buf, int samplesLen) {
|
|||
|
||||
bool SfxPlayer::mix(int8_t *buf, int len) {
|
||||
if (_playing) {
|
||||
memset(buf, 0, len);
|
||||
const int samplesPerTick = _mix->getSampleRate() / 50;
|
||||
while (len != 0) {
|
||||
if (_samplesLeft == 0) {
|
||||
|
@ -158,6 +158,12 @@ bool SfxPlayer::mix(int8_t *buf, int len) {
|
|||
return _playing;
|
||||
}
|
||||
|
||||
bool SfxPlayer::mixCallback(void *param, int8_t *buf, int len) {
|
||||
return ((SfxPlayer *)param)->mix(buf, len);
|
||||
bool SfxPlayer::mixCallback(void *param, int16_t *samples, int 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 playSample(int channel, const uint8_t *sampleData, uint16_t period);
|
||||
void handleTick();
|
||||
bool mix(int8_t *buf, int len);
|
||||
void mixSamples(int8_t *buf, int samplesLen);
|
||||
void mixSamples(int8_t *samples, 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__
|
||||
|
|
183
staticres.cpp
183
staticres.cpp
|
@ -188,7 +188,7 @@ const uint16_t Cutscene::_sinTable[] = {
|
|||
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,
|
||||
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,
|
||||
|
@ -356,6 +356,164 @@ const uint8_t Cutscene::_creditsData[] = {
|
|||
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[] = {
|
||||
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
|
||||
};
|
||||
|
||||
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[] = {
|
||||
{ "level1", "level1", "level1", 0x00, 1, 3 },
|
||||
{ "level2", "level2", "level2", 0x2F, 1, 4 },
|
||||
|
|
|
@ -45,7 +45,7 @@ struct PlayerInput {
|
|||
};
|
||||
|
||||
struct SystemStub {
|
||||
typedef void (*AudioCallback)(void *param, int8_t *stream, int len);
|
||||
typedef void (*AudioCallback)(void *param, int16_t *stream, int len);
|
||||
|
||||
PlayerInput _pi;
|
||||
|
||||
|
|
|
@ -9,26 +9,31 @@
|
|||
#include "systemstub.h"
|
||||
#include "util.h"
|
||||
|
||||
struct SystemStub_SDL : SystemStub {
|
||||
enum {
|
||||
MAX_BLIT_RECTS = 200,
|
||||
SOUND_SAMPLE_RATE = 22050,
|
||||
JOYSTICK_COMMIT_VALUE = 3200
|
||||
};
|
||||
static const int kAudioHz = 22050;
|
||||
static const int kJoystickCommitValue = 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 *_fadeScreenBuffer;
|
||||
SDL_Surface *_screenSurface;
|
||||
bool _fullscreen;
|
||||
int _currentScaler;
|
||||
int _scaler;
|
||||
uint8_t _overscanColor;
|
||||
uint16_t _pal[256];
|
||||
int _screenW, _screenH;
|
||||
SDL_Joystick *_joystick;
|
||||
SDL_Rect _blitRects[MAX_BLIT_RECTS];
|
||||
SDL_Rect _blitRects[200];
|
||||
int _numBlitRects;
|
||||
bool _fadeOnUpdateScreen;
|
||||
void (*_audioCbProc)(void *, int8_t *, int);
|
||||
void (*_audioCbProc)(void *, int16_t *, int);
|
||||
void *_audioCbData;
|
||||
int _screenshot;
|
||||
|
||||
|
@ -53,11 +58,11 @@ struct SystemStub_SDL : SystemStub {
|
|||
virtual void unlockAudio();
|
||||
|
||||
void processEvent(const SDL_Event &ev, bool &paused);
|
||||
void prepareGfxMode();
|
||||
void cleanupGfxMode();
|
||||
void switchGfxMode(bool fullscreen, uint8_t scaler);
|
||||
void flipGfx();
|
||||
void forceGfxRedraw();
|
||||
void prepareGraphics();
|
||||
void cleanupGraphics();
|
||||
void changeGraphics(bool fullscreen, uint8_t scaler);
|
||||
void flipGraphics();
|
||||
void forceGraphicsRedraw();
|
||||
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) {
|
||||
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK);
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
SDL_WM_SetCaption(title, NULL);
|
||||
_caption = title;
|
||||
memset(&_pi, 0, sizeof(_pi));
|
||||
_screenBuffer = 0;
|
||||
_fadeScreenBuffer = 0;
|
||||
_fadeOnUpdateScreen = false;
|
||||
_fullscreen = fullscreen;
|
||||
_currentScaler = scaler;
|
||||
_scaler = scaler;
|
||||
memset(_pal, 0, sizeof(_pal));
|
||||
_screenW = _screenH = 0;
|
||||
setScreenSize(w, h);
|
||||
_joystick = NULL;
|
||||
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() {
|
||||
cleanupGfxMode();
|
||||
if (SDL_JoystickOpened(0)) {
|
||||
cleanupGraphics();
|
||||
if (_joystick) {
|
||||
SDL_JoystickClose(_joystick);
|
||||
_joystick = 0;
|
||||
}
|
||||
SDL_Quit();
|
||||
}
|
||||
|
@ -108,7 +115,7 @@ void SystemStub_SDL::setScreenSize(int w, int h) {
|
|||
}
|
||||
_screenW = w;
|
||||
_screenH = h;
|
||||
prepareGfxMode();
|
||||
prepareGraphics();
|
||||
}
|
||||
|
||||
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 g = pal[i * 3 + 1];
|
||||
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) {
|
||||
_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) {
|
||||
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) {
|
||||
|
@ -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) {
|
||||
if (_numBlitRects >= MAX_BLIT_RECTS) {
|
||||
if (_numBlitRects >= ARRAYSIZE(_blitRects)) {
|
||||
warning("SystemStub_SDL::copyRect() Too many blit rects, you may experience graphical glitches");
|
||||
} else {
|
||||
// extend the dirty region by 1 pixel for scalers accessing 'outer' pixels
|
||||
|
@ -211,24 +218,39 @@ static uint16_t blendPixel16(uint16_t colorSrc, uint16_t colorDst, uint32_t mask
|
|||
}
|
||||
|
||||
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) {
|
||||
const int tempScreenBufferSize = (_screenH + 2) * (_screenW + 2) * sizeof(uint16_t);
|
||||
uint16_t *tempScreenBuffer = (uint16_t *)calloc(tempScreenBufferSize, 1);
|
||||
assert(tempScreenBuffer);
|
||||
const SDL_PixelFormat *pf = _screenSurface->format;
|
||||
const uint32_t colorMask = (pf->Gmask << 16) | (pf->Rmask | pf->Bmask);
|
||||
const uint32_t colorMask = (_fmt->Gmask << 16) | (_fmt->Rmask | _fmt->Bmask);
|
||||
const uint16_t *screenBuffer = _screenBuffer + _screenW + 1;
|
||||
for (int i = 1; i <= 16; ++i) {
|
||||
for (int x = 0; x < _screenH * _screenW; ++x) {
|
||||
tempScreenBuffer[_screenW + 1 + x] = blendPixel16(_fadeScreenBuffer[x], screenBuffer[x], colorMask, i);
|
||||
}
|
||||
SDL_LockSurface(_screenSurface);
|
||||
uint16_t *dst = (uint16_t *)_screenSurface->pixels;
|
||||
SDL_LockSurface(_surface);
|
||||
uint16_t *dst = (uint16_t *)_surface->pixels;
|
||||
const uint16_t *src = tempScreenBuffer + _screenW + 1;
|
||||
(*_scalers[_currentScaler].proc)(dst, _screenSurface->pitch, src, _screenW, _screenW, _screenH);
|
||||
SDL_UnlockSurface(_screenSurface);
|
||||
SDL_UpdateRect(_screenSurface, 0, 0, _screenW * mul, _screenH * mul);
|
||||
(*_scalers[_scaler].proc)(dst, _surface->pitch, src, _screenW, _screenW, _screenH);
|
||||
SDL_UnlockSurface(_surface);
|
||||
SDL_UpdateRect(_surface, 0, 0, _screenW * mul, _screenH * mul);
|
||||
SDL_Delay(30);
|
||||
}
|
||||
free(tempScreenBuffer);
|
||||
|
@ -240,35 +262,36 @@ void SystemStub_SDL::updateScreen(int shakeOffset) {
|
|||
SDL_Rect *br = &_blitRects[i];
|
||||
int dx = br->x * mul;
|
||||
int dy = br->y * mul;
|
||||
SDL_LockSurface(_screenSurface);
|
||||
uint16_t *dst = (uint16_t *)_screenSurface->pixels + dy * _screenSurface->pitch / 2 + dx;
|
||||
SDL_LockSurface(_surface);
|
||||
uint16_t *dst = (uint16_t *)_surface->pixels + dy * _surface->pitch / 2 + dx;
|
||||
const uint16_t *src = _screenBuffer + (br->y + 1) * _screenW + (br->x + 1);
|
||||
(*_scalers[_currentScaler].proc)(dst, _screenSurface->pitch, src, _screenW, br->w, br->h);
|
||||
SDL_UnlockSurface(_screenSurface);
|
||||
(*_scalers[_scaler].proc)(dst, _surface->pitch, src, _screenW, br->w, br->h);
|
||||
SDL_UnlockSurface(_surface);
|
||||
br->x *= mul;
|
||||
br->y *= mul;
|
||||
br->w *= mul;
|
||||
br->h *= mul;
|
||||
}
|
||||
SDL_UpdateRects(_screenSurface, _numBlitRects, _blitRects);
|
||||
SDL_UpdateRects(_surface, _numBlitRects, _blitRects);
|
||||
} else {
|
||||
SDL_LockSurface(_screenSurface);
|
||||
SDL_LockSurface(_surface);
|
||||
int w = _screenW;
|
||||
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;
|
||||
(*_scalers[_currentScaler].proc)(dst, _screenSurface->pitch, src, _screenW, w, h);
|
||||
SDL_UnlockSurface(_screenSurface);
|
||||
(*_scalers[_scaler].proc)(dst, _surface->pitch, src, _screenW, w, h);
|
||||
SDL_UnlockSurface(_surface);
|
||||
|
||||
SDL_Rect r;
|
||||
r.x = 0;
|
||||
r.y = 0;
|
||||
r.w = _screenW * 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;
|
||||
}
|
||||
|
||||
|
@ -294,13 +317,26 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
|
|||
case SDL_QUIT:
|
||||
_pi.quit = true;
|
||||
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:
|
||||
if (ev.active.state & SDL_APPINPUTFOCUS) {
|
||||
paused = ev.active.gain == 0;
|
||||
SDL_PauseAudio(paused ? 1 : 0);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case SDL_JOYHATMOTION:
|
||||
if (_joystick) {
|
||||
_pi.dirMask = 0;
|
||||
if (ev.jhat.value & SDL_HAT_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) {
|
||||
_pi.dirMask |= PlayerInput::DIR_RIGHT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_JOYAXISMOTION:
|
||||
if (_joystick) {
|
||||
switch (ev.jaxis.axis) {
|
||||
case 0:
|
||||
if (ev.jaxis.value > JOYSTICK_COMMIT_VALUE) {
|
||||
_pi.dirMask |= PlayerInput::DIR_RIGHT;
|
||||
if (_pi.dirMask & PlayerInput::DIR_LEFT) {
|
||||
_pi.dirMask &= ~PlayerInput::DIR_LEFT;
|
||||
}
|
||||
} else if (ev.jaxis.value < -JOYSTICK_COMMIT_VALUE) {
|
||||
_pi.dirMask |= PlayerInput::DIR_LEFT;
|
||||
if (_pi.dirMask & PlayerInput::DIR_RIGHT) {
|
||||
_pi.dirMask &= ~PlayerInput::DIR_RIGHT;
|
||||
}
|
||||
} else {
|
||||
_pi.dirMask &= ~(PlayerInput::DIR_RIGHT | PlayerInput::DIR_LEFT);
|
||||
if (ev.jaxis.value > kJoystickCommitValue) {
|
||||
_pi.dirMask |= PlayerInput::DIR_RIGHT;
|
||||
} else if (ev.jaxis.value < -kJoystickCommitValue) {
|
||||
_pi.dirMask |= PlayerInput::DIR_LEFT;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (ev.jaxis.value > JOYSTICK_COMMIT_VALUE) {
|
||||
_pi.dirMask |= PlayerInput::DIR_DOWN;
|
||||
if (_pi.dirMask & PlayerInput::DIR_UP) {
|
||||
_pi.dirMask &= ~PlayerInput::DIR_UP;
|
||||
}
|
||||
} else if (ev.jaxis.value < -JOYSTICK_COMMIT_VALUE) {
|
||||
_pi.dirMask |= PlayerInput::DIR_UP;
|
||||
if (_pi.dirMask & PlayerInput::DIR_DOWN) {
|
||||
_pi.dirMask &= ~PlayerInput::DIR_DOWN;
|
||||
}
|
||||
} else {
|
||||
_pi.dirMask &= ~(PlayerInput::DIR_UP | PlayerInput::DIR_DOWN);
|
||||
if (ev.jaxis.value > kJoystickCommitValue) {
|
||||
_pi.dirMask |= PlayerInput::DIR_DOWN;
|
||||
} else if (ev.jaxis.value < -kJoystickCommitValue) {
|
||||
_pi.dirMask |= PlayerInput::DIR_UP;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
if (_joystick) {
|
||||
switch (ev.jbutton.button) {
|
||||
case 0:
|
||||
_pi.space = true;
|
||||
|
@ -364,8 +390,10 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
|
|||
_pi.backspace = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_JOYBUTTONUP:
|
||||
if (_joystick) {
|
||||
switch (ev.jbutton.button) {
|
||||
case 0:
|
||||
_pi.space = false;
|
||||
|
@ -380,6 +408,7 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
|
|||
_pi.backspace = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
switch (ev.key.keysym.sym) {
|
||||
|
@ -415,23 +444,26 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
|
|||
case SDL_KEYDOWN:
|
||||
if (ev.key.keysym.mod & KMOD_ALT) {
|
||||
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) {
|
||||
uint8_t s = _currentScaler + 1;
|
||||
uint8_t s = _scaler + 1;
|
||||
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) {
|
||||
int8_t s = _currentScaler - 1;
|
||||
if (_currentScaler > 0) {
|
||||
switchGfxMode(_fullscreen, s);
|
||||
int8_t s = _scaler - 1;
|
||||
if (_scaler > 0) {
|
||||
changeGraphics(_fullscreen, s);
|
||||
}
|
||||
} else if (ev.key.keysym.sym == SDLK_s) {
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
#else
|
||||
char name[32];
|
||||
snprintf(name, sizeof(name), "screenshot-%03d.bmp", _screenshot);
|
||||
SDL_SaveBMP(_screenSurface, name);
|
||||
SDL_SaveBMP(_surface, name);
|
||||
++_screenshot;
|
||||
debug(DBG_INFO, "Written '%s'", name);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
} 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;
|
||||
} else if (ev.key.keysym.sym == SDLK_m) {
|
||||
_pi.mirrorMode = !_pi.mirrorMode;
|
||||
flipGfx();
|
||||
flipGraphics();
|
||||
} else if (ev.key.keysym.sym == SDLK_s) {
|
||||
_pi.save = true;
|
||||
} else if (ev.key.keysym.sym == SDLK_l) {
|
||||
|
@ -506,22 +538,20 @@ uint32_t SystemStub_SDL::getTimeStamp() {
|
|||
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;
|
||||
stub->_audioCbProc(stub->_audioCbData, (int8_t *)buf, len);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
buf[i] ^= 0x80;
|
||||
}
|
||||
memset(buf, 0, len);
|
||||
stub->_audioCbProc(stub->_audioCbData, (int16_t *)buf, len / 2);
|
||||
}
|
||||
|
||||
void SystemStub_SDL::startAudio(AudioCallback callback, void *param) {
|
||||
SDL_AudioSpec desired, obtained;
|
||||
memset(&desired, 0, sizeof(desired));
|
||||
desired.freq = SOUND_SAMPLE_RATE;
|
||||
desired.format = AUDIO_U8;
|
||||
desired.freq = kAudioHz;
|
||||
desired.format = AUDIO_S16SYS;
|
||||
desired.channels = 1;
|
||||
desired.samples = 2048;
|
||||
desired.callback = mixAudioS8ToU8;
|
||||
desired.callback = mixAudioS16;
|
||||
desired.userdata = this;
|
||||
if (SDL_OpenAudio(&desired, &obtained) == 0) {
|
||||
_audioCbProc = callback;
|
||||
|
@ -537,7 +567,7 @@ void SystemStub_SDL::stopAudio() {
|
|||
}
|
||||
|
||||
uint32_t SystemStub_SDL::getOutputSampleRate() {
|
||||
return SOUND_SAMPLE_RATE;
|
||||
return kAudioHz;
|
||||
}
|
||||
|
||||
void SystemStub_SDL::lockAudio() {
|
||||
|
@ -548,17 +578,49 @@ void SystemStub_SDL::unlockAudio() {
|
|||
SDL_UnlockAudio();
|
||||
}
|
||||
|
||||
void SystemStub_SDL::prepareGfxMode() {
|
||||
int w = _screenW * _scalers[_currentScaler].factor;
|
||||
int h = _screenH * _scalers[_currentScaler].factor;
|
||||
_screenSurface = SDL_SetVideoMode(w, h, 16, _fullscreen ? (SDL_FULLSCREEN | SDL_HWSURFACE) : SDL_HWSURFACE);
|
||||
if (!_screenSurface) {
|
||||
error("SystemStub_SDL::prepareGfxMode() Unable to allocate _screen buffer");
|
||||
void SystemStub_SDL::prepareGraphics() {
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
switch (_scaler) {
|
||||
case SCALER_SCALE_2X:
|
||||
case SCALER_SCALE_3X:
|
||||
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) {
|
||||
free(_screenBuffer);
|
||||
_screenBuffer = 0;
|
||||
|
@ -567,21 +629,56 @@ void SystemStub_SDL::cleanupGfxMode() {
|
|||
free(_fadeScreenBuffer);
|
||||
_fadeScreenBuffer = 0;
|
||||
}
|
||||
if (_screenSurface) {
|
||||
// freed by SDL_Quit()
|
||||
_screenSurface = 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
|
||||
if (_surface) {
|
||||
// freed by SDL_Quit()
|
||||
_surface = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SystemStub_SDL::switchGfxMode(bool fullscreen, uint8_t scaler) {
|
||||
SDL_FreeSurface(_screenSurface);
|
||||
void SystemStub_SDL::changeGraphics(bool fullscreen, uint8_t scaler) {
|
||||
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;
|
||||
_currentScaler = scaler;
|
||||
prepareGfxMode();
|
||||
forceGfxRedraw();
|
||||
_scaler = scaler;
|
||||
prepareGraphics();
|
||||
forceGraphicsRedraw();
|
||||
}
|
||||
|
||||
void SystemStub_SDL::flipGfx() {
|
||||
void SystemStub_SDL::flipGraphics() {
|
||||
uint16_t scanline[256];
|
||||
assert(_screenW <= 256);
|
||||
uint16_t *p = _screenBuffer + _screenW + 1;
|
||||
|
@ -593,10 +690,10 @@ void SystemStub_SDL::flipGfx() {
|
|||
memcpy(p, scanline, _screenW * sizeof(uint16_t));
|
||||
p += _screenW;
|
||||
}
|
||||
forceGfxRedraw();
|
||||
forceGraphicsRedraw();
|
||||
}
|
||||
|
||||
void SystemStub_SDL::forceGfxRedraw() {
|
||||
void SystemStub_SDL::forceGraphicsRedraw() {
|
||||
_numBlitRects = 1;
|
||||
_blitRects[0].x = 0;
|
||||
_blitRects[0].y = 0;
|
||||
|
|
95
video.cpp
95
video.cpp
|
@ -25,6 +25,15 @@ Video::Video(Resource *res, SystemStub *stub)
|
|||
_charFrontColor = 0;
|
||||
_charTransparentColor = 0;
|
||||
_charShadowColor = 0;
|
||||
_drawChar = 0;
|
||||
switch (_res->_type) {
|
||||
case kResourceTypeAmiga:
|
||||
_drawChar = &Video::AMIGA_drawStringChar;
|
||||
break;
|
||||
case kResourceTypeDOS:
|
||||
_drawChar = &Video::PC_drawStringChar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Video::~Video() {
|
||||
|
@ -150,6 +159,12 @@ void Video::setPaletteSlotLE(int palSlot, const uint8_t *palData) {
|
|||
void Video::setTextPalette() {
|
||||
debug(DBG_VIDEO, "Video::setTextPalette()");
|
||||
setPaletteSlotLE(0xE, _textPal);
|
||||
if (_res->isAmiga()) {
|
||||
Color c;
|
||||
c.r = c.g = 0xEE;
|
||||
c.b = 0;
|
||||
_stub->setPaletteEntry(0xE7, &c);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
dst += y0 * 256 + x0;
|
||||
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) {
|
||||
int code = READ_BE_UINT16(src) & 0x7FFF; src += 2;
|
||||
const uint8_t *end = src + code;
|
||||
do {
|
||||
code = *src++;
|
||||
const int size = READ_BE_UINT16(src) & 0x7FFF; src += 2;
|
||||
for (int i = 0; i < size; ) {
|
||||
int code = src[i++];
|
||||
if ((code & 0x80) == 0) {
|
||||
++code;
|
||||
memcpy(dst, src, code);
|
||||
src += code;
|
||||
if (i + code > size) {
|
||||
code = size - i;
|
||||
}
|
||||
memcpy(dst, &src[i], code);
|
||||
i += code;
|
||||
} else {
|
||||
code = 1 - ((int8_t)code);
|
||||
memset(dst, *src, code);
|
||||
++src;
|
||||
memset(dst, src[i], code);
|
||||
++i;
|
||||
}
|
||||
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) {
|
||||
|
@ -615,12 +660,17 @@ void Video::AMIGA_decodeLev(int level, int room) {
|
|||
// done in ::PC_setLevelPalettes
|
||||
return;
|
||||
}
|
||||
// background
|
||||
setPaletteSlotBE(0x0, _mapPalSlot1);
|
||||
for (int i = 1; i < 5; ++i) {
|
||||
setPaletteSlotBE(i, _mapPalSlot3);
|
||||
}
|
||||
setPaletteSlotBE(0x6, _mapPalSlot3);
|
||||
// objects
|
||||
setPaletteSlotBE(0x1, (level == 0 || level == 1) ? _mapPalSlot3 : _mapPalSlot2);
|
||||
setPaletteSlotBE(0x2, _mapPalSlot3);
|
||||
setPaletteSlotBE(0x3, _mapPalSlot3);
|
||||
// conrad
|
||||
setPaletteSlotBE(0x4, _mapPalSlot3);
|
||||
// foreground
|
||||
setPaletteSlotBE(0x8, _mapPalSlot1);
|
||||
// inventory
|
||||
setPaletteSlotBE(0xA, _mapPalSlot3);
|
||||
}
|
||||
|
||||
|
@ -655,6 +705,9 @@ void Video::AMIGA_decodeSpc(const uint8_t *src, int w, int h, uint8_t *dst) {
|
|||
case 32:
|
||||
AMIGA_planar16(dst, w / 16, h, 4, src);
|
||||
break;
|
||||
case 24:
|
||||
AMIGA_planar24(dst, w, h, src);
|
||||
break;
|
||||
default:
|
||||
warning("AMIGA_decodeSpc w=%d unimplemented", w);
|
||||
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 x = 0; x < 8; ++x) {
|
||||
if (src[x] != 0) {
|
||||
dst[x] = 0x1D;
|
||||
dst[x] = color;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
debug(DBG_VIDEO, "Video::drawString('%s', %d, %d, 0x%X)", str, x, y, col);
|
||||
void (Video::*drawCharFunc)(uint8_t *, int, const uint8_t *, uint8_t, uint8_t) = 0;
|
||||
switch (_res->_type) {
|
||||
case kResourceTypeAmiga:
|
||||
drawCharFunc = &Video::AMIGA_drawStringChar;
|
||||
break;
|
||||
case kResourceTypeDOS:
|
||||
drawCharFunc = &Video::PC_drawStringChar;
|
||||
break;
|
||||
}
|
||||
drawCharFunc dcf = _drawChar;
|
||||
int len = 0;
|
||||
uint8_t *dst = _frontLayer + y * 256 + x;
|
||||
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) {
|
||||
break;
|
||||
}
|
||||
(this->*drawCharFunc)(dst, 256, _res->_fnt, col, c);
|
||||
(this->*dcf)(dst, 256, _res->_fnt, col, c);
|
||||
dst += CHAR_W;
|
||||
++len;
|
||||
}
|
||||
|
|
3
video.h
3
video.h
|
@ -13,6 +13,8 @@ struct Resource;
|
|||
struct SystemStub;
|
||||
|
||||
struct Video {
|
||||
typedef void (Video::*drawCharFunc)(uint8_t *, int, const uint8_t *, uint8_t, uint8_t);
|
||||
|
||||
enum {
|
||||
GAMESCREEN_W = 256,
|
||||
GAMESCREEN_H = 224,
|
||||
|
@ -44,6 +46,7 @@ struct Video {
|
|||
uint8_t *_screenBlocks;
|
||||
bool _fullRefresh;
|
||||
uint8_t _shakeOffset;
|
||||
drawCharFunc _drawChar;
|
||||
|
||||
Video(Resource *res, SystemStub *stub);
|
||||
~Video();
|
||||
|
|
Loading…
Reference in New Issue