Import 0.3.3

This commit is contained in:
Gregory Montoir 2017-06-08 00:00:00 +08:00
parent 5addfc699a
commit 1cd2866af7
19 changed files with 274 additions and 125 deletions

View File

@ -1,12 +1,12 @@
SDL_CFLAGS = `sdl-config --cflags` SDL_CFLAGS := `sdl2-config --cflags`
SDL_LIBS = `sdl-config --libs` SDL_LIBS := `sdl2-config --libs`
MODPLUG_LIBS = -lmodplug
# TREMOR_LIBS = -lvorbisidec -logg
ZLIB_LIBS = -lz
CXX := clang++ MODPLUG_LIBS := -lmodplug
CXXFLAGS := -Wall -MMD $(SDL_CFLAGS) -DUSE_MODPLUG -DUSE_ZLIB # -DUSE_TREMOR TREMOR_LIBS := -lvorbisidec -logg
ZLIB_LIBS := -lz
CXXFLAGS += -Wall -MMD $(SDL_CFLAGS) -DUSE_MODPLUG -DUSE_TREMOR -DUSE_ZLIB
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 \

View File

@ -1,6 +1,6 @@
REminiscence README REminiscence README
Release version: 0.3.2 Release version: 0.3.3
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -24,30 +24,9 @@ Data Files:
You will need the original files of the PC (DOS or CD) or Amiga release. You will need the original files of the PC (DOS or CD) or Amiga release.
To hear background music during polygonal cutscenes with the PC version, To have background music during polygonal cutscenes with the PC version,
you'll need to copy the .mod files of the Amiga version : you need to copy the music/ directory of the Amiga version or use the .mod
fileset from unexotica.
mod.flashback-ascenseur
mod.flashback-ceinturea
mod.flashback-chute
mod.flashback-desintegr
mod.flashback-donneobjt
mod.flashback-fin
mod.flashback-fin2
mod.flashback-game_over
mod.flashback-holocube
mod.flashback-introb
mod.flashback-jungle
mod.flashback-logo
mod.flashback-memoire
mod.flashback-missionca
mod.flashback-options1
mod.flashback-options2
mod.flashback-reunion
mod.flashback-taxi
mod.flashback-teleport2
mod.flashback-teleporta
mod.flashback-voyage
To hear voice during in-game dialogues, you'll need to copy the 'VOICE.VCE' To hear voice during in-game dialogues, you'll need to copy the 'VOICE.VCE'
file from the SegaCD version to the DATA directory. file from the SegaCD version to the DATA directory.
@ -87,7 +66,6 @@ Debug hotkeys :
Ctrl F toggle fast mode Ctrl F toggle fast mode
Ctrl I Conrad 'infinite' life Ctrl I Conrad 'infinite' life
Ctrl B toggle display of updated dirty blocks Ctrl B toggle display of updated dirty blocks
Ctrl M mirror mode (right - left swapped)
Credits: Credits:

View File

@ -33,7 +33,7 @@ void Cutscene::sync() {
} }
void Cutscene::copyPalette(const uint8_t *pal, uint16_t num) { void Cutscene::copyPalette(const uint8_t *pal, uint16_t num) {
uint8_t *dst = (uint8_t *)_palBuf; uint8_t *dst = _palBuf;
if (num != 0) { if (num != 0) {
dst += 0x20; dst += 0x20;
} }
@ -1091,10 +1091,11 @@ void Cutscene::play() {
} }
} }
} }
if (g_options.use_text_cutscenes && _res->_lang == LANG_FR) { if (g_options.use_text_cutscenes) {
for (int i = 0; _frTextsTable[i].str; ++i) { const Text *textsTable = (_res->_lang == LANG_FR) ? _frTextsTable : _enTextsTable;
if (_id == _frTextsTable[i].num) { for (int i = 0; textsTable[i].str; ++i) {
playText(_frTextsTable[i].str); if (_id == textsTable[i].num) {
playText(textsTable[i].str);
break; break;
} }
} }

View File

@ -40,6 +40,7 @@ struct Cutscene {
static const uint8_t _musicTable[]; static const uint8_t _musicTable[];
static const uint8_t _protectionShapeData[]; static const uint8_t _protectionShapeData[];
static const Text _frTextsTable[]; static const Text _frTextsTable[];
static const Text _enTextsTable[];
Graphics _gfx; Graphics _gfx;
Resource *_res; Resource *_res;

View File

@ -11,6 +11,10 @@
#ifdef USE_ZLIB #ifdef USE_ZLIB
#include "zlib.h" #include "zlib.h"
#endif #endif
#ifdef USE_RWOPS
#include <SDL_filesystem.h>
#include <SDL_rwops.h>
#endif
struct File_impl { struct File_impl {
bool _ioErr; bool _ioErr;
@ -128,6 +132,62 @@ struct GzipFile : File_impl {
}; };
#endif #endif
#ifdef USE_RWOPS
struct AssetFile: File_impl {
SDL_RWops *_rw;
AssetFile() : _rw(0) {}
bool open(const char *path, const char *mode) {
_ioErr = false;
_rw = SDL_RWFromFile(path, "rb");
if (!_rw) {
// try uppercase
char fixedPath[MAXPATHLEN];
{
int i = 0;
for (; path[i] && i < MAXPATHLEN - 1; ++i) {
fixedPath[i] = path[i];
if (fixedPath[i] >= 'a' && fixedPath[i] <= 'z') {
fixedPath[i] += 'A' - 'a';
}
}
fixedPath[i] = 0;
}
_rw = SDL_RWFromFile(fixedPath, "rb");
}
return _rw != 0;
}
void close() {
if (_rw) {
SDL_RWclose(_rw);
_rw = 0;
}
}
uint32_t size() {
if (_rw) {
return SDL_RWsize(_rw);
}
return 0;
}
void seek(int32_t off) {
if (_rw) {
SDL_RWseek(_rw, off, RW_SEEK_SET);
}
}
uint32_t read(void *ptr, uint32_t len) {
if (_rw) {
const int count = SDL_RWread(_rw, ptr, 1, len);
if (count != len) {
_ioErr = true;
}
}
return 0;
}
uint32_t write(void *ptr, uint32_t len) {
_ioErr = true;
return 0;
}
};
#endif
File::File() File::File()
: _impl(0) { : _impl(0) {
@ -155,6 +215,23 @@ bool File::open(const char *filename, const char *mode, FileSystem *fs) {
free(path); free(path);
return ret; return ret;
} }
#ifdef USE_RWOPS
if (mode[0] == 'r') {
_impl = new AssetFile;
return _impl->open(filename, mode);
} else if (mode[0] == 'w') {
bool ret = false;
char *prefPath = SDL_GetPrefPath("org.cyxdown", "fb");
if (prefPath) {
char path[MAXPATHLEN];
snprintf(path, sizeof(path), "%s/%s", prefPath, filename);
_impl = new StdioFile;
ret = _impl->open(path, mode);
SDL_free(prefPath);
}
return ret;
}
#endif
return false; return false;
} }

43
fs.cpp
View File

@ -12,6 +12,9 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/param.h> #include <sys/param.h>
#endif #endif
#ifdef USE_RWOPS
#include <SDL_rwops.h>
#endif
#include "fs.h" #include "fs.h"
#include "util.h" #include "util.h"
@ -47,18 +50,26 @@ struct FileSystem_impl {
debug(DBG_FILE, "Found %d files and %d directories", _filesCount, _dirsCount); debug(DBG_FILE, "Found %d files and %d directories", _filesCount, _dirsCount);
} }
char *findPath(const char *name) const { int findPathIndex(const char *name) const {
for (int i = 0; i < _filesCount; ++i) { for (int i = 0; i < _filesCount; ++i) {
if (strcasecmp(_filesList[i].name, name) == 0) { if (strcasecmp(_filesList[i].name, name) == 0) {
const char *dir = _dirsList[_filesList[i].dir]; return i;
const int len = strlen(dir) + 1 + strlen(_filesList[i].name) + 1;
char *p = (char *)malloc(len);
if (p) {
snprintf(p, len, "%s/%s", dir, _filesList[i].name);
}
return p;
} }
} }
return -1;
}
char *getPath(const char *name) const {
const int i = findPathIndex(name);
if (i >= 0) {
const char *dir = _dirsList[_filesList[i].dir];
const int len = strlen(dir) + 1 + strlen(_filesList[i].name) + 1;
char *p = (char *)malloc(len);
if (p) {
snprintf(p, len, "%s/%s", dir, _filesList[i].name);
}
return p;
}
return 0; return 0;
} }
@ -146,13 +157,19 @@ FileSystem::~FileSystem() {
} }
char *FileSystem::findPath(const char *filename) const { char *FileSystem::findPath(const char *filename) const {
return _impl->findPath(filename); return _impl->getPath(filename);
} }
bool FileSystem::exists(const char *filename) const { bool FileSystem::exists(const char *filename) const {
char *path = findPath(filename); if (_impl->findPathIndex(filename) >= 0) {
if (path) { return true;
free(path);
} }
return path != 0; #ifdef USE_RWOPS
SDL_RWops *rw = SDL_RWFromFile(filename, "rb");
if (rw) {
SDL_RWclose(rw);
return true;
}
#endif
return false;
} }

View File

@ -28,7 +28,7 @@ void Game::run() {
_randSeed = time(0); _randSeed = time(0);
if (_demoBin != -1) { if (_demoBin != -1) {
if (_demoBin < (int)ARRAYSIZE(_demoInputs)) { if (_demoBin < ARRAYSIZE(_demoInputs)) {
const char *fn = _demoInputs[_demoBin].name; const char *fn = _demoInputs[_demoBin].name;
debug(DBG_INFO, "Loading inputs from '%s'", fn); debug(DBG_INFO, "Loading inputs from '%s'", fn);
_res.load_DEM(fn); _res.load_DEM(fn);
@ -50,7 +50,9 @@ void Game::run() {
break; break;
case kResourceTypeDOS: case kResourceTypeDOS:
_res.load("FB_TXT", Resource::OT_FNT); _res.load("FB_TXT", Resource::OT_FNT);
_res._hasSeqData = _fs->exists("INTRO.SEQ"); if (g_options.use_seq_cutscenes) {
_res._hasSeqData = _fs->exists("INTRO.SEQ");
}
if (_fs->exists("logosssi.cmd")) { if (_fs->exists("logosssi.cmd")) {
_cut._patchedOffsetsTable = Cutscene::_ssiOffsetsTable; _cut._patchedOffsetsTable = Cutscene::_ssiOffsetsTable;
} }
@ -91,10 +93,12 @@ void Game::run() {
if (_demoBin != -1) { if (_demoBin != -1) {
_currentLevel = _demoInputs[_demoBin].level; _currentLevel = _demoInputs[_demoBin].level;
_randSeed = 0; _randSeed = 0;
} else if (_res._isDemo) {
// do not present title screen and menus
} else { } else {
_mix.playMusic(1);
switch (_res._type) { switch (_res._type) {
case kResourceTypeDOS: case kResourceTypeDOS:
_mix.playMusic(1);
_menu.handleTitleScreen(); _menu.handleTitleScreen();
if (_menu._selectedOption == Menu::MENU_OPTION_ITEM_QUIT || _stub->_pi.quit) { if (_menu._selectedOption == Menu::MENU_OPTION_ITEM_QUIT || _stub->_pi.quit) {
_stub->_pi.quit = true; _stub->_pi.quit = true;
@ -148,11 +152,10 @@ void Game::displayTitleScreenAmiga() {
_res.load_CMP_menu(FILENAME, _res._memBuf); _res.load_CMP_menu(FILENAME, _res._memBuf);
static const int kW = 320; static const int kW = 320;
static const int kH = 224; static const int kH = 224;
uint8_t *buf = (uint8_t *)malloc(kW * kH); uint8_t *buf = (uint8_t *)calloc(kW * kH, 1);
if (!buf) { if (!buf) {
error("Failed to allocate screen buffer w=%d h=%d", kW, kH); error("Failed to allocate screen buffer w=%d h=%d", kW, kH);
} }
_vid.AMIGA_decodeCmp(_res._memBuf + 6, buf);
static const int kAmigaColors[] = { static const int kAmigaColors[] = {
0x000, 0x123, 0x012, 0x134, 0x433, 0x453, 0x046, 0x245, 0x000, 0x123, 0x012, 0x134, 0x433, 0x453, 0x046, 0x245,
0x751, 0x455, 0x665, 0x268, 0x961, 0x478, 0x677, 0x786, 0x751, 0x455, 0x665, 0x268, 0x961, 0x478, 0x677, 0x786,
@ -166,7 +169,14 @@ void Game::displayTitleScreenAmiga() {
_stub->setScreenSize(kW, kH); _stub->setScreenSize(kW, kH);
_stub->copyRect(0, 0, kW, kH, buf, kW); _stub->copyRect(0, 0, kW, kH, buf, kW);
_stub->updateScreen(0); _stub->updateScreen(0);
_vid.AMIGA_decodeCmp(_res._memBuf + 6, buf);
free(buf); free(buf);
for (int h = 0; h < kH / 2; h += 2) {
const int y = kH / 2 - h;
_stub->copyRect(0, y, kW, h * 2, buf, kW);
_stub->updateScreen(0);
_stub->sleep(30);
}
while (1) { while (1) {
_stub->processEvents(); _stub->processEvents();
if (_stub->_pi.quit) { if (_stub->_pi.quit) {
@ -243,6 +253,9 @@ void Game::mainLoop() {
} }
} }
if (oldLevel != _currentLevel) { if (oldLevel != _currentLevel) {
if (_res._isDemo) {
_currentLevel = oldLevel;
}
changeLevel(); changeLevel();
_pge_opTempVar1 = 0; _pge_opTempVar1 = 0;
return; return;
@ -598,7 +611,9 @@ bool Game::handleContinueAbort() {
bool Game::handleProtectionScreen() { bool Game::handleProtectionScreen() {
bool valid = true; bool valid = true;
_cut.prepare(); _cut.prepare();
_cut.copyPalette(_protectionPal, 0); const int palOffset = _res.isAmiga() ? 32 : 0;
_cut.copyPalette(_protectionPal + palOffset, 0);
_cut.updatePalette(); _cut.updatePalette();
_cut._gfx.setClippingRect(64, 48, 128, 128); _cut._gfx.setClippingRect(64, 48, 128, 128);
@ -622,10 +637,10 @@ bool Game::handleProtectionScreen() {
do { do {
codeText[len] = '\0'; codeText[len] = '\0';
memcpy(_vid._frontLayer, _vid._tempLayer, _vid._layerSize); memcpy(_vid._frontLayer, _vid._tempLayer, _vid._layerSize);
_menu.drawString("PROTECTION", 2, 11, 5); _vid.drawString("PROTECTION", 11 * 8, 2 * 8, _menu._charVar2);
char buf[20]; char buf[20];
snprintf(buf, sizeof(buf), "CODE %d : %s", codeNum + 1, codeText); snprintf(buf, sizeof(buf), "CODE %d : %s", codeNum + 1, codeText);
_menu.drawString(buf, 23, 8, 5); _vid.drawString(buf, 8 * 8, 23 * 8, _menu._charVar2);
_vid.updateScreen(); _vid.updateScreen();
_stub->sleep(50); _stub->sleep(50);
_stub->processEvents(); _stub->processEvents();
@ -679,7 +694,11 @@ void Game::printLevelCode() {
--_printLevelCodeCounter; --_printLevelCodeCounter;
if (_printLevelCodeCounter != 0) { if (_printLevelCodeCounter != 0) {
char buf[32]; char buf[32];
snprintf(buf, sizeof(buf), "CODE: %s", _menu._passwords[_currentLevel][_skillLevel]); const char *code = Menu::_passwords[_currentLevel][_skillLevel];
if (_res.isAmiga() && _res._lang == LANG_FR) {
code = Menu::_passwordsFrAmiga[_skillLevel * 7 + _currentLevel];
}
snprintf(buf, sizeof(buf), "CODE: %s", code);
_vid.drawString(buf, (_vid._w - strlen(buf) * 8) / 2, 16, 0xE7); _vid.drawString(buf, (_vid._w - strlen(buf) * 8) / 2, 16, 0xE7);
} }
} }
@ -1506,16 +1525,30 @@ void Game::handleInventory() {
int icon_h = 5; int icon_h = 5;
int icon_y = 140; int icon_y = 140;
int icon_num = 31; int icon_num = 31;
static const int icon_spr_w = 16;
static const int icon_spr_h = 16;
do { do {
int icon_x = 56; int icon_x = 56;
int icon_w = 9; int icon_w = 9;
do { do {
drawIcon(icon_num, icon_x, icon_y, 0xF); drawIcon(icon_num, icon_x, icon_y, 0xF);
++icon_num; ++icon_num;
icon_x += 16; icon_x += icon_spr_w;
} while (--icon_w); } while (--icon_w);
icon_y += 16; icon_y += icon_spr_h;
} while (--icon_h); } while (--icon_h);
if (_res._type == kResourceTypeAmiga) {
// draw outline rectangle
static const uint8_t outline_color = 0xE7;
uint8_t *p = _vid._frontLayer + 140 * Video::GAMESCREEN_W + 56;
memset(p + 1, outline_color, 9 * icon_spr_w - 2);
p += Video::GAMESCREEN_W;
for (int y = 1; y < 5 * icon_spr_h - 1; ++y) {
p[0] = p[9 * icon_spr_w - 1] = outline_color;
p += Video::GAMESCREEN_W;
}
memset(p + 1, outline_color, 9 * icon_spr_w - 2);
}
if (!display_score) { if (!display_score) {
int icon_x_pos = 72; int icon_x_pos = 72;

View File

@ -7,24 +7,20 @@
#ifndef INTERN_H__ #ifndef INTERN_H__
#define INTERN_H__ #define INTERN_H__
#include <cstdio> #include <stdio.h>
#include <cstring> #include <string.h>
#include <cstdlib> #include <stdlib.h>
#include <cassert> #include <assert.h>
#include <stdint.h> #include <stdint.h>
#ifndef ABS #undef ABS
#define ABS(x) ((x)<0?-(x):(x)) #define ABS(x) ((x)<0?-(x):(x))
#endif #undef MAX
#ifndef MAX
#define MAX(x,y) ((x)>(y)?(x):(y)) #define MAX(x,y) ((x)>(y)?(x):(y))
#endif #undef MIN
#ifndef MIN
#define MIN(x,y) ((x)<(y)?(x):(y)) #define MIN(x,y) ((x)<(y)?(x):(y))
#endif #undef ARRAYSIZE
#ifndef ARRAYSIZE #define ARRAYSIZE(a) (int)(sizeof(a)/sizeof(a[0]))
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
#endif
inline uint16_t READ_BE_UINT16(const void *ptr) { inline uint16_t READ_BE_UINT16(const void *ptr) {
const uint8_t *b = (const uint8_t *)ptr; const uint8_t *b = (const uint8_t *)ptr;
@ -93,6 +89,7 @@ struct Options {
bool fade_out_palette; bool fade_out_palette;
bool use_tiledata; bool use_tiledata;
bool use_text_cutscenes; bool use_text_cutscenes;
bool use_seq_cutscenes;
}; };
struct Color { struct Color {

View File

@ -4,6 +4,7 @@
* Copyright (C) 2005-2015 Gregory Montoir (cyx@users.sourceforge.net) * Copyright (C) 2005-2015 Gregory Montoir (cyx@users.sourceforge.net)
*/ */
#include <SDL.h>
#include <ctype.h> #include <ctype.h>
#include <getopt.h> #include <getopt.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -19,7 +20,7 @@ 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 Level to start from (default '0')\n" " --levelnum=NUM Start to level, bypass introduction\n"
" --fullscreen Fullscreen display\n" " --fullscreen Fullscreen display\n"
" --scaler=INDEX Graphics scaler\n" " --scaler=INDEX Graphics scaler\n"
" --language=LANG Language (fr,en,de,sp,it)\n" " --language=LANG Language (fr,en,de,sp,it)\n"
@ -36,7 +37,7 @@ static int detectVersion(FileSystem *fs) {
{ "LEVEL1.MAP", kResourceTypeDOS, "DOS" }, { "LEVEL1.MAP", kResourceTypeDOS, "DOS" },
{ "LEVEL1.LEV", kResourceTypeAmiga, "Amiga" }, { "LEVEL1.LEV", kResourceTypeAmiga, "Amiga" },
{ "DEMO.LEV", kResourceTypeAmiga, "Amiga (Demo)" }, { "DEMO.LEV", kResourceTypeAmiga, "Amiga (Demo)" },
{ 0, -1 } { 0, -1, 0 }
}; };
for (int i = 0; table[i].filename; ++i) { for (int i = 0; table[i].filename; ++i) {
File f; File f;
@ -82,6 +83,7 @@ static void initOptions() {
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; g_options.use_text_cutscenes = false;
g_options.use_seq_cutscenes = true;
// read configuration file // read configuration file
struct { struct {
const char *name; const char *name;
@ -93,6 +95,7 @@ static void initOptions() {
{ "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 }, { "use_text_cutscenes", &g_options.use_text_cutscenes },
{ "use_seq_cutscenes", &g_options.use_seq_cutscenes },
{ 0, 0 } { 0, 0 }
}; };
static const char *filename = "rs.cfg"; static const char *filename = "rs.cfg";
@ -126,7 +129,6 @@ static void initOptions() {
static const int DEFAULT_SCALER = SCALER_SCALE_3X; static const int DEFAULT_SCALER = SCALER_SCALE_3X;
#undef main
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
const char *dataPath = "DATA"; const char *dataPath = "DATA";
const char *savePath = "."; const char *savePath = ".";

1
menu.h
View File

@ -40,6 +40,7 @@ struct Menu {
}; };
static const char *_passwords[8][3]; static const char *_passwords[8][3];
static const char *_passwordsFrAmiga[];
Resource *_res; Resource *_res;
SystemStub *_stub; SystemStub *_stub;

View File

@ -488,9 +488,6 @@ void Game::pge_addToCurrentRoomList(LivePGE *pge, uint8_t room) {
void Game::pge_getInput() { void Game::pge_getInput() {
inp_update(); inp_update();
_inp_lastKeysHit = _stub->_pi.dirMask; _inp_lastKeysHit = _stub->_pi.dirMask;
if (_stub->_pi.mirrorMode && (_inp_lastKeysHit & 0xC)) {
_inp_lastKeysHit ^= 0xC; // invert left/right
}
if ((_inp_lastKeysHit & 0xC) && (_inp_lastKeysHit & 0x3)) { if ((_inp_lastKeysHit & 0xC) && (_inp_lastKeysHit & 0x3)) {
const uint8_t mask = (_inp_lastKeysHit & 0xF0) | (_inp_lastKeysHitLeftRight & 0xF); const uint8_t mask = (_inp_lastKeysHit & 0xF0) | (_inp_lastKeysHitLeftRight & 0xF);
_pge_inpKeysMask = mask; _pge_inpKeysMask = mask;

View File

@ -949,6 +949,7 @@ void Resource::load_PGE(File *f) {
_pgeNum = f->readUint16LE(); _pgeNum = f->readUint16LE();
memset(_pgeInit, 0, sizeof(_pgeInit)); memset(_pgeInit, 0, sizeof(_pgeInit));
debug(DBG_RES, "_pgeNum=%d", _pgeNum); debug(DBG_RES, "_pgeNum=%d", _pgeNum);
assert(_pgeNum <= ARRAYSIZE(_pgeInit));
for (uint16_t i = 0; i < _pgeNum; ++i) { for (uint16_t i = 0; i < _pgeNum; ++i) {
InitPGE *pge = &_pgeInit[i]; InitPGE *pge = &_pgeInit[i];
pge->type = f->readUint16LE(); pge->type = f->readUint16LE();
@ -979,6 +980,7 @@ void Resource::decodePGE(const uint8_t *p, int size) {
_pgeNum = _readUint16(p); p += 2; _pgeNum = _readUint16(p); p += 2;
memset(_pgeInit, 0, sizeof(_pgeInit)); memset(_pgeInit, 0, sizeof(_pgeInit));
debug(DBG_RES, "len=%d _pgeNum=%d", size, _pgeNum); debug(DBG_RES, "len=%d _pgeNum=%d", size, _pgeNum);
assert(_pgeNum <= ARRAYSIZE(_pgeInit));
for (uint16_t i = 0; i < _pgeNum; ++i) { for (uint16_t i = 0; i < _pgeNum; ++i) {
InitPGE *pge = &_pgeInit[i]; InitPGE *pge = &_pgeInit[i];
pge->type = _readUint16(p); p += 2; pge->type = _readUint16(p); p += 2;

5
rs.cfg
View File

@ -13,5 +13,8 @@ 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) # display text instead of playing the polygon cutscenes
use_text_cutscenes=false use_text_cutscenes=false
# enable playback of .SEQ cutscenes (use polygonal if false)
use_seq_cutscenes=true

View File

@ -19,7 +19,7 @@ enum {
SCALER_SCALE_3X, SCALER_SCALE_3X,
SCALER_POINT_4X, SCALER_POINT_4X,
SCALER_SCALE_4X, SCALER_SCALE_4X,
NUM_SCALERS = 7 NUM_SCALERS
}; };
struct Scaler { struct Scaler {

View File

@ -836,6 +836,29 @@ const Cutscene::Text Cutscene::_frTextsTable[] = {
{ -1, 0 } { -1, 0 }
}; };
const Cutscene::Text Cutscene::_enTextsTable[] = {
{ 1, "YOU PICK UP THE HOLOCUBE" },
{ 2, "YOU PICK UP THE KEY" },
{ 3, "YOU PICK UP THE GUN" },
{ 5, "YOUR SHIELD IS RECHARGED" },
{ 10, "YOU PICK UP THE CREDIT CARD" },
{ 14, "THE CARTRIDGE IS RECHARGED" },
{ 15, "YOU PICK UP THE CARTRIDGE" },
{ 16, "YOU PICK UP THE TELEPORTER" },
{ 18, "YOU PICK UP THE I.D. CARD" },
{ 21, "YOU GIVE HIM THE TELEPORTER" },
{ 32, "THE RECEPTIONIST GIVES YOU||A PACKAGE" },
{ 33, "YOU GIVE THE PARCEL" },
{ 34, "THE GOVERNOR GIVES YOU||A WORKING PERMIT" },
{ 35, "THE FORGER GIVES YOU||A FAKE I.D. CARD" },
{ 36, "YOU PICK UP THE FUSE" },
{ 43, "YOU GIVE HIM||YOUR PAPERS" },
{ 44, "YOU GIVE HIM MONEY" },
{ 49, "HE GIVES YOU||AN ANTI-G BELT" },
{ 60, "YOU PICK UP THE TELE RECEPTER" },
{ -1, 0}
};
const Demo Game::_demoInputs[] = { const Demo Game::_demoInputs[] = {
{ "demo1.bin", 0, 0x33, 0x60, 0x46 }, { "demo1.bin", 0, 0x33, 0x60, 0x46 },
{ "demo51.bin", 5, 0x00, 0x60, 0xD6 }, { "demo51.bin", 5, 0x00, 0x60, 0xD6 },
@ -2700,8 +2723,12 @@ const uint8_t Game::_protectionCodeData[] = {
}; };
const uint8_t Game::_protectionPal[] = { const uint8_t Game::_protectionPal[] = {
0x00, 0x00, 0x00, 0x42, 0x00, 0x63, 0x00, 0x00, 0x0F, 0xFF, 0x0F, 0xF0, 0x07, 0x77, 0x00, 0x00, // DOS
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x42, 0x00, 0x63, 0x00, 0x00, 0x0F, 0xFF, 0x0F, 0xF0, 0x07, 0x77, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Amiga
0x00, 0x00, 0x03, 0x04, 0x06, 0x05, 0x00, 0x00, 0x04, 0x44, 0x05, 0x55, 0x06, 0x66, 0x07, 0x77,
0x08, 0x88, 0x09, 0x99, 0x0A, 0xAA, 0x0B, 0xBB, 0x0C, 0xCC, 0x0D, 0xDD, 0x0E, 0xEE, 0x0F, 0xFF
}; };
const char *Menu::_passwords[8][3] = { const char *Menu::_passwords[8][3] = {
@ -2715,6 +2742,12 @@ const char *Menu::_passwords[8][3] = {
{ "BELUGA", "BELUGA", "BELUGA" } { "BELUGA", "BELUGA", "BELUGA" }
}; };
const char *Menu::_passwordsFrAmiga[] = {
"BACK", "LOUP", "CINE", "GOOD", "SPIZ", "BIOS", "HALL", // easy
"PLAY", "TOIT", "ZAPP", "LYNX", "SCSI", "GARY", "PONT", // normal
"CLOP", "CARA", "CALE", "FONT", "HASH", "FIBO", "TIPS", // hard
};
const uint8_t Video::_conradPal1[] = { const uint8_t Video::_conradPal1[] = {
0x00, 0x00, 0xCC, 0x0C, 0x8F, 0x08, 0x7E, 0x07, 0x6C, 0x06, 0x5B, 0x05, 0x4A, 0x04, 0x63, 0x09, 0x00, 0x00, 0xCC, 0x0C, 0x8F, 0x08, 0x7E, 0x07, 0x6C, 0x06, 0x5B, 0x05, 0x4A, 0x04, 0x63, 0x09,
0x52, 0x07, 0x41, 0x06, 0x30, 0x06, 0x76, 0x0C, 0x14, 0x09, 0x25, 0x0B, 0x88, 0x08, 0xFF, 0x0F 0x52, 0x07, 0x41, 0x06, 0x30, 0x06, 0x76, 0x0C, 0x14, 0x09, 0x25, 0x0B, 0x88, 0x08, 0xFF, 0x0F

View File

@ -35,8 +35,6 @@ struct PlayerInput {
bool load; bool load;
int stateSlot; int stateSlot;
bool mirrorMode;
uint8_t dbgMask; uint8_t dbgMask;
bool quit; bool quit;
}; };

View File

@ -19,6 +19,7 @@ struct SystemStub_SDL : SystemStub {
SDL_Window *_window; SDL_Window *_window;
SDL_Renderer *_renderer; SDL_Renderer *_renderer;
SDL_Texture *_texture; SDL_Texture *_texture;
int _texW, _texH;
SDL_GameController *_controller; SDL_GameController *_controller;
#else #else
SDL_Surface *_surface; SDL_Surface *_surface;
@ -125,10 +126,7 @@ void SystemStub_SDL::setScreenSize(int w, int h) {
if (_screenW == w && _screenH == h) { if (_screenW == w && _screenH == h) {
return; return;
} }
free(_screenBuffer); cleanupGraphics();
_screenBuffer = 0;
free(_fadeScreenBuffer);
_fadeScreenBuffer = 0;
// allocate some extra bytes for the scaling routines // allocate some extra bytes for the scaling routines
const int screenBufferSize = (w + 2) * (h + 2) * sizeof(uint16_t); const int screenBufferSize = (w + 2) * (h + 2) * sizeof(uint16_t);
_screenBuffer = (uint16_t *)calloc(1, screenBufferSize); _screenBuffer = (uint16_t *)calloc(1, screenBufferSize);
@ -190,7 +188,7 @@ void SystemStub_SDL::copyRect(int x, int y, int w, int h, const uint8_t *buf, in
} }
SDL_Rect *br = &_blitRects[_numBlitRects]; SDL_Rect *br = &_blitRects[_numBlitRects];
br->x = _pi.mirrorMode ? _screenW - (x + w) : x; br->x = x;
br->y = y; br->y = y;
br->w = w; br->w = w;
br->h = h; br->h = h;
@ -199,22 +197,12 @@ void SystemStub_SDL::copyRect(int x, int y, int w, int h, const uint8_t *buf, in
uint16_t *p = _screenBuffer + (br->y + 1) * _screenW + (br->x + 1); uint16_t *p = _screenBuffer + (br->y + 1) * _screenW + (br->x + 1);
buf += y * pitch + x; buf += y * pitch + x;
if (_pi.mirrorMode) { while (h--) {
while (h--) { for (int i = 0; i < w; ++i) {
for (int i = 0; i < w; ++i) { p[i] = _pal[buf[i]];
p[i] = _pal[buf[w - 1 - i]];
}
p += _screenW;
buf += pitch;
}
} else {
while (h--) {
for (int i = 0; i < w; ++i) {
p[i] = _pal[buf[i]];
}
p += _screenW;
buf += pitch;
} }
p += _screenW;
buf += pitch;
} }
if (_pi.dbgMask & PlayerInput::DF_DBLOCKS) { if (_pi.dbgMask & PlayerInput::DF_DBLOCKS) {
drawRect(br, 0xE7, _screenBuffer + _screenW + 1, _screenW * 2); drawRect(br, 0xE7, _screenBuffer + _screenW + 1, _screenW * 2);
@ -244,7 +232,16 @@ 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) {
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_UpdateTexture(_texture, 0, _screenBuffer + _screenW + 1, _screenW * sizeof(uint16_t)); if (_texW != _screenW || _texH != _screenH) {
void *dst = 0;
int pitch = 0;
if (SDL_LockTexture(_texture, 0, &dst, &pitch) == 0) {
(*_scalers[_scaler].proc)((uint16_t *)dst, pitch, _screenBuffer + _screenW + 1, _screenW, _screenW, _screenH);
SDL_UnlockTexture(_texture);
}
} else {
SDL_UpdateTexture(_texture, 0, _screenBuffer + _screenW + 1, _screenW * sizeof(uint16_t));
}
SDL_RenderClear(_renderer); SDL_RenderClear(_renderer);
if (_fadeOnUpdateScreen) { if (_fadeOnUpdateScreen) {
SDL_SetRenderDrawBlendMode(_renderer, SDL_BLENDMODE_BLEND); SDL_SetRenderDrawBlendMode(_renderer, SDL_BLENDMODE_BLEND);
@ -582,9 +579,6 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
_pi.dbgMask ^= PlayerInput::DF_DBLOCKS; _pi.dbgMask ^= PlayerInput::DF_DBLOCKS;
} else if (ev.key.keysym.sym == SDLK_i) { } else if (ev.key.keysym.sym == SDLK_i) {
_pi.dbgMask ^= PlayerInput::DF_SETLIFE; _pi.dbgMask ^= PlayerInput::DF_SETLIFE;
} else if (ev.key.keysym.sym == SDLK_m) {
_pi.mirrorMode = !_pi.mirrorMode;
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) {
@ -690,9 +684,13 @@ void SystemStub_SDL::prepareGraphics() {
case SCALER_SCALE_3X: case SCALER_SCALE_3X:
case SCALER_SCALE_4X: case SCALER_SCALE_4X:
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
_texW = _screenW * _scalers[_scaler].factor;
_texH = _screenH * _scalers[_scaler].factor;
break; break;
default: default:
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); // nearest pixel sampling SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); // nearest pixel sampling
_texW = _screenW;
_texH = _screenH;
break; break;
} }
const int windowW = _screenW * _scalers[_scaler].factor; const int windowW = _screenW * _scalers[_scaler].factor;
@ -705,7 +703,7 @@ void SystemStub_SDL::prepareGraphics() {
_renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED); _renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED);
SDL_RenderSetLogicalSize(_renderer, windowW, windowH); SDL_RenderSetLogicalSize(_renderer, windowW, windowH);
static const uint32_t kPixelFormat = SDL_PIXELFORMAT_RGB565; static const uint32_t kPixelFormat = SDL_PIXELFORMAT_RGB565;
_texture = SDL_CreateTexture(_renderer, kPixelFormat, SDL_TEXTUREACCESS_STREAMING, _screenW, _screenH); _texture = SDL_CreateTexture(_renderer, kPixelFormat, SDL_TEXTUREACCESS_STREAMING, _texW, _texH);
_fmt = SDL_AllocFormat(kPixelFormat); _fmt = SDL_AllocFormat(kPixelFormat);
#else #else
SDL_WM_SetCaption(_caption, NULL); SDL_WM_SetCaption(_caption, NULL);

View File

@ -8,7 +8,11 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#endif #endif
#include <cstdarg> #ifdef __ANDROID__
#define LOG_TAG "FbJni"
#include <android/log.h>
#endif
#include <stdarg.h>
#include "util.h" #include "util.h"
@ -21,8 +25,11 @@ void debug(uint16_t cm, const char *msg, ...) {
va_start(va, msg); va_start(va, msg);
vsprintf(buf, msg, va); vsprintf(buf, msg, va);
va_end(va); va_end(va);
printf("%s\n", buf); fprintf(stdout, "%s\n", buf);
fflush(stdout); fflush(stdout);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "%s", buf);
#endif
} }
} }
@ -35,6 +42,9 @@ void error(const char *msg, ...) {
fprintf(stderr, "ERROR: %s!\n", buf); fprintf(stderr, "ERROR: %s!\n", buf);
#ifdef _WIN32 #ifdef _WIN32
MessageBox(0, buf, g_caption, MB_ICONERROR); MessageBox(0, buf, g_caption, MB_ICONERROR);
#endif
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", buf);
#endif #endif
exit(-1); exit(-1);
} }
@ -46,5 +56,8 @@ void warning(const char *msg, ...) {
vsnprintf(buf, sizeof(buf), msg, va); vsnprintf(buf, sizeof(buf), msg, va);
va_end(va); va_end(va);
fprintf(stderr, "WARNING: %s!\n", buf); fprintf(stderr, "WARNING: %s!\n", buf);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_WARN, LOG_TAG, "%s", buf);
#endif
} }

View File

@ -558,8 +558,8 @@ static void decodeLevHelper(uint8_t *dst, const uint8_t *src, int offset10, int
const bool yflip = (d3 & (1 << 12)) != 0; const bool yflip = (d3 & (1 << 12)) != 0;
const bool xflip = (d3 & (1 << 11)) != 0; const bool xflip = (d3 & (1 << 11)) != 0;
int mask = 0; int mask = 0;
if ((d3 < (1 << 15)) == 0) { if ((d3 & 0x8000) != 0) {
mask = 0x80; mask = 0x80 + ((d3 >> 6) & 0x10);
} }
if (isPC) { if (isPC) {
PC_drawTile(dst + y * 256 + x, a2, mask, xflip, yflip, -1); PC_drawTile(dst + y * 256 + x, a2, mask, xflip, yflip, -1);
@ -586,8 +586,8 @@ static void decodeLevHelper(uint8_t *dst, const uint8_t *src, int offset10, int
int mask = 0; int mask = 0;
if ((d3 & 0x6000) != 0 && sgdBuf) { if ((d3 & 0x6000) != 0 && sgdBuf) {
mask = 0x10; mask = 0x10;
} else if ((d3 < (1 << 15)) == 0) { } else if ((d3 & 0x8000) != 0) {
mask = 0x80; mask = 0x80 + ((d3 >> 6) & 0x10);
} }
if (isPC) { if (isPC) {
PC_drawTile(dst + y * 256 + x, a2, mask, xflip, yflip, 0); PC_drawTile(dst + y * 256 + x, a2, mask, xflip, yflip, 0);
@ -663,13 +663,14 @@ void Video::AMIGA_decodeLev(int level, int room) {
// background // background
setPaletteSlotBE(0x0, _mapPalSlot1); setPaletteSlotBE(0x0, _mapPalSlot1);
// objects // objects
setPaletteSlotBE(0x1, (level == 0 || level == 1) ? _mapPalSlot3 : _mapPalSlot2); setPaletteSlotBE(0x1, (level == 0) ? _mapPalSlot3 : _mapPalSlot2);
setPaletteSlotBE(0x2, _mapPalSlot3); setPaletteSlotBE(0x2, _mapPalSlot3);
setPaletteSlotBE(0x3, _mapPalSlot3); setPaletteSlotBE(0x3, _mapPalSlot3);
// conrad // conrad
setPaletteSlotBE(0x4, _mapPalSlot3); setPaletteSlotBE(0x4, _mapPalSlot3);
// foreground // foreground
setPaletteSlotBE(0x8, _mapPalSlot1); setPaletteSlotBE(0x8, _mapPalSlot1);
setPaletteSlotBE(0x9, (level == 0) ? _mapPalSlot1 : _mapPalSlot3);
// inventory // inventory
setPaletteSlotBE(0xA, _mapPalSlot3); setPaletteSlotBE(0xA, _mapPalSlot3);
} }
@ -803,11 +804,8 @@ void Video::PC_drawChar(uint8_t c, int16_t y, int16_t x) {
const uint8_t *src = _res->_fnt + (c - 32) * 32; const uint8_t *src = _res->_fnt + (c - 32) * 32;
uint8_t *dst = _frontLayer + x + 256 * y; uint8_t *dst = _frontLayer + x + 256 * y;
for (int h = 0; h < 8; ++h) { for (int h = 0; h < 8; ++h) {
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i, ++src) {
uint8_t c1 = (*src & 0xF0) >> 4; const uint8_t c1 = *src >> 4;
uint8_t c2 = (*src & 0x0F) >> 0;
++src;
if (c1 != 0) { if (c1 != 0) {
if (c1 != 2) { if (c1 != 2) {
*dst = _charFrontColor; *dst = _charFrontColor;
@ -818,7 +816,7 @@ void Video::PC_drawChar(uint8_t c, int16_t y, int16_t x) {
*dst = _charTransparentColor; *dst = _charTransparentColor;
} }
++dst; ++dst;
const uint8_t c2 = *src & 15;
if (c2 != 0) { if (c2 != 0) {
if (c2 != 2) { if (c2 != 2) {
*dst = _charFrontColor; *dst = _charFrontColor;