Skip to content

Commit

Permalink
Merge 0.2.7 changes
Browse files Browse the repository at this point in the history
  • Loading branch information
usineur committed Jan 25, 2020
2 parents b3d0fcc + 1eab1a4 commit 2a47a55
Show file tree
Hide file tree
Showing 25 changed files with 954 additions and 307 deletions.
7 changes: 6 additions & 1 deletion CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
* release 0.2.7
- added 'projection' submenu
- added PSX backgrounds (MDEC)
- fixed menu on big endian platforms

* release 0.2.6
- added initial code for menu
- added initial code for PSX sounds (SPU ADPCM)
- added PSX sounds (SPU ADPCM)
- fixed skull animation in 'rock' screen 18

* release 0.2.5
Expand Down
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ add_executable(${CMAKE_PROJECT_NAME}
level9_dark.cpp
lzw.cpp
main.cpp
mdec.cpp
menu.cpp
mixer.cpp
monsters.cpp
Expand Down Expand Up @@ -61,7 +62,7 @@ if(SWITCH_LIBNX)
add_definitions(-D__SWITCH__)
add_custom_target(${CMAKE_PROJECT_NAME}.nro
DEPENDS ${CMAKE_PROJECT_NAME}
COMMAND nacptool --create "Heart of Darkness" "cyx, usineur" "0.2.6" ${CMAKE_PROJECT_NAME}.nacp
COMMAND nacptool --create "Heart of Darkness" "cyx, usineur" "0.2.7" ${CMAKE_PROJECT_NAME}.nacp
COMMAND elf2nro ${CMAKE_PROJECT_NAME} ${CMAKE_PROJECT_NAME}.nro --icon=${CMAKE_SOURCE_DIR}/res/icon.jpg --nacp=${CMAKE_PROJECT_NAME}.nacp
)
add_custom_target(nxlink
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ CPPFLAGS += -g -Wall -Wpedantic $(SDL_CFLAGS) $(DEFINES) -MMD
SRCS = andy.cpp benchmark.cpp fileio.cpp fs_posix.cpp game.cpp \
level1_rock.cpp level2_fort.cpp level3_pwr1.cpp level4_isld.cpp \
level5_lava.cpp level6_pwr2.cpp level7_lar1.cpp level8_lar2.cpp level9_dark.cpp \
lzw.cpp main.cpp menu.cpp mixer.cpp monsters.cpp paf.cpp random.cpp resource.cpp \
screenshot.cpp sound.cpp staticres.cpp system_sdl2.cpp \
lzw.cpp main.cpp mdec.cpp menu.cpp mixer.cpp monsters.cpp paf.cpp random.cpp \
resource.cpp screenshot.cpp sound.cpp staticres.cpp system_sdl2.cpp \
util.cpp video.cpp

SCALERS := scaler_nearest.cpp scaler_xbr.cpp
Expand Down
8 changes: 4 additions & 4 deletions README.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

hode README
Release version: 0.2.6
Release version: 0.2.7
-------------------------------------------------------------------------------


Expand Down Expand Up @@ -48,10 +48,10 @@ Game progress is saved in 'setup.cfg', similar to the original engine.
Status:
-------

Settings and projection menus are not implemented.
Settings submenu is not implemented.

PSX version datafiles can be used but background screens and overlays (MDEC)
are not decoded yet.
PSX version datafiles can be used but background overlays (MDEC) are not
decoded and menu is unavailable.


Credits:
Expand Down
2 changes: 1 addition & 1 deletion defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ struct SetupConfig {
uint8_t currentPlayer; // 0xD1
uint8_t unkD2;
uint8_t checksum;
} PACKED; // sizeof == 212
}; // sizeof == 212

struct Point8_t {
int8_t x;
Expand Down
2 changes: 1 addition & 1 deletion fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ struct FileSystem {

FILE *openAssetFile(const char *filename);
FILE *openSaveFile(const char *filename, bool write);
void closeFile(FILE *);
int closeFile(FILE *);

void addFilePath(const char *path);
void listFiles(const char *dir);
Expand Down
8 changes: 4 additions & 4 deletions fs_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ FILE *FileSystem::openSaveFile(const char *filename, bool write) {
return fp;
}

void FileSystem::closeFile(FILE *fp) {
if (fp) {
fclose(fp);
}
int FileSystem::closeFile(FILE *fp) {
const int err = ferror(fp);
fclose(fp);
return err;
}
4 changes: 3 additions & 1 deletion fs_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ FILE *FileSystem::openSaveFile(const char *filename, bool write) {
return fopen(path, write ? "wb" : "rb");
}

void FileSystem::closeFile(FILE *fp) {
int FileSystem::closeFile(FILE *fp) {
const int err = ferror(fp);
fclose(fp);
return err;
}

void FileSystem::addFilePath(const char *path) {
Expand Down
137 changes: 57 additions & 80 deletions game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
#include "util.h"
#include "video.h"

// menu settings and player progress
static const char *_setupCfg = "setup.cfg";

// starting level cutscene number
static const uint8_t _cutscenes[] = { 0, 2, 4, 5, 6, 8, 10, 14, 19 };

Expand Down Expand Up @@ -319,7 +316,7 @@ void Game::setupBackgroundBitmap() {
playSound(lvl->backgroundBitmapId, 0, 0, 3);
}
if (_res->_isPsx) {
assert(READ_LE_UINT16(pic + 4) == 0x3800);
_video->decodeBackgroundPsx(pic + 2);
} else {
decodeLZW(pic, _video->_backgroundLayer);
}
Expand Down Expand Up @@ -1310,13 +1307,14 @@ void Game::updateScreenHelper(int num) {
if (_res->_isPsx) {
p->framesCount = READ_LE_UINT32(data); data += 4;
ptr->currentSound = READ_LE_UINT32(data); data += 4;
p->nextSpriteData = READ_LE_UINT16(data + 6) + data + 6;
} else {
p->framesCount = READ_LE_UINT16(data); data += 2;
ptr->currentSound = READ_LE_UINT16(data); data += 2;
p->nextSpriteData = READ_LE_UINT16(data + 4) + data + 4;
}
p->currentSpriteData = p->otherSpriteData = data;
p->currentFrame = 0;
p->nextSpriteData = READ_LE_UINT16(data + 4) + data + 4;
}
break;
case 1: {
Expand Down Expand Up @@ -2107,6 +2105,8 @@ void Game::mainLoop(int level, int checkpoint, bool levelChanged) {
}
_paf->_playedMask = _setupConfig.players[num].cutscenesMask;
debug(kDebug_GAME, "Restart at level %d checkpoint %d cutscenes 0x%x", level, checkpoint, _paf->_playedMask);
// resume once, on the starting level
_resumeGame = false;
}
_video->_font = _res->_fontBuffer;
assert(level < kLvl_test);
Expand Down Expand Up @@ -2166,7 +2166,6 @@ void Game::mainLoop(int level, int checkpoint, bool levelChanged) {
g_system->sleep(delay);
} while (!_endLevel);
_animBackgroundDataCount = 0;
saveSetupCfg();
callLevel_terminate();
}

Expand Down Expand Up @@ -2248,36 +2247,42 @@ void Game::updateLvlObjectLists() {
}

LvlObject *Game::updateAnimatedLvlObjectType0(LvlObject *ptr) {
const bool isPsx = _res->_isPsx;
const int soundDataLen = isPsx ? sizeof(uint32_t) : sizeof(uint16_t);
AnimBackgroundData *vg = (AnimBackgroundData *)getLvlObjectDataPtr(ptr, kObjectDataTypeAnimBackgroundData);
const uint8_t *vf = vg->currentSpriteData + 2;
const uint8_t *data = vg->currentSpriteData + soundDataLen;
if (_res->_currentScreenResourceNum == ptr->screenNum) {
if (ptr->currentSound != 0xFFFF) {
playSound(ptr->currentSound, ptr, 0, 3);
ptr->currentSound = 0xFFFF;
}
Sprite *spr = _spritesNextPtr;
if (spr && READ_LE_UINT16(vf + 2) > 8) {
spr->xPos = vf[0];
spr->yPos = vf[1];
spr->w = READ_LE_UINT16(vf + 4);
spr->h = READ_LE_UINT16(vf + 6);
spr->bitmapBits = vf + 8;
spr->num = ptr->flags2;
const int index = spr->num & 0x1F;
_spritesNextPtr = spr->nextPtr;
spr->nextPtr = _typeSpritesList[index];
_typeSpritesList[index] = spr;
if (isPsx) {
_video->decodeTilePsx(data);
} else {
Sprite *spr = _spritesNextPtr;
if (spr && READ_LE_UINT16(data + 2) > 8) {
spr->xPos = data[0];
spr->yPos = data[1];
spr->w = READ_LE_UINT16(data + 4);
spr->h = READ_LE_UINT16(data + 6);
spr->bitmapBits = data + 8;
spr->num = ptr->flags2;
const int index = spr->num & 0x1F;
_spritesNextPtr = spr->nextPtr;
spr->nextPtr = _typeSpritesList[index];
_typeSpritesList[index] = spr;
}
}
}
int16_t soundNum = -1;
const int len = READ_LE_UINT16(vf + 2);
const uint8_t *nextSpriteData = len + vf + 2;
const int len = READ_LE_UINT16(data + 2);
const uint8_t *nextSpriteData = len + data + 2;
switch (ptr->objectUpdateType - 1) {
case 6:
vg->currentSpriteData = vg->nextSpriteData;
if (vg->currentFrame == 0) {
vg->currentFrame = 1;
soundNum = READ_LE_UINT16(vg->nextSpriteData);
soundNum = isPsx ? READ_LE_UINT32(vg->nextSpriteData) : READ_LE_UINT16(vg->nextSpriteData);
}
ptr->objectUpdateType = 4;
break;
Expand All @@ -2290,48 +2295,50 @@ LvlObject *Game::updateAnimatedLvlObjectType0(LvlObject *ptr) {
++vg->currentFrame;
if (vg->currentFrame < vg->framesCount) {
vg->currentSpriteData = nextSpriteData;
soundNum = READ_LE_UINT16(nextSpriteData);
} else {
vg->currentFrame = 0;
vg->currentSpriteData = vg->otherSpriteData;
ptr->objectUpdateType = 1;
soundNum = READ_LE_UINT16(vg->currentSpriteData);
}
soundNum = isPsx ? READ_LE_UINT32(vg->currentSpriteData) : READ_LE_UINT16(vg->currentSpriteData);
break;
case 4:
++vg->currentFrame;
if (vg->currentFrame < vg->framesCount) { // bugfix: original uses '<=' (out of bounds)
vg->currentSpriteData = nextSpriteData;
soundNum = READ_LE_UINT16(nextSpriteData);
} else {
vg->currentFrame = 0;
vg->currentSpriteData = vg->otherSpriteData;
ptr->objectUpdateType = 1;
soundNum = READ_LE_UINT16(vg->currentSpriteData);
}
soundNum = isPsx ? READ_LE_UINT32(vg->currentSpriteData) : READ_LE_UINT16(vg->currentSpriteData);
break;
case 2:
while (vg->currentFrame < vg->framesCount - 2) {
++vg->currentFrame;
vg->currentSpriteData = nextSpriteData;
nextSpriteData += 2;
nextSpriteData += soundDataLen;
const int len = READ_LE_UINT16(nextSpriteData + 2);
nextSpriteData += len + 2;
}
nextSpriteData = vg->currentSpriteData + 2;
data = vg->currentSpriteData + soundDataLen;
if (_res->_currentScreenResourceNum == ptr->screenNum) {
Sprite *spr = _spritesNextPtr;
if (spr && READ_LE_UINT16(nextSpriteData + 2) > 8) {
spr->w = READ_LE_UINT16(nextSpriteData + 4);
spr->h = READ_LE_UINT16(nextSpriteData + 6);
spr->bitmapBits = nextSpriteData + 8;
spr->xPos = nextSpriteData[0];
spr->yPos = nextSpriteData[1];
_spritesNextPtr = spr->nextPtr;
spr->num = ptr->flags2;
const int index = spr->num & 0x1F;
spr->nextPtr = _typeSpritesList[index];
_typeSpritesList[index] = spr;
if (isPsx) {
_video->decodeTilePsx(data);
} else {
Sprite *spr = _spritesNextPtr;
if (spr && READ_LE_UINT16(data + 2) > 8) {
spr->w = READ_LE_UINT16(data + 4);
spr->h = READ_LE_UINT16(data + 6);
spr->bitmapBits = data + 8;
spr->xPos = data[0];
spr->yPos = data[1];
_spritesNextPtr = spr->nextPtr;
spr->num = ptr->flags2;
const int index = spr->num & 0x1F;
spr->nextPtr = _typeSpritesList[index];
_typeSpritesList[index] = spr;
}
}
}
ptr->objectUpdateType = 1;
Expand All @@ -2340,7 +2347,7 @@ LvlObject *Game::updateAnimatedLvlObjectType0(LvlObject *ptr) {
++vg->currentFrame;
if (vg->currentFrame < vg->framesCount - 1) {
vg->currentSpriteData = nextSpriteData;
soundNum = READ_LE_UINT16(vg->currentSpriteData);
soundNum = isPsx ? READ_LE_UINT32(vg->currentSpriteData) : READ_LE_UINT16(vg->currentSpriteData);
} else {
if (vg->currentFrame > vg->framesCount) {
vg->currentFrame = vg->framesCount;
Expand All @@ -2352,7 +2359,7 @@ LvlObject *Game::updateAnimatedLvlObjectType0(LvlObject *ptr) {
case 0:
return ptr->nextPtr;
default:
soundNum = READ_LE_UINT16(vg->currentSpriteData);
soundNum = isPsx ? READ_LE_UINT32(vg->currentSpriteData) : READ_LE_UINT16(vg->currentSpriteData);
if (ptr->hitCount == 0) {
++vg->currentFrame;
if (vg->currentFrame >= vg->framesCount) {
Expand Down Expand Up @@ -2490,9 +2497,6 @@ LvlObject *Game::updateAnimatedLvlObjectTypeDefault(LvlObject *ptr) {
LvlObject *Game::updateAnimatedLvlObject(LvlObject *o) {
switch (o->type) {
case 0:
if (_res->_isPsx) {
return o->nextPtr;
}
o = updateAnimatedLvlObjectType0(o);
break;
case 1:
Expand Down Expand Up @@ -4787,21 +4791,14 @@ void Game::updateWormHoleSprites() {

bool Game::loadSetupCfg(bool resume) {
_resumeGame = resume;
FILE *fp = _fs.openSaveFile(_setupCfg, false);
if (fp) {
_res->readSetupCfg(fp, &_setupConfig);
_fs.closeFile(fp);
if (_res->readSetupCfg(&_setupConfig)) {
return true;
}
memset(&_setupConfig, 0, sizeof(_setupConfig));
return false;
}

void Game::saveSetupCfg() {
if (!_resumeGame) {
// do not save progress when game is started from a specific level/checkpoint
return;
}
const int num = _setupConfig.currentPlayer;
if (_currentLevelCheckpoint > _setupConfig.players[num].progress[_currentLevel]) {
_setupConfig.players[num].progress[_currentLevel] = _currentLevelCheckpoint;
Expand All @@ -4814,39 +4811,19 @@ void Game::saveSetupCfg() {
if (_currentLevel > _setupConfig.players[num].currentLevel) {
_setupConfig.players[num].currentLevel = _currentLevel;
}
FILE *fp = _fs.openSaveFile(_setupCfg, true);
if (fp) {
_res->writeSetupCfg(fp, &_setupConfig);
_fs.closeFile(fp);
} else {
warning("Failed to save '%s'", _setupCfg);
}
_res->writeSetupCfg(&_setupConfig);
}

void Game::captureScreenshot() {
static int screenshot = 1;
char name[64];

snprintf(name, sizeof(name), "screenshot-%03d-front.bmp", screenshot);
saveBMP(name, _video->_frontLayer, _video->_palette, Video::W, Video::H);

snprintf(name, sizeof(name), "screenshot-%03d-background.bmp", screenshot);
saveBMP(name, _video->_backgroundLayer, _video->_palette, Video::W, Video::H);

snprintf(name, sizeof(name), "screenshot-%03d-shadow.bmp", screenshot);
saveBMP(name, _video->_shadowLayer, _video->_palette, Video::W, Video::H);

static const int kPaletteRectSize = 8;
uint8_t paletteBuffer[8 * 256 * 8];
for (int x = 0; x < 256; ++x) {
const int xOffset = x * kPaletteRectSize;
for (int y = 0; y < kPaletteRectSize; ++y) {
memset(paletteBuffer + xOffset + y * 256 * kPaletteRectSize, x, kPaletteRectSize);
}
char name[64];
snprintf(name, sizeof(name), "screenshot-%03d.bmp", screenshot);
FILE *fp = _fs.openSaveFile(name, true);
if (fp) {
saveBMP(fp, _video->_frontLayer, _video->_palette, Video::W, Video::H);
fclose(fp);
}

snprintf(name, sizeof(name), "screenshot-%03d-palette.bmp", screenshot);
saveBMP(name, paletteBuffer, _video->_palette, 256 * kPaletteRectSize, kPaletteRectSize);

++screenshot;
}
Loading

0 comments on commit 2a47a55

Please sign in to comment.