Import 0.3.2

This commit is contained in:
Gregory Montoir 2016-08-08 00:00:00 +08:00
parent 577fec920a
commit 5addfc699a
14 changed files with 269 additions and 168 deletions

View File

@ -1,6 +1,6 @@
REminiscence README REminiscence README
Release version: 0.3.1 Release version: 0.3.2
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -23,8 +23,6 @@ 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.
If you have a version distributed by SSI, you'll have to rename the files
and drop the 'ssi' suffix (ie. logosssi.cmd -> logos.cmd).
To hear background music during polygonal cutscenes with the PC version, To hear background music during polygonal cutscenes with the PC version,
you'll need to copy the .mod files of the Amiga version : you'll need to copy the .mod files of the Amiga version :
@ -83,8 +81,6 @@ In-game hotkeys :
Ctrl S save game state Ctrl S save game state
Ctrl L load game state Ctrl L load game state
Ctrl + and - change game state slot Ctrl + and - change game state slot
Ctrl R toggle input keys record
Ctrl P toggle input keys replay
Debug hotkeys : Debug hotkeys :

View File

@ -40,7 +40,7 @@ void Game::col_clearState() {
} }
void Game::col_preparePiegeState(LivePGE *pge) { void Game::col_preparePiegeState(LivePGE *pge) {
debug(DBG_COL, "Game::col_preparePiegeState() pge_num=%d", pge - &_pgeLive[0]); debug(DBG_COL, "Game::col_preparePiegeState() pge_num=%ld", pge - &_pgeLive[0]);
CollisionSlot *ct_slot1, *ct_slot2; CollisionSlot *ct_slot1, *ct_slot2;
if (pge->init_PGE->unk1C == 0) { if (pge->init_PGE->unk1C == 0) {
pge->collision_slot = 0xFF; pge->collision_slot = 0xFF;

View File

@ -31,6 +31,7 @@ struct Cutscene {
static const char *_namesTable[]; static const char *_namesTable[];
static const uint16_t _offsetsTable[]; static const uint16_t _offsetsTable[];
static const uint8_t _amigaDemoOffsetsTable[]; static const uint8_t _amigaDemoOffsetsTable[];
static const uint8_t _ssiOffsetsTable[];
static const uint16_t _cosTable[]; static const uint16_t _cosTable[];
static const uint16_t _sinTable[]; static const uint16_t _sinTable[];
static const uint8_t _creditsDataDOS[]; static const uint8_t _creditsDataDOS[];

185
game.cpp
View File

@ -13,31 +13,47 @@
#include "unpack.h" #include "unpack.h"
#include "util.h" #include "util.h"
Game::Game(SystemStub *stub, FileSystem *fs, const char *savePath, int level, ResourceType ver, Language lang) Game::Game(SystemStub *stub, FileSystem *fs, const char *savePath, int level, int demo, ResourceType ver, Language lang)
: _cut(&_res, stub, &_vid), _menu(&_res, stub, &_vid), : _cut(&_res, stub, &_vid), _menu(&_res, stub, &_vid),
_mix(fs, stub), _res(fs, ver, lang), _seq(stub, &_mix), _vid(&_res, stub), _mix(fs, stub), _res(fs, ver, lang), _seq(stub, &_mix), _vid(&_res, stub),
_stub(stub), _fs(fs), _savePath(savePath) { _stub(stub), _fs(fs), _savePath(savePath) {
_stateSlot = 1; _stateSlot = 1;
_inp_demo = 0; _inp_demPos = 0;
_inp_record = false;
_inp_replay = false;
_skillLevel = _menu._skill = 1; _skillLevel = _menu._skill = 1;
_currentLevel = _menu._level = level; _currentLevel = _menu._level = level;
_demoBin = demo;
} }
void Game::run() { void Game::run() {
_randSeed = time(0); _randSeed = time(0);
if (_demoBin != -1) {
if (_demoBin < (int)ARRAYSIZE(_demoInputs)) {
const char *fn = _demoInputs[_demoBin].name;
debug(DBG_INFO, "Loading inputs from '%s'", fn);
_res.load_DEM(fn);
}
if (_res._demLen == 0) {
return;
}
}
_res.init(); _res.init();
_res.load_TEXT(); _res.load_TEXT();
switch (_res._type) { switch (_res._type) {
case kResourceTypeAmiga: case kResourceTypeAmiga:
_res.load("FONT8", Resource::OT_FNT, "SPR"); _res.load("FONT8", Resource::OT_FNT, "SPR");
if (_res._isDemo) {
_cut._patchedOffsetsTable = Cutscene::_amigaDemoOffsetsTable;
}
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"); _res._hasSeqData = _fs->exists("INTRO.SEQ");
if (_fs->exists("logosssi.cmd")) {
_cut._patchedOffsetsTable = Cutscene::_ssiOffsetsTable;
}
break; break;
} }
@ -51,8 +67,10 @@ void Game::run() {
_mix.init(); _mix.init();
_mix._mod._isAmiga = _res.isAmiga(); _mix._mod._isAmiga = _res.isAmiga();
playCutscene(0x40); if (_demoBin == -1) {
playCutscene(0x0D); playCutscene(0x40);
playCutscene(0x0D);
}
switch (_res._type) { switch (_res._type) {
case kResourceTypeAmiga: case kResourceTypeAmiga:
@ -70,25 +88,30 @@ void Game::run() {
} }
while (!_stub->_pi.quit) { while (!_stub->_pi.quit) {
switch (_res._type) { if (_demoBin != -1) {
case kResourceTypeDOS: _currentLevel = _demoInputs[_demoBin].level;
_mix.playMusic(1); _randSeed = 0;
_menu.handleTitleScreen(); } else {
if (_menu._selectedOption == Menu::MENU_OPTION_ITEM_QUIT || _stub->_pi.quit) { switch (_res._type) {
_stub->_pi.quit = true; case kResourceTypeDOS:
_mix.playMusic(1);
_menu.handleTitleScreen();
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; 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) { if (_currentLevel == 7) {
_vid.fadeOut(); _vid.fadeOut();
@ -107,6 +130,10 @@ void Game::run() {
_frameTimestamp = _stub->getTimeStamp(); _frameTimestamp = _stub->getTimeStamp();
while (!_stub->_pi.quit && !_endLoop) { while (!_stub->_pi.quit && !_endLoop) {
mainLoop(); mainLoop();
if (_demoBin != -1 && _inp_demPos >= _res._demLen) {
debug(DBG_INFO, "End of demo");
_stub->_pi.quit = true;
}
} }
} }
} }
@ -370,52 +397,6 @@ void Game::inp_handleSpecialKeys() {
} }
_stub->_pi.stateSlot = 0; _stub->_pi.stateSlot = 0;
} }
if (_stub->_pi.inpRecord || _stub->_pi.inpReplay) {
bool replay = false;
bool record = false;
char demoFile[20];
makeGameDemoName(demoFile);
if (_inp_demo) {
_inp_demo->close();
delete _inp_demo;
}
_inp_demo = new File;
if (_stub->_pi.inpRecord) {
if (_inp_record) {
debug(DBG_INFO, "Stop recording input keys");
} else {
if (_inp_demo->open(demoFile, "zwb", _savePath)) {
debug(DBG_INFO, "Recording input keys");
static const uint32_t TAG_FBDM = 0x4642444D;
_inp_demo->writeUint32BE(TAG_FBDM);
_inp_demo->writeUint16BE(0);
_inp_demo->writeUint32BE(_randSeed);
record = true;
} else {
warning("Unable to save demo file '%s'", demoFile);
}
}
}
if (_stub->_pi.inpReplay) {
if (_inp_replay) {
debug(DBG_INFO, "Stop replaying input keys");
} else {
if (_inp_demo->open(demoFile, "zrb", _savePath)) {
debug(DBG_INFO, "Replaying input keys");
_inp_demo->readUint32BE();
_inp_demo->readUint16BE();
_randSeed = _inp_demo->readUint32BE();
replay = true;
} else {
warning("Unable to open demo file '%s'", demoFile);
}
}
}
_inp_record = record;
_inp_replay = replay;
_stub->_pi.inpReplay = false;
_stub->_pi.inpRecord = false;
}
} }
void Game::drawCurrentInventoryItem() { void Game::drawCurrentInventoryItem() {
@ -838,7 +819,7 @@ void Game::prepareAnims() {
} }
void Game::prepareAnimsHelper(LivePGE *pge, int16_t dx, int16_t dy) { void Game::prepareAnimsHelper(LivePGE *pge, int16_t dx, int16_t dy) {
debug(DBG_GAME, "Game::prepareAnimsHelper() dx=0x%X dy=0x%X pge_num=%d pge->flags=0x%X pge->anim_number=0x%X", dx, dy, pge - &_pgeLive[0], pge->flags, pge->anim_number); debug(DBG_GAME, "Game::prepareAnimsHelper() dx=0x%X dy=0x%X pge_num=%ld pge->flags=0x%X pge->anim_number=0x%X", dx, dy, pge - &_pgeLive[0], pge->flags, pge->anim_number);
if (!(pge->flags & 8)) { if (!(pge->flags & 8)) {
if (pge->index != 0 && loadMonsterSprites(pge) == 0) { if (pge->index != 0 && loadMonsterSprites(pge) == 0) {
return; return;
@ -980,7 +961,7 @@ void Game::drawObject(const uint8_t *dataPtr, int16_t x, int16_t y, uint8_t flag
} }
void Game::drawObjectFrame(const uint8_t *bankDataPtr, const uint8_t *dataPtr, int16_t x, int16_t y, uint8_t flags) { void Game::drawObjectFrame(const uint8_t *bankDataPtr, const uint8_t *dataPtr, int16_t x, int16_t y, uint8_t flags) {
debug(DBG_GAME, "Game::drawObjectFrame(0x%X, %d, %d, 0x%X)", dataPtr, x, y, flags); debug(DBG_GAME, "Game::drawObjectFrame(%p, %d, %d, 0x%X)", dataPtr, x, y, flags);
const uint8_t *src = bankDataPtr + dataPtr[0] * 32; const uint8_t *src = bankDataPtr + dataPtr[0] * 32;
int16_t sprite_y = y + dataPtr[2]; int16_t sprite_y = y + dataPtr[2];
@ -1111,8 +1092,7 @@ void Game::decodeCharacterFrame(const uint8_t *dataPtr, uint8_t *dstPtr) {
} }
void Game::drawCharacter(const uint8_t *dataPtr, int16_t pos_x, int16_t pos_y, uint8_t a, uint8_t b, uint8_t flags) { void Game::drawCharacter(const uint8_t *dataPtr, int16_t pos_x, int16_t pos_y, uint8_t a, uint8_t b, uint8_t flags) {
debug(DBG_GAME, "Game::drawCharacter(0x%X, %d, %d, 0x%X, 0x%X, 0x%X)", dataPtr, pos_x, pos_y, a, b, flags); debug(DBG_GAME, "Game::drawCharacter(%p, %d, %d, 0x%X, 0x%X, 0x%X)", dataPtr, pos_x, pos_y, a, b, flags);
bool var16 = false; // sprite_mirror_y bool var16 = false; // sprite_mirror_y
if (b & 0x40) { if (b & 0x40) {
b &= 0xBF; b &= 0xBF;
@ -1197,7 +1177,7 @@ void Game::drawCharacter(const uint8_t *dataPtr, int16_t pos_x, int16_t pos_y, u
uint32_t dst_offset = 256 * pos_y + pos_x; uint32_t dst_offset = 256 * pos_y + pos_x;
uint8_t sprite_col_mask = ((flags & 0x60) == 0x60) ? 0x50 : 0x40; uint8_t sprite_col_mask = ((flags & 0x60) == 0x60) ? 0x50 : 0x40;
debug(DBG_GAME, "dst_offset=0x%X src_offset=0x%X", dst_offset, src - dataPtr); debug(DBG_GAME, "dst_offset=0x%X src_offset=%ld", dst_offset, src - dataPtr);
if (!(flags & 2)) { if (!(flags & 2)) {
if (var16) { if (var16) {
@ -1302,7 +1282,6 @@ void Game::loadLevelData() {
switch (_res._type) { switch (_res._type) {
case kResourceTypeAmiga: case kResourceTypeAmiga:
if (_res._isDemo) { if (_res._isDemo) {
_cut._patchedOffsetsTable = Cutscene::_amigaDemoOffsetsTable;
static const char *fname1 = "demo"; static const char *fname1 = "demo";
static const char *fname2 = "demof"; static const char *fname2 = "demof";
_res.load(fname1, Resource::OT_MBK); _res.load(fname1, Resource::OT_MBK);
@ -1397,6 +1376,17 @@ void Game::loadLevelData() {
pge_loadForCurrentLevel(n); pge_loadForCurrentLevel(n);
} }
if (_demoBin != -1) {
_cut._id = -1;
if (_demoInputs[_demoBin].room != 255) {
_pgeLive[0].room_location = _demoInputs[_demoBin].room;
_pgeLive[0].pos_x = _demoInputs[_demoBin].x;
_pgeLive[0].pos_y = _demoInputs[_demoBin].y;
} else {
_inp_demPos = 1;
}
}
for (uint16_t i = 0; i < _res._pgeNum; ++i) { for (uint16_t i = 0; i < _res._pgeNum; ++i) {
if (_res._pgeInit[i].skill <= _skillLevel) { if (_res._pgeInit[i].skill <= _skillLevel) {
LivePGE *pge = &_pgeLive[i]; LivePGE *pge = &_pgeLive[i];
@ -1466,7 +1456,7 @@ void Game::playSound(uint8_t sfxId, uint8_t softVol) {
uint16_t Game::getRandomNumber() { uint16_t Game::getRandomNumber() {
uint32_t n = _randSeed * 2; uint32_t n = _randSeed * 2;
if (_randSeed > n) { if (((int32_t)_randSeed) >= 0) {
n ^= 0x1D872B41; n ^= 0x1D872B41;
} }
_randSeed = n; _randSeed = n;
@ -1614,44 +1604,17 @@ void Game::handleInventory() {
} }
void Game::inp_update() { void Game::inp_update() {
if (_inp_replay && _inp_demo) {
uint8_t keymask = _inp_demo->readByte();
if (_inp_demo->ioErr()) {
_inp_replay = false;
} else {
_stub->_pi.dirMask = keymask & 0xF;
_stub->_pi.enter = (keymask & 0x10) != 0;
_stub->_pi.space = (keymask & 0x20) != 0;
_stub->_pi.shift = (keymask & 0x40) != 0;
_stub->_pi.quit = (keymask & 0x80) != 0;
}
}
_stub->processEvents(); _stub->processEvents();
if (_inp_record && _inp_demo) { if (_inp_demPos < _res._demLen) {
uint8_t keymask = _stub->_pi.dirMask; const int keymask = _res._dem[_inp_demPos++];
if (_stub->_pi.enter) { _stub->_pi.dirMask = keymask & 0xF;
keymask |= 0x10; _stub->_pi.enter = (keymask & 0x10) != 0;
} _stub->_pi.space = (keymask & 0x20) != 0;
if (_stub->_pi.space) { _stub->_pi.shift = (keymask & 0x40) != 0;
keymask |= 0x20; _stub->_pi.backspace = (keymask & 0x80) != 0;
}
if (_stub->_pi.shift) {
keymask |= 0x40;
}
if (_stub->_pi.quit) {
keymask |= 0x80;
}
_inp_demo->writeByte(keymask);
if (_inp_demo->ioErr()) {
_inp_record = false;
}
} }
} }
void Game::makeGameDemoName(char *buf) {
sprintf(buf, "rs-level%d.demo", _currentLevel + 1);
}
void Game::makeGameStateName(uint8_t slot, char *buf) { void Game::makeGameStateName(uint8_t slot, char *buf) {
sprintf(buf, "rs-level%d-%02d.state", _currentLevel + 1, slot); sprintf(buf, "rs-level%d-%02d.state", _currentLevel + 1, slot);
} }
@ -1856,7 +1819,7 @@ void Game::loadState(File *f) {
} }
void AnimBuffers::addState(uint8_t stateNum, int16_t x, int16_t y, const uint8_t *dataPtr, LivePGE *pge, uint8_t w, uint8_t h) { void AnimBuffers::addState(uint8_t stateNum, int16_t x, int16_t y, const uint8_t *dataPtr, LivePGE *pge, uint8_t w, uint8_t h) {
debug(DBG_GAME, "AnimBuffers::addState() stateNum=%d x=%d y=%d dataPtr=0x%X pge=0x%X", stateNum, x, y, dataPtr, pge); debug(DBG_GAME, "AnimBuffers::addState() stateNum=%d x=%d y=%d dataPtr=%p pge=%p", stateNum, x, y, dataPtr, pge);
assert(stateNum < 4); assert(stateNum < 4);
AnimBufferState *state = _states[stateNum]; AnimBufferState *state = _states[stateNum];
state->x = x; state->x = x;

9
game.h
View File

@ -32,6 +32,7 @@ struct Game {
CT_LEFT_ROOM = 0xC0 CT_LEFT_ROOM = 0xC0
}; };
static const Demo _demoInputs[3];
static const Level _gameLevels[]; static const Level _gameLevels[];
static const uint16_t _scoreTable[]; static const uint16_t _scoreTable[];
static const uint8_t _monsterListLevel1[]; static const uint8_t _monsterListLevel1[];
@ -63,6 +64,7 @@ struct Game {
const char **_textsTable; const char **_textsTable;
uint8_t _currentLevel; uint8_t _currentLevel;
uint8_t _skillLevel; uint8_t _skillLevel;
int _demoBin;
uint32_t _score; uint32_t _score;
uint8_t _currentRoom; uint8_t _currentRoom;
uint8_t _currentIcon; uint8_t _currentIcon;
@ -85,7 +87,7 @@ struct Game {
bool _endLoop; bool _endLoop;
uint32_t _frameTimestamp; uint32_t _frameTimestamp;
Game(SystemStub *, FileSystem *, const char *savePath, int level, ResourceType ver, Language lang); Game(SystemStub *, FileSystem *, const char *savePath, int level, int demo, ResourceType ver, Language lang);
void run(); void run();
void displayTitleScreenAmiga(); void displayTitleScreenAmiga();
@ -351,9 +353,7 @@ struct Game {
// input // input
uint8_t _inp_lastKeysHit; uint8_t _inp_lastKeysHit;
uint8_t _inp_lastKeysHitLeftRight; uint8_t _inp_lastKeysHitLeftRight;
bool _inp_replay; int _inp_demPos;
bool _inp_record;
File *_inp_demo;
void inp_handleSpecialKeys(); void inp_handleSpecialKeys();
void inp_update(); void inp_update();
@ -363,7 +363,6 @@ struct Game {
uint8_t _stateSlot; uint8_t _stateSlot;
bool _validSaveState; bool _validSaveState;
void makeGameDemoName(char *buf);
void makeGameStateName(uint8_t slot, char *buf); void makeGameStateName(uint8_t slot, char *buf);
bool saveGameState(uint8_t slot); bool saveGameState(uint8_t slot);
bool loadGameState(uint8_t slot); bool loadGameState(uint8_t slot);

View File

@ -106,6 +106,13 @@ struct Point {
int16_t y; int16_t y;
}; };
struct Demo {
const char *name;
int level;
int room;
int x, y;
};
struct Level { struct Level {
const char *name; const char *name;
const char *name2; const char *name2;

View File

@ -134,6 +134,7 @@ int main(int argc, char *argv[]) {
int scaler = DEFAULT_SCALER; int scaler = DEFAULT_SCALER;
bool fullscreen = false; bool fullscreen = false;
int forcedLanguage = -1; int forcedLanguage = -1;
int demoNum = -1;
if (argc == 2) { if (argc == 2) {
// data path as the only command line argument // data path as the only command line argument
struct stat st; struct stat st;
@ -149,6 +150,7 @@ int main(int argc, char *argv[]) {
{ "fullscreen", no_argument, 0, 4 }, { "fullscreen", no_argument, 0, 4 },
{ "scaler", required_argument, 0, 5 }, { "scaler", required_argument, 0, 5 },
{ "language", required_argument, 0, 6 }, { "language", required_argument, 0, 6 },
{ "playdemo", required_argument, 0, 7 },
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
}; };
int index; int index;
@ -195,6 +197,9 @@ int main(int argc, char *argv[]) {
} }
} }
break; break;
case 7:
demoNum = atoi(optarg);
break;
default: default:
printf(USAGE, argv[0]); printf(USAGE, argv[0]);
return 0; return 0;
@ -210,7 +215,7 @@ int main(int argc, char *argv[]) {
} }
const Language language = (forcedLanguage == -1) ? detectLanguage(&fs) : (Language)forcedLanguage; const Language language = (forcedLanguage == -1) ? detectLanguage(&fs) : (Language)forcedLanguage;
SystemStub *stub = SystemStub_SDL_create(); SystemStub *stub = SystemStub_SDL_create();
Game *g = new Game(stub, &fs, savePath, levelNum, (ResourceType)version, language); Game *g = new Game(stub, &fs, savePath, levelNum, demoNum, (ResourceType)version, language);
stub->init(g_caption, Video::GAMESCREEN_W, Video::GAMESCREEN_H, scaler, fullscreen); stub->init(g_caption, Video::GAMESCREEN_W, Video::GAMESCREEN_H, scaler, fullscreen);
g->run(); g->run();
delete g; delete g;

View File

@ -113,7 +113,7 @@ void Game::pge_loadForCurrentLevel(uint16_t idx) {
} }
void Game::pge_process(LivePGE *pge) { void Game::pge_process(LivePGE *pge) {
debug(DBG_PGE, "Game::pge_process() pge_num=%d", pge - &_pgeLive[0]); debug(DBG_PGE, "Game::pge_process() pge_num=%ld", pge - &_pgeLive[0]);
_pge_playAnimSound = true; _pge_playAnimSound = true;
_pge_currentPiegeFacingDir = (pge->flags & 1) != 0; _pge_currentPiegeFacingDir = (pge->flags & 1) != 0;
_pge_currentPiegeRoom = pge->room_location; _pge_currentPiegeRoom = pge->room_location;
@ -226,7 +226,7 @@ void Game::pge_playAnimSound(LivePGE *pge, uint16_t arg2) {
} }
void Game::pge_setupAnim(LivePGE *pge) { void Game::pge_setupAnim(LivePGE *pge) {
debug(DBG_PGE, "Game::pge_setupAnim() pgeNum=%d", pge - &_pgeLive[0]); debug(DBG_PGE, "Game::pge_setupAnim() pgeNum=%ld", pge - &_pgeLive[0]);
const uint8_t *anim_data = _res.getAniData(pge->obj_type); const uint8_t *anim_data = _res.getAniData(pge->obj_type);
if (_res._readUint16(anim_data) < pge->anim_seq) { if (_res._readUint16(anim_data) < pge->anim_seq) {
pge->anim_seq = 0; pge->anim_seq = 0;
@ -254,7 +254,7 @@ void Game::pge_setupAnim(LivePGE *pge) {
} }
int Game::pge_execute(LivePGE *live_pge, InitPGE *init_pge, const Object *obj) { int Game::pge_execute(LivePGE *live_pge, InitPGE *init_pge, const Object *obj) {
debug(DBG_PGE, "Game::pge_execute() pge_num=%d op1=0x%X op2=0x%X op3=0x%X", live_pge - &_pgeLive[0], obj->opcode1, obj->opcode2, obj->opcode3); debug(DBG_PGE, "Game::pge_execute() pge_num=%ld op1=0x%X op2=0x%X op3=0x%X", live_pge - &_pgeLive[0], obj->opcode1, obj->opcode2, obj->opcode3);
pge_OpcodeProc op; pge_OpcodeProc op;
ObjectOpcodeArgs args; ObjectOpcodeArgs args;
if (obj->opcode1) { if (obj->opcode1) {
@ -378,7 +378,7 @@ void Game::pge_setupDefaultAnim(LivePGE *pge) {
pge->flags |= 8; pge->flags |= 8;
} }
pge->anim_number = _res._readUint16(anim_frame) & 0x7FFF; pge->anim_number = _res._readUint16(anim_frame) & 0x7FFF;
debug(DBG_PGE, "Game::pge_setupDefaultAnim() pgeNum=%d pge->flags=0x%X pge->anim_number=0x%X pge->anim_seq=0x%X", pge - &_pgeLive[0], pge->flags, pge->anim_number, pge->anim_seq); debug(DBG_PGE, "Game::pge_setupDefaultAnim() pgeNum=%ld pge->flags=0x%X pge->anim_number=0x%X pge->anim_seq=0x%X", pge - &_pgeLive[0], pge->flags, pge->anim_number, pge->anim_seq);
} }
} }
@ -464,7 +464,7 @@ void Game::pge_setupOtherPieges(LivePGE *pge, InitPGE *init_pge) {
} }
void Game::pge_addToCurrentRoomList(LivePGE *pge, uint8_t room) { void Game::pge_addToCurrentRoomList(LivePGE *pge, uint8_t room) {
debug(DBG_PGE, "Game::pge_addToCurrentRoomList() pgeNum=%d room=%d", pge - &_pgeLive[0], room); debug(DBG_PGE, "Game::pge_addToCurrentRoomList() pgeNum=%ld room=%d", pge - &_pgeLive[0], room);
if (room != pge->room_location) { if (room != pge->room_location) {
LivePGE *cur_pge = _pge_liveTable1[room]; LivePGE *cur_pge = _pge_liveTable1[room];
LivePGE *prev_pge = 0; LivePGE *prev_pge = 0;

View File

@ -84,6 +84,19 @@ void Resource::clearLevelRes() {
free_OBJ(); free_OBJ();
} }
void Resource::load_DEM(const char *filename) {
free(_dem); _dem = 0;
_demLen = 0;
File f;
if (f.open(filename, "rb", _fs)) {
_demLen = f.size();
_dem = (uint8_t *)malloc(_demLen);
if (_dem) {
f.read(_dem, _demLen);
}
}
}
void Resource::load_FIB(const char *fileName) { void Resource::load_FIB(const char *fileName) {
debug(DBG_RES, "Resource::load_FIB('%s')", fileName); debug(DBG_RES, "Resource::load_FIB('%s')", fileName);
static const uint8_t fibonacciTable[] = { static const uint8_t fibonacciTable[] = {

View File

@ -148,6 +148,8 @@ struct Resource {
uint8_t *_bankDataTail; uint8_t *_bankDataTail;
BankSlot _bankBuffers[NUM_BANK_BUFFERS]; BankSlot _bankBuffers[NUM_BANK_BUFFERS];
int _bankBuffersCount; int _bankBuffersCount;
uint8_t *_dem;
int _demLen;
Resource(FileSystem *fs, ResourceType type, Language lang); Resource(FileSystem *fs, ResourceType type, Language lang);
~Resource(); ~Resource();
@ -159,6 +161,7 @@ struct Resource {
bool isAmiga() const { return _type == kResourceTypeAmiga; } bool isAmiga() const { return _type == kResourceTypeAmiga; }
void clearLevelRes(); void clearLevelRes();
void load_DEM(const char *filename);
void load_FIB(const char *fileName); void load_FIB(const char *fileName);
void load_SPL_demo(); void load_SPL_demo();
void load_MAP_menu(const char *fileName, uint8_t *dstPtr); void load_MAP_menu(const char *fileName, uint8_t *dstPtr);

View File

@ -64,7 +64,8 @@ const char *Cutscene::_namesTable[] = {
"INTRO2", "INTRO2",
"SERRURE", "SERRURE",
"HOLOCUBE", "HOLOCUBE",
"CHUTE2" "CHUTE2",
"LOGOSSSI",
}; };
const uint16_t Cutscene::_offsetsTable[] = { const uint16_t Cutscene::_offsetsTable[] = {
@ -92,6 +93,11 @@ const uint8_t Cutscene::_amigaDemoOffsetsTable[] = {
255 255
}; };
const uint8_t Cutscene::_ssiOffsetsTable[] = {
64, 34, 0, /* LOGOSSSI */
255
};
const uint16_t Cutscene::_cosTable[] = { const uint16_t Cutscene::_cosTable[] = {
0x0100, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FE, 0x00FE, 0x0100, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FE, 0x00FE,
0x00FD, 0x00FC, 0x00FC, 0x00FB, 0x00FA, 0x00F9, 0x00F8, 0x00F7, 0x00FD, 0x00FC, 0x00FC, 0x00FB, 0x00FA, 0x00F9, 0x00F8, 0x00F7,
@ -830,6 +836,12 @@ const Cutscene::Text Cutscene::_frTextsTable[] = {
{ -1, 0 } { -1, 0 }
}; };
const Demo Game::_demoInputs[] = {
{ "demo1.bin", 0, 0x33, 0x60, 0x46 },
{ "demo51.bin", 5, 0x00, 0x60, 0xD6 },
{ "demo3.bin" , 2, 0xFF, 0x00, 0x00 }
};
const Level Game::_gameLevels[] = { const Level Game::_gameLevels[] = {
{ "level1", "level1", "level1", 0x00, 1, 3 }, { "level1", "level1", "level1", 0x00, 1, 3 },
{ "level2", "level2", "level2", 0x2F, 1, 4 }, { "level2", "level2", "level2", 0x2F, 1, 4 },

View File

@ -35,9 +35,6 @@ struct PlayerInput {
bool load; bool load;
int stateSlot; int stateSlot;
bool inpRecord;
bool inpReplay;
bool mirrorMode; bool mirrorMode;
uint8_t dbgMask; uint8_t dbgMask;

View File

@ -10,6 +10,8 @@
#include "util.h" #include "util.h"
static const int kAudioHz = 22050; static const int kAudioHz = 22050;
static const int kJoystickIndex = 0;
static const int kJoystickCommitValue = 3200; static const int kJoystickCommitValue = 3200;
struct SystemStub_SDL : SystemStub { struct SystemStub_SDL : SystemStub {
@ -17,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;
SDL_GameController *_controller;
#else #else
SDL_Surface *_surface; SDL_Surface *_surface;
#endif #endif
@ -83,15 +86,34 @@ void SystemStub_SDL::init(const char *title, int w, int h, int scaler, bool full
memset(_pal, 0, sizeof(_pal)); memset(_pal, 0, sizeof(_pal));
_screenW = _screenH = 0; _screenW = _screenH = 0;
setScreenSize(w, h); setScreenSize(w, h);
_joystick = NULL; _joystick = 0;
#if SDL_VERSION_ATLEAST(2, 0, 0)
_controller = 0;
if (SDL_NumJoysticks() > 0) { if (SDL_NumJoysticks() > 0) {
_joystick = SDL_JoystickOpen(0); SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt");
if (SDL_IsGameController(kJoystickIndex)) {
_controller = SDL_GameControllerOpen(kJoystickIndex);
}
if (!_controller) {
_joystick = SDL_JoystickOpen(kJoystickIndex);
}
} }
#else
if (SDL_NumJoysticks() > 0) {
_joystick = SDL_JoystickOpen(kJoystickIndex);
}
#endif
_screenshot = 1; _screenshot = 1;
} }
void SystemStub_SDL::destroy() { void SystemStub_SDL::destroy() {
cleanupGraphics(); cleanupGraphics();
#if SDL_VERSION_ATLEAST(2, 0, 0)
if (_controller) {
SDL_GameControllerClose(_controller);
_controller = 0;
}
#endif
if (_joystick) { if (_joystick) {
SDL_JoystickClose(_joystick); SDL_JoystickClose(_joystick);
_joystick = 0; _joystick = 0;
@ -141,7 +163,7 @@ void SystemStub_SDL::setOverscanColor(int i) {
} }
void SystemStub_SDL::copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch) { void SystemStub_SDL::copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch) {
if (_numBlitRects >= ARRAYSIZE(_blitRects)) { if (_numBlitRects >= (int)ARRAYSIZE(_blitRects)) {
warning("SystemStub_SDL::copyRect() Too many blit rects, you may experience graphical glitches"); warning("SystemStub_SDL::copyRect() Too many blit rects, you may experience graphical glitches");
} else { } else {
// extend the dirty region by 1 pixel for scalers accessing 'outer' pixels // extend the dirty region by 1 pixel for scalers accessing 'outer' pixels
@ -201,13 +223,16 @@ void SystemStub_SDL::copyRect(int x, int y, int w, int h, const uint8_t *buf, in
} }
void SystemStub_SDL::fadeScreen() { void SystemStub_SDL::fadeScreen() {
const int fadeScreenBufferSize = _screenH * _screenW * sizeof(uint16_t); const int bufferSize = _screenH * _screenW * sizeof(uint16_t);
if (!_fadeScreenBuffer) { if (!_fadeScreenBuffer) {
_fadeScreenBuffer = (uint16_t *)malloc(fadeScreenBufferSize); _fadeScreenBuffer = (uint16_t *)malloc(bufferSize);
assert(_fadeScreenBuffer); if (!_fadeScreenBuffer) {
warning("SystemStub_SDL::fadeScreen() Unable to allocate buffer size %d", bufferSize);
return;
}
} }
_fadeOnUpdateScreen = true; _fadeOnUpdateScreen = true;
memcpy(_fadeScreenBuffer, _screenBuffer + _screenW + 1, fadeScreenBufferSize); memcpy(_fadeScreenBuffer, _screenBuffer + _screenW + 1, bufferSize);
} }
static uint16_t blendPixel16(uint16_t colorSrc, uint16_t colorDst, uint32_t mask, int step) { static uint16_t blendPixel16(uint16_t colorSrc, uint16_t colorDst, uint32_t mask, int step) {
@ -219,9 +244,23 @@ 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)
// _fadeOnUpdateScreen
SDL_UpdateTexture(_texture, 0, _screenBuffer + _screenW + 1, _screenW * sizeof(uint16_t)); SDL_UpdateTexture(_texture, 0, _screenBuffer + _screenW + 1, _screenW * sizeof(uint16_t));
SDL_RenderClear(_renderer); SDL_RenderClear(_renderer);
if (_fadeOnUpdateScreen) {
SDL_SetRenderDrawBlendMode(_renderer, SDL_BLENDMODE_BLEND);
SDL_Rect r;
r.x = r.y = 0;
SDL_GetRendererOutputSize(_renderer, &r.w, &r.h);
for (int i = 1; i <= 16; ++i) {
SDL_SetRenderDrawColor(_renderer, 0, 0, 0, 256 - i * 16);
SDL_RenderCopy(_renderer, _texture, 0, 0);
SDL_RenderFillRect(_renderer, &r);
SDL_RenderPresent(_renderer);
SDL_Delay(30);
}
_fadeOnUpdateScreen = false;
return;
}
if (shakeOffset != 0) { if (shakeOffset != 0) {
SDL_Rect r; SDL_Rect r;
r.x = 0; r.x = 0;
@ -375,41 +414,111 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
} }
break; break;
case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONDOWN:
if (_joystick) {
switch (ev.jbutton.button) {
case 0:
_pi.space = true;
break;
case 1:
_pi.shift = true;
break;
case 2:
_pi.enter = true;
break;
case 3:
_pi.backspace = true;
break;
}
}
break;
case SDL_JOYBUTTONUP: case SDL_JOYBUTTONUP:
if (_joystick) { if (_joystick) {
const bool pressed = (ev.jbutton.state == SDL_PRESSED);
switch (ev.jbutton.button) { switch (ev.jbutton.button) {
case 0: case 0:
_pi.space = false; _pi.space = pressed;
break; break;
case 1: case 1:
_pi.shift = false; _pi.shift = pressed;
break; break;
case 2: case 2:
_pi.enter = false; _pi.enter = pressed;
break; break;
case 3: case 3:
_pi.backspace = false; _pi.backspace = pressed;
break; break;
} }
} }
break; break;
#if SDL_VERSION_ATLEAST(2, 0, 0)
case SDL_CONTROLLERAXISMOTION:
if (_controller) {
switch (ev.caxis.axis) {
case SDL_CONTROLLER_AXIS_LEFTX:
case SDL_CONTROLLER_AXIS_RIGHTX:
if (ev.caxis.value < -kJoystickCommitValue) {
_pi.dirMask |= PlayerInput::DIR_LEFT;
} else {
_pi.dirMask &= ~PlayerInput::DIR_LEFT;
}
if (ev.caxis.value > kJoystickCommitValue) {
_pi.dirMask |= PlayerInput::DIR_RIGHT;
} else {
_pi.dirMask &= ~PlayerInput::DIR_RIGHT;
}
break;
case SDL_CONTROLLER_AXIS_LEFTY:
case SDL_CONTROLLER_AXIS_RIGHTY:
if (ev.caxis.value < -kJoystickCommitValue) {
_pi.dirMask |= PlayerInput::DIR_UP;
} else {
_pi.dirMask &= ~PlayerInput::DIR_UP;
}
if (ev.caxis.value > kJoystickCommitValue) {
_pi.dirMask |= PlayerInput::DIR_DOWN;
} else {
_pi.dirMask &= ~PlayerInput::DIR_DOWN;
}
break;
}
}
break;
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
if (_controller) {
const bool pressed = (ev.cbutton.state == SDL_PRESSED);
switch (ev.cbutton.button) {
case SDL_CONTROLLER_BUTTON_A:
_pi.enter = pressed;
break;
case SDL_CONTROLLER_BUTTON_B:
_pi.space = pressed;
break;
case SDL_CONTROLLER_BUTTON_X:
_pi.shift = pressed;
break;
case SDL_CONTROLLER_BUTTON_Y:
_pi.backspace = pressed;
break;
case SDL_CONTROLLER_BUTTON_BACK:
case SDL_CONTROLLER_BUTTON_START:
_pi.escape = pressed;
break;
case SDL_CONTROLLER_BUTTON_DPAD_UP:
if (pressed) {
_pi.dirMask |= PlayerInput::DIR_UP;
} else {
_pi.dirMask &= ~PlayerInput::DIR_UP;
}
break;
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
if (pressed) {
_pi.dirMask |= PlayerInput::DIR_DOWN;
} else {
_pi.dirMask &= ~PlayerInput::DIR_DOWN;
}
break;
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
if (pressed) {
_pi.dirMask |= PlayerInput::DIR_LEFT;
} else {
_pi.dirMask &= ~PlayerInput::DIR_LEFT;
}
break;
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
if (pressed) {
_pi.dirMask |= PlayerInput::DIR_RIGHT;
} else {
_pi.dirMask &= ~PlayerInput::DIR_RIGHT;
}
break;
}
}
break;
#endif
case SDL_KEYUP: case SDL_KEYUP:
switch (ev.key.keysym.sym) { switch (ev.key.keysym.sym) {
case SDLK_LEFT: case SDLK_LEFT:
@ -484,10 +593,6 @@ void SystemStub_SDL::processEvent(const SDL_Event &ev, bool &paused) {
_pi.stateSlot = 1; _pi.stateSlot = 1;
} else if (ev.key.keysym.sym == SDLK_KP_MINUS || ev.key.keysym.sym == SDLK_PAGEDOWN) { } else if (ev.key.keysym.sym == SDLK_KP_MINUS || ev.key.keysym.sym == SDLK_PAGEDOWN) {
_pi.stateSlot = -1; _pi.stateSlot = -1;
} else if (ev.key.keysym.sym == SDLK_r) {
_pi.inpRecord = true;
} else if (ev.key.keysym.sym == SDLK_p) {
_pi.inpReplay = true;
} }
} }
_pi.lastChar = ev.key.keysym.sym; _pi.lastChar = ev.key.keysym.sym;

6
util.h
View File

@ -27,8 +27,8 @@ enum {
extern uint16_t g_debugMask; extern uint16_t g_debugMask;
extern void debug(uint16_t cm, const char *msg, ...); extern void debug(uint16_t cm, const char *msg, ...); // __attribute__((__format__(__printf__, 2, 3)))
extern void error(const char *msg, ...); extern void error(const char *msg, ...); // __attribute__((__format__(__printf__, 1, 2)))
extern void warning(const char *msg, ...); extern void warning(const char *msg, ...); // __attribute__((__format__(__printf__, 1, 2)))
#endif // UTIL_H__ #endif // UTIL_H__