Import 0.4.4
This commit is contained in:
parent
514785d0a1
commit
222984d851
2
Makefile
2
Makefile
|
@ -7,7 +7,7 @@ MODPLUG_LIBS := -lmodplug
|
||||||
TREMOR_LIBS := -lvorbisidec -logg
|
TREMOR_LIBS := -lvorbisidec -logg
|
||||||
ZLIB_LIBS := -lz
|
ZLIB_LIBS := -lz
|
||||||
|
|
||||||
CXXFLAGS += -O2 -Wall -MMD $(SDL_CFLAGS) -DUSE_MODPLUG -DUSE_STATIC_SCALER -DUSE_TREMOR -DUSE_ZLIB
|
CXXFLAGS += -Wall -Wpedantic -MMD $(SDL_CFLAGS) -DUSE_MODPLUG -DUSE_STATIC_SCALER -DUSE_TREMOR -DUSE_ZLIB
|
||||||
|
|
||||||
SRCS = collision.cpp cutscene.cpp decode_mac.cpp dynlib.cpp file.cpp fs.cpp game.cpp graphics.cpp main.cpp \
|
SRCS = collision.cpp cutscene.cpp decode_mac.cpp dynlib.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 \
|
menu.cpp mixer.cpp mod_player.cpp ogg_player.cpp piege.cpp resource.cpp resource_aba.cpp \
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
REminiscence README
|
REminiscence README
|
||||||
Release version: 0.4.3
|
Release version: 0.4.4
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ These paths can be changed using command line switches :
|
||||||
--widescreen=MODE 16:9 display
|
--widescreen=MODE 16:9 display
|
||||||
--scaler=NAME@X Graphics scaler (default 'scale@3')
|
--scaler=NAME@X Graphics scaler (default 'scale@3')
|
||||||
--language=LANG Language (fr,en,de,sp,it,jp)
|
--language=LANG Language (fr,en,de,sp,it,jp)
|
||||||
|
--autosave Save game state automatically
|
||||||
|
|
||||||
The scaler option specifies the algorithm used to smoothen the image in
|
The scaler option specifies the algorithm used to smoothen the image in
|
||||||
addition to a scaling factor. External scalers are also supported, the suffix
|
addition to a scaling factor. External scalers are also supported, the suffix
|
||||||
|
@ -53,7 +54,7 @@ shall be used as the name. Eg. If you have scaler_xbrz.dll, you can pass
|
||||||
'--scaler xbrz@2' to use that algorithm with a doubled window size (512x448).
|
'--scaler xbrz@2' to use that algorithm with a doubled window size (512x448).
|
||||||
|
|
||||||
The widescreen option accepts two modes :
|
The widescreen option accepts two modes :
|
||||||
'adjacent' : left and right rooms bitmaps will be drawn (default)
|
'adjacent' : left and right rooms bitmaps will be drawn
|
||||||
'mirror' : the current room bitmap will be drawn mirrored
|
'mirror' : the current room bitmap will be drawn mirrored
|
||||||
|
|
||||||
In-game hotkeys :
|
In-game hotkeys :
|
||||||
|
@ -83,7 +84,6 @@ Credits:
|
||||||
|
|
||||||
Delphine Software, obviously, for making another great game.
|
Delphine Software, obviously, for making another great game.
|
||||||
Yaz0r, Pixel and gawd for sharing information they gathered on the game.
|
Yaz0r, Pixel and gawd for sharing information they gathered on the game.
|
||||||
Nicolas Bondoux for sound fixes.
|
|
||||||
|
|
||||||
|
|
||||||
Contact:
|
Contact:
|
||||||
|
|
61
cutscene.cpp
61
cutscene.cpp
|
@ -112,12 +112,12 @@ static bool isNewLineChar(uint8_t chr, Resource *res) {
|
||||||
return chr == nl;
|
return chr == nl;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t Cutscene::findTextSeparators(const uint8_t *p) {
|
uint16_t Cutscene::findTextSeparators(const uint8_t *p, int len) {
|
||||||
uint8_t *q = _textSep;
|
uint8_t *q = _textSep;
|
||||||
uint16_t ret = 0;
|
uint16_t ret = 0;
|
||||||
uint16_t pos = 0;
|
uint16_t pos = 0;
|
||||||
for (; *p != 0xA && *p; ++p) {
|
for (int i = 0; i < len && p[i] != 0xA; ++i) {
|
||||||
if (isNewLineChar(*p, _res)) {
|
if (isNewLineChar(p[i], _res)) {
|
||||||
*q++ = pos;
|
*q++ = pos;
|
||||||
if (pos > ret) {
|
if (pos > ret) {
|
||||||
ret = pos;
|
ret = pos;
|
||||||
|
@ -137,41 +137,43 @@ 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, int textJustify) {
|
void Cutscene::drawText(int16_t x, int16_t y, const uint8_t *p, uint16_t color, uint8_t *page, int textJustify) {
|
||||||
debug(DBG_CUT, "Cutscene::drawText(x=%d, y=%d, c=%d, justify=%d)", x, y, color, textJustify);
|
debug(DBG_CUT, "Cutscene::drawText(x=%d, y=%d, c=%d, justify=%d)", x, y, color, textJustify);
|
||||||
|
int len = 0;
|
||||||
if (_res->_type == kResourceTypeMac) {
|
if (_res->_type == kResourceTypeMac) {
|
||||||
warning("Unhandled Cutscene::drawText"); // TODO
|
len = *p++;
|
||||||
return;
|
} else {
|
||||||
|
len = strlen((const char *)p);
|
||||||
}
|
}
|
||||||
Video::drawCharFunc dcf = _vid->_drawChar;
|
Video::drawCharFunc dcf = _vid->_drawChar;
|
||||||
const uint8_t *fnt = (_res->_lang == LANG_JP) ? Video::_font8Jp : _res->_fnt;
|
const uint8_t *fnt = (_res->_lang == LANG_JP) ? Video::_font8Jp : _res->_fnt;
|
||||||
uint16_t last_sep = 0;
|
uint16_t lastSep = 0;
|
||||||
if (textJustify != kTextJustifyLeft) {
|
if (textJustify != kTextJustifyLeft) {
|
||||||
last_sep = findTextSeparators(p);
|
lastSep = findTextSeparators(p, len);
|
||||||
if (textJustify != kTextJustifyCenter) {
|
if (textJustify != kTextJustifyCenter) {
|
||||||
last_sep = (_res->_lang == LANG_JP) ? 20 : 30;
|
lastSep = (_res->_lang == LANG_JP) ? 20 : 30;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const uint8_t *sep = _textSep;
|
const uint8_t *sep = _textSep;
|
||||||
y += 50;
|
y += 50;
|
||||||
x += (_res->_lang == LANG_JP) ? 0 : 8;
|
x += (_res->_lang == LANG_JP) ? 0 : 8;
|
||||||
int16_t yy = y;
|
int16_t yPos = y;
|
||||||
int16_t xx = x;
|
int16_t xPos = x;
|
||||||
if (textJustify != kTextJustifyLeft) {
|
if (textJustify != kTextJustifyLeft) {
|
||||||
xx += ((last_sep - *sep++) / 2) * Video::CHAR_W;
|
xPos += ((lastSep - *sep++) / 2) * Video::CHAR_W;
|
||||||
}
|
}
|
||||||
for (; *p != 0xA && *p; ++p) {
|
for (int i = 0; i < len && p[i] != 0xA; ++i) {
|
||||||
if (isNewLineChar(*p, _res)) {
|
if (isNewLineChar(p[i], _res)) {
|
||||||
yy += Video::CHAR_H;
|
yPos += Video::CHAR_H;
|
||||||
xx = x;
|
xPos = x;
|
||||||
if (textJustify != kTextJustifyLeft) {
|
if (textJustify != kTextJustifyLeft) {
|
||||||
xx += ((last_sep - *sep++) / 2) * Video::CHAR_W;
|
xPos += ((lastSep - *sep++) / 2) * Video::CHAR_W;
|
||||||
}
|
}
|
||||||
} else if (*p == 0x20) {
|
} else if (p[i] == 0x20) {
|
||||||
xx += Video::CHAR_W;
|
xPos += Video::CHAR_W;
|
||||||
} else if (*p == 0x9) {
|
} else if (p[i] == 0x9) {
|
||||||
// ignore tab
|
// ignore tab
|
||||||
} else {
|
} else {
|
||||||
(_vid->*dcf)(page, _vid->_w, xx, yy, fnt, color, *p);
|
(_vid->*dcf)(page, _vid->_w, xPos, yPos, fnt, color, p[i]);
|
||||||
xx += Video::CHAR_W;
|
xPos += Video::CHAR_W;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -415,9 +417,12 @@ void Cutscene::op_drawStringAtBottom() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(_pageC + 179 * _vid->_w, 0xC0, 45 * _vid->_w);
|
const int h = 45 * _vid->_layerScale;
|
||||||
memset(_page1 + 179 * _vid->_w, 0xC0, 45 * _vid->_w);
|
const int y = Video::GAMESCREEN_H * _vid->_layerScale - h;
|
||||||
memset(_page0 + 179 * _vid->_w, 0xC0, 45 * _vid->_w);
|
|
||||||
|
memset(_pageC + y * _vid->_w, 0xC0, h * _vid->_w);
|
||||||
|
memset(_page1 + y * _vid->_w, 0xC0, h * _vid->_w);
|
||||||
|
memset(_page0 + y * _vid->_w, 0xC0, h * _vid->_w);
|
||||||
if (strId != 0xFFFF) {
|
if (strId != 0xFFFF) {
|
||||||
const uint8_t *str = _res->getCineString(strId);
|
const uint8_t *str = _res->getCineString(strId);
|
||||||
if (str) {
|
if (str) {
|
||||||
|
@ -878,7 +883,7 @@ void Cutscene::op_drawStringAtPos() {
|
||||||
// 'voyage' - cutscene script redraws the string to refresh the screen
|
// 'voyage' - cutscene script redraws the string to refresh the screen
|
||||||
if (_id == 0x34 && (strId & 0xFFF) == 0x45) {
|
if (_id == 0x34 && (strId & 0xFFF) == 0x45) {
|
||||||
if ((_cmdPtr - _cmdPtrBak) == 0xA) {
|
if ((_cmdPtr - _cmdPtrBak) == 0xA) {
|
||||||
_stub->copyRect(0, 0, _vid->_w, _vid->_h, _page1, 256);
|
_stub->copyRect(0, 0, _vid->_w, _vid->_h, _page1, _vid->_w);
|
||||||
_stub->updateScreen(0);
|
_stub->updateScreen(0);
|
||||||
} else {
|
} else {
|
||||||
_stub->sleep(15);
|
_stub->sleep(15);
|
||||||
|
@ -1059,9 +1064,7 @@ void Cutscene::unload() {
|
||||||
void Cutscene::prepare() {
|
void Cutscene::prepare() {
|
||||||
_page0 = _vid->_frontLayer;
|
_page0 = _vid->_frontLayer;
|
||||||
_page1 = _vid->_tempLayer;
|
_page1 = _vid->_tempLayer;
|
||||||
memset(_page1, 0, _vid->_layerSize);
|
|
||||||
_pageC = _vid->_tempLayer2;
|
_pageC = _vid->_tempLayer2;
|
||||||
memset(_pageC, 0, _vid->_layerSize);
|
|
||||||
_stub->_pi.dirMask = 0;
|
_stub->_pi.dirMask = 0;
|
||||||
_stub->_pi.enter = false;
|
_stub->_pi.enter = false;
|
||||||
_stub->_pi.space = false;
|
_stub->_pi.space = false;
|
||||||
|
@ -1080,6 +1083,10 @@ void Cutscene::prepare() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cutscene::playCredits() {
|
void Cutscene::playCredits() {
|
||||||
|
if (_res->isMac()) {
|
||||||
|
warning("Cutscene::playCredits() unimplemented");
|
||||||
|
return;
|
||||||
|
}
|
||||||
_textCurPtr = _res->isAmiga() ? _creditsDataAmiga : _creditsDataDOS;
|
_textCurPtr = _res->isAmiga() ? _creditsDataAmiga : _creditsDataDOS;
|
||||||
_textBuf[0] = 0xA;
|
_textBuf[0] = 0xA;
|
||||||
_textCurBuf = _textBuf;
|
_textCurBuf = _textBuf;
|
||||||
|
|
|
@ -113,7 +113,7 @@ struct Cutscene {
|
||||||
void updatePalette();
|
void updatePalette();
|
||||||
void setPalette();
|
void setPalette();
|
||||||
void setRotationTransform(uint16_t a, uint16_t b, uint16_t c);
|
void setRotationTransform(uint16_t a, uint16_t b, uint16_t c);
|
||||||
uint16_t findTextSeparators(const uint8_t *p);
|
uint16_t findTextSeparators(const uint8_t *p, int len);
|
||||||
void drawText(int16_t x, int16_t y, const uint8_t *p, uint16_t color, uint8_t *page, int textJustify);
|
void drawText(int16_t x, int16_t y, const uint8_t *p, uint16_t color, uint8_t *page, int textJustify);
|
||||||
void swapLayers();
|
void swapLayers();
|
||||||
void drawCreditsText();
|
void drawCreditsText();
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "decode_mac.h"
|
||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
uint8_t *decodeLzss(File &f, uint32_t &decodedSize) {
|
||||||
|
decodedSize = f.readUint32BE();
|
||||||
|
uint8_t *dst = (uint8_t *)malloc(decodedSize);
|
||||||
|
uint32_t count = 0;
|
||||||
|
while (count < decodedSize) {
|
||||||
|
const int code = f.readByte();
|
||||||
|
for (int i = 0; i < 8 && count < decodedSize; ++i) {
|
||||||
|
if ((code & (1 << i)) == 0) {
|
||||||
|
dst[count++] = f.readByte();
|
||||||
|
} else {
|
||||||
|
int offset = f.readUint16BE();
|
||||||
|
const int len = (offset >> 12) + 3;
|
||||||
|
offset &= 0xFFF;
|
||||||
|
for (int j = 0; j < len; ++j) {
|
||||||
|
dst[count + j] = dst[count - offset - 1 + j];
|
||||||
|
}
|
||||||
|
count += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(count == decodedSize);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setPixel(int x, int y, int w, int h, uint8_t color, DecodeBuffer *buf) {
|
||||||
|
buf->setPixel(buf, x, y, w, h, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decodeC103(const uint8_t *a3, int w, int h, DecodeBuffer *buf) {
|
||||||
|
uint8_t d0;
|
||||||
|
int d3 = 0;
|
||||||
|
int d7 = 1;
|
||||||
|
int d6 = 0;
|
||||||
|
int d1 = 0;
|
||||||
|
static const uint32_t d5 = 0xFFF;
|
||||||
|
uint8_t a1[0x1000];
|
||||||
|
|
||||||
|
for (int y = 0; y < h; ++y) {
|
||||||
|
for (int x = 0; x < w; ++x) {
|
||||||
|
assert(d6 >= 0);
|
||||||
|
if (d6 == 0) {
|
||||||
|
int carry = d7 & 1;
|
||||||
|
d7 >>= 1;
|
||||||
|
if (d7 == 0) {
|
||||||
|
d7 = *a3++;
|
||||||
|
const int extended_bit = carry ? 0x80 : 0;
|
||||||
|
carry = d7 & 1;
|
||||||
|
d7 = extended_bit | (d7 >> 1);
|
||||||
|
}
|
||||||
|
if (!carry) {
|
||||||
|
d0 = *a3++;
|
||||||
|
a1[d3] = d0;
|
||||||
|
++d3;
|
||||||
|
d3 &= d5;
|
||||||
|
setPixel(x, y, w, h, d0, buf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
d1 = READ_BE_UINT16(a3); a3 += 2;
|
||||||
|
d6 = d1;
|
||||||
|
d1 &= d5;
|
||||||
|
++d1;
|
||||||
|
d1 = (d3 - d1) & d5;
|
||||||
|
d6 >>= 12;
|
||||||
|
d6 += 3;
|
||||||
|
}
|
||||||
|
d0 = a1[d1++];
|
||||||
|
d1 &= d5;
|
||||||
|
a1[d3++] = d0;
|
||||||
|
d3 &= d5;
|
||||||
|
setPixel(x, y, w, h, d0, buf);
|
||||||
|
--d6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void decodeC211(const uint8_t *a3, int w, int h, DecodeBuffer *buf) {
|
||||||
|
struct {
|
||||||
|
const uint8_t *ptr;
|
||||||
|
int repeatCount;
|
||||||
|
} stack[512];
|
||||||
|
int y = 0;
|
||||||
|
int x = 0;
|
||||||
|
int sp = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
uint8_t d0 = *a3++;
|
||||||
|
if ((d0 & 0x80) != 0) {
|
||||||
|
++y;
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
int d1 = d0 & 0x1F;
|
||||||
|
if (d1 == 0) {
|
||||||
|
d1 = READ_BE_UINT16(a3); a3 += 2;
|
||||||
|
}
|
||||||
|
const int carry_set = (d0 & 0x40) != 0;
|
||||||
|
d0 <<= 2;
|
||||||
|
if (!carry_set) {
|
||||||
|
if ((d0 & 0x80) == 0) {
|
||||||
|
--d1;
|
||||||
|
if (d1 == 0) {
|
||||||
|
assert(sp > 0);
|
||||||
|
--stack[sp - 1].repeatCount;
|
||||||
|
if (stack[sp - 1].repeatCount >= 0) {
|
||||||
|
a3 = stack[sp - 1].ptr;
|
||||||
|
} else {
|
||||||
|
--sp;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(sp < ARRAYSIZE(stack));
|
||||||
|
stack[sp].ptr = a3;
|
||||||
|
stack[sp].repeatCount = d1;
|
||||||
|
++sp;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
x += d1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((d0 & 0x80) == 0) {
|
||||||
|
if (d1 == 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uint8_t color = *a3++;
|
||||||
|
for (int i = 0; i < d1; ++i) {
|
||||||
|
setPixel(x++, y, w, h, color, buf);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < d1; ++i) {
|
||||||
|
setPixel(x++, y, w, h, *a3++, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
#ifndef DECODE_MAC_H__
|
||||||
|
#define DECODE_MAC_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
uint8_t *decodeLzss(File &f, uint32_t &decodedSize);
|
||||||
|
|
||||||
|
struct DecodeBuffer {
|
||||||
|
uint8_t *ptr;
|
||||||
|
int w, h, pitch;
|
||||||
|
int x, y;
|
||||||
|
bool xflip;
|
||||||
|
|
||||||
|
void (*setPixel)(DecodeBuffer *buf, int src_x, int src_y, int src_w, int src_h, uint8_t color);
|
||||||
|
void *dataPtr;
|
||||||
|
};
|
||||||
|
|
||||||
|
void decodeC103(const uint8_t *a3, int w, int h, DecodeBuffer *buf);
|
||||||
|
void decodeC211(const uint8_t *a3, int w, int h, DecodeBuffer *buf);
|
||||||
|
|
||||||
|
#endif
|
89
game.cpp
89
game.cpp
|
@ -14,7 +14,7 @@
|
||||||
#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, WidescreenMode widescreenMode)
|
Game::Game(SystemStub *stub, FileSystem *fs, const char *savePath, int level, ResourceType ver, Language lang, WidescreenMode widescreenMode, bool autoSave)
|
||||||
: _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) {
|
||||||
|
@ -24,6 +24,7 @@ Game::Game(SystemStub *stub, FileSystem *fs, const char *savePath, int level, Re
|
||||||
_currentLevel = _menu._level = level;
|
_currentLevel = _menu._level = level;
|
||||||
_demoBin = -1;
|
_demoBin = -1;
|
||||||
_widescreenMode = widescreenMode;
|
_widescreenMode = widescreenMode;
|
||||||
|
_autoSave = autoSave;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::run() {
|
void Game::run() {
|
||||||
|
@ -150,6 +151,7 @@ void Game::run() {
|
||||||
resetGameState();
|
resetGameState();
|
||||||
_endLoop = false;
|
_endLoop = false;
|
||||||
_frameTimestamp = _stub->getTimeStamp();
|
_frameTimestamp = _stub->getTimeStamp();
|
||||||
|
_saveTimestamp = _frameTimestamp;
|
||||||
while (!_stub->_pi.quit && !_endLoop) {
|
while (!_stub->_pi.quit && !_endLoop) {
|
||||||
mainLoop();
|
mainLoop();
|
||||||
if (_demoBin != -1 && _inp_demPos >= _res._demLen) {
|
if (_demoBin != -1 && _inp_demPos >= _res._demLen) {
|
||||||
|
@ -166,8 +168,8 @@ void Game::run() {
|
||||||
_stub->_pi.shift = false;
|
_stub->_pi.shift = false;
|
||||||
// clear widescreen borders
|
// clear widescreen borders
|
||||||
if (_stub->hasWidescreen()) {
|
if (_stub->hasWidescreen()) {
|
||||||
_stub->copyRectLeftBorder(Video::GAMESCREEN_W, Video::GAMESCREEN_H, 0);
|
_stub->copyRectLeftBorder(_vid._w, _vid._h, 0);
|
||||||
_stub->copyRectRightBorder(Video::GAMESCREEN_W, Video::GAMESCREEN_H, 0);
|
_stub->copyRectRightBorder(_vid._w, _vid._h, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,10 +273,34 @@ void Game::displayTitleScreenMac(int num) {
|
||||||
Color c;
|
Color c;
|
||||||
c.r = c.g = c.b = 0;
|
c.r = c.g = c.b = 0;
|
||||||
_stub->setPaletteEntry(0, &c);
|
_stub->setPaletteEntry(0, &c);
|
||||||
|
} else if (num == Menu::kMacTitleScreen_Flashback) {
|
||||||
|
_vid.setTextPalette();
|
||||||
|
_vid._charShadowColor = 0xE0;
|
||||||
}
|
}
|
||||||
_stub->copyRect(0, 0, _vid._w, _vid._h, _vid._frontLayer, _vid._w);
|
_stub->copyRect(0, 0, _vid._w, _vid._h, _vid._frontLayer, _vid._w);
|
||||||
_stub->updateScreen(0);
|
_stub->updateScreen(0);
|
||||||
while (1) {
|
while (1) {
|
||||||
|
if (num == Menu::kMacTitleScreen_Flashback) {
|
||||||
|
static const uint8_t selectedColor = 0xE4;
|
||||||
|
static const uint8_t defaultColor = 0xE8;
|
||||||
|
for (int i = 0; i < 7; ++i) {
|
||||||
|
const char *str = Menu::_levelNames[i];
|
||||||
|
_vid.drawString(str, 24, 24 + i * 16, (_currentLevel == i) ? selectedColor : defaultColor);
|
||||||
|
}
|
||||||
|
if (_stub->_pi.dirMask & PlayerInput::DIR_UP) {
|
||||||
|
_stub->_pi.dirMask &= ~PlayerInput::DIR_UP;
|
||||||
|
if (_currentLevel > 0) {
|
||||||
|
--_currentLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_stub->_pi.dirMask & PlayerInput::DIR_DOWN) {
|
||||||
|
_stub->_pi.dirMask &= ~PlayerInput::DIR_DOWN;
|
||||||
|
if (_currentLevel < 6) {
|
||||||
|
++_currentLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_vid.updateScreen();
|
||||||
|
}
|
||||||
_stub->processEvents();
|
_stub->processEvents();
|
||||||
if (_stub->_pi.quit) {
|
if (_stub->_pi.quit) {
|
||||||
break;
|
break;
|
||||||
|
@ -324,10 +350,10 @@ void Game::mainLoop() {
|
||||||
playCutscene(0x41);
|
playCutscene(0x41);
|
||||||
_endLoop = true;
|
_endLoop = true;
|
||||||
} else {
|
} else {
|
||||||
if (_validSaveState) {
|
if (_autoSave && loadGameState(kAutoSaveSlot)) {
|
||||||
if (!loadGameState(0)) {
|
// autosave
|
||||||
_endLoop = true;
|
} else if (_validSaveState && loadGameState(kIngameSaveSlot)) {
|
||||||
}
|
// ingame save
|
||||||
} else {
|
} else {
|
||||||
loadLevelData();
|
loadLevelData();
|
||||||
resetGameState();
|
resetGameState();
|
||||||
|
@ -393,6 +419,13 @@ void Game::mainLoop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inp_handleSpecialKeys();
|
inp_handleSpecialKeys();
|
||||||
|
if (_stub->getTimeStamp() - _saveTimestamp >= kAutoSaveIntervalMs) {
|
||||||
|
// do not save if we just died
|
||||||
|
if (_pgeLive[0].life > 0) {
|
||||||
|
saveGameState(kAutoSaveSlot);
|
||||||
|
_saveTimestamp = _stub->getTimeStamp();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::updateTiming() {
|
void Game::updateTiming() {
|
||||||
|
@ -474,7 +507,7 @@ void Game::playCutscene(int id) {
|
||||||
_cut.play();
|
_cut.play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_res._type == kResourceTypeMac) {
|
if (_res._type == kResourceTypeMac && !(id == 0x48 || id == 0x49)) { // continue or score screens
|
||||||
// restore palette entries modified by the cutscene player (0xC and 0xD)
|
// restore palette entries modified by the cutscene player (0xC and 0xD)
|
||||||
Color palette[32];
|
Color palette[32];
|
||||||
_res.MAC_copyClut16(palette, 0, 0x37);
|
_res.MAC_copyClut16(palette, 0, 0x37);
|
||||||
|
@ -533,8 +566,8 @@ void Game::drawCurrentInventoryItem() {
|
||||||
|
|
||||||
void Game::showFinalScore() {
|
void Game::showFinalScore() {
|
||||||
if (_stub->hasWidescreen()) {
|
if (_stub->hasWidescreen()) {
|
||||||
_stub->copyRectLeftBorder(Video::GAMESCREEN_W, Video::GAMESCREEN_H, 0);
|
_stub->copyRectLeftBorder(_vid._w, _vid._h, 0);
|
||||||
_stub->copyRectRightBorder(Video::GAMESCREEN_W, Video::GAMESCREEN_H, 0);
|
_stub->copyRectRightBorder(_vid._w, _vid._h, 0);
|
||||||
}
|
}
|
||||||
playCutscene(0x49);
|
playCutscene(0x49);
|
||||||
char buf[50];
|
char buf[50];
|
||||||
|
@ -697,8 +730,8 @@ bool Game::handleConfigPanel() {
|
||||||
|
|
||||||
bool Game::handleContinueAbort() {
|
bool Game::handleContinueAbort() {
|
||||||
if (_stub->hasWidescreen()) {
|
if (_stub->hasWidescreen()) {
|
||||||
_stub->copyRectLeftBorder(Video::GAMESCREEN_W, Video::GAMESCREEN_H, 0);
|
_stub->copyRectLeftBorder(_vid._w, _vid._h, 0);
|
||||||
_stub->copyRectRightBorder(Video::GAMESCREEN_W, Video::GAMESCREEN_H, 0);
|
_stub->copyRectRightBorder(_vid._w, _vid._h, 0);
|
||||||
}
|
}
|
||||||
playCutscene(0x48);
|
playCutscene(0x48);
|
||||||
int timeout = 100;
|
int timeout = 100;
|
||||||
|
@ -1362,7 +1395,7 @@ void Game::drawObjectFrame(const uint8_t *bankDataPtr, const uint8_t *dataPtr, i
|
||||||
_vid.drawSpriteSub4(src, _vid._frontLayer + dst_offset, sprite_w, sprite_clipped_h, sprite_clipped_w, sprite_col_mask);
|
_vid.drawSpriteSub4(src, _vid._frontLayer + dst_offset, sprite_w, sprite_clipped_h, sprite_clipped_w, sprite_col_mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_vid.markBlockAsDirty(sprite_x, sprite_y, sprite_clipped_w, sprite_clipped_h);
|
_vid.markBlockAsDirty(sprite_x, sprite_y, sprite_clipped_w, sprite_clipped_h, _vid._layerScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::decodeCharacterFrame(const uint8_t *dataPtr, uint8_t *dstPtr) {
|
void Game::decodeCharacterFrame(const uint8_t *dataPtr, uint8_t *dstPtr) {
|
||||||
|
@ -1499,7 +1532,7 @@ void Game::drawCharacter(const uint8_t *dataPtr, int16_t pos_x, int16_t pos_y, u
|
||||||
_vid.drawSpriteSub4(src, _vid._frontLayer + dst_offset, sprite_w, sprite_clipped_h, sprite_clipped_w, sprite_col_mask);
|
_vid.drawSpriteSub4(src, _vid._frontLayer + dst_offset, sprite_w, sprite_clipped_h, sprite_clipped_w, sprite_col_mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_vid.markBlockAsDirty(pos_x, pos_y, sprite_clipped_w, sprite_clipped_h);
|
_vid.markBlockAsDirty(pos_x, pos_y, sprite_clipped_w, sprite_clipped_h, _vid._layerScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Game::loadMonsterSprites(LivePGE *pge) {
|
int Game::loadMonsterSprites(LivePGE *pge) {
|
||||||
|
@ -1617,14 +1650,30 @@ void Game::loadLevelMap() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_vid.PC_decodeMap(_currentLevel, _currentRoom);
|
_vid.PC_decodeMap(_currentLevel, _currentRoom);
|
||||||
if (_stub->hasWidescreen() && _widescreenMode == kWidescreenMirrorRoom) {
|
|
||||||
_stub->copyRectMirrorBorders(Video::GAMESCREEN_W, Video::GAMESCREEN_H, _vid._backLayer);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case kResourceTypeMac:
|
case kResourceTypeMac:
|
||||||
|
if (_stub->hasWidescreen() && _widescreenMode == kWidescreenAdjacentRooms) {
|
||||||
|
const int leftRoom = _res._ctData[CT_LEFT_ROOM + _currentRoom];
|
||||||
|
if (leftRoom > 0 && hasLevelMap(_currentLevel, leftRoom)) {
|
||||||
|
_vid.MAC_decodeMap(_currentLevel, leftRoom);
|
||||||
|
_stub->copyRectLeftBorder(_vid._w, _vid._h, _vid._backLayer);
|
||||||
|
} else {
|
||||||
|
_stub->copyRectLeftBorder(_vid._w, _vid._h, 0);
|
||||||
|
}
|
||||||
|
const int rightRoom = _res._ctData[CT_RIGHT_ROOM + _currentRoom];
|
||||||
|
if (rightRoom > 0 && hasLevelMap(_currentLevel, rightRoom)) {
|
||||||
|
_vid.MAC_decodeMap(_currentLevel, rightRoom);
|
||||||
|
_stub->copyRectRightBorder(_vid._w, _vid._h, _vid._backLayer);
|
||||||
|
} else {
|
||||||
|
_stub->copyRectRightBorder(_vid._w, _vid._h, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
_vid.MAC_decodeMap(_currentLevel, _currentRoom);
|
_vid.MAC_decodeMap(_currentLevel, _currentRoom);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (_stub->hasWidescreen() && _widescreenMode == kWidescreenMirrorRoom) {
|
||||||
|
_stub->copyRectMirrorBorders(_vid._w, _vid._h, _vid._backLayer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::loadLevelData() {
|
void Game::loadLevelData() {
|
||||||
|
@ -1806,7 +1855,7 @@ void Game::drawIcon(uint8_t iconNum, int16_t x, int16_t y, uint8_t colMask) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_vid.drawSpriteSub1(buf, _vid._frontLayer + x + y * _vid._w, 16, 16, 16, colMask << 4);
|
_vid.drawSpriteSub1(buf, _vid._frontLayer + x + y * _vid._w, 16, 16, 16, colMask << 4);
|
||||||
_vid.markBlockAsDirty(x, y, 16, 16);
|
_vid.markBlockAsDirty(x, y, 16, 16, _vid._layerScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::playSound(uint8_t sfxId, uint8_t softVol) {
|
void Game::playSound(uint8_t sfxId, uint8_t softVol) {
|
||||||
|
@ -2006,7 +2055,7 @@ static const uint32_t TAG_FBSV = 0x46425356;
|
||||||
|
|
||||||
bool Game::saveGameState(uint8_t slot) {
|
bool Game::saveGameState(uint8_t slot) {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
char stateFile[20];
|
char stateFile[32];
|
||||||
makeGameStateName(slot, stateFile);
|
makeGameStateName(slot, stateFile);
|
||||||
File f;
|
File f;
|
||||||
if (!f.open(stateFile, "zwb", _savePath)) {
|
if (!f.open(stateFile, "zwb", _savePath)) {
|
||||||
|
@ -2033,7 +2082,7 @@ bool Game::saveGameState(uint8_t slot) {
|
||||||
|
|
||||||
bool Game::loadGameState(uint8_t slot) {
|
bool Game::loadGameState(uint8_t slot) {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
char stateFile[20];
|
char stateFile[32];
|
||||||
makeGameStateName(slot, stateFile);
|
makeGameStateName(slot, stateFile);
|
||||||
File f;
|
File f;
|
||||||
if (!f.open(stateFile, "zrb", _savePath)) {
|
if (!f.open(stateFile, "zrb", _savePath)) {
|
||||||
|
|
10
game.h
10
game.h
|
@ -25,6 +25,12 @@ struct Game {
|
||||||
typedef int (Game::*col_Callback1)(LivePGE *, LivePGE *, int16_t, int16_t);
|
typedef int (Game::*col_Callback1)(LivePGE *, LivePGE *, int16_t, int16_t);
|
||||||
typedef int (Game::*col_Callback2)(LivePGE *, int16_t, int16_t, int16_t);
|
typedef int (Game::*col_Callback2)(LivePGE *, int16_t, int16_t, int16_t);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kIngameSaveSlot = 0,
|
||||||
|
kAutoSaveSlot = 255,
|
||||||
|
kAutoSaveIntervalMs = 30 * 1000
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CT_UP_ROOM = 0x00,
|
CT_UP_ROOM = 0x00,
|
||||||
CT_DOWN_ROOM = 0x40,
|
CT_DOWN_ROOM = 0x40,
|
||||||
|
@ -87,8 +93,10 @@ struct Game {
|
||||||
bool _endLoop;
|
bool _endLoop;
|
||||||
uint32_t _frameTimestamp;
|
uint32_t _frameTimestamp;
|
||||||
WidescreenMode _widescreenMode;
|
WidescreenMode _widescreenMode;
|
||||||
|
bool _autoSave;
|
||||||
|
uint32_t _saveTimestamp;
|
||||||
|
|
||||||
Game(SystemStub *, FileSystem *, const char *savePath, int level, ResourceType ver, Language lang, WidescreenMode widescreenMode);
|
Game(SystemStub *, FileSystem *, const char *savePath, int level, ResourceType ver, Language lang, WidescreenMode widescreenMode, bool autoSave);
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
void displayTitleScreenAmiga();
|
void displayTitleScreenAmiga();
|
||||||
|
|
15
graphics.cpp
15
graphics.cpp
|
@ -211,21 +211,18 @@ void Graphics::fillArea(uint8_t color, bool hasAlpha) {
|
||||||
if (x1 >= 0) {
|
if (x1 >= 0) {
|
||||||
if (hasAlpha && color > 0xC7) {
|
if (hasAlpha && color > 0xC7) {
|
||||||
do {
|
do {
|
||||||
int16_t x2 = *pts++;
|
const int16_t x2 = MIN<int16_t>(_crw - 1, *pts++);
|
||||||
if (x2 < _crw && x2 >= x1) {
|
for (; x1 <= x2; ++x1) {
|
||||||
int len = x2 - x1 + 1;
|
*(dst + x1) |= color & 8;
|
||||||
for (int i = 0; i < len; ++i) {
|
|
||||||
*(dst + x1 + i) |= color & 8; // XXX 0x88
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
dst += _layerPitch;
|
dst += _layerPitch;
|
||||||
x1 = *pts++;
|
x1 = *pts++;
|
||||||
} while (x1 >= 0);
|
} while (x1 >= 0);
|
||||||
} else {
|
} else {
|
||||||
do {
|
do {
|
||||||
int16_t x2 = *pts++;
|
const int16_t x2 = MIN<int16_t>(_crw - 1, *pts++);
|
||||||
if (x2 < _crw && x2 >= x1) {
|
if (x1 <= x2) {
|
||||||
int len = x2 - x1 + 1;
|
const int len = x2 - x1 + 1;
|
||||||
memset(dst + x1, color, len);
|
memset(dst + x1, color, len);
|
||||||
}
|
}
|
||||||
dst += _layerPitch;
|
dst += _layerPitch;
|
||||||
|
|
34
intern.h
34
intern.h
|
@ -13,12 +13,6 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#undef ABS
|
|
||||||
#define ABS(x) ((x)<0?-(x):(x))
|
|
||||||
#undef MAX
|
|
||||||
#define MAX(x,y) ((x)>(y)?(x):(y))
|
|
||||||
#undef MIN
|
|
||||||
#define MIN(x,y) ((x)<(y)?(x):(y))
|
|
||||||
#undef ARRAYSIZE
|
#undef ARRAYSIZE
|
||||||
#define ARRAYSIZE(a) (int)(sizeof(a)/sizeof(a[0]))
|
#define ARRAYSIZE(a) (int)(sizeof(a)/sizeof(a[0]))
|
||||||
|
|
||||||
|
@ -42,16 +36,6 @@ inline uint32_t READ_LE_UINT32(const void *ptr) {
|
||||||
return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
|
return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int8_t ADDC_S8(int a, int b) {
|
|
||||||
a += b;
|
|
||||||
if (a < -128) {
|
|
||||||
a = -128;
|
|
||||||
} else if (a > 127) {
|
|
||||||
a = 127;
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int16_t ADDC_S16(int a, int b) {
|
inline int16_t ADDC_S16(int a, int b) {
|
||||||
a += b;
|
a += b;
|
||||||
if (a < -32768) {
|
if (a < -32768) {
|
||||||
|
@ -79,6 +63,24 @@ inline T CLIP(const T& val, const T& a, const T& b) {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef MIN
|
||||||
|
template<typename T>
|
||||||
|
inline T MIN(T v1, T v2) {
|
||||||
|
return (v1 < v2) ? v1 : v2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef MAX
|
||||||
|
template<typename T>
|
||||||
|
inline T MAX(T v1, T v2) {
|
||||||
|
return (v1 > v2) ? v1 : v2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef ABS
|
||||||
|
template<typename T>
|
||||||
|
inline T ABS(T t) {
|
||||||
|
return (t < 0) ? -t : t;
|
||||||
|
}
|
||||||
|
|
||||||
enum Language {
|
enum Language {
|
||||||
LANG_FR,
|
LANG_FR,
|
||||||
LANG_EN,
|
LANG_EN,
|
||||||
|
|
8
main.cpp
8
main.cpp
|
@ -25,6 +25,7 @@ static const char *USAGE =
|
||||||
" --widescreen=MODE 16:9 display\n"
|
" --widescreen=MODE 16:9 display\n"
|
||||||
" --scaler=NAME@X Graphics scaler (default 'scale@3')\n"
|
" --scaler=NAME@X Graphics scaler (default 'scale@3')\n"
|
||||||
" --language=LANG Language (fr,en,de,sp,it,jp)\n"
|
" --language=LANG Language (fr,en,de,sp,it,jp)\n"
|
||||||
|
" --autosave Save game state automatically\n"
|
||||||
;
|
;
|
||||||
|
|
||||||
static int detectVersion(FileSystem *fs) {
|
static int detectVersion(FileSystem *fs) {
|
||||||
|
@ -215,6 +216,7 @@ int main(int argc, char *argv[]) {
|
||||||
const char *savePath = ".";
|
const char *savePath = ".";
|
||||||
int levelNum = 0;
|
int levelNum = 0;
|
||||||
bool fullscreen = false;
|
bool fullscreen = false;
|
||||||
|
bool autoSave = false;
|
||||||
WidescreenMode widescreen = kWidescreenNone;
|
WidescreenMode widescreen = kWidescreenNone;
|
||||||
ScalerParameters scalerParameters = ScalerParameters::defaults();
|
ScalerParameters scalerParameters = ScalerParameters::defaults();
|
||||||
int forcedLanguage = -1;
|
int forcedLanguage = -1;
|
||||||
|
@ -234,6 +236,7 @@ int main(int argc, char *argv[]) {
|
||||||
{ "scaler", required_argument, 0, 5 },
|
{ "scaler", required_argument, 0, 5 },
|
||||||
{ "language", required_argument, 0, 6 },
|
{ "language", required_argument, 0, 6 },
|
||||||
{ "widescreen", required_argument, 0, 7 },
|
{ "widescreen", required_argument, 0, 7 },
|
||||||
|
{ "autosave", no_argument, 0, 8 },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
int index;
|
int index;
|
||||||
|
@ -281,6 +284,9 @@ int main(int argc, char *argv[]) {
|
||||||
case 7:
|
case 7:
|
||||||
widescreen = parseWidescreen(optarg);
|
widescreen = parseWidescreen(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 8:
|
||||||
|
autoSave = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf(USAGE, argv[0]);
|
printf(USAGE, argv[0]);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -296,7 +302,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, widescreen);
|
Game *g = new Game(stub, &fs, savePath, levelNum, (ResourceType)version, language, widescreen, autoSave);
|
||||||
stub->init(g_caption, g->_vid._w, g->_vid._h, fullscreen, widescreen != kWidescreenNone, &scalerParameters);
|
stub->init(g_caption, g->_vid._w, g->_vid._h, fullscreen, widescreen != kWidescreenNone, &scalerParameters);
|
||||||
g->run();
|
g->run();
|
||||||
delete g;
|
delete g;
|
||||||
|
|
19
menu.cpp
19
menu.cpp
|
@ -84,7 +84,7 @@ void Menu::drawString2(const char *str, int16_t y, int16_t x) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_vid->markBlockAsDirty(x * w, y * h, len * w, h);
|
_vid->markBlockAsDirty(x * w, y * h, len * w, h, _vid->_layerScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::loadPicture(const char *prefix) {
|
void Menu::loadPicture(const char *prefix) {
|
||||||
|
@ -201,7 +201,7 @@ bool Menu::handlePasswordScreen() {
|
||||||
}
|
}
|
||||||
_vid->PC_drawChar(0x20, 21, len + 15);
|
_vid->PC_drawChar(0x20, 21, len + 15);
|
||||||
|
|
||||||
_vid->markBlockAsDirty(15 * Video::CHAR_W, 21 * Video::CHAR_H, (len + 1) * Video::CHAR_W, Video::CHAR_H);
|
_vid->markBlockAsDirty(15 * Video::CHAR_W, 21 * Video::CHAR_H, (len + 1) * Video::CHAR_W, Video::CHAR_H, _vid->_layerScale);
|
||||||
_vid->updateScreen();
|
_vid->updateScreen();
|
||||||
_stub->sleep(EVENTS_DELAY);
|
_stub->sleep(EVENTS_DELAY);
|
||||||
_stub->processEvents();
|
_stub->processEvents();
|
||||||
|
@ -254,24 +254,15 @@ bool Menu::handleLevelScreen() {
|
||||||
int currentSkill = _skill;
|
int currentSkill = _skill;
|
||||||
int currentLevel = _level;
|
int currentLevel = _level;
|
||||||
do {
|
do {
|
||||||
static const char *levelTitles[] = {
|
|
||||||
"Titan / The Jungle",
|
|
||||||
"Titan / New Washington",
|
|
||||||
"Titan / Death Tower Show",
|
|
||||||
"Earth / Surface",
|
|
||||||
"Earth / Paradise Club",
|
|
||||||
"Planet Morphs / Surface",
|
|
||||||
"Planet Morphs / Inner Core"
|
|
||||||
};
|
|
||||||
for (int i = 0; i < 7; ++i) {
|
for (int i = 0; i < 7; ++i) {
|
||||||
drawString(levelTitles[i], 7 + i * 2, 4, (currentLevel == i) ? 2 : 3);
|
drawString(_levelNames[i], 7 + i * 2, 4, (currentLevel == i) ? 2 : 3);
|
||||||
}
|
}
|
||||||
_vid->markBlockAsDirty(4 * Video::CHAR_W, 7 * Video::CHAR_H, 192, 7 * Video::CHAR_H);
|
_vid->markBlockAsDirty(4 * Video::CHAR_W, 7 * Video::CHAR_H, 192, 7 * Video::CHAR_H, _vid->_layerScale);
|
||||||
|
|
||||||
drawString(_res->getMenuString(LocaleData::LI_13_EASY), 23, 4, (currentSkill == 0) ? 2 : 3);
|
drawString(_res->getMenuString(LocaleData::LI_13_EASY), 23, 4, (currentSkill == 0) ? 2 : 3);
|
||||||
drawString(_res->getMenuString(LocaleData::LI_14_NORMAL), 23, 14, (currentSkill == 1) ? 2 : 3);
|
drawString(_res->getMenuString(LocaleData::LI_14_NORMAL), 23, 14, (currentSkill == 1) ? 2 : 3);
|
||||||
drawString(_res->getMenuString(LocaleData::LI_15_EXPERT), 23, 24, (currentSkill == 2) ? 2 : 3);
|
drawString(_res->getMenuString(LocaleData::LI_15_EXPERT), 23, 24, (currentSkill == 2) ? 2 : 3);
|
||||||
_vid->markBlockAsDirty(4 * Video::CHAR_W, 23 * Video::CHAR_H, 192, Video::CHAR_H);
|
_vid->markBlockAsDirty(4 * Video::CHAR_W, 23 * Video::CHAR_H, 192, Video::CHAR_H, _vid->_layerScale);
|
||||||
|
|
||||||
_vid->updateScreen();
|
_vid->updateScreen();
|
||||||
_stub->sleep(EVENTS_DELAY);
|
_stub->sleep(EVENTS_DELAY);
|
||||||
|
|
1
menu.h
1
menu.h
|
@ -48,6 +48,7 @@ struct Menu {
|
||||||
int opt;
|
int opt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char *_levelNames[];
|
||||||
static const char *_passwordsDOS[];
|
static const char *_passwordsDOS[];
|
||||||
static const char *_passwordsFrAmiga[];
|
static const char *_passwordsFrAmiga[];
|
||||||
static const char *_passwordsEnAmiga[];
|
static const char *_passwordsEnAmiga[];
|
||||||
|
|
10
mixer.cpp
10
mixer.cpp
|
@ -139,6 +139,15 @@ void Mixer::stopMusic() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nr(int16_t *buf, int len) {
|
||||||
|
static int prev = 0;
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
const int vnr = buf[i] >> 1;
|
||||||
|
buf[i] = vnr + prev;
|
||||||
|
prev = vnr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Mixer::mix(int16_t *out, int len) {
|
void Mixer::mix(int16_t *out, int len) {
|
||||||
if (_premixHook) {
|
if (_premixHook) {
|
||||||
if (!_premixHook(_premixHookData, out, len)) {
|
if (!_premixHook(_premixHookData, out, len)) {
|
||||||
|
@ -160,6 +169,7 @@ void Mixer::mix(int16_t *out, int len) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
nr(out, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mixer::mixCallback(void *param, int16_t *buf, int len) {
|
void Mixer::mixCallback(void *param, int16_t *buf, int len) {
|
||||||
|
|
|
@ -156,8 +156,7 @@ struct ModPlayer_impl {
|
||||||
void applyVibrato(int trackNum);
|
void applyVibrato(int trackNum);
|
||||||
void applyPortamento(int trackNum);
|
void applyPortamento(int trackNum);
|
||||||
void handleEffect(int trackNum, bool tick);
|
void handleEffect(int trackNum, bool tick);
|
||||||
void mixSamples(int8_t *buf, int len);
|
void mixSamples(int16_t *buf, int len);
|
||||||
bool mixS8(int8_t *buf, int len);
|
|
||||||
bool mix(int16_t *buf, int len);
|
bool mix(int16_t *buf, int len);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -584,11 +583,11 @@ void ModPlayer_impl::handleTick() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModPlayer_impl::mixSamples(int8_t *buf, int samplesLen) {
|
void ModPlayer_impl::mixSamples(int16_t *buf, int samplesLen) {
|
||||||
for (int i = 0; i < NUM_TRACKS; ++i) {
|
for (int i = 0; i < NUM_TRACKS; ++i) {
|
||||||
Track *tk = &_tracks[i];
|
Track *tk = &_tracks[i];
|
||||||
if (tk->sample != 0 && tk->delayCounter == 0) {
|
if (tk->sample != 0 && tk->delayCounter == 0) {
|
||||||
int8_t *mixbuf = buf;
|
int16_t *mixbuf = buf;
|
||||||
SampleInfo *si = tk->sample;
|
SampleInfo *si = tk->sample;
|
||||||
int len = si->len << FRAC_BITS;
|
int len = si->len << FRAC_BITS;
|
||||||
int loopLen = si->repeatLen << FRAC_BITS;
|
int loopLen = si->repeatLen << FRAC_BITS;
|
||||||
|
@ -614,7 +613,7 @@ void ModPlayer_impl::mixSamples(int8_t *buf, int samplesLen) {
|
||||||
}
|
}
|
||||||
while (count--) {
|
while (count--) {
|
||||||
const int out = si->getPCM(pos >> FRAC_BITS);
|
const int out = si->getPCM(pos >> FRAC_BITS);
|
||||||
*mixbuf = ADDC_S8(*mixbuf, out * tk->volume / 64);
|
*mixbuf = ADDC_S16(*mixbuf, (out * tk->volume / 64) << 8);
|
||||||
++mixbuf;
|
++mixbuf;
|
||||||
pos += deltaPos;
|
pos += deltaPos;
|
||||||
}
|
}
|
||||||
|
@ -624,7 +623,8 @@ void ModPlayer_impl::mixSamples(int8_t *buf, int samplesLen) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModPlayer_impl::mixS8(int8_t *buf, int len) {
|
bool ModPlayer_impl::mix(int16_t *buf, int len) {
|
||||||
|
memset(buf, 0, sizeof(int16_t) * len);
|
||||||
if (_playing) {
|
if (_playing) {
|
||||||
const int samplesPerTick = _mixingRate / (50 * _songTempo / 125);
|
const int samplesPerTick = _mixingRate / (50 * _songTempo / 125);
|
||||||
while (len != 0) {
|
while (len != 0) {
|
||||||
|
@ -644,16 +644,6 @@ bool ModPlayer_impl::mixS8(int8_t *buf, int len) {
|
||||||
}
|
}
|
||||||
return _playing;
|
return _playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModPlayer_impl::mix(int16_t *samples, int len) {
|
|
||||||
int8_t buf[len];
|
|
||||||
memset(buf, 0, sizeof(buf));
|
|
||||||
const bool ret = mixS8(buf, len);
|
|
||||||
for (int i = 0; i < len; ++i) {
|
|
||||||
samples[i] = buf[i] << 8;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ModPlayer::ModPlayer(Mixer *mixer, FileSystem *fs)
|
ModPlayer::ModPlayer(Mixer *mixer, FileSystem *fs)
|
||||||
|
|
|
@ -325,7 +325,7 @@ int Game::pge_execute(LivePGE *live_pge, InitPGE *init_pge, const Object *obj) {
|
||||||
++live_pge->life;
|
++live_pge->life;
|
||||||
}
|
}
|
||||||
if (obj->flags & 8) {
|
if (obj->flags & 8) {
|
||||||
live_pge->life = 0xFFFF;
|
live_pge->life = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (live_pge->flags & 1) {
|
if (live_pge->flags & 1) {
|
||||||
|
@ -1428,7 +1428,7 @@ int Game::pge_op_setCollisionState2(ObjectOpcodeArgs *args) {
|
||||||
|
|
||||||
int Game::pge_op_saveState(ObjectOpcodeArgs *args) {
|
int Game::pge_op_saveState(ObjectOpcodeArgs *args) {
|
||||||
_saveStateCompleted = true;
|
_saveStateCompleted = true;
|
||||||
_validSaveState = saveGameState(0);
|
_validSaveState = saveGameState(kIngameSaveSlot);
|
||||||
return 0xFFFF;
|
return 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1679,6 +1679,10 @@ void Resource::MAC_loadCutsceneText() {
|
||||||
_cine_off = 0; // offsets are prepended to _cine_txt
|
_cine_off = 0; // offsets are prepended to _cine_txt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Resource::MAC_loadCreditsText() {
|
||||||
|
_credits = decodeResourceMacData("Credit strings", false);
|
||||||
|
}
|
||||||
|
|
||||||
void Resource::MAC_loadSounds() {
|
void Resource::MAC_loadSounds() {
|
||||||
static const int8_t table[NUM_SFXS] = {
|
static const int8_t table[NUM_SFXS] = {
|
||||||
0, -1, 1, 2, 3, 4, -1, 5, 6, 7, 8, 9, 10, 11, -1, 12,
|
0, -1, 1, 2, 3, 4, -1, 5, 6, 7, 8, 9, 10, 11, -1, 12,
|
||||||
|
|
|
@ -177,6 +177,7 @@ struct Resource {
|
||||||
uint8_t *_perso;
|
uint8_t *_perso;
|
||||||
uint8_t *_monster;
|
uint8_t *_monster;
|
||||||
uint8_t *_str;
|
uint8_t *_str;
|
||||||
|
uint8_t *_credits;
|
||||||
|
|
||||||
Resource(FileSystem *fs, ResourceType type, Language lang);
|
Resource(FileSystem *fs, ResourceType type, Language lang);
|
||||||
~Resource();
|
~Resource();
|
||||||
|
@ -335,6 +336,7 @@ struct Resource {
|
||||||
void MAC_unloadCutscene();
|
void MAC_unloadCutscene();
|
||||||
void MAC_loadCutscene(const char *cutscene);
|
void MAC_loadCutscene(const char *cutscene);
|
||||||
void MAC_loadCutsceneText();
|
void MAC_loadCutsceneText();
|
||||||
|
void MAC_loadCreditsText();
|
||||||
void MAC_loadSounds();
|
void MAC_loadSounds();
|
||||||
|
|
||||||
int MAC_getPersoFrame(int anim) const {
|
int MAC_getPersoFrame(int anim) const {
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "fs.h"
|
||||||
|
#include "resource_mac.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
const char *ResourceMac::FILENAME1 = "Flashback.bin";
|
||||||
|
const char *ResourceMac::FILENAME2 = "Flashback.rsrc";
|
||||||
|
|
||||||
|
ResourceMac::ResourceMac(const char *filePath, FileSystem *fs)
|
||||||
|
: _dataOffset(0), _types(0), _entries(0) {
|
||||||
|
memset(&_map, 0, sizeof(_map));
|
||||||
|
_f.open(filePath, "rb", fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceMac::~ResourceMac() {
|
||||||
|
if (_entries) {
|
||||||
|
for (int i = 0; i < _map.typesCount; ++i) {
|
||||||
|
free(_entries[i]);
|
||||||
|
}
|
||||||
|
free(_entries);
|
||||||
|
}
|
||||||
|
free(_types);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceMac::load() {
|
||||||
|
const uint32_t sig = _f.readUint32BE();
|
||||||
|
if (sig == 0x00051607) { // AppleDouble
|
||||||
|
debug(DBG_INFO, "Load Macintosh data from AppleDouble");
|
||||||
|
_f.seek(24);
|
||||||
|
const int count = _f.readUint16BE();
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
const int id = _f.readUint32BE();
|
||||||
|
const int offset = _f.readUint32BE();
|
||||||
|
const int length = _f.readUint32BE();
|
||||||
|
if (id == 2) { // resource fork
|
||||||
|
loadResourceFork(offset, length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // MacBinary
|
||||||
|
debug(DBG_INFO, "Load Macintosh data from MacBinary");
|
||||||
|
_f.seek(83);
|
||||||
|
uint32_t dataSize = _f.readUint32BE();
|
||||||
|
uint32_t resourceOffset = 128 + ((dataSize + 127) & ~127);
|
||||||
|
loadResourceFork(resourceOffset, dataSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceMac::loadResourceFork(uint32_t resourceOffset, uint32_t dataSize) {
|
||||||
|
_f.seek(resourceOffset);
|
||||||
|
_dataOffset = resourceOffset + _f.readUint32BE();
|
||||||
|
uint32_t mapOffset = resourceOffset + _f.readUint32BE();
|
||||||
|
|
||||||
|
_f.seek(mapOffset + 22);
|
||||||
|
_f.readUint16BE();
|
||||||
|
_map.typesOffset = _f.readUint16BE();
|
||||||
|
_map.namesOffset = _f.readUint16BE();
|
||||||
|
_map.typesCount = _f.readUint16BE() + 1;
|
||||||
|
|
||||||
|
_f.seek(mapOffset + _map.typesOffset + 2);
|
||||||
|
_types = (ResourceMacType *)calloc(_map.typesCount, sizeof(ResourceMacType));
|
||||||
|
for (int i = 0; i < _map.typesCount; ++i) {
|
||||||
|
_f.read(_types[i].id, 4);
|
||||||
|
_types[i].count = _f.readUint16BE() + 1;
|
||||||
|
_types[i].startOffset = _f.readUint16BE();
|
||||||
|
}
|
||||||
|
_entries = (ResourceMacEntry **)calloc(_map.typesCount, sizeof(ResourceMacEntry *));
|
||||||
|
for (int i = 0; i < _map.typesCount; ++i) {
|
||||||
|
_f.seek(mapOffset + _map.typesOffset + _types[i].startOffset);
|
||||||
|
_entries[i] = (ResourceMacEntry *)calloc(_types[i].count, sizeof(ResourceMacEntry));
|
||||||
|
for (int j = 0; j < _types[i].count; ++j) {
|
||||||
|
_entries[i][j].id = _f.readUint16BE();
|
||||||
|
_entries[i][j].nameOffset = _f.readUint16BE();
|
||||||
|
_entries[i][j].dataOffset = _f.readUint32BE() & 0x00FFFFFF;
|
||||||
|
_f.readUint32BE();
|
||||||
|
}
|
||||||
|
for (int j = 0; j < _types[i].count; ++j) {
|
||||||
|
_entries[i][j].name[0] = '\0';
|
||||||
|
if (_entries[i][j].nameOffset != 0xFFFF) {
|
||||||
|
_f.seek(mapOffset + _map.namesOffset + _entries[i][j].nameOffset);
|
||||||
|
const int len = _f.readByte();
|
||||||
|
assert(len < kResourceMacEntryNameLength - 1);
|
||||||
|
_f.read(_entries[i][j].name, len);
|
||||||
|
_entries[i][j].name[len] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ResourceMacEntry *ResourceMac::findEntry(const char *name) const {
|
||||||
|
for (int type = 0; type < _map.typesCount; ++type) {
|
||||||
|
for (int i = 0; i < _types[type].count; ++i) {
|
||||||
|
if (strcmp(name, _entries[type][i].name) == 0) {
|
||||||
|
return &_entries[type][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
|
||||||
|
#ifndef RESOURCE_MAC_H__
|
||||||
|
#define RESOURCE_MAC_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
struct ResourceMacMap {
|
||||||
|
uint16_t typesOffset;
|
||||||
|
uint16_t namesOffset;
|
||||||
|
uint16_t typesCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ResourceMacType {
|
||||||
|
unsigned char id[4];
|
||||||
|
uint16_t count;
|
||||||
|
uint16_t startOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kResourceMacEntryNameLength = 64
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ResourceMacEntry {
|
||||||
|
uint16_t id;
|
||||||
|
uint16_t nameOffset;
|
||||||
|
uint32_t dataOffset;
|
||||||
|
char name[kResourceMacEntryNameLength];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ResourceMac {
|
||||||
|
|
||||||
|
static const char *FILENAME1;
|
||||||
|
static const char *FILENAME2;
|
||||||
|
|
||||||
|
File _f;
|
||||||
|
|
||||||
|
uint32_t _dataOffset;
|
||||||
|
ResourceMacMap _map;
|
||||||
|
ResourceMacType *_types;
|
||||||
|
ResourceMacEntry **_entries;
|
||||||
|
|
||||||
|
ResourceMac(const char *filePath, FileSystem *);
|
||||||
|
~ResourceMac();
|
||||||
|
|
||||||
|
bool isOpen() const { return _entries != 0; }
|
||||||
|
void load();
|
||||||
|
void loadResourceFork(uint32_t offset, uint32_t size);
|
||||||
|
const ResourceMacEntry *findEntry(const char *name) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -97,11 +97,11 @@ void SfxPlayer::handleTick() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SfxPlayer::mixSamples(int8_t *buf, int samplesLen) {
|
void SfxPlayer::mixSamples(int16_t *buf, int samplesLen) {
|
||||||
for (int i = 0; i < NUM_CHANNELS; ++i) {
|
for (int i = 0; i < NUM_CHANNELS; ++i) {
|
||||||
SampleInfo *si = &_samples[i];
|
SampleInfo *si = &_samples[i];
|
||||||
if (si->data) {
|
if (si->data) {
|
||||||
int8_t *mixbuf = buf;
|
int16_t *mixbuf = buf;
|
||||||
int len = si->len << FRAC_BITS;
|
int len = si->len << FRAC_BITS;
|
||||||
int loopLen = si->loopLen << FRAC_BITS;
|
int loopLen = si->loopLen << FRAC_BITS;
|
||||||
int loopPos = si->loopPos << FRAC_BITS;
|
int loopPos = si->loopPos << FRAC_BITS;
|
||||||
|
@ -127,7 +127,7 @@ void SfxPlayer::mixSamples(int8_t *buf, int samplesLen) {
|
||||||
}
|
}
|
||||||
while (count--) {
|
while (count--) {
|
||||||
const int out = si->getPCM(pos >> FRAC_BITS);
|
const int out = si->getPCM(pos >> FRAC_BITS);
|
||||||
*mixbuf = ADDC_S8(*mixbuf, out * si->vol / 64);
|
*mixbuf = ADDC_S16(*mixbuf, (out * si->vol / 64) << 8);
|
||||||
++mixbuf;
|
++mixbuf;
|
||||||
pos += deltaPos;
|
pos += deltaPos;
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,8 @@ void SfxPlayer::mixSamples(int8_t *buf, int samplesLen) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SfxPlayer::mix(int8_t *buf, int len) {
|
bool SfxPlayer::mix(int16_t *buf, int len) {
|
||||||
|
memset(buf, 0, sizeof(int16_t) * len);
|
||||||
if (_playing) {
|
if (_playing) {
|
||||||
const int samplesPerTick = _mix->getSampleRate() / 50;
|
const int samplesPerTick = _mix->getSampleRate() / 50;
|
||||||
while (len != 0) {
|
while (len != 0) {
|
||||||
|
@ -159,11 +160,5 @@ bool SfxPlayer::mix(int8_t *buf, int len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SfxPlayer::mixCallback(void *param, int16_t *samples, int len) {
|
bool SfxPlayer::mixCallback(void *param, int16_t *samples, int len) {
|
||||||
int8_t buf[len];
|
return ((SfxPlayer *)param)->mix(samples, 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,9 +81,9 @@ struct SfxPlayer {
|
||||||
void stop();
|
void stop();
|
||||||
void playSample(int channel, const uint8_t *sampleData, uint16_t period);
|
void playSample(int channel, const uint8_t *sampleData, uint16_t period);
|
||||||
void handleTick();
|
void handleTick();
|
||||||
void mixSamples(int8_t *samples, int samplesLen);
|
void mixSamples(int16_t *samples, int samplesLen);
|
||||||
|
|
||||||
bool mix(int8_t *buf, int len);
|
bool mix(int16_t *buf, int len);
|
||||||
static bool mixCallback(void *param, int16_t *buf, int len);
|
static bool mixCallback(void *param, int16_t *buf, int len);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3223,6 +3223,16 @@ const uint8_t Game::_protectionPal[] = {
|
||||||
0x08, 0x88, 0x09, 0x99, 0x0A, 0xAA, 0x0B, 0xBB, 0x0C, 0xCC, 0x0D, 0xDD, 0x0E, 0xEE, 0x0F, 0xFF
|
0x08, 0x88, 0x09, 0x99, 0x0A, 0xAA, 0x0B, 0xBB, 0x0C, 0xCC, 0x0D, 0xDD, 0x0E, 0xEE, 0x0F, 0xFF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *Menu::_levelNames[] {
|
||||||
|
"Titan / The Jungle",
|
||||||
|
"Titan / New Washington",
|
||||||
|
"Titan / Death Tower Show",
|
||||||
|
"Earth / Surface",
|
||||||
|
"Earth / Paradise Club",
|
||||||
|
"Planet Morphs / Surface",
|
||||||
|
"Planet Morphs / Inner Core"
|
||||||
|
};
|
||||||
|
|
||||||
const char *Menu::_passwordsDOS[] = {
|
const char *Menu::_passwordsDOS[] = {
|
||||||
"JAGUAR", "COMBEL", "ANTIC", "NOLAN", "ARTHUR", "SHIRYU", "RENDER", "BELUGA", // easy
|
"JAGUAR", "COMBEL", "ANTIC", "NOLAN", "ARTHUR", "SHIRYU", "RENDER", "BELUGA", // easy
|
||||||
"BANTHA", "SHIVA", "KASYYK", "SARLAC", "MAENOC", "SULUST", "NEPTUN", "BELUGA", // normal
|
"BANTHA", "SHIVA", "KASYYK", "SARLAC", "MAENOC", "SULUST", "NEPTUN", "BELUGA", // normal
|
||||||
|
|
19
video.cpp
19
video.cpp
|
@ -49,12 +49,12 @@ Video::~Video() {
|
||||||
free(_screenBlocks);
|
free(_screenBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Video::markBlockAsDirty(int16_t x, int16_t y, uint16_t w, uint16_t h) {
|
void Video::markBlockAsDirty(int16_t x, int16_t y, uint16_t w, uint16_t h, int scale) {
|
||||||
debug(DBG_VIDEO, "Video::markBlockAsDirty(%d, %d, %d, %d)", x, y, w, h);
|
debug(DBG_VIDEO, "Video::markBlockAsDirty(%d, %d, %d, %d)", x, y, w, h);
|
||||||
int bx1 = _layerScale * x / SCREENBLOCK_W;
|
int bx1 = scale * x / SCREENBLOCK_W;
|
||||||
int by1 = _layerScale * y / SCREENBLOCK_H;
|
int by1 = scale * y / SCREENBLOCK_H;
|
||||||
int bx2 = _layerScale * (x + w - 1) / SCREENBLOCK_W;
|
int bx2 = scale * (x + w - 1) / SCREENBLOCK_W;
|
||||||
int by2 = _layerScale * (y + h - 1) / SCREENBLOCK_H;
|
int by2 = scale * (y + h - 1) / SCREENBLOCK_H;
|
||||||
if (bx1 < 0) {
|
if (bx1 < 0) {
|
||||||
bx1 = 0;
|
bx1 = 0;
|
||||||
}
|
}
|
||||||
|
@ -907,7 +907,7 @@ static uint8_t _MAC_fontShadowColor;
|
||||||
void Video::MAC_drawStringChar(uint8_t *dst, int pitch, int x, int y, const uint8_t *src, uint8_t color, uint8_t chr) {
|
void Video::MAC_drawStringChar(uint8_t *dst, int pitch, int x, int y, const uint8_t *src, uint8_t color, uint8_t chr) {
|
||||||
DecodeBuffer buf;
|
DecodeBuffer buf;
|
||||||
memset(&buf, 0, sizeof(buf));
|
memset(&buf, 0, sizeof(buf));
|
||||||
buf.ptr = _frontLayer;
|
buf.ptr = dst;
|
||||||
buf.w = buf.pitch = _w;
|
buf.w = buf.pitch = _w;
|
||||||
buf.h = _h;
|
buf.h = _h;
|
||||||
buf.x = x * _layerScale;
|
buf.x = x * _layerScale;
|
||||||
|
@ -931,7 +931,7 @@ const char *Video::drawString(const char *str, int16_t x, int16_t y, uint8_t col
|
||||||
(this->*_drawChar)(_frontLayer, _w, x + len * CHAR_W, y, fnt, col, c);
|
(this->*_drawChar)(_frontLayer, _w, x + len * CHAR_W, y, fnt, col, c);
|
||||||
++len;
|
++len;
|
||||||
}
|
}
|
||||||
markBlockAsDirty(x, y, len * CHAR_W, CHAR_H);
|
markBlockAsDirty(x, y, len * CHAR_W, CHAR_H, _layerScale);
|
||||||
return str - 1;
|
return str - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -940,7 +940,7 @@ void Video::drawStringLen(const char *str, int len, int x, int y, uint8_t color)
|
||||||
for (int i = 0; i < len; ++i) {
|
for (int i = 0; i < len; ++i) {
|
||||||
(this->*_drawChar)(_frontLayer, _w, x + i * CHAR_W, y, fnt, color, str[i]);
|
(this->*_drawChar)(_frontLayer, _w, x + i * CHAR_W, y, fnt, color, str[i]);
|
||||||
}
|
}
|
||||||
markBlockAsDirty(x, y, len * CHAR_W, CHAR_H);
|
markBlockAsDirty(x, y, len * CHAR_W, CHAR_H, _layerScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
Color Video::AMIGA_convertColor(const uint16_t color, bool bgr) { // 4bits to 8bits
|
Color Video::AMIGA_convertColor(const uint16_t color, bool bgr) { // 4bits to 8bits
|
||||||
|
@ -1052,7 +1052,6 @@ void Video::MAC_drawSprite(int x, int y, const uint8_t *data, int frame, bool xf
|
||||||
buf.setPixel = eraseBackground ? MAC_drawBuffer : MAC_drawBufferMask;
|
buf.setPixel = eraseBackground ? MAC_drawBuffer : MAC_drawBufferMask;
|
||||||
fixOffsetDecodeBuffer(&buf, dataPtr);
|
fixOffsetDecodeBuffer(&buf, dataPtr);
|
||||||
_res->MAC_decodeImageData(data, frame, &buf);
|
_res->MAC_decodeImageData(data, frame, &buf);
|
||||||
// divide by screen scale as the dirty blocks range is 256,224
|
markBlockAsDirty(buf.x, buf.y, READ_BE_UINT16(dataPtr), READ_BE_UINT16(dataPtr + 2), 1);
|
||||||
markBlockAsDirty(buf.x / _layerScale, buf.y / _layerScale, READ_BE_UINT16(dataPtr) / _layerScale, READ_BE_UINT16(dataPtr + 2) / _layerScale);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
video.h
2
video.h
|
@ -53,7 +53,7 @@ struct Video {
|
||||||
Video(Resource *res, SystemStub *stub);
|
Video(Resource *res, SystemStub *stub);
|
||||||
~Video();
|
~Video();
|
||||||
|
|
||||||
void markBlockAsDirty(int16_t x, int16_t y, uint16_t w, uint16_t h);
|
void markBlockAsDirty(int16_t x, int16_t y, uint16_t w, uint16_t h, int scale);
|
||||||
void updateScreen();
|
void updateScreen();
|
||||||
void fullRefresh();
|
void fullRefresh();
|
||||||
void fadeOut();
|
void fadeOut();
|
||||||
|
|
Loading…
Reference in New Issue