diff --git a/CHANGES.txt b/CHANGES.txt index a0f742b..6b3481d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,20 @@ +* release 0.2.9d + - added gain to sounds + - added no-hit cheat for 'rock' and 'lava' + +* release 0.2.9c + - added original sounds limiter (16 channels) + - fixed checkpoint 7 for 'lar1' screen 19 + - fixed some bounding box checks + - fixed sound glitches when resuming the game after a cutscene + +* release 0.2.9b + - added PSX hint screens + - added 'volume' submenu + - fixed sounds volume and panning + - fixed walk on chain bridge in 'lar1' screen 3 + - fixed gate not closing in 'lar2' screen 8 + * release 0.2.9 - added PSP and Wii platforms specific code - added support for PC demo v1.0 data files diff --git a/CMakeLists.txt b/CMakeLists.txt index 12e0b3d..c8fe556 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ if(NSWITCH) 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.9" ${CMAKE_PROJECT_NAME}.nacp + COMMAND nacptool --create "Heart of Darkness" "cyx, usineur" "0.2.9d" ${CMAKE_PROJECT_NAME}.nacp COMMAND elf2nro ${CMAKE_PROJECT_NAME} ${CMAKE_PROJECT_NAME}.nro --icon=${CMAKE_SOURCE_DIR}/3p/res/icon.jpg --nacp=${CMAKE_PROJECT_NAME}.nacp ) add_custom_target(nxlink diff --git a/README.txt b/README.txt index 4c04f9b..1e6f1fe 100644 --- a/README.txt +++ b/README.txt @@ -1,6 +1,6 @@ hode README -Release version: 0.2.9 +Release version: 0.2.9d ------------------------------------------------------------------------------- @@ -45,14 +45,6 @@ Display and engine settings can be configured in the 'hode.ini' file. Game progress is saved in 'setup.cfg', similar to the original engine. -Status: -------- - -Settings submenu is not implemented. - -PSX datafiles can be used, but menu and videos are missing. - - Credits: -------- diff --git a/RELEASES.yaml b/RELEASES.yaml index 5e99e7f..79bf632 100644 --- a/RELEASES.yaml +++ b/RELEASES.yaml @@ -46,6 +46,54 @@ - rock_hod.mst: 5b49637348f6c6a2737a64cacf01f9bcef8e83f6 - rock_hod.sss: 55c841f6c091c2ae68f0636c075c66405d00cc6a - setup.dat: 1d476d896cafd3d4af00b15eb2eb695a804a0662 +- name: Heart of Darkness German (Win32) + files: + - dark_hod.lvl: e7c188e5c47632d512d96d9da89fc8c060528d45 + - dark_hod.mst: 6c2d93b2e31c299215d0fdf05ac1e8e8e95e9042 + - dark_hod.sss: 8d5b19842e551b8ec73bda411c210cc96e08569a + - fort_hod.lvl: 82456ed6e29780b5b8031a67ba3dddb8da813c19 + - fort_hod.mst: ce55095902ade9f1d8a198f271d0946d6228b90d + - fort_hod.sss: 6ff572b553d93040c9cad74891db05b2cc8267c6 + - hod.dem: 5d40f812b6ed1385b7e502527911023f28136341 + - hod.paf: f51a9f9addad0b21ab524840838fb8fd6e235396 + - hod_res.dll: 09de4fb219ad63fc39f10a3f49bd7d003f3244b7 + - hodwin32.exe: eb0f032f343e2c27d60291c79ae667034a0c7389 + securom: false + version_info: + - Comments: Release Candidate 0 + - CompanyName: Amazing Studio - 9 rue d' Enhgien - 75010 Paris FRANCE - Email: hod@amazingstudio.com + - FileDescription: Heart Of Darkness + - FileVersion: 1, 1, 0, 0 + - InternalName: Heart Of Darkness + - LegalCopyright: (c) 1998 by Amazing Studio & Infogrames + - LegalTrademarks: by Amazing Studio - All rights reserved + - OriginalFilename: Heart Of Darkness + - PrivateBuild: HEARTMM5511 + - ProductName: Heart Of Darkness - Windows 95 / 98 & NT - DirectX 3.x or greater + - ProductVersion: 1, 1, 0, 0 + - SpecialBuild: VC5.0 Sp3 + - isld_hod.lvl: f78e9316f2187c0ca9e42abe8a2242b3d3e6feaf + - isld_hod.mst: 448e5dd5bbe59621279562d8695c9a864cb4c286 + - isld_hod.sss: 61c5da6dfcf80684c56baebddb04125ca0c1f209 + - lar1_hod.lvl: 84f7b33a9b57f2afa68063e0128512991f86dfa0 + - lar1_hod.mst: 9db53a4a75327eeca45ffa5b761a9f04af5e5204 + - lar1_hod.sss: 72667991fde3caf36978da1fa929695de80abe4b + - lar2_hod.lvl: 999b2548490f586f955c9f5c6db95f88d49102f3 + - lar2_hod.mst: 333ea4e6be6ca9aad735fafe59177546aab41c4e + - lar2_hod.sss: c5c655b718ead1d2eb460a058df7eb3b795dea9e + - lava_hod.lvl: 2921eb2f78354e79c1257ef55543bb1a1492e914 + - lava_hod.mst: c05ce42c0abdbb2dbfc109cbb4ea7eee1937445d + - lava_hod.sss: 8fc8d2c86f67e13ca840d604c603249b20723f85 + - pwr1_hod.lvl: cd6489e11914770d95034aa6afaa2fc67f035ce8 + - pwr1_hod.mst: f821e5686ae27b2ed5000ea4b38a464ecebe44a7 + - pwr1_hod.sss: cbb39e1bfd24dcbd5bf65f9e0b92faaa9b6b02a6 + - pwr2_hod.lvl: 7263ecf8d51d45c2c62dc11701eac03b67738fd8 + - pwr2_hod.mst: 132b29e758a28529009e979ef31a29a42d0a5c4b + - pwr2_hod.sss: 24342241b4353777cc22696be8a684d635f9c809 + - rock_hod.lvl: cdb3d7ad1ae13f2234380f79bc8ec57e1e505cef + - rock_hod.mst: 5b49637348f6c6a2737a64cacf01f9bcef8e83f6 + - rock_hod.sss: 55c841f6c091c2ae68f0636c075c66405d00cc6a + - setup.dat: d362500a5c028a35f9341c2cb5c69901afba87c3 - name: Heart of Darkness Italian (Win32) files: - dark_hod.lvl: e7c188e5c47632d512d96d9da89fc8c060528d45 diff --git a/andy.cpp b/andy.cpp index e543912..9152a1f 100644 --- a/andy.cpp +++ b/andy.cpp @@ -1444,20 +1444,9 @@ void Game::setupAndyObjectMoveData(LvlObject *ptr) { _andyMoveData.yPos = ptr->yPos; _andyPosX = _res->_screensBasePos[ptr->screenNum].u + _andyMoveData.xPos; _andyPosY = _res->_screensBasePos[ptr->screenNum].v + _andyMoveData.yPos; - _andyMoveData.anim = ptr->anim; - _andyMoveData.unkA = ptr->currentSprite; - _andyMoveData.frame = ptr->frame; _andyMoveData.flags0 = ptr->flags0; _andyMoveData.flags1 = ptr->flags1; _andyMoveMask = (ptr->flags1 >> 4) & 3; - _andyMoveData.unk16 = ptr->width; - _andyMoveData.unk18 = ptr->height; - const LvlObjectData *dat = ptr->levelData0x2988; - _andyMoveData.unkC = dat->hotspotsCount; - _andyMoveData.unk1C = dat->animsInfoData; - _andyMoveData.framesData = dat->framesData; - _andyMoveData.unk24 = dat->movesData; - _andyMoveData.unk28 = dat->hotspotsData; _andyLevelData0x288PosTablePtr = ptr->posTable; } @@ -1598,25 +1587,25 @@ void Game::updateAndyObject(LvlObject *ptr) { uint16_t w, h; _res->getLvlSpriteFramePtr(dat, ash->firstFrame, &w, &h); - ptr->flags1 = ((ptr->flags1 & 0x30) ^ ((asfh->unk5 & 3) << 4)) | (ptr->flags1 & ~0x30); + ptr->flags1 = ((ptr->flags1 & 0x30) ^ ((asfh->flags & 3) << 4)) | (ptr->flags1 & ~0x30); int type = (ptr->flags1 >> 4) & 3; switch (type) { case 0: - ptr->xPos += asfh->unk6; - ptr->yPos += asfh->unk7; + ptr->xPos += asfh->xOffset; + ptr->yPos += asfh->yOffset; break; case 1: - ptr->xPos += ptr->width - asfh->unk6 - w; - ptr->yPos += asfh->unk7; + ptr->xPos += ptr->width - asfh->xOffset - w; + ptr->yPos += asfh->yOffset; break; case 2: - ptr->xPos += asfh->unk6; - ptr->yPos += ptr->height - asfh->unk7 - h; + ptr->xPos += asfh->xOffset; + ptr->yPos += ptr->height - asfh->yOffset - h; break; case 3: - ptr->xPos += ptr->width - asfh->unk6 - w; - ptr->yPos += ptr->height - asfh->unk7 - h; + ptr->xPos += ptr->width - asfh->xOffset - w; + ptr->yPos += ptr->height - asfh->yOffset - h; break; } diff --git a/benchmark.cpp b/benchmark.cpp index 5474aba..1a2b943 100644 --- a/benchmark.cpp +++ b/benchmark.cpp @@ -5,7 +5,7 @@ #include "util.h" #include "video.h" -uint32_t Game::benchmarkLoop(const uint8_t *p, int count) { +static uint32_t benchmarkLoop(const uint8_t *p, int count) { uint32_t accum = 0; count >>= 2; // sizeof(uint32_t) if (count > 0) { diff --git a/defs.h b/defs.h index 5a4114a..52d7770 100644 --- a/defs.h +++ b/defs.h @@ -16,10 +16,12 @@ enum { enum { kNone = 0xFFFFFFFF, // (uint32_t)-1 kNoScreen = 0xFF, // (uint8_t)-1 + kFrameDuration = 80, // original engine frame duration is 80ms (12.5hz) kLvlAnimHdrOffset = 0x2C, kMaxScreens = 40, kMaxSpriteTypes = 32, - kMonsterInfoDataSize = 948 // (32 * 28 + 52) + kMonsterInfoSize = 28, + kMonsterInfoDataSize = 948 // (32 * kMonsterInfoSize + 52) }; enum { @@ -80,23 +82,23 @@ struct Point16_t { struct AnimBackgroundData { const uint8_t *currentSpriteData; // 0 - uint8_t *nextSpriteData; // 4 - uint8_t *otherSpriteData; // 8 + const uint8_t *nextSpriteData; // 4 + const uint8_t *otherSpriteData; // 8 uint16_t framesCount; // 12 uint16_t currentFrame; // 14 }; struct LvlAnimSeqHeader { uint16_t firstFrame; - uint16_t unk2; + uint16_t unk2; // unused int8_t dx; // 4 int8_t dy; // 5 uint8_t count; // 6 - uint8_t unk7; // 7 + uint8_t unk7; // unused uint16_t sound; uint16_t flags0; uint16_t flags1; - uint16_t unkE; + uint16_t unkE; // unused uint32_t offset; // 0x10, LvlAnimSeqFrameHeader } PACKED; // sizeof == 20 @@ -104,9 +106,9 @@ struct LvlAnimSeqFrameHeader { uint16_t move; // 0 uint16_t anim; // 2 uint8_t frame; // 4 - uint8_t unk5; // 5 - int8_t unk6; - int8_t unk7; + uint8_t flags; // 5 + int8_t xOffset; // 6 + int8_t yOffset; // 7 } PACKED; // sizeof == 8 struct LvlAnimHeader { @@ -195,10 +197,10 @@ struct SssObject { uint32_t flags0; // 0xC uint32_t flags1; // 0x10 int32_t panning; // 0x14 panning default:64 - int32_t volume; // 0x18 volume (db) default:128 + int32_t volume; // 0x18 volume default:128 int panL; // 0x1C int panR; // 0x20 - int panType; // 0x24 : 0: silent, 1:fullRight 2:fullLeft 3:both + int panType; // 0x24 : 0: silent, 1:right 2:left 3:center 4:balance const int16_t *currentPcmPtr; // 0x28 int32_t pcmFramesCount; // 0x2C SssObject *prevPtr; // 0x30 @@ -217,9 +219,9 @@ struct SssObject { int32_t panningModulateCurrent; // 0x64 int32_t panningModulateDelta; // 0x68 int32_t currentPcmFrame; // 0x6C - int *panningPtr; // 0x70 + int *panningPtr; // 0x70 if != 0, panning is relative to the object position LvlObject *lvlObject; // 0x74 - int32_t nextSoundBank; // 0x78 indexes + int32_t nextSoundBank; // 0x78 int32_t nextSoundSample; // 0x7C SssFilter *filter; }; @@ -319,22 +321,9 @@ struct AndyShootData { struct AndyMoveData { int32_t xPos; int32_t yPos; - uint16_t anim; // 8 - uint16_t unkA; - uint16_t unkC; - uint16_t unkE; - uint8_t frame; // 0x10 - uint8_t unk11; - uint16_t flags0; + uint16_t flags0; // 0x12 uint16_t flags1; - uint16_t unk16; - uint16_t unk18; - uint16_t unk1A; - const uint8_t *unk1C; - const uint8_t *framesData; - const uint8_t *unk24; - const uint8_t *unk28; -}; // sizeof == 0x2C +}; struct MstBoundingBox { int x1; // 0 @@ -427,7 +416,7 @@ struct MonsterObject1 { int collideDistance; // 0xEC int shootActionIndex; // 0xF0 [0..8] int shootSource; // 0xF4 - uint8_t unkF8; // 0xF8 + uint8_t goalDirectionKeyMask; // 0xF8 int shootDirection; // 0xFC }; // sizeof == 256 diff --git a/game.cpp b/game.cpp index b30d9cd..9cb510e 100644 --- a/game.cpp +++ b/game.cpp @@ -27,9 +27,8 @@ Game::Game(const char *dataPath, const char *savePath, uint32_t cheats) _cheats = cheats; _playDemo = false; - _frameMs = kFrameTimeStamp; - _difficulty = 1; - _loadingScreenEnabled = true; + _frameMs = kFrameDuration; + _difficulty = 1; // normal memset(_screenLvlObjectsList, 0, sizeof(_screenLvlObjectsList)); _andyObject = 0; @@ -73,6 +72,7 @@ Game::Game(const char *dataPath, const char *savePath, uint32_t cheats) _sssDisabled = false; _snd_muted = false; + _snd_bufferOffset = _snd_bufferSize = 0; _snd_masterPanning = kDefaultSoundPanning; _snd_masterVolume = kDefaultSoundVolume; _sssObjectsCount = 0; @@ -102,6 +102,26 @@ void Game::clearShootLvlObjectData(LvlObject *ptr) { ptr->dataPtr = 0; } +void Game::addShootLvlObject(LvlObject *vd, LvlObject *ptr) { + vd->dataPtr = _shootLvlObjectDataNextPtr; + if (_shootLvlObjectDataNextPtr) { + _shootLvlObjectDataNextPtr = _shootLvlObjectDataNextPtr->nextPtr; + memset(vd->dataPtr, 0, sizeof(ShootLvlObjectData)); + } else { + warning("Nothing free in _shootLvlObjectDataNextPtr"); + } + vd->xPos = ptr->xPos; + vd->yPos = ptr->yPos; + vd->flags1 &= ~0x30; + vd->screenNum = ptr->screenNum; + vd->anim = 7; + vd->frame = 0; + vd->bitmapBits = 0; + vd->flags2 = (ptr->flags2 & ~0x2000) - 1; + vd->nextPtr = _lvlObjectsList0; + _lvlObjectsList0 = vd; +} + void Game::setShakeScreen(int type, int counter) { static const uint8_t table1[] = { 1, 2, 3, 4 }; static const uint8_t table2[] = { 2, 3, 4, 5 }; @@ -188,11 +208,11 @@ static BoundingBox _screenTransformRects[] = { }; void Game::transformShadowLayer(int delta) { - const uint8_t *src = _video->_transformShadowBuffer + _video->_transformShadowLayerDelta; // vg - uint8_t *dst = _video->_shadowLayer; // va + const uint8_t *src = _video->_transformShadowBuffer + _video->_transformShadowLayerDelta; + uint8_t *dst = _video->_shadowLayer; _video->_transformShadowLayerDelta += delta; // overflow/wrap at 255 for (int y = 0; y < Video::H; ++y) { - if (0) { + if (0) { // original clips the screen width to 250px for (int x = 0; x < Video::W - 6; ++x) { const int offset = x + *src++; *dst++ = _video->_frontLayer[y * Video::W + offset]; @@ -283,14 +303,16 @@ void Game::decodeShadowScreenMask(LvlBackgroundData *lvl) { } // a: type/source (0, 1, 2) b: num/index (3, monster1Index, monster2.monster1Index) -void Game::playSound(int num, LvlObject *ptr, int a, int b) { +SssObject *Game::playSound(int num, LvlObject *ptr, int a, int b) { MixerLock ml(&_mix); + SssObject *so = 0; if (num < _res->_sssHdr.infosDataCount) { debug(kDebug_GAME, "playSound num %d/%d a=%d b=%d", num, _res->_sssHdr.infosDataCount, a, b); _currentSoundLvlObject = ptr; - playSoundObject(&_res->_sssInfosData[num], a, b); + so = playSoundObject(&_res->_sssInfosData[num], a, b); _currentSoundLvlObject = 0; } + return so; } void Game::removeSound(LvlObject *ptr) { @@ -308,8 +330,8 @@ void Game::setupBackgroundBitmap() { const int num = lvl->currentBackgroundId; const uint8_t *pal = lvl->backgroundPaletteTable[num]; lvl->backgroundPaletteId = READ_LE_UINT16(pal); pal += 2; - const uint8_t *pic = lvl->backgroundBitmapTable[num]; - lvl->backgroundBitmapId = READ_LE_UINT16(pic); pic += 2; + const uint8_t *bmp = lvl->backgroundBitmapTable[num]; + lvl->backgroundBitmapId = READ_LE_UINT16(bmp); bmp += 2; if (lvl->backgroundPaletteId != 0xFFFF) { playSound(lvl->backgroundPaletteId, 0, 0, 3); } @@ -317,10 +339,9 @@ void Game::setupBackgroundBitmap() { playSound(lvl->backgroundBitmapId, 0, 0, 3); } if (_res->_isPsx) { - const int size = Video::W * Video::H * sizeof(uint16_t); - _video->decodeBackgroundPsx(pic + 2, size, Video::W, Video::H); + _video->decodeBackgroundPsx(bmp + 2, -1, Video::W, Video::H); } else { - decodeLZW(pic, _video->_backgroundLayer); + decodeLZW(bmp, _video->_backgroundLayer); } if (lvl->shadowCount != 0) { decodeShadowScreenMask(lvl); @@ -614,10 +635,10 @@ void Game::randomizeInterpolatePoints(int32_t *pts, int count) { } int Game::fixPlasmaCannonPointsScreenMask(int num) { - uint8_t _dl = ((~_plasmaCannonDirection) & 1) | 6; + const uint8_t _dl = ((~_plasmaCannonDirection) & 1) | 6; int var1 = _plasmaCannonFirstIndex; - int vf = _res->_screensBasePos[num].u; - int ve = _res->_screensBasePos[num].v; + const int vf = _res->_screensBasePos[num].u; + const int ve = _res->_screensBasePos[num].v; uint8_t _al = 0; if (_andyObject->anim == 84) { int yPos, xPos; @@ -659,45 +680,27 @@ int Game::fixPlasmaCannonPointsScreenMask(int num) { void Game::setupPlasmaCannonPointsHelper() { if (_plasmaCannonPointsSetupCounter == 0) { - int xR = _rnd.update(); - for (int i = 0; i < 64; ++i) { - const int index = _pointDstIndexTable[i]; - const int x1 = _plasmaCannonPosX[_pointSrcIndex1Table[index]]; - const int x2 = _plasmaCannonPosX[_pointSrcIndex2Table[index]]; - _plasmaCannonPosX[index] = (x1 + x2 + (xR >> _pointRandomizeShiftTable[i])) / 2; - xR *= 2; - } - int yR = _rnd.update(); - for (int i = 0; i < 64; ++i) { - const int index = _pointDstIndexTable[i]; - const int y1 = _plasmaCannonPosY[_pointSrcIndex1Table[index]]; - const int y2 = _plasmaCannonPosY[_pointSrcIndex2Table[index]]; - _plasmaCannonPosY[index] = (y1 + y2 + (yR >> _pointRandomizeShiftTable[i])) / 2; - yR *= 2; - } + randomizeInterpolatePoints(_plasmaCannonPosX, 64); + randomizeInterpolatePoints(_plasmaCannonPosY, 64); if (_andyObject->anim == 84) { - for (int i = 0; i <= 496; i += 8) { - const int index = i / 4; - _plasmaCannonXPointsTable2[2 + index] = (_plasmaCannonPosX[4 + index] - _plasmaCannonXPointsTable1[4 + index]) / 2; - _plasmaCannonYPointsTable2[2 + index] = (_plasmaCannonPosY[4 + index] - _plasmaCannonYPointsTable1[4 + index]) / 8; + for (int i = 0; i <= 496 / 4; i += 2) { + _plasmaCannonXPointsTable2[2 + i] = (_plasmaCannonPosX[4 + i] - _plasmaCannonXPointsTable1[4 + i]) / 2; + _plasmaCannonYPointsTable2[2 + i] = (_plasmaCannonPosY[4 + i] - _plasmaCannonYPointsTable1[4 + i]) / 8; } } else { - for (int i = 0; i <= 496; i += 8) { - const int index = i / 4; - _plasmaCannonXPointsTable2[2 + index] = (_plasmaCannonPosX[4 + index] - _plasmaCannonXPointsTable1[4 + index]) / 2; - _plasmaCannonYPointsTable2[2 + index] = (_plasmaCannonPosY[4 + index] - _plasmaCannonYPointsTable1[4 + index]) / 2; + for (int i = 0; i <= 496 / 4; i += 2) { + _plasmaCannonXPointsTable2[2 + i] = (_plasmaCannonPosX[4 + i] - _plasmaCannonXPointsTable1[4 + i]) / 2; + _plasmaCannonYPointsTable2[2 + i] = (_plasmaCannonPosY[4 + i] - _plasmaCannonYPointsTable1[4 + i]) / 2; } } - for (int i = 0; i <= 504; i += 8) { - const int index = i / 4; - _plasmaCannonXPointsTable1[2 + index] = _plasmaCannonPosX[2 + index]; - _plasmaCannonYPointsTable1[2 + index] = _plasmaCannonPosY[2 + index]; + for (int i = 0; i <= 504 / 4; i += 2) { + _plasmaCannonXPointsTable1[2 + i] = _plasmaCannonPosX[2 + i]; + _plasmaCannonYPointsTable1[2 + i] = _plasmaCannonPosY[2 + i]; } } else { - for (int i = 0; i <= 496; i += 8) { - const int index = i / 4; - _plasmaCannonXPointsTable1[4 + index] += _plasmaCannonXPointsTable2[2 + index]; - _plasmaCannonYPointsTable1[4 + index] += _plasmaCannonYPointsTable2[2 + index]; + for (int i = 0; i <= 496 / 4; i += 2) { + _plasmaCannonXPointsTable1[4 + i] += _plasmaCannonXPointsTable2[2 + i]; + _plasmaCannonYPointsTable1[4 + i] += _plasmaCannonYPointsTable2[2 + i]; } } ++_plasmaCannonPointsSetupCounter; @@ -761,8 +764,8 @@ void Game::destroyLvlObject(LvlObject *o) { } if (o->sssObject) { removeSound(o); + o->sssObject = 0; } - o->sssObject = 0; o->bitmapBits = 0; } @@ -777,19 +780,19 @@ void Game::setupPlasmaCannonPoints(LvlObject *ptr) { const int num = ((ptr->flags0 >> 5) & 7) - 3; switch (num) { case 0: - _plasmaCannonPosY[128] -= 176; // 192 - 16 + _plasmaCannonPosY[128] -= Video::H - 16; _plasmaCannonDirection = 3; break; case 1: - _plasmaCannonPosY[128] += 176; + _plasmaCannonPosY[128] += Video::H - 16; _plasmaCannonDirection = 6; break; case 3: - _plasmaCannonPosY[128] -= 176; + _plasmaCannonPosY[128] -= Video::H - 16; _plasmaCannonDirection = 1; break; case 4: - _plasmaCannonPosY[128] += 176; + _plasmaCannonPosY[128] += Video::H - 16; _plasmaCannonDirection = 4; break; default: @@ -799,11 +802,11 @@ void Game::setupPlasmaCannonPoints(LvlObject *ptr) { if (ptr->flags1 & 0x10) { if (_plasmaCannonDirection != 1) { _plasmaCannonDirection = (_plasmaCannonDirection & ~2) | 8; - _plasmaCannonPosX[128] -= 264; // 256 + 8 + _plasmaCannonPosX[128] -= Video::W + 8; } } else { if (_plasmaCannonDirection != 1) { - _plasmaCannonPosX[128] += 264; + _plasmaCannonPosX[128] += Video::W + 8; } } if (_plasmaCannonPrevDirection != _plasmaCannonDirection) { @@ -943,29 +946,7 @@ void Game::clearLvlObjectsList0() { LvlObject *ptr = _lvlObjectsList0; while (ptr) { LvlObject *next = ptr->nextPtr; - if (ptr->type == 8) { - _res->decLvlSpriteDataRefCounter(ptr); - ptr->nextPtr = _declaredLvlObjectsNextPtr; - --_declaredLvlObjectsListCount; - _declaredLvlObjectsNextPtr = ptr; - switch (ptr->spriteNum) { - case 0: - case 2: - ptr->dataPtr = 0; - break; - case 3: - case 7: - if (ptr->dataPtr) { - clearShootLvlObjectData(ptr); - } - break; - } - if (ptr->sssObject) { - removeSound(ptr); - } - ptr->sssObject = 0; - ptr->bitmapBits = 0; - } + destroyLvlObject(ptr); ptr = next; } _lvlObjectsList0 = 0; @@ -984,29 +965,7 @@ void Game::clearLvlObjectsList1() { LvlObject *ptr = _lvlObjectsList1; while (ptr) { LvlObject *next = ptr->nextPtr; - if (ptr->type == 8) { - _res->decLvlSpriteDataRefCounter(ptr); - ptr->nextPtr = _declaredLvlObjectsNextPtr; - --_declaredLvlObjectsListCount; - _declaredLvlObjectsNextPtr = ptr; - switch (ptr->spriteNum) { - case 0: - case 2: - ptr->dataPtr = 0; - break; - case 3: - case 7: - if (ptr->dataPtr) { - clearShootLvlObjectData(ptr); - } - break; - } - if (ptr->sssObject) { - removeSound(ptr); - } - ptr->sssObject = 0; - ptr->bitmapBits = 0; - } + destroyLvlObject(ptr); ptr = next; } _lvlObjectsList1 = 0; @@ -1016,29 +975,7 @@ void Game::clearLvlObjectsList2() { LvlObject *ptr = _lvlObjectsList2; while (ptr) { LvlObject *next = ptr->nextPtr; - if (ptr->type == 8) { - _res->decLvlSpriteDataRefCounter(ptr); - ptr->nextPtr = _declaredLvlObjectsNextPtr; - --_declaredLvlObjectsListCount; - _declaredLvlObjectsNextPtr = ptr; - switch (ptr->spriteNum) { - case 0: - case 2: - ptr->dataPtr = 0; - break; - case 3: - case 7: - if (ptr->dataPtr) { - clearShootLvlObjectData(ptr); - } - break; - } - if (ptr->sssObject) { - removeSound(ptr); - } - ptr->sssObject = 0; - ptr->bitmapBits = 0; - } + destroyLvlObject(ptr); ptr = next; } _lvlObjectsList2 = 0; @@ -1048,119 +985,47 @@ void Game::clearLvlObjectsList3() { LvlObject *ptr = _lvlObjectsList3; while (ptr != 0) { LvlObject *next = ptr->nextPtr; - if (ptr->type == 8) { - _res->decLvlSpriteDataRefCounter(ptr); - ptr->nextPtr = _declaredLvlObjectsNextPtr; - --_declaredLvlObjectsListCount; - _declaredLvlObjectsNextPtr = ptr; - switch (ptr->spriteNum) { - case 0: - case 2: - ptr->dataPtr = 0; - break; - case 3: - case 7: - if (ptr->dataPtr) { - clearShootLvlObjectData(ptr); - } - break; - } - if (ptr->sssObject) { - removeSound(ptr); - } - ptr->sssObject = 0; - ptr->bitmapBits = 0; - } + destroyLvlObject(ptr); ptr = next; } _lvlObjectsList3 = 0; } LvlObject *Game::addLvlObjectToList0(int num) { - if (_res->_resLevelData0x2988PtrTable[num] != 0 && _declaredLvlObjectsListCount < kMaxLvlObjects) { - assert(_declaredLvlObjectsNextPtr); - LvlObject *ptr = _declaredLvlObjectsNextPtr; - _declaredLvlObjectsNextPtr = _declaredLvlObjectsNextPtr->nextPtr; - ++_declaredLvlObjectsListCount; - ptr->spriteNum = num; - ptr->type = 8; - _res->incLvlSpriteDataRefCounter(ptr); - lvlObjectTypeCallback(ptr); - ptr->currentSprite = 0; - ptr->sssObject = 0; - ptr->nextPtr = 0; - ptr->bitmapBits = 0; + LvlObject *ptr = declareLvlObject(8, num); + if (ptr) { ptr->nextPtr = _lvlObjectsList0; _lvlObjectsList0 = ptr; - return ptr; } - return 0; + return ptr; } LvlObject *Game::addLvlObjectToList1(int type, int num) { - if ((type != 8 || _res->_resLevelData0x2988PtrTable[num] != 0) && _declaredLvlObjectsListCount < kMaxLvlObjects) { - assert(_declaredLvlObjectsNextPtr); - LvlObject *ptr = _declaredLvlObjectsNextPtr; - _declaredLvlObjectsNextPtr = _declaredLvlObjectsNextPtr->nextPtr; - ++_declaredLvlObjectsListCount; - ptr->spriteNum = num; - ptr->type = type; - if (type == 8) { - _res->incLvlSpriteDataRefCounter(ptr); - lvlObjectTypeCallback(ptr); - } - ptr->currentSprite = 0; - ptr->sssObject = 0; - ptr->nextPtr = 0; - ptr->bitmapBits = 0; + LvlObject *ptr = declareLvlObject(type, num); + if (ptr) { ptr->nextPtr = _lvlObjectsList1; _lvlObjectsList1 = ptr; - return ptr; } - return 0; + return ptr; } LvlObject *Game::addLvlObjectToList2(int num) { - if (_res->_resLevelData0x2988PtrTable[num] != 0 && _declaredLvlObjectsListCount < kMaxLvlObjects) { - assert(_declaredLvlObjectsNextPtr); - LvlObject *ptr = _declaredLvlObjectsNextPtr; - _declaredLvlObjectsNextPtr = _declaredLvlObjectsNextPtr->nextPtr; - ++_declaredLvlObjectsListCount; - ptr->spriteNum = num; - ptr->type = 8; - _res->incLvlSpriteDataRefCounter(ptr); - lvlObjectTypeCallback(ptr); - ptr->currentSprite = 0; - ptr->sssObject = 0; - ptr->nextPtr = 0; - ptr->bitmapBits = 0; + LvlObject *ptr = declareLvlObject(8, num); + if (ptr) { ptr->nextPtr = _lvlObjectsList2; _lvlObjectsList2 = ptr; - return ptr; } - return 0; + return ptr; } LvlObject *Game::addLvlObjectToList3(int num) { - if (_res->_resLevelData0x2988PtrTable[num] != 0 && _declaredLvlObjectsListCount < kMaxLvlObjects) { - assert(_declaredLvlObjectsNextPtr); - LvlObject *ptr = _declaredLvlObjectsNextPtr; - _declaredLvlObjectsNextPtr = _declaredLvlObjectsNextPtr->nextPtr; - ++_declaredLvlObjectsListCount; - ptr->spriteNum = num; - ptr->type = 8; - _res->incLvlSpriteDataRefCounter(ptr); - lvlObjectTypeCallback(ptr); - ptr->currentSprite = 0; - ptr->sssObject = 0; - ptr->nextPtr = 0; - ptr->bitmapBits = 0; + LvlObject *ptr = declareLvlObject(8, num); + if (ptr) { ptr->nextPtr = _lvlObjectsList3; _lvlObjectsList3 = ptr; ptr->callbackFuncPtr = &Game::lvlObjectList3Callback; - return ptr; } - return 0; + return ptr; } void Game::removeLvlObject(LvlObject *ptr) { @@ -1175,46 +1040,10 @@ void Game::removeLvlObject(LvlObject *ptr) { void Game::removeLvlObject2(LvlObject *o) { if (o->type != 2) { - LvlObject *ptr = _lvlObjectsList1; - if (ptr) { - if (ptr == o) { - _lvlObjectsList1 = o->nextPtr; - } else { - LvlObject *prev = 0; - do { - prev = ptr; - ptr = ptr->nextPtr; - } while (ptr && ptr != o); - assert(ptr); - prev->nextPtr = ptr->nextPtr; - } - } + removeLvlObjectFromList(&_lvlObjectsList1, o); } o->dataPtr = 0; - if (o->type == 8) { - _res->decLvlSpriteDataRefCounter(o); - o->nextPtr = _declaredLvlObjectsNextPtr; - _declaredLvlObjectsNextPtr = o; - --_declaredLvlObjectsListCount; - } else { - switch (o->spriteNum) { - case 0: - case 2: - o->dataPtr = 0; - break; - case 3: - case 7: - if (o->dataPtr) { - clearShootLvlObjectData(o); - } - break; - } - } - if (o->sssObject) { - removeSound(o); - o->sssObject = 0; - } - o->bitmapBits = 0; + destroyLvlObject(o); } void Game::setAndySprite(int num) { @@ -1279,7 +1108,7 @@ void Game::setupScreenLvlObjects(int num) { switch (ptr->type) { case 0: { AnimBackgroundData *p = (AnimBackgroundData *)getLvlObjectDataPtr(ptr, kObjectDataTypeAnimBackgroundData); - uint8_t *data = _res->_resLvlScreenBackgroundDataTable[num].backgroundAnimationTable[ptr->dataNum]; + const uint8_t *data = _res->_resLvlScreenBackgroundDataTable[num].backgroundAnimationTable[ptr->dataNum]; if (!data) { warning("No backgroundAnimationData num %d screen %d", ptr->dataNum, num); break; @@ -1356,13 +1185,12 @@ void Game::setupScreenLvlObjects(int num) { } void Game::resetDisplay() { -// _video_blitSrcPtr = _video_blitSrcPtr2; _video->_displayShadowLayer = false; _shakeScreenDuration = 0; _levelRestartCounter = 0; _fadePalette = false; memset(_video->_fadePaletteBuffer, 0, sizeof(_video->_fadePaletteBuffer)); - _snd_masterVolume = kDefaultSoundVolume; // _plyConfigTable[_plyConfigNumber].soundVolume; + _snd_masterVolume = _setupConfig.players[_setupConfig.currentPlayer].volume; } void Game::setupScreen(uint8_t num) { @@ -1409,7 +1237,6 @@ void Game::setupScreen(uint8_t num) { setupBackgroundBitmap(); setupScreenMask(num); resetDisplay(); -// _time_counter1 = GetTickCount(); } void Game::resetScreen() { @@ -1551,7 +1378,7 @@ void Game::setAndyAnimationForArea(BoundingBox *box, int dx) { uint8_t _al = 0; if (_currentLevel != kLvl_rock) { if (_bl == 1) { - if (((_andyObject->flags0 >> 5) & 7) == 3) { + if (((_andyObject->flags0 >> 5) & 7) != 3) { _al = 0x80; } } @@ -1764,69 +1591,69 @@ int Game::clipLvlObjectsBoundingBoxHelper(LvlObject *o1, BoundingBox *box1, LvlO int Game::clipLvlObjectsBoundingBox(LvlObject *o, LvlObject *ptr, int type) { BoundingBox obj1, obj2; - obj1.x1 = o->xPos + _res->_screensBasePos[o->screenNum].u; + obj1.x1 = obj1.x2 = o->xPos + _res->_screensBasePos[o->screenNum].u; obj1.y1 = obj1.y2 = o->yPos + _res->_screensBasePos[o->screenNum].v; - obj2.x1 = ptr->xPos + _res->_screensBasePos[ptr->screenNum].u; + obj2.x1 = obj2.x2 = ptr->xPos + _res->_screensBasePos[ptr->screenNum].u; obj2.y1 = obj2.y2 = ptr->yPos + _res->_screensBasePos[ptr->screenNum].v; switch (type - 17) { case 1: - obj1.x2 = obj1.x1 + o->posTable[1].x; + obj1.x2 += o->posTable[1].x; obj1.x1 += o->posTable[0].x; obj1.y2 += o->posTable[1].y; obj1.y1 += o->posTable[0].y; - obj2.x2 = obj2.x1 + ptr->width - 1; + obj2.x2 += ptr->width - 1; obj2.y2 += ptr->height - 1; return clipBoundingBox(&obj1, &obj2); case 17: - obj1.x2 = obj1.x1 + o->posTable[1].x; + obj1.x2 += o->posTable[1].x; obj1.x1 += o->posTable[0].x; obj1.y2 += o->posTable[1].y; obj1.y1 += o->posTable[0].y; - obj2.x2 = obj2.x1 + ptr->posTable[1].x; + obj2.x2 += ptr->posTable[1].x; obj2.x1 += ptr->posTable[0].x; obj2.y2 += ptr->posTable[1].y; obj2.y1 += ptr->posTable[0].y; return clipBoundingBox(&obj1, &obj2); case 49: - obj1.x2 = obj1.x1 + o->posTable[1].x; + obj1.x2 += o->posTable[1].x; obj1.x1 += o->posTable[0].x; obj1.y2 += o->posTable[1].y; obj1.y1 += o->posTable[0].y; - obj2.x2 = obj2.x1 + ptr->width - 1; + obj2.x2 += ptr->width - 1; obj2.y2 += ptr->height - 1; if (clipBoundingBox(&obj1, &obj2)) { updateBoundingBoxClippingOffset(&obj1, &obj2, _res->getLvlSpriteCoordPtr(ptr->levelData0x2988, ptr->currentSprite), (ptr->flags1 >> 4) & 3); } break; case 16: - obj1.x2 = obj1.x1 + o->width - 1; + obj1.x2 += o->width - 1; obj1.y2 += o->height - 1; obj2.y1 += ptr->posTable[0].y; - obj2.x2 = obj2.x1 + ptr->posTable[1].x; + obj2.x2 += ptr->posTable[1].x; obj2.x1 += ptr->posTable[0].x; obj2.y2 += ptr->posTable[1].y; return clipBoundingBox(&obj1, &obj2); case 0: - obj1.x2 = obj1.x1 + o->width - 1; + obj1.x2 += o->width - 1; obj1.y2 += o->height - 1; - obj2.x2 = obj2.x1 + ptr->width - 1; + obj2.x2 += ptr->width - 1; obj2.y2 += ptr->height - 1; return clipBoundingBox(&obj1, &obj2); case 48: - obj1.x2 = obj1.x1 + o->width - 1; + obj1.x2 += o->width - 1; obj1.y2 += o->height - 1; - obj2.x2 = obj2.x1 + ptr->width - 1; + obj2.x2 += ptr->width - 1; obj2.y2 += ptr->height - 1; if (clipBoundingBox(&obj1, &obj2)) { return updateBoundingBoxClippingOffset(&obj1, &obj2, _res->getLvlSpriteCoordPtr(ptr->levelData0x2988, ptr->currentSprite), (ptr->flags1 >> 4) & 3); } break; case 19: - obj1.x2 = obj1.x1 + o->width - 1; + obj1.x2 += o->width - 1; obj1.y2 += o->height - 1; - obj2.x2 = obj2.x1 + ptr->posTable[1].x; + obj2.x2 += ptr->posTable[1].x; obj2.x1 += ptr->posTable[0].x; obj2.y1 += ptr->posTable[0].y; obj2.y2 += ptr->posTable[1].y; @@ -1835,29 +1662,29 @@ int Game::clipLvlObjectsBoundingBox(LvlObject *o, LvlObject *ptr, int type) { } break; case 3: - obj1.x2 = obj1.x1 + o->width - 1; + obj1.x2 += o->width - 1; obj1.y2 += o->height - 1; - obj2.x2 = obj2.x1 + ptr->width - 1; + obj2.x2 += ptr->width - 1; obj2.y2 += ptr->height - 1; if (clipBoundingBox(&obj2, &obj1)) { return updateBoundingBoxClippingOffset(&obj2, &obj1, _res->getLvlSpriteCoordPtr(o->levelData0x2988, o->currentSprite), (o->flags1 >> 4) & 3); } break; case 51: - obj1.x2 = obj1.x1 + o->width - 1; + obj1.x2 += o->width - 1; obj1.y2 += o->height - 1; - obj2.x2 = obj2.x1 + ptr->width - 1; + obj2.x2 += ptr->width - 1; obj2.y2 += ptr->height - 1; return clipLvlObjectsBoundingBoxHelper(o, &obj1, ptr, &obj2); case 115: if (o->width == 3) { obj1.y2 += 7; - obj1.x2 = obj1.x1 + 7; + obj1.x2 += 7; } else { - obj1.x2 = obj1.x1 + o->width - 1; + obj1.x2 += o->width - 1; obj1.y2 += o->height - 1; } - obj2.x2 = obj2.x1 + ptr->width - 9; + obj2.x2 += ptr->width - 9; obj2.x1 += 4; obj2.y2 += ptr->height - 13; obj2.y1 += 6; @@ -1888,7 +1715,7 @@ int Game::clipLvlObjectsSmall(LvlObject *o1, LvlObject *o2, int type) { int Game::restoreAndyCollidesLava() { int ret = 0; - if (_lvlObjectsList1 && !_hideAndyObjectFlag && (_mstFlags & 0x80000000) == 0) { + if ((_cheats & kCheatLavaNoHit) == 0 && _lvlObjectsList1 && !_hideAndyObjectFlag && (_mstFlags & 0x80000000) == 0) { AndyLvlObjectData *data = (AndyLvlObjectData *)getLvlObjectDataPtr(_andyObject, kObjectDataTypeAndy); for (LvlObject *o = _lvlObjectsList1; o; o = o->nextPtr) { if (o->spriteNum != 21 || o->screenNum != _res->_currentScreenResourceNum) { @@ -2075,6 +1902,10 @@ void Game::drawScreen() { } } +static void gamePafCallback(void *userdata) { + ((Game *)userdata)->resetSound(); +} + void Game::mainLoop(int level, int checkpoint, bool levelChanged) { if (_playDemo && _res->loadHodDem()) { _rnd._rndSeed = _res->_dem.randSeed; @@ -2092,11 +1923,21 @@ void Game::mainLoop(int level, int checkpoint, bool levelChanged) { if (checkpoint != 0 && checkpoint >= _res->_datHdr.levelCheckpointsCount[level]) { checkpoint = _setupConfig.players[num].progress[level]; } - _paf->_playedMask = _setupConfig.players[num].cutscenesMask; debug(kDebug_GAME, "Restart at level %d checkpoint %d cutscenes 0x%x", level, checkpoint, _paf->_playedMask); + _paf->_playedMask = _setupConfig.players[num].cutscenesMask; + _snd_masterVolume = _setupConfig.players[num].volume; + _paf->setVolume(_snd_masterVolume); + _difficulty = _setupConfig.players[num].difficulty; // resume once, on the starting level _resumeGame = false; } + + PafCallback pafCb; + pafCb.frameProc = 0; + pafCb.endProc = gamePafCallback; + pafCb.userdata = this; + _paf->setCallback(&pafCb); + _video->_font = _res->_fontBuffer; assert(level < kLvl_test); _currentLevel = level; @@ -2146,15 +1987,15 @@ void Game::mainLoop(int level, int checkpoint, bool levelChanged) { resetShootLvlObjectDataTable(); callLevel_initialize(); restartLevel(); - do { + while (true) { const int frameTimeStamp = g_system->getTimeStamp() + _frameMs; levelMainLoop(); - if (g_system->inp.quit) { + if (g_system->inp.quit || _endLevel) { break; } const int delay = MAX(10, frameTimeStamp - g_system->getTimeStamp()); g_system->sleep(delay); - } while (!_endLevel); + } _animBackgroundDataCount = 0; callLevel_terminate(); } @@ -2167,22 +2008,18 @@ void Game::mixAudio(int16_t *buf, int len) { const int kStereoSamples = _res->_isPsx ? 1792 * 2 : 1764 * 2; // stereo - static int count = 0; - - static int16_t buffer[4096]; - static int bufferOffset = 0; - static int bufferSize = 0; - // flush samples from previous run - if (bufferSize > 0) { - const int count = len < bufferSize ? len : bufferSize; - memcpy(buf, buffer + bufferOffset, count * sizeof(int16_t)); + if (_snd_bufferSize > 0) { + const int count = len < _snd_bufferSize ? len : _snd_bufferSize; + memcpy(buf, _snd_buffer + _snd_bufferOffset, count * sizeof(int16_t)); buf += count; len -= count; - bufferOffset += count; - bufferSize -= count; + _snd_bufferOffset += count; + _snd_bufferSize -= count; } + static int count = 0; + while (len > 0) { // this enqueues 1764*2 bytes for mono samples and 3528*2 bytes for stereo _mix._mixingQueueSize = 0; @@ -2200,11 +2037,11 @@ void Game::mixAudio(int16_t *buf, int len) { buf += kStereoSamples; len -= kStereoSamples; } else { - memset(buffer, 0, sizeof(buffer)); - _mix.mix(buffer, kStereoSamples); - memcpy(buf, buffer, len * sizeof(int16_t)); - bufferOffset = len; - bufferSize = kStereoSamples - len; + memset(_snd_buffer, 0, sizeof(_snd_buffer)); + _mix.mix(_snd_buffer, kStereoSamples); + memcpy(buf, _snd_buffer, len * sizeof(int16_t)); + _snd_bufferOffset = len; + _snd_bufferSize = kStereoSamples - len; break; } } @@ -2264,8 +2101,7 @@ LvlObject *Game::updateAnimatedLvlObjectType0(LvlObject *ptr) { } } int16_t soundNum = -1; - const int len = READ_LE_UINT16(data + 2); - const uint8_t *nextSpriteData = len + data + 2; + const uint8_t *nextSpriteData = READ_LE_UINT16(data + 2) + data + 2; switch (ptr->objectUpdateType - 1) { case 6: vg->currentSpriteData = vg->nextSpriteData; @@ -2394,7 +2230,7 @@ LvlObject *Game::updateAnimatedLvlObjectType2(LvlObject *ptr) { LvlObject *next, *o; o = next = ptr->nextPtr; - if ((ptr->spriteNum > 15 && ptr->dataPtr == 0) || ptr->levelData0x2988 == 0) { + if ((ptr->spriteNum > 15 && !ptr->dataPtr) || !ptr->levelData0x2988) { if (ptr->childPtr) { o = ptr->childPtr->nextPtr; } @@ -2472,19 +2308,15 @@ LvlObject *Game::updateAnimatedLvlObjectType2(LvlObject *ptr) { return o; } -LvlObject *Game::updateAnimatedLvlObjectTypeDefault(LvlObject *ptr) { - return ptr->nextPtr; -} - LvlObject *Game::updateAnimatedLvlObject(LvlObject *o) { switch (o->type) { - case 0: + case 0: // background animation o = updateAnimatedLvlObjectType0(o); break; - case 1: + case 1: // background sound o = updateAnimatedLvlObjectType1(o); break; - case 2: + case 2: // sprite / monster o = updateAnimatedLvlObjectType2(o); break; case 3: @@ -2492,7 +2324,7 @@ LvlObject *Game::updateAnimatedLvlObject(LvlObject *o) { case 5: case 6: case 7: - o = updateAnimatedLvlObjectTypeDefault(o); + o = o->nextPtr; break; default: error("updateAnimatedLvlObject unhandled type %d", o->type); @@ -2706,10 +2538,12 @@ void Game::levelMainLoop() { callLevel_postScreenUpdate(_currentRightScreen); } } + if (_endLevel) { + return; + } _currentLevelCheckpoint = _level->_checkpoint; - if (updateAndyLvlObject() != 0) { + if (updateAndyLvlObject()) { callLevel_tick(); -// _time_counter1 -= _time_counter2; return; } executeMstCode(); @@ -2727,9 +2561,6 @@ void Game::levelMainLoop() { updatePlasmaCannonExplosionLvlObject(_plasmaExplosionObject->nextPtr); } } - if (_res->_sssHdr.infosDataCount != 0) { - // sound thread signaling - } if (_video->_paletteChanged) { _video->_paletteChanged = false; _video->updateGamePalette(_video->_displayPaletteBuffer); @@ -2747,11 +2578,7 @@ void Game::levelMainLoop() { } if (_shakeScreenDuration != 0 || _levelRestartCounter != 0 || _video->_displayShadowLayer) { shakeScreen(); - uint8_t *p = _video->_shadowLayer; - if (!_video->_displayShadowLayer) { - p = _video->_frontLayer; - } - _video->updateGameDisplay(p); + _video->updateGameDisplay(_video->_displayShadowLayer ? _video->_shadowLayer : _video->_frontLayer); } else { _video->updateGameDisplay(_video->_frontLayer); } @@ -2760,7 +2587,6 @@ void Game::levelMainLoop() { if (g_system->inp.keyPressed(SYS_INP_ESC) || g_system->inp.exit) { // display exit confirmation screen if (displayHintScreen(-1, 0)) { g_system->inp.quit = true; - return; } } else { // displayHintScreen(1, 0); @@ -2825,10 +2651,20 @@ void Game::callLevel_terminate() { } void Game::displayLoadingScreen() { - if (_loadingScreenEnabled && _res->loadDatLoadingImage(_video->_frontLayer, _video->_palette)) { - g_system->setPalette(_video->_palette, 256, 6); - g_system->copyRect(0, 0, Video::W, Video::H, _video->_frontLayer, 256); - g_system->updateScreen(false); + if (_res->_isPsx) { + static const int kHintPsxLoading = 39; + if (_res->loadDatHintImage(kHintPsxLoading, _video->_frontLayer, 0)) { + _video->decodeBackgroundPsx(_video->_frontLayer, _res->_datHdr.hintsImageSizeTable[kHintPsxLoading], Video::W, Video::H); + g_system->fillRect(0, 0, Video::W, Video::H, 0); + _video->updateYuvDisplay(); + g_system->updateScreen(false); + } + } else { + if (_res->loadDatLoadingImage(_video->_frontLayer, _video->_palette)) { + g_system->setPalette(_video->_palette, 256, 6); + g_system->copyRect(0, 0, Video::W, Video::H, _video->_frontLayer, 256); + g_system->updateScreen(false); + } } } @@ -2841,15 +2677,26 @@ int Game::displayHintScreen(int num, int pause) { _video->_frontLayer, _video->_shadowLayer, }; + const bool isPsx = _res->_isPsx; muteSound(); if (num == -1) { - num = _res->_datHdr.yesNoQuitImage; // 'Yes' - _res->loadDatHintImage(num + 1, _video->_shadowLayer, _video->_palette); // 'No' - confirmQuit = true; + if (isPsx) { + num = 35; // 'Pause' on PSX + } else { + num = _res->_datHdr.yesNoQuitImage; // 'Yes' + _res->loadDatHintImage(num + 1, _video->_shadowLayer, _video->_palette); // 'No' + confirmQuit = true; + } } if (_res->loadDatHintImage(num, _video->_frontLayer, _video->_palette)) { - g_system->setPalette(_video->_palette, 256, 6); - g_system->copyRect(0, 0, Video::W, Video::H, _video->_frontLayer, 256); + if (isPsx) { + _video->decodeBackgroundPsx(_video->_frontLayer, _res->_datHdr.hintsImageSizeTable[num], Video::W, Video::H); + g_system->fillRect(0, 0, Video::W, Video::H, 0); + _video->updateYuvDisplay(); + } else { + g_system->setPalette(_video->_palette, 256, 6); + g_system->copyRect(0, 0, Video::W, Video::H, _video->_frontLayer, 256); + } g_system->updateScreen(false); do { g_system->processEvents(); @@ -2871,14 +2718,14 @@ int Game::displayHintScreen(int num, int pause) { _video->_paletteChanged = true; } unmuteSound(); + if (isPsx) { // restore level screen bitmap + LvlBackgroundData *lvl = &_res->_resLvlScreenBackgroundDataTable[_res->_currentScreenResourceNum]; + const uint8_t *bmp = lvl->backgroundBitmapTable[lvl->currentBackgroundId]; + _video->decodeBackgroundPsx(bmp + 4, -1, Video::W, Video::H); + } return confirmQuit && quit == kQuitYes; } -void Game::prependLvlObjectToList(LvlObject **list, LvlObject *ptr) { - ptr->nextPtr = *list; - *list = ptr; -} - void Game::removeLvlObjectFromList(LvlObject **list, LvlObject *ptr) { LvlObject *current = *list; if (current && ptr) { @@ -2889,8 +2736,11 @@ void Game::removeLvlObjectFromList(LvlObject **list, LvlObject *ptr) { do { prev = current; current = current->nextPtr; - } while (current && current != ptr); - assert(prev); + if (!current) { + warning("LvlObject %p not found for removal", ptr); + return; + } + } while (current != ptr); prev->nextPtr = current->nextPtr; } } @@ -2954,10 +2804,11 @@ void Game::lvlObjectType1Init(LvlObject *ptr) { o->anim = 13; o->frame = 0; o->screenNum = ptr->screenNum; - o->flags1 = merge_bits(o->flags1, ptr->flags1, 0x30); // vg->flags1 ^= (vg->flags1 ^ ptr->flags1) & 0x30; + o->flags1 = merge_bits(o->flags1, ptr->flags1, 0x30); o->flags2 = ptr->flags2 & ~0x2000; setupLvlObjectBitmap(o); - prependLvlObjectToList(&_plasmaExplosionObject, o); + o->nextPtr = _plasmaExplosionObject; + _plasmaExplosionObject = o; o = declareLvlObject(8, 1); assert(o); @@ -2967,10 +2818,11 @@ void Game::lvlObjectType1Init(LvlObject *ptr) { o->anim = 5; o->frame = 0; o->screenNum = ptr->screenNum; - o->flags1 = merge_bits(o->flags1, ptr->flags1, 0x30); // vg->flags1 ^= (vg->flags1 ^ ptr->flags1) & 0x30; + o->flags1 = merge_bits(o->flags1, ptr->flags1, 0x30); o->flags2 = ptr->flags2 & ~0x2000; setupLvlObjectBitmap(o); - prependLvlObjectToList(&_plasmaExplosionObject, o); + o->nextPtr = _plasmaExplosionObject; + _plasmaExplosionObject = o; } void Game::lvlObjectTypeInit(LvlObject *o) { @@ -3024,11 +2876,11 @@ void Game::lvlObjectType0CallbackHelper1() { _bl |= 4; } if (_andyObject->spriteNum == 2 && (_bl & 5) == 5) { - AndyLvlObjectData *data = (AndyLvlObjectData *)getLvlObjectDataPtr(_andyObject, kObjectDataTypeAndy); - LvlObject *o = data->shootLvlObject; + AndyLvlObjectData *andyData = (AndyLvlObjectData *)getLvlObjectDataPtr(_andyObject, kObjectDataTypeAndy); + LvlObject *o = andyData->shootLvlObject; if (o) { - ShootLvlObjectData *dataUnk1 = (ShootLvlObjectData *)getLvlObjectDataPtr(o, kObjectDataTypeShoot); - if (dataUnk1->type < 4) { + ShootLvlObjectData *dat = (ShootLvlObjectData *)getLvlObjectDataPtr(o, kObjectDataTypeShoot); + if (dat->type < 4) { _bl |= 0xC0; } } @@ -3259,30 +3111,10 @@ void Game::setupSpecialPowers(LvlObject *ptr) { if (!vf->shootLvlObject) { LvlObject *vd = declareLvlObject(8, 3); vf->shootLvlObject = vd; - vd->dataPtr = _shootLvlObjectDataNextPtr; - if (_shootLvlObjectDataNextPtr) { - _shootLvlObjectDataNextPtr = _shootLvlObjectDataNextPtr->nextPtr; - memset(vd->dataPtr, 0, sizeof(ShootLvlObjectData)); - } else { - warning("Nothing free in _shootLvlObjectDataNextPtr"); - } - vd->xPos = ptr->xPos; - vd->yPos = ptr->yPos; - vd->flags1 &= ~0x30; - vd->screenNum = ptr->screenNum; - vd->anim = 7; - vd->frame = 0; - vd->bitmapBits = 0; - vd->flags2 = (ptr->flags2 & ~0x2000) - 1; - prependLvlObjectToList(&_lvlObjectsList0, vd); + addShootLvlObject(vd, ptr); } - AndyLvlObjectData *vc = (AndyLvlObjectData *)getLvlObjectDataPtr(ptr, kObjectDataTypeAndy); - LvlObject *va = vc->shootLvlObject; - if (va) { - if (!va->dataPtr) { - warning("lvlObject %p with NULL dataPtr", va); - break; - } + LvlObject *va = vf->shootLvlObject; + if (va && va->dataPtr) { ShootLvlObjectData *vd = (ShootLvlObjectData *)getLvlObjectDataPtr(va, kObjectDataTypeShoot); vd->type = 0; } @@ -3306,31 +3138,10 @@ void Game::setupSpecialPowers(LvlObject *ptr) { if (!vf->shootLvlObject) { LvlObject *vd = declareLvlObject(8, 3); vf->shootLvlObject = vd; - vd->dataPtr = _shootLvlObjectDataNextPtr; - if (_shootLvlObjectDataNextPtr) { - _shootLvlObjectDataNextPtr = _shootLvlObjectDataNextPtr->nextPtr; - memset(vd->dataPtr, 0, sizeof(ShootLvlObjectData)); - } else { - warning("Nothing free in _shootLvlObjectDataNextPtr"); - } - vd->xPos = ptr->xPos; - vd->yPos = ptr->yPos; - vd->flags1 &= ~0x30; - vd->screenNum = ptr->screenNum; - vd->anim = 7; - vd->frame = 0; - vd->bitmapBits = 0; - vd->flags2 = (ptr->flags2 & ~0x2000) - 1; - prependLvlObjectToList(&_lvlObjectsList0, vd); + addShootLvlObject(vd, ptr); } - AndyLvlObjectData *vc = (AndyLvlObjectData *)getLvlObjectDataPtr(ptr, kObjectDataTypeAndy); - assert(vc == vf); - LvlObject *va = vc->shootLvlObject; - if (va) { - if (!va->dataPtr) { - warning("lvlObject %p with NULL dataPtr", va); - break; - } + LvlObject *va = vf->shootLvlObject; + if (va && va->dataPtr) { ShootLvlObjectData *vd = (ShootLvlObjectData *)getLvlObjectDataPtr(va, kObjectDataTypeShoot); vd->type = 0; } @@ -3346,30 +3157,10 @@ void Game::setupSpecialPowers(LvlObject *ptr) { if (!vf->shootLvlObject) { LvlObject *vd = declareLvlObject(8, 3); vf->shootLvlObject = vd; - vd->dataPtr = _shootLvlObjectDataNextPtr; - if (_shootLvlObjectDataNextPtr) { - _shootLvlObjectDataNextPtr = _shootLvlObjectDataNextPtr->nextPtr; - memset(vd->dataPtr, 0, sizeof(ShootLvlObjectData)); - } else { - warning("Nothing free in _shootLvlObjectDataNextPtr"); - } - vd->xPos = ptr->xPos; - vd->yPos = ptr->yPos; - vd->flags1 &= ~0x30; - vd->screenNum = ptr->screenNum; - vd->anim = 7; - vd->frame = 0; - vd->bitmapBits = 0; - vd->flags2 = (ptr->flags2 & ~0x2000) - 1; - prependLvlObjectToList(&_lvlObjectsList0, vd); + addShootLvlObject(vd, ptr); } - AndyLvlObjectData *vc = (AndyLvlObjectData *)getLvlObjectDataPtr(ptr, kObjectDataTypeAndy); - LvlObject *va = vc->shootLvlObject; - if (va) { - if (!va->dataPtr) { - warning("lvlObject %p with NULL dataPtr", va); - break; - } + LvlObject *va = vf->shootLvlObject; + if (va && va->dataPtr) { ShootLvlObjectData *vd = (ShootLvlObjectData *)getLvlObjectDataPtr(va, kObjectDataTypeShoot); vd->type = 4; // large power } @@ -3494,16 +3285,16 @@ int Game::lvlObjectType1Callback(LvlObject *ptr) { } int Game::lvlObjectType7Callback(LvlObject *ptr) { - ShootLvlObjectData *dat = (ShootLvlObjectData *)getLvlObjectDataPtr(ptr, kObjectDataTypeShoot); - if (!dat) { + if (!ptr->dataPtr) { return 0; } + ShootLvlObjectData *dat = (ShootLvlObjectData *)getLvlObjectDataPtr(ptr, kObjectDataTypeShoot); if ((ptr->flags0 & 0x1F) == 1) { dat->xPosObject = ptr->posTable[7].x + ptr->xPos; dat->yPosObject = ptr->posTable[7].y + ptr->yPos; ptr->xPos += dat->dxPos; ptr->yPos += dat->dyPos; - if (!_hideAndyObjectFlag && ptr->screenNum == _andyObject->screenNum && (_andyObject->flags0 & 0x1F) != 0xB && clipLvlObjectsBoundingBox(_andyObject, ptr, 68) && (_mstFlags & 0x80000000) == 0 && (_cheats & kCheatSpectreFireballNoHit) == 0) { + if ((_cheats & kCheatSpectreFireballNoHit) == 0 && !_hideAndyObjectFlag && ptr->screenNum == _andyObject->screenNum && (_andyObject->flags0 & 0x1F) != 0xB && clipLvlObjectsBoundingBox(_andyObject, ptr, 68) && (_mstFlags & 0x80000000) == 0) { dat->unk3 = 0x80; dat->xPosShoot = _clipBoxOffsetX; dat->yPosShoot = _clipBoxOffsetY; @@ -3603,7 +3394,7 @@ int Game::lvlObjectType8Callback(LvlObject *ptr) { return 0; } int vb, var4; - MonsterObject1 *m = 0; // ve + MonsterObject1 *m = 0; if (dataPtr >= &_monsterObjects1Table[0] && dataPtr < &_monsterObjects1Table[kMaxMonsterObjects1]) { m = (MonsterObject1 *)ptr->dataPtr; vb = 1; @@ -3628,13 +3419,13 @@ int Game::lvlObjectType8Callback(LvlObject *ptr) { vb = 0; var4 = 4; } - m = 0; // ve = 0 + m = 0; if (mo->flags24 & 8) { ptr->bitmapBits = 0; return 0; } } - LvlObject *o = 0; // vf + LvlObject *o = 0; updateAndyObject(ptr); if (m && m->o20) { o = m->o20; @@ -3649,9 +3440,9 @@ int Game::lvlObjectType8Callback(LvlObject *ptr) { if (ptr->screenNum == _currentScreen || ptr->screenNum == _currentLeftScreen || ptr->screenNum == _currentRightScreen || o || (_currentLevel == kLvl_lar2 && ptr->spriteNum == 27) || (_currentLevel == kLvl_isld && ptr->spriteNum == 26)) { if (ptr->currentSound != 0xFFFF) { playSound(ptr->currentSound, ptr, vb, var4); - } - if (o && o->currentSound != 0xFFFF) { - playSound(o->currentSound, o, vb, var4); + if (o && o->currentSound != 0xFFFF) { + playSound(o->currentSound, o, vb, var4); + } } } } @@ -3664,43 +3455,8 @@ int Game::lvlObjectType8Callback(LvlObject *ptr) { int Game::lvlObjectList3Callback(LvlObject *o) { const uint8_t flags = o->flags0 & 0xFF; if ((o->spriteNum <= 7 && (flags & 0x1F) == 0xB) || (o->spriteNum > 7 && flags == 0x1F)) { - if (_lvlObjectsList3 && o) { - if (o != _lvlObjectsList3) { - LvlObject *prev = 0; - LvlObject *ptr = _lvlObjectsList3; - do { - prev = ptr; - ptr = ptr->nextPtr; - } while (ptr && ptr != o); - assert(ptr); - prev->nextPtr = ptr->nextPtr; - } else { - _lvlObjectsList3 = o->nextPtr; - } - } - if (o->type == 8) { - _res->decLvlSpriteDataRefCounter(o); - o->nextPtr = _declaredLvlObjectsNextPtr; - --_declaredLvlObjectsListCount; - _declaredLvlObjectsNextPtr = o; - switch (o->spriteNum) { - case 0: - case 2: - o->dataPtr = 0; - break; - case 3: - case 7: - if (o->dataPtr) { - clearShootLvlObjectData(o); - } - break; - } - } - if (o->sssObject) { - removeSound(o); - } - o->sssObject = 0; - o->bitmapBits = 0; + removeLvlObjectFromList(&_lvlObjectsList3, o); + destroyLvlObject(o); } else { updateAndyObject(o); o->actionKeyMask = 0; @@ -3791,33 +3547,33 @@ uint8_t Game::lvlObjectCallbackCollideScreen(LvlObject *o) { uint8_t screenNum = o->screenNum; uint8_t var30 = 0; - int yPos = o->yPos; // va + int yPos = o->yPos; if ((o->flags0 & 0xE0) != 0x20) { yPos += o->posTable[6].y; } else { yPos += o->posTable[3].y; } - int xPos = o->xPos + o->posTable[3].x; // vc + int xPos = o->xPos + o->posTable[3].x; - int var1C = 0; - int var20 = 0; + int yOffset = 0; + int xOffset = 0; if (xPos < 0) { xPos += Video::W; - var20 = -Video::W; + xOffset = -Video::W; screenNum = _res->_screensGrid[screenNum][kPosLeftScreen]; } else if (xPos >= Video::W) { xPos -= Video::W; - var20 = Video::W; + xOffset = Video::W; screenNum = _res->_screensGrid[screenNum][kPosRightScreen]; } if (screenNum != kNoScreen) { if (yPos < 0) { yPos += Video::H; - var1C = -Video::H; + yOffset = -Video::H; screenNum = _res->_screensGrid[screenNum][kPosTopScreen]; } else if (yPos >= Video::H) { yPos -= Video::H; - var1C = Video::H; + yOffset = Video::H; screenNum = _res->_screensGrid[screenNum][kPosBottomScreen]; } } @@ -3835,15 +3591,15 @@ uint8_t Game::lvlObjectCallbackCollideScreen(LvlObject *o) { 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x08, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0xF8, 0xF8 }; - static const int offsets1[] = { + static const int16_t offsets1[] = { 0, 1, 1, 1, 0, -513, -513, -513, 0, 511, 511, 511, 0, -511, -511, -511, 0, 513, 513, 513, 0, -1, -1, -1, 0, -512, -512, -512, 0, 512, 512, 512 }; - static const int offsets2[] = { + static const int16_t offsets2[] = { 0, 1, 512, -1, 0, -1, 512, 1, 0, 1, -512, -1, 0, -1, -512, 1 }; uint8_t _bl, _cl = dat->type; const uint8_t *var10; - const int *vg; + const int16_t *vg; if (_cl == 4) { _bl = _cl; const uint8_t num = (o->flags1 >> 4) & 3; @@ -3858,7 +3614,7 @@ uint8_t Game::lvlObjectCallbackCollideScreen(LvlObject *o) { int num; int var2E = _bl; int vd = _res->_screensBasePos[screenNum].v + yPos; - int vf = _res->_screensBasePos[screenNum].u + xPos; // vf + int vf = _res->_screensBasePos[screenNum].u + xPos; vd = screenMaskOffset(vf, vd); int var4 = screenGridOffset(xPos, yPos); if (_cl >= 4) { @@ -3923,8 +3679,9 @@ uint8_t Game::lvlObjectCallbackCollideScreen(LvlObject *o) { vd += *vg++; } } - dat->xPosShoot = (int8_t)var10[num * 2 ] + var20 + (xPos & ~7); - dat->yPosShoot = (int8_t)var10[num * 2 + 1] + var1C + (yPos & ~7); + var10 += num * 2; + dat->xPosShoot = (int8_t)var10[0] + xOffset + (xPos & ~7); + dat->yPosShoot = (int8_t)var10[1] + yOffset + (yPos & ~7); _bl = dat->state; if (_bl != 2 && _bl != 4 && _bl != 7) { return var30; @@ -4176,25 +3933,22 @@ int Game::setLvlObjectPosInScreenGrid(LvlObject *o, int pos) { } LvlObject *Game::declareLvlObject(uint8_t type, uint8_t num) { - if (type != 8 || _res->_resLevelData0x2988PtrTable[num] != 0) { - if (_declaredLvlObjectsListCount < kMaxLvlObjects) { - assert(_declaredLvlObjectsNextPtr); - LvlObject *ptr = _declaredLvlObjectsNextPtr; - _declaredLvlObjectsNextPtr = _declaredLvlObjectsNextPtr->nextPtr; - assert(ptr); - ++_declaredLvlObjectsListCount; - ptr->spriteNum = num; - ptr->type = type; - if (type == 8) { - _res->incLvlSpriteDataRefCounter(ptr); - lvlObjectTypeCallback(ptr); - } - ptr->currentSprite = 0; - ptr->sssObject = 0; - ptr->nextPtr = 0; - ptr->bitmapBits = 0; - return ptr; + if ((type != 8 || _res->_resLevelData0x2988PtrTable[num] != 0) && _declaredLvlObjectsListCount < kMaxLvlObjects) { + assert(_declaredLvlObjectsNextPtr); + LvlObject *ptr = _declaredLvlObjectsNextPtr; + _declaredLvlObjectsNextPtr = _declaredLvlObjectsNextPtr->nextPtr; + ++_declaredLvlObjectsListCount; + ptr->spriteNum = num; + ptr->type = type; + if (type == 8) { + _res->incLvlSpriteDataRefCounter(ptr); + lvlObjectTypeCallback(ptr); } + ptr->currentSprite = 0; + ptr->sssObject = 0; + ptr->nextPtr = 0; + ptr->bitmapBits = 0; + return ptr; } return 0; } @@ -4332,7 +4086,8 @@ void Game::setLavaAndyAnimation(int yPos) { } void Game::updateGatesLar(LvlObject *o, uint8_t *p, int num) { - uint32_t mask = 1 << num; // ve + p += num * 4; + uint32_t mask = 1 << num; uint8_t _cl = p[0] & 15; if (_cl >= 3) { if ((o->flags0 & 0x1F) == 0) { @@ -4340,12 +4095,12 @@ void Game::updateGatesLar(LvlObject *o, uint8_t *p, int num) { if (_cl == 3) { p[0] = (p[0] & ~0xB) | 4; p[3] = p[1]; - o->directionKeyMask = 1; + o->directionKeyMask = 1; // up (open) o->actionKeyMask = 0; } else { p[0] = (p[0] & ~0xC) | 3; p[3] = p[2]; - o->directionKeyMask = 4; + o->directionKeyMask = 4; // down (close) o->actionKeyMask = 0; } } else { @@ -4355,7 +4110,6 @@ void Game::updateGatesLar(LvlObject *o, uint8_t *p, int num) { } } } else { - num = p[1]; if ((p[1] | p[2]) != 0) { uint8_t _dl = p[0] >> 4; if (_cl != _dl) { @@ -4369,10 +4123,10 @@ void Game::updateGatesLar(LvlObject *o, uint8_t *p, int num) { } if (p[3] == 0) { if (p[0] & 0xF) { - o->directionKeyMask = 1; + o->directionKeyMask = 1; // up (open) _mstAndyVarMask &= ~mask; } else { - o->directionKeyMask = 4; + o->directionKeyMask = 4; // down (close) _mstAndyVarMask |= mask; } _mstLevelGatesMask |= mask; @@ -4390,10 +4144,10 @@ void Game::updateGatesLar(LvlObject *o, uint8_t *p, int num) { uint8_t _al = (p[0] & 0xF0) | _dl; p[0] = _al; if (_al & 0xF0) { - o->directionKeyMask = 1; + o->directionKeyMask = 1; // up (open) _mstAndyVarMask &= ~mask; } else { - o->directionKeyMask = 4; + o->directionKeyMask = 4; // down (close) _mstAndyVarMask |= mask; } _mstLevelGatesMask |= mask; @@ -4406,9 +4160,9 @@ void Game::updateGatesLar(LvlObject *o, uint8_t *p, int num) { } } } - int y1 = o->yPos + o->posTable[1].y; // ve - int h1 = o->posTable[1].y - o->posTable[2].y - 7; // vc - int x1 = o->xPos + o->posTable[1].x; // vd + int y1 = o->yPos + o->posTable[1].y; + int h1 = o->posTable[1].y - o->posTable[2].y - 7; + int x1 = o->xPos + o->posTable[1].x; if (x1 < 0) { x1 = 0; } @@ -4433,9 +4187,9 @@ void Game::updateGatesLar(LvlObject *o, uint8_t *p, int num) { updateAndyObject(o); } } - int y2 = o->yPos + o->posTable[1].y; // vb - int h2 = o->posTable[2].y - o->posTable[1].y + 7; // vc - int x2 = o->xPos + o->posTable[1].x; // vd + int y2 = o->yPos + o->posTable[1].y; + int h2 = o->posTable[2].y - o->posTable[1].y + 7; + int x2 = o->xPos + o->posTable[1].x; if (x2 < 0) { x2 = 0; } @@ -4579,11 +4333,11 @@ int Game::updateSwitchesLar_checkAndy(int num, uint8_t *p, BoundingBox *b1, Boun } return ret; } - if ((p[1] & 0xC) == 0 && (p[1] & 0x80) != 0) { + uint8_t _al = p[1]; + if ((_al & 0xC) == 0 && (_al & 0x80) != 0) { + const uint8_t _cl = (_al >> 5) & 1; + _al = ((~_al) >> 1) & 1; p = &gatesData[p[3] * 4]; - const uint8_t _cl = (p[1] >> 5) & 1; - uint8_t _al = ((~p[1]) >> 1) & 1; - uint8_t _bl = p[0] >> 4; if (_bl != _al) { _bl = (_al << 4) | (p[0] & 0xF); @@ -4599,7 +4353,7 @@ int Game::updateSwitchesLar_checkAndy(int num, uint8_t *p, BoundingBox *b1, Boun int Game::updateSwitchesLar_toggle(bool flag, uint8_t dataNum, int screenNum, int switchNum, int anim, const BoundingBox *box) { uint8_t _al = (_andyObject->flags0 >> 5) & 7; uint8_t _cl = (_andyObject->flags0 & 0x1F); - int ret = 0; // _bl + int ret = 0; if ((dataNum & 0x80) == 0) { const int dy = box->y2 - box->y1; const int dx = box->x2 - box->x1; @@ -4774,13 +4528,12 @@ void Game::updateWormHoleSprites() { _res->decLvlSpriteDataRefCounter(&tmp); } -bool Game::loadSetupCfg(bool resume) { +void Game::loadSetupCfg(bool resume) { _resumeGame = resume; - if (_res->readSetupCfg(&_setupConfig)) { - return true; + if (!_res->readSetupCfg(&_setupConfig)) { + memset(&_setupConfig, 0, sizeof(_setupConfig)); + _res->setDefaultsSetupCfg(&_setupConfig, 0); } - memset(&_setupConfig, 0, sizeof(_setupConfig)); - return false; } void Game::saveSetupCfg() { diff --git a/game.h b/game.h index 952c9f0..6b36d95 100644 --- a/game.h +++ b/game.h @@ -42,7 +42,9 @@ enum { kCheatOneHitPlasmaCannon = 1 << 1, kCheatOneHitSpecialPowers = 1 << 2, kCheatWalkOnLava = 1 << 3, - kCheatGateNoCrush = 1 << 4 + kCheatGateNoCrush = 1 << 4, + kCheatLavaNoHit = 1 << 5, + kCheatRockShadowNoHit = 1 << 6 }; struct Game { @@ -61,9 +63,7 @@ struct Game { kMaxBoundingBoxes = 64, kDefaultSoundPanning = 64, - kDefaultSoundVolume = 128, - - kFrameTimeStamp = 50 // original is 80ms (12.5hz) + kDefaultSoundVolume = 128 }; static const uint8_t _specialPowersDxDyTable[]; @@ -94,7 +94,6 @@ struct Game { uint32_t _cheats; int _frameMs; int _difficulty; - bool _loadingScreenEnabled; SetupConfig _setupConfig; bool _playDemo; @@ -178,7 +177,6 @@ struct Game { Task *_currentTask; int _mstOp54Counter; int _mstOp56Counter; - uint8_t _mstOp54Table[32]; bool _mstDisabled; LvlObject _declaredLvlObjectsList[kMaxLvlObjects]; LvlObject *_declaredLvlObjectsNextPtr; // pointer to the next free entry @@ -221,7 +219,7 @@ struct Game { int _mstBoundingBoxesCount; MstBoundingBox _mstBoundingBoxesTable[kMaxBoundingBoxes]; Task *_mstCurrentTask; - MstCollision _mstCollisionTable[2][32]; // 0:facingRight, 1:facingLeft + MstCollision _mstCollisionTable[2][kMaxMonsterObjects1]; // 0:facingRight, 1:facingLeft int _wormHoleSpritesCount; WormHoleSprite _wormHoleSpritesTable[6]; @@ -240,7 +238,6 @@ struct Game { } // benchmark.cpp - uint32_t benchmarkLoop(const uint8_t *p, int count); uint32_t benchmarkCpu(); // game.cpp @@ -248,6 +245,7 @@ struct Game { void mixAudio(int16_t *buf, int len); void resetShootLvlObjectDataTable(); void clearShootLvlObjectData(LvlObject *ptr); + void addShootLvlObject(LvlObject *_edx, LvlObject *ptr); void setShakeScreen(int type, int counter); void fadeScreenPalette(); void shakeScreen(); @@ -255,7 +253,7 @@ struct Game { void loadTransformLayerData(const uint8_t *data); void unloadTransformLayerData(); void decodeShadowScreenMask(LvlBackgroundData *lvl); - void playSound(int num, LvlObject *ptr, int a, int b); + SssObject *playSound(int num, LvlObject *ptr, int a, int b); void removeSound(LvlObject *ptr); void setupBackgroundBitmap(); void addToSpriteList(Sprite *spr); @@ -315,7 +313,6 @@ struct Game { LvlObject *updateAnimatedLvlObjectType0(LvlObject *ptr); LvlObject *updateAnimatedLvlObjectType1(LvlObject *ptr); LvlObject *updateAnimatedLvlObjectType2(LvlObject *ptr); - LvlObject *updateAnimatedLvlObjectTypeDefault(LvlObject *ptr); LvlObject *updateAnimatedLvlObject(LvlObject *o); void updateAnimatedLvlObjectsLeftRightCurrentScreens(); void updatePlasmaCannonExplosionLvlObject(LvlObject *ptr); @@ -331,7 +328,6 @@ struct Game { void callLevel_terminate(); void displayLoadingScreen(); int displayHintScreen(int num, int pause); - void prependLvlObjectToList(LvlObject **list, LvlObject *ptr); void removeLvlObjectFromList(LvlObject **list, LvlObject *ptr); void *getLvlObjectDataPtr(LvlObject *o, int type) const; void lvlObjectType0Init(LvlObject *ptr); @@ -372,7 +368,7 @@ struct Game { int clipAndyLvlObjectLar(BoundingBox *a, BoundingBox *b, bool flag); void resetWormHoleSprites(); void updateWormHoleSprites(); - bool loadSetupCfg(bool resume); + void loadSetupCfg(bool resume); void saveSetupCfg(); void captureScreenshot(); @@ -505,6 +501,8 @@ struct Game { // sound.cpp bool _sssDisabled; + int16_t _snd_buffer[4096]; + int _snd_bufferOffset, _snd_bufferSize; bool _snd_muted; int _snd_masterPanning; int _snd_masterVolume; @@ -513,7 +511,7 @@ struct Game { int _sssObjectsCount; SssObject *_sssObjectsList1; // playing SssObject *_sssObjectsList2; // paused/idle - SssObject *_lowRankSssObject; + SssObject *_lowPrioritySssObject; bool _sssUpdatedObjectsTable[kMaxSssObjects]; int _playingSssObjectsMax; int _playingSssObjectsCount; @@ -521,7 +519,9 @@ struct Game { void muteSound(); void unmuteSound(); void resetSound(); - SssObject *findLowestRankSoundObject() const; + int getSoundPosition(const SssObject *so); + void setSoundPanning(SssObject *so, int panning); + SssObject *findLowPrioritySoundObject() const; void removeSoundObjectFromList(SssObject *so); void updateSoundObject(SssObject *so); void sssOp4_removeSounds(uint32_t flags); @@ -534,7 +534,7 @@ struct Game { void updateSssGroup2(uint32_t flags); SssObject *createSoundObject(int bankIndex, int sampleIndex, uint32_t flags); SssObject *startSoundObject(int bankIndex, int sampleIndex, uint32_t flags); - void playSoundObject(SssInfo *s, int source, int b); + SssObject *playSoundObject(SssInfo *s, int source, int b); void clearSoundObjects(); void setLowPrioritySoundObject(SssObject *so); int getSoundObjectPanning(SssObject *so) const; diff --git a/intern.h b/intern.h index 73df74e..d908293 100644 --- a/intern.h +++ b/intern.h @@ -26,8 +26,7 @@ static const bool kByteSwapData = false; // no byteswap needed on little endian #define htole32(x) OSSwapHostToLittleInt32(x) #include static const bool kByteSwapData = (BYTE_ORDER == BIG_ENDIAN); -#else -#if defined(WII) // big endian +#elif defined(WII) // big endian #include #define le16toh(x) __bswap16(x) #define le32toh(x) __bswap32(x) @@ -38,7 +37,6 @@ static const bool kByteSwapData = true; #include static const bool kByteSwapData = (__BYTE_ORDER == __BIG_ENDIAN); #endif -#endif #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) #define PACKED __attribute__((packed)) diff --git a/level1_rock.cpp b/level1_rock.cpp index 7782c3d..137d6f6 100644 --- a/level1_rock.cpp +++ b/level1_rock.cpp @@ -448,7 +448,7 @@ void Game::objectUpdate_rockShadow(LvlObject *ptr, uint8_t *p) { ptr->directionKeyMask = _level1OpHelper1KeyMaskTable[index * 2]; ptr->actionKeyMask = _level1OpHelper1KeyMaskTable[index * 2 + 1]; } - if ((ptr->actionKeyMask & 4) != 0 && sameScreen && (ptr->flags0 & 0x300) == 0x300) { + if ((_cheats & kCheatRockShadowNoHit) == 0 && (ptr->actionKeyMask & 4) != 0 && sameScreen && (ptr->flags0 & 0x300) == 0x300) { if (clipLvlObjectsBoundingBox(_andyObject, ptr, 20)) { _mstFlags |= 0x80000000; setAndySpecialAnimation(0x80); diff --git a/level5_lava.cpp b/level5_lava.cpp index a7f8079..20d46cf 100644 --- a/level5_lava.cpp +++ b/level5_lava.cpp @@ -594,7 +594,7 @@ void Level_lava::tick() { void Level_lava::setupScreenCheckpoint_lava_screen3() { LvlObject *ptr = _g->findLvlObject(2, 0, 3); assert(ptr); - ptr->flags0 &= 0xFC00; + ptr->flags0 &= ~0x3FF; ptr->xPos = 138; ptr->yPos = 157; ptr->anim = 0; @@ -602,7 +602,7 @@ void Level_lava::setupScreenCheckpoint_lava_screen3() { ptr->directionKeyMask = 0; ptr = findLvlObject_lava(ptr); assert(ptr); - ptr->flags0 &= 0xFC00; + ptr->flags0 &= ~0x3FF; ptr->anim = 0; ptr->frame = 0; ptr->directionKeyMask = 0; diff --git a/level7_lar1.cpp b/level7_lar1.cpp index c8db812..a74869b 100644 --- a/level7_lar1.cpp +++ b/level7_lar1.cpp @@ -1,4 +1,6 @@ +// lar1_hod - "into the lair" + #include "game.h" #include "level.h" #include "paf.h" @@ -14,7 +16,7 @@ static const CheckpointData _lar1_checkpointData[9] = { { 40, 145, 0x300c, 232, 14, 2 }, { 213, 25, 0x700c, 232, 16, 2 }, { 123, 57, 0x300c, 232, 20, 2 }, - { 224, 43, 0x700c, 232, 5, 2 } + { 224, 43, 0x700c, 232, 5, 2 } // not reachable, _datHdr.levelCheckpointsCount[6] == 8 }; static const uint8_t _lar1_screenStartData[56] = { @@ -220,16 +222,16 @@ void Level_lar1::postScreenUpdate_lar1_screen3() { void Level_lar1::postScreenUpdate_lar1_screen4() { LvlObject *o = _g->findLvlObject(2, 0, 4); - _g->updateGatesLar(o, &_lar1_gatesData[0 * 4], 0); + _g->updateGatesLar(o, _lar1_gatesData, 0); } void Level_lar1::postScreenUpdate_lar1_screen5() { LvlObject *o1 = _g->findLvlObject(2, 0, 5); - _g->updateGatesLar(o1, &_lar1_gatesData[1 * 4], 1); + _g->updateGatesLar(o1, _lar1_gatesData, 1); LvlObject *o2 = _g->findLvlObject(2, 1, 5); - _g->updateGatesLar(o2, &_lar1_gatesData[2 * 4], 2); + _g->updateGatesLar(o2, _lar1_gatesData, 2); LvlObject *o3 = _g->findLvlObject(2, 2, 5); - _g->updateGatesLar(o3, &_lar1_gatesData[3 * 4], 3); + _g->updateGatesLar(o3, _lar1_gatesData, 3); if (_res->_currentScreenResourceNum == 5) { if (_checkpoint >= 1 && _checkpoint <= 3) { BoundingBox b = { 194, 0, 255, 88 }; @@ -244,9 +246,9 @@ void Level_lar1::postScreenUpdate_lar1_screen5() { void Level_lar1::postScreenUpdate_lar1_screen8() { LvlObject *o1 = _g->findLvlObject(2, 0, 8); - _g->updateGatesLar(o1, &_lar1_gatesData[4 * 4], 4); + _g->updateGatesLar(o1, _lar1_gatesData, 4); LvlObject *o2 = _g->findLvlObject(2, 1, 8); - _g->updateGatesLar(o2, &_lar1_gatesData[5 * 4], 5); + _g->updateGatesLar(o2, _lar1_gatesData, 5); if (_res->_currentScreenResourceNum == 8) { if (_checkpoint >= 1 && _checkpoint <= 3) { BoundingBox b = { 104, 0, 255, 80 }; @@ -264,7 +266,7 @@ void Level_lar1::postScreenUpdate_lar1_screen8() { void Level_lar1::postScreenUpdate_lar1_screen9() { LvlObject *o = _g->findLvlObject(2, 0, 9); - _g->updateGatesLar(o, &_lar1_gatesData[6 * 4], 6); + _g->updateGatesLar(o, _lar1_gatesData, 6); } void Level_lar1::postScreenUpdate_lar1_screen12() { @@ -303,7 +305,7 @@ void Level_lar1::postScreenUpdate_lar1_screen12() { void Level_lar1::postScreenUpdate_lar1_screen13() { LvlObject *o = _g->findLvlObject(2, 0, 13); - _g->updateGatesLar(o, &_lar1_gatesData[7 * 4], 7); + _g->updateGatesLar(o, _lar1_gatesData, 7); } void Level_lar1::postScreenUpdate_lar1_screen14() { @@ -373,24 +375,24 @@ void Level_lar1::postScreenUpdate_lar1_screen14() { } } LvlObject *o = _g->findLvlObject(2, 0, 14); - _g->updateGatesLar(o, &_lar1_gatesData[8 * 4], 8); + _g->updateGatesLar(o, _lar1_gatesData, 8); } void Level_lar1::postScreenUpdate_lar1_screen15() { LvlObject *o = _g->findLvlObject(2, 0, 15); - _g->updateGatesLar(o, &_lar1_gatesData[9 * 4], 9); + _g->updateGatesLar(o, _lar1_gatesData, 9); } void Level_lar1::postScreenUpdate_lar1_screen16() { LvlObject *o = _g->findLvlObject(2, 0, 16); - _g->updateGatesLar(o, &_lar1_gatesData[10 * 4], 10); + _g->updateGatesLar(o, _lar1_gatesData, 10); } void Level_lar1::postScreenUpdate_lar1_screen18() { LvlObject *o1 = _g->findLvlObject(2, 0, 18); - _g->updateGatesLar(o1, &_lar1_gatesData[11 * 4], 11); + _g->updateGatesLar(o1, _lar1_gatesData, 11); LvlObject *o2 = _g->findLvlObject(2, 1, 18); - _g->updateGatesLar(o2, &_lar1_gatesData[12 * 4], 12); + _g->updateGatesLar(o2, _lar1_gatesData, 12); if ((_lar1_switchesData[0x59] & 0x40) == 0 && (_lar1_switchesData[0x59] & 0x80) != 0) { if ((_lar1_switchesData[0x4D] & 1) == 0) { _lar1_switchesData[0x4D] |= 1; @@ -690,7 +692,7 @@ void Level_lar1::preScreenUpdate_lar1_screen19() { void Level_lar1::preScreenUpdate_lar1_screen20() { if (_res->_currentScreenResourceNum == 20) { if (_checkpoint == 6) { - if ((_andyObject->flags0 & 0x1F) == 0xB) { + if ((_andyObject->flags0 & 0x1F) != 0xB) { _checkpoint = 7; } } diff --git a/level8_lar2.cpp b/level8_lar2.cpp index 2ce5354..cdada0c 100644 --- a/level8_lar2.cpp +++ b/level8_lar2.cpp @@ -1,4 +1,6 @@ +// lar2_hod - "heart of darkness" + #include "game.h" #include "level.h" #include "paf.h" @@ -178,12 +180,12 @@ void Level_lar2::postScreenUpdate_lar2_screen2() { void Level_lar2::postScreenUpdate_lar2_screen3() { LvlObject *o = _g->findLvlObject(2, 0, 3); - _g->updateGatesLar(o, _lar2_gatesData + 4, 1); + _g->updateGatesLar(o, _lar2_gatesData, 1); } void Level_lar2::postScreenUpdate_lar2_screen4() { if (_g->_currentLevelCheckpoint == 8 && _checkpoint == 9) { - _lar2_gatesData[8] = (_lar2_gatesData[8] & 0xF) | 0x10; + _lar2_gatesData[4 * 2] = (_lar2_gatesData[4 * 2] & 0xF) | 0x10; if (!_paf->_skipCutscenes) { _paf->play(18); _paf->unload(18); @@ -193,15 +195,15 @@ void Level_lar2::postScreenUpdate_lar2_screen4() { _g->setupScreen(_andyObject->screenNum); } LvlObject *o = _g->findLvlObject(2, 0, 4); - _g->updateGatesLar(o, _lar2_gatesData + 8, 2); + _g->updateGatesLar(o, _lar2_gatesData, 2); } void Level_lar2::postScreenUpdate_lar2_screen5() { if (_g->_currentLevelCheckpoint == 7 && _checkpoint == 8) { - _lar2_gatesData[0xC] &= 0xF; + _lar2_gatesData[4 * 3] &= 0xF; } LvlObject *o = _g->findLvlObject(2, 0, 5); - _g->updateGatesLar(o, _lar2_gatesData + 0xC, 3); + _g->updateGatesLar(o, _lar2_gatesData, 3); } void Level_lar2::postScreenUpdate_lar2_screen6() { @@ -246,19 +248,19 @@ void Level_lar2::postScreenUpdate_lar2_screen7() { void Level_lar2::postScreenUpdate_lar2_screen8() { LvlObject *o = _g->findLvlObject(2, 0, 8); - _g->updateGatesLar(o, _lar2_gatesData + 0x1C, 7); + _g->updateGatesLar(o, _lar2_gatesData, 7); } void Level_lar2::postScreenUpdate_lar2_screen10() { LvlObject *o = _g->findLvlObject(2, 0, 10); - _g->updateGatesLar(o, _lar2_gatesData + 0x10, 4); + _g->updateGatesLar(o, _lar2_gatesData, 4); } void Level_lar2::postScreenUpdate_lar2_screen11() { LvlObject *o = _g->findLvlObject(2, 0, 11); - _g->updateGatesLar(o, _lar2_gatesData + 0x14, 5); + _g->updateGatesLar(o, _lar2_gatesData, 5); o = _g->findLvlObject(2, 1, 11); - _g->updateGatesLar(o, _lar2_gatesData + 0x18, 6); + _g->updateGatesLar(o, _lar2_gatesData, 6); int offset = 0x18; if ((_lar2_switchesData[0x11] & 1) == 0 && (_lar2_switchesData[0x11] & 0x40) != 0 && (_lar2_switchesData[0x19] & 1) == 0) { _lar2_switchesData[0x19] = (_lar2_switchesData[0x19] | 1) & ~0x40; @@ -285,14 +287,14 @@ void Level_lar2::postScreenUpdate_lar2_screen11() { void Level_lar2::postScreenUpdate_lar2_screen12() { LvlObject *o = _g->findLvlObject(2, 0, 12); - _g->updateGatesLar(o, _lar2_gatesData + 0x20, 8); + _g->updateGatesLar(o, _lar2_gatesData, 8); o = _g->findLvlObject(2, 1, 12); - _g->updateGatesLar(o, _lar2_gatesData + 0x24, 9); + _g->updateGatesLar(o, _lar2_gatesData, 9); if (_res->_currentScreenResourceNum == 12) { BoundingBox b1 = { 65, 84, 75, 88 }; AndyLvlObjectData *data = (AndyLvlObjectData *)_g->getLvlObjectDataPtr(_andyObject, kObjectDataTypeAndy); if (_g->clipBoundingBox(&b1, &data->boundingBox)) { - _lar2_gatesData[0x20] &= 0xF; + _lar2_gatesData[4 * 8] &= 0xF; o = _g->findLvlObject2(0, 0, 12); if (o) { o->objectUpdateType = 7; @@ -300,7 +302,7 @@ void Level_lar2::postScreenUpdate_lar2_screen12() { } else { BoundingBox b2 = { 65, 163, 75, 167 }; if (_g->clipBoundingBox(&b2, &data->boundingBox)) { - _lar2_gatesData[0x24] &= 0xF; + _lar2_gatesData[4 * 9] &= 0xF; o = _g->findLvlObject2(0, 1, 12); if (o) { o->objectUpdateType = 7; @@ -381,7 +383,7 @@ void Level_lar2::postScreenUpdate(int num) { void Level_lar2::preScreenUpdate_lar2_screen2() { LvlObject *o = _g->findLvlObject(2, 0, 2); - _g->updateGatesLar(o, _lar2_gatesData, 1); + _g->updateGatesLar(o, _lar2_gatesData, 0); if (_res->_currentScreenResourceNum == 2) { if (_checkpoint == 0) { _checkpoint = 1; @@ -395,9 +397,9 @@ void Level_lar2::preScreenUpdate_lar2_screen4() { _checkpoint = 2; } if (_checkpoint >= 2) { - _lar2_gatesData[4] &= 0xF; + _lar2_gatesData[4 * 1] &= 0xF; if (_checkpoint == 8) { - _lar2_gatesData[8] &= 0xF; + _lar2_gatesData[4 * 2] &= 0xF; if (!_paf->_skipCutscenes) { _paf->preload(18); } @@ -409,9 +411,9 @@ void Level_lar2::preScreenUpdate_lar2_screen4() { void Level_lar2::preScreenUpdate_lar2_screen5() { if (_res->_currentScreenResourceNum == 5) { if (_checkpoint == 7) { - _lar2_gatesData[0xC] = (_lar2_gatesData[0xC] & 0xF) | 0x10; + _lar2_gatesData[4 * 3] = (_lar2_gatesData[4 * 3] & 0xF) | 0x10; } else if (_checkpoint >= 3) { - _lar2_gatesData[0xC] &= 0xF; + _lar2_gatesData[4 * 3] &= 0xF; } } } @@ -425,7 +427,7 @@ void Level_lar2::preScreenUpdate_lar2_screen6() { if (!_paf->_skipCutscenes) { _paf->preload(15); } - _lar2_gatesData[0xC] &= 0xF; // bugfix: conditioned with _pafSkipCutscenes + _lar2_gatesData[4 * 3] &= 0xF; // bugfix: conditioned with _pafSkipCutscenes } else if (_checkpoint == 6) { if (!_paf->_skipCutscenes) { _paf->preload(17); @@ -457,16 +459,16 @@ void Level_lar2::preScreenUpdate_lar2_screen7() { } void Level_lar2::preScreenUpdate_lar2_screen8() { - if (_res->_currentScreenResourceNum == 8 && _lar2_gatesData[0x1E] > 1) { - _lar2_gatesData[0x1E] = 1; + if (_res->_currentScreenResourceNum == 8 && _lar2_gatesData[4 * 7 + 2] > 1) { + _lar2_gatesData[4 * 7 + 2] = 1; } LvlObject *o = _g->findLvlObject(2, 0, 8); - _g->updateGatesLar(o, _lar2_gatesData + 0x1C, 7); + _g->updateGatesLar(o, _lar2_gatesData, 7); } void Level_lar2::preScreenUpdate_lar2_screen9() { if (_res->_currentScreenResourceNum == 9) { - _lar2_gatesData[0x1E] = 0x24; + _lar2_gatesData[4 * 7 + 2] = 36; // gate closing countdown } } @@ -526,26 +528,22 @@ void Level_lar2::tick() { } void Level_lar2::setupScreenCheckpoint_lar2_screen19() { - int num1 = _lar2_setupScreen19Data[_checkpoint * 3 + 1]; - for (int i = num1; i < 13; ++i) { - const int offset = i * 4; - _lar2_switchesData[offset + 1] &= ~0x40; - _lar2_switchesData[offset + 1] |= 1; - } - for (int i = num1; i != 0; --i) { - const int offset = (i - 1) * 4; - _lar2_switchesData[offset + 1] &= ~1; - _lar2_switchesData[offset + 1] |= 0x40; - } - static const uint8_t data[17] = { - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; + const int switchIndex = _lar2_setupScreen19Data[_checkpoint * 3 + 1]; + for (int i = switchIndex; i < 13; ++i) { + const int offset = i * 4 + 1; + _lar2_switchesData[offset] = (_lar2_switchesData[offset] & ~0x40) | 1; + } + for (int i = switchIndex; i != 0; --i) { + const int offset = (i - 1) * 4 + 1; + _lar2_switchesData[offset] = (_lar2_switchesData[offset] & ~1) | 0x40; + } + static const uint8_t data[10] = { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 }; const int gateIndex = _lar2_setupScreen19Data[_checkpoint * 3]; for (int i = gateIndex; i < 10; ++i) { const int num = i; _lar2_gatesData[num * 4] = (data[num] << 4) | 2; const uint32_t mask = 1 << num; - if (_lar2_gatesData[num * 4] & 0xF0) { + if (_lar2_gatesData[num * 4] & 0xF0) { // bugfix: original uses _lar1_gatesData _g->_mstAndyVarMask &= ~mask; } else { _g->_mstAndyVarMask |= mask; @@ -556,7 +554,7 @@ void Level_lar2::setupScreenCheckpoint_lar2_screen19() { const int num = i - 1; _lar2_gatesData[num * 4] = (((data[num] == 0) ? 1 : 0) << 4) | 2; const uint32_t mask = 1 << num; - if (_lar2_gatesData[num * 4] & 0xF0) { + if (_lar2_gatesData[num * 4] & 0xF0) { // bugfix: original uses _lar1_gatesData _g->_mstAndyVarMask &= ~mask; } else { _g->_mstAndyVarMask |= mask; diff --git a/main.cpp b/main.cpp index 261b0c5..da0fc35 100644 --- a/main.cpp +++ b/main.cpp @@ -6,9 +6,6 @@ #if !defined(PSP) && !defined(WII) #include #endif -#if defined(WII) -#include -#endif #include #include @@ -49,6 +46,7 @@ static bool _widescreen = false; static const bool _runBenchmark = false; static bool _runMenu = true; +static bool _displayLoadingScreen = true; static void lockAudio(int flag) { if (flag) { @@ -110,9 +108,9 @@ static int handleConfigIni(void *userdata, const char *section, const char *name } else if (strcmp(name, "difficulty") == 0) { g->_difficulty = atoi(value); } else if (strcmp(name, "frame_duration") == 0) { - g->_frameMs = atoi(value); + g->_frameMs = g->_paf->_frameMs = atoi(value); } else if (strcmp(name, "loading_screen") == 0) { - g->_loadingScreenEnabled = configBool(value); + _displayLoadingScreen = configBool(value); } } else if (strcmp(section, "display") == 0) { if (strcmp(name, "scale_factor") == 0) { @@ -151,7 +149,7 @@ int main(int argc, char *argv[]) { int cheats = 0; #ifdef WII - fatInitDefault(); + System_earlyInit(); static const char *pathsWII[] = { "sd:/hode", "usb:/hode", @@ -165,92 +163,100 @@ int main(int argc, char *argv[]) { break; } } -#else -#if !defined(PSP) - if (argc == 2) { - // data path as the only command line argument - struct stat st; - if (stat(argv[1], &st) == 0 && S_ISDIR(st.st_mode)) { - dataPath = strdup(argv[1]); - } - } - while (1) { - static struct option options[] = { - { "datapath", required_argument, 0, 1 }, - { "savepath", required_argument, 0, 2 }, - { "level", required_argument, 0, 3 }, - { "checkpoint", required_argument, 0, 4 }, - { "debug", required_argument, 0, 5 }, - { "cheats", required_argument, 0, 6 }, - { 0, 0, 0, 0 }, - }; - int index; - const int c = getopt_long(argc, argv, "", options, &index); - if (c == -1) { - break; +#endif + if (System_hasCommandLine()) { + if (argc == 2) { + // data path as the only command line argument + struct stat st; + if (stat(argv[1], &st) == 0 && S_ISDIR(st.st_mode)) { + dataPath = strdup(argv[1]); + } } - switch (c) { - case 1: - dataPath = strdup(optarg); - break; - case 2: - savePath = strdup(optarg); - break; - case 3: - if (optarg[0] >= '0' && optarg[0] <= '9') { - level = atoi(optarg); - } else { - for (int i = 0; _levelNames[i]; ++i) { - if (strcmp(_levelNames[i], optarg) == 0) { - level = i; - break; + while (1) { + static struct option options[] = { + { "datapath", required_argument, 0, 1 }, + { "savepath", required_argument, 0, 2 }, + { "level", required_argument, 0, 3 }, + { "checkpoint", required_argument, 0, 4 }, + { "debug", required_argument, 0, 5 }, + { "cheats", required_argument, 0, 6 }, + { 0, 0, 0, 0 }, + }; + int index; + const int c = getopt_long(argc, argv, "", options, &index); + if (c == -1) { + break; + } + switch (c) { + case 1: + dataPath = strdup(optarg); + break; + case 2: + savePath = strdup(optarg); + break; + case 3: + if (optarg[0] >= '0' && optarg[0] <= '9') { + level = atoi(optarg); + } else { + for (int i = 0; _levelNames[i]; ++i) { + if (strcmp(_levelNames[i], optarg) == 0) { + level = i; + break; + } } } + resume = false; + break; + case 4: + checkpoint = atoi(optarg); + resume = false; + break; + case 5: + g_debugMask |= atoi(optarg); + break; + case 6: + cheats |= atoi(optarg); + break; + default: + fprintf(stdout, "%s\n", _usage); + return -1; } - resume = false; - break; - case 4: - checkpoint = atoi(optarg); - resume = false; - break; - case 5: - g_debugMask |= atoi(optarg); - break; - case 6: - cheats |= atoi(optarg); - break; - default: - fprintf(stdout, "%s\n", _usage); - return -1; } } -#endif -#endif Game *g = new Game(dataPath ? dataPath : _defaultDataPath, savePath ? savePath : _defaultSavePath, cheats); ini_parse(_configIni, handleConfigIni, g); if (_runBenchmark) { g->benchmarkCpu(); } - // load setup.dat and detects if these are PC or PSX datafiles + // load setup.dat (PC) or setup.dax (PSX) g->_res->loadSetupDat(); const bool isPsx = g->_res->_isPsx; g_system->init(_title, Video::W, Video::H, _fullscreen, _widescreen, isPsx); setupAudio(g); - g->loadSetupCfg(resume); - bool runGame = true; - g->_video->init(isPsx); - g->displayLoadingScreen(); - if (_runMenu && resume && !isPsx) { - Menu *m = new Menu(g, g->_paf, g->_res, g->_video); - runGame = m->mainLoop(); - delete m; + if (isPsx) { + g->_video->initPsx(); + _runMenu = false; } - if (runGame && !g_system->inp.quit) { + if (_displayLoadingScreen) { + g->displayLoadingScreen(); + } + do { + g->loadSetupCfg(resume); + if (_runMenu && resume) { + Menu *m = new Menu(g, g->_paf, g->_res, g->_video); + const bool runGame = m->mainLoop(); + delete m; + if (!runGame) { + break; + } + } bool levelChanged = false; - do { - g->displayLoadingScreen(); + while (!g_system->inp.quit && level < kLvl_test) { + if (_displayLoadingScreen) { + g->displayLoadingScreen(); + } g->mainLoop(level, checkpoint, levelChanged); - // do not save progress when game is started from a specific level/checkpoint + // do not save progress when starting from a specific level checkpoint if (resume) { g->saveSetupCfg(); } @@ -260,8 +266,8 @@ int main(int argc, char *argv[]) { level = g->_currentLevel + 1; checkpoint = 0; levelChanged = true; - } while (!g_system->inp.quit && level < kLvl_test); - } + } + } while (!g_system->inp.quit && resume && !isPsx); // do not return to menu when starting from a specific level checkpoint g_system->stopAudio(); g_system->destroy(); delete g; diff --git a/mdec.cpp b/mdec.cpp index 5e8731a..d14775a 100644 --- a/mdec.cpp +++ b/mdec.cpp @@ -192,13 +192,13 @@ int decodeMDEC(const uint8_t *src, int len, const uint8_t *mborder, int mblen, i const int yPitch = out->planes[kOutputPlaneY].pitch; uint8_t *yPtr = out->planes[kOutputPlaneY].ptr + out->y * yPitch + out->x; const int cbPitch = out->planes[kOutputPlaneCb].pitch; - uint8_t *cbPtr = out->planes[kOutputPlaneCb].ptr + out->y / 2 * cbPitch + out->x / 2; + uint8_t *cbPtr = out->planes[kOutputPlaneCb].ptr + (out->y * cbPitch + out->x) / 2; const int crPitch = out->planes[kOutputPlaneCr].pitch; - uint8_t *crPtr = out->planes[kOutputPlaneCr].ptr + out->y / 2 * crPitch + out->x / 2; + uint8_t *crPtr = out->planes[kOutputPlaneCr].ptr + (out->y * crPitch + out->x) / 2; int z = 0; - for (int x = 0; x < blockW; ++x) { - for (int y = 0; y < blockH; ++y) { + for (int x = 0, x2 = 0; x < blockW; ++x, x2 += 2) { + for (int y = 0, y2 = 0; y < blockH; ++y, y2 += 2) { if (z < mblen) { const uint8_t xy = mborder[z]; if ((xy & 15) != x || (xy >> 4) != y) { @@ -208,10 +208,10 @@ int decodeMDEC(const uint8_t *src, int len, const uint8_t *mborder, int mblen, i } decodeBlock(&bs, x, y, crPtr, crPitch, qscale, version); decodeBlock(&bs, x, y, cbPtr, cbPitch, qscale, version); - decodeBlock(&bs, 2 * x, 2 * y, yPtr, yPitch, qscale, version); - decodeBlock(&bs, 2 * x + 1, 2 * y, yPtr, yPitch, qscale, version); - decodeBlock(&bs, 2 * x, 2 * y + 1, yPtr, yPitch, qscale, version); - decodeBlock(&bs, 2 * x + 1, 2 * y + 1, yPtr, yPitch, qscale, version); + decodeBlock(&bs, x2, y2, yPtr, yPitch, qscale, version); + decodeBlock(&bs, x2 + 1, y2, yPtr, yPitch, qscale, version); + decodeBlock(&bs, x2, y2 + 1, yPtr, yPitch, qscale, version); + decodeBlock(&bs, x2 + 1, y2 + 1, yPtr, yPitch, qscale, version); if (mborder && z == mblen) { goto end; } @@ -220,7 +220,7 @@ int decodeMDEC(const uint8_t *src, int len, const uint8_t *mborder, int mblen, i end: if (!mborder && bs.bitsAvailable() >= 11) { const int eof = bs.getBits(11); - assert(eof == 0x3FE); // v2 frame + assert(eof == 0x3FE || eof == 0x3FF); } return bs._src - src; diff --git a/menu.cpp b/menu.cpp index 6d09891..075f758 100644 --- a/menu.cpp +++ b/menu.cpp @@ -28,14 +28,22 @@ enum { }; enum { - kSound_0x60 = 0x60 / 8, - kSound_0x70 = 0x70 / 8, - kSound_0x78 = 0x78 / 8, - kSound_0x80 = 0x80 / 8, - kSound_0x88 = 0x88 / 8, - kSound_0x90 = 0x90 / 8, + kSound_0x60 = 0x60 / 8, // test sound + kSound_0x70 = 0x70 / 8, // move cursor + kSound_0x78 = 0x78 / 8, // select + kSound_0x80 = 0x80 / 8, // return + kSound_0x88 = 0x88 / 8, // reset sound setting + kSound_0x90 = 0x90 / 8, // increase/decrease volume kSound_0x98 = 0x98 / 8, - kSound_0xA0 = 0xA0 / 8 + kSound_0xA0 = 0xA0 / 8 // background sounds +}; + +enum { + kCursor_Select = 0, + kCursor_Left = 1, + kCursor_Right = 2, + kCursor_Up = 3, + kCursor_Down = 4 }; enum { @@ -54,23 +62,6 @@ enum { kSoundNum_Reset = 5 }; -static void setDefaultsSetupCfg(SetupConfig *config, int num) { - assert(num >= 0 && num < 4); - memset(config->players[num].progress, 0, 10); - config->players[num].levelNum = 0; - config->players[num].checkpointNum = 0; - config->players[num].cutscenesMask = 0; - memset(config->players[num].controls, 0, 32); - config->players[num].controls[0x0] = 0x11; - config->players[num].controls[0x4] = 0x22; - config->players[num].controls[0x8] = 0x84; - config->players[num].controls[0xC] = 0x48; - config->players[num].difficulty = 1; - config->players[num].stereo = 1; - config->players[num].volume = Game::kDefaultSoundVolume; - config->players[num].lastLevelNum = 0; -} - static bool isEmptySetupCfg(SetupConfig *config, int num) { return config->players[num].levelNum == 0 && config->players[num].checkpointNum == 0 && config->players[num].cutscenesMask == 0; } @@ -85,11 +76,6 @@ void Menu::setVolume() { const int volume = _config->players[_config->currentPlayer].volume; if (volume != _g->_snd_masterVolume) { _g->_snd_masterVolume = volume; - if (volume == 0) { - _g->muteSound(); - } else { - _g->unmuteSound(); - } } } @@ -178,7 +164,6 @@ void Menu::loadData() { _soundData = ptr + ptrOffset; readSoundData(_res->_menuBuffer1 + ptrOffset, _res->_datHdr.soundDataSize); - ptrOffset += _res->_datHdr.soundDataSize; } else if (version == 11) { @@ -230,7 +215,7 @@ void Menu::loadData() { const int levelsCount = _res->_datHdr.levelsCount; _levelsBitmaps = (DatBitmapsGroup *)(ptr + hdrOffset); _levelsBitmapsData = ptr + ptrOffset; - ptrOffset += readBitmapsGroup(levelsCount, _levelsBitmaps, ptrOffset, paletteSize); + readBitmapsGroup(levelsCount, _levelsBitmaps, ptrOffset, paletteSize); } ptr = _res->_menuBuffer0; @@ -264,10 +249,13 @@ void Menu::loadData() { } if (_res->_isPsx) { - return; + for (int i = 0; i < 3; ++i) { + DatSpritesGroup *sprites = (DatSpritesGroup *)(ptr + ptrOffset); + ptrOffset += sizeof(DatSpritesGroup) + ((le32toh(sprites->size) + 3) & ~3); + } + ptrOffset += 0x300 * 3; } - hdrOffset = ptrOffset; _iconsSprites = (DatSpritesGroup *)(ptr + ptrOffset); const int iconsCount = _res->_datHdr.iconsCount; ptrOffset += iconsCount * sizeof(DatSpritesGroup); @@ -324,21 +312,38 @@ void Menu::loadData() { } int Menu::getSoundNum(int num, int index) const { - const int soundListsCount = READ_LE_UINT32(_soundData + 4); - if (num < soundListsCount) { - const int count = READ_LE_UINT32(_soundData + 8 + num * 8 + 4); - assert(index < count); - const uint8_t *data = _soundData + READ_LE_UINT32(_soundData + 8 + num * 8); - return (int16_t)READ_LE_UINT16(data + index * 2); + const uint8_t *data = _soundData; + int count = READ_LE_UINT32(data + 4); + if (num < count) { + data += 8 + num * 8; + count = READ_LE_UINT32(data + 4); + if (index < count) { + data = _soundData + READ_LE_UINT32(data); + return (int16_t)READ_LE_UINT16(data + index * 2); + } else { + warning("Invalid sound index %d count %d", index, count); + } } return -1; } -void Menu::playSound(int num) { +SssObject *Menu::playSound(int num) { num = getSoundNum(num); debug(kDebug_MENU, "playSound %d", num); if (num != -1) { - _g->playSound(num, 0, 0, 5); + return _g->playSound(num, 0, 0, 5); + } + return 0; +} + +void Menu::drawBitmap(const uint8_t *data, uint32_t size, bool setPalette) { + if (_res->_isPsx) { + _video->decodeBackgroundPsx(data, size, Video::W, Video::H); + } else { + decodeLZW(data, _video->_frontLayer); + if (setPalette) { + g_system->setPalette(data + size, 256, 6); + } } } @@ -384,10 +389,7 @@ void Menu::drawSpriteAnim(DatSpritesGroup *spriteGroup, const uint8_t *ptr, uint } } -void Menu::refreshScreen(bool updatePalette) { - if (updatePalette) { - g_system->setPalette(_paletteBuffer, 256, 6); - } +void Menu::refreshScreen() { _video->updateGameDisplay(_video->_frontLayer); g_system->updateScreen(false); } @@ -399,11 +401,11 @@ void Menu::pafCallback(int frameNum, const uint8_t *frameData) { _g->playSound(num, 0, 0, 5); } } + memcpy(_video->_frontLayer, frameData, Video::W * Video::H); if (_currentOptionButtonSprite && frameNum == _currentOptionButtonSprite->num) { - memcpy(_video->_frontLayer, frameData, Video::W * Video::H); drawSpriteAnim(_currentOptionButtonSprite, _optionsButtonSpritesData, 0); - g_system->copyRect(0, 0, Video::W, Video::H, _video->_frontLayer, Video::W); } + g_system->copyRect(0, 0, Video::W, Video::H, _video->_frontLayer, Video::W); } static void menuPafCallback(void *userdata, int frame, const uint8_t *buffer) { @@ -418,46 +420,36 @@ bool Menu::mainLoop() { if (option == kTitleScreen_AssignPlayer) { handleAssignPlayer(); debug(kDebug_MENU, "currentPlayer %d", _config->currentPlayer); + continue; } else if (option == kTitleScreen_Play) { - return true; + ret = true; } else if (option == kTitleScreen_Options) { PafCallback pafCb; - pafCb.proc = menuPafCallback; + pafCb.frameProc = menuPafCallback; + pafCb.endProc = 0; pafCb.userdata = this; _paf->setCallback(&pafCb); playSound(kSound_0xA0); - handleOptions(); - debug(kDebug_MENU, "optionNum %d", _optionNum); + ret = handleOptions(); _g->resetSound(); _paf->setCallback(0); - if (_optionNum == kMenu_NewGame + 1 || _optionNum == kMenu_CurrentGame + 1 || _optionNum == kMenu_ResumeGame) { - ret = true; - break; - } else if (_optionNum == kMenu_Quit + 1) { - break; - } } else if (option == kTitleScreen_Quit) { - break; } + break; } _res->unloadDatMenuBuffers(); return ret; } void Menu::drawTitleScreen(int option) { - if (_res->_isPsx) { - _video->decodeBackgroundPsx(_titleBitmapData, _titleBitmapSize, Video::W, Video::H); - } else { - decodeLZW(_titleBitmapData, _video->_frontLayer); - g_system->setPalette(_titleBitmapData + _titleBitmapSize, 256, 6); - } + drawBitmap(_titleBitmapData, _titleBitmapSize, true); drawSprite(_titleSprites, (const uint8_t *)&_titleSprites[1], option); - refreshScreen(false); + refreshScreen(); } int Menu::handleTitleScreen() { const int firstOption = kTitleScreen_AssignPlayer; - const int lastOption = _res->_isPsx ? kTitleScreen_Play : kTitleScreen_Quit; + const int lastOption = _res->_isPsx ? kTitleScreenPSX_Save : kTitleScreen_Quit; int currentOption = kTitleScreen_Play; while (!g_system->inp.quit) { g_system->processEvents(); @@ -478,7 +470,7 @@ int Menu::handleTitleScreen() { break; } drawTitleScreen(currentOption); - g_system->sleep(15); + g_system->sleep(kDelayMs); } return currentOption; } @@ -564,11 +556,7 @@ void Menu::setLevelCheckpoint(int num) { } void Menu::drawPlayerProgress(int state, int cursor) { - if (_res->_isPsx) { - _video->decodeBackgroundPsx(_playerBitmapData, _playerBitmapSize, Video::W, Video::H); - } else { - decodeLZW(_playerBitmapData, _video->_frontLayer); - } + drawBitmap(_playerBitmapData, _playerBitmapSize); int player = 0; for (int y = 96; y < 164; y += 17) { if (isEmptySetupCfg(_config, player)) { @@ -616,7 +604,7 @@ void Menu::drawPlayerProgress(int state, int cursor) { if (state > 2) { drawSprite(_playerSprites, (const uint8_t *)&_playerSprites[1], 2); // MessageBox } - refreshScreen(false); + refreshScreen(); } void Menu::handleAssignPlayer() { @@ -645,15 +633,15 @@ void Menu::handleAssignPlayer() { } else if (state == 1) { // select --cursor; _config->currentPlayer = cursor; - // setVolume(); + setVolume(); cursor = 0; } else if (state == 2) { // clear state = 5; // 'No' } else { if (state == 4) { // 'Yes', clear confirmation --cursor; - setDefaultsSetupCfg(_config, cursor); - // setVolume(); + _res->setDefaultsSetupCfg(_config, cursor); + setVolume(); } setCurrentPlayer(_config->currentPlayer); state = 2; @@ -691,7 +679,7 @@ void Menu::handleAssignPlayer() { } } drawPlayerProgress(state, cursor); - g_system->sleep(15); + g_system->sleep(kDelayMs); } } @@ -725,7 +713,7 @@ void Menu::updateBitmapsCircularList(const DatBitmapsGroup *bitmapsGroup, const } void Menu::drawBitmapsCircularList(const DatBitmapsGroup *bitmapsGroup, const uint8_t *bitmapData, int num, int count, bool updatePalette) { - memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 768); + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); if (updatePalette) { g_system->setPalette(_paletteBuffer, 256, 6); } @@ -740,7 +728,7 @@ void Menu::drawBitmapsCircularList(const DatBitmapsGroup *bitmapsGroup, const ui } void Menu::drawCheckpointScreen() { - decodeLZW(_optionsBitmapData[_optionNum], _video->_frontLayer); + drawBitmap(_optionsBitmapData[_optionNum], _optionsBitmapSize[_optionNum]); drawBitmapsCircularList(_checkpointsBitmaps[_levelNum], _checkpointsBitmapsData[_levelNum], _checkpointNum, _lastLevelCheckpointNum[_levelNum], false); drawSpriteAnim(_iconsSprites, _iconsSpritesData, 5); drawSprite(&_iconsSprites[0], _iconsSpritesData, (_checkpointNum + 1) / 10, 119, 108); @@ -752,21 +740,21 @@ void Menu::drawCheckpointScreen() { drawSpriteAnim(_iconsSprites, _iconsSpritesData, (num != 0) ? 8 : 7); } drawSpriteAnim(_iconsSprites, _iconsSpritesData, 6); - refreshScreen(false); + refreshScreen(); } void Menu::drawLevelScreen() { - decodeLZW(_optionsBitmapData[_optionNum], _video->_frontLayer); + drawBitmap(_optionsBitmapData[_optionNum], _optionsBitmapSize[_optionNum]); drawSprite(&_iconsSprites[1], _iconsSpritesData, _levelNum); DatBitmapsGroup *bitmap = &_levelsBitmaps[_levelNum]; drawBitmap(bitmap, _levelsBitmapsData + bitmap->offset, 23, 10, bitmap->w, bitmap->h, 192); drawSpriteAnim(_iconsSprites, _iconsSpritesData, 4); drawSpriteAnim(_iconsSprites, _iconsSpritesData, (_loadLevelButtonState != 0) ? 3 : 2); - refreshScreen(false); + refreshScreen(); } void Menu::drawCutsceneScreen() { - decodeLZW(_optionsBitmapData[_optionNum], _video->_frontLayer); + drawBitmap(_optionsBitmapData[_optionNum], _optionsBitmapSize[_optionNum]); drawBitmapsCircularList(_cutscenesBitmaps, _cutscenesBitmapsData, _cutsceneNum, _cutsceneIndexesCount, false); drawSpriteAnim(_iconsSprites, _iconsSpritesData, 10); drawSprite(&_iconsSprites[0], _iconsSpritesData, (_cutsceneNum + 1) / 10, 119, 108); @@ -778,23 +766,23 @@ void Menu::drawCutsceneScreen() { drawSpriteAnim(_iconsSprites, _iconsSpritesData, (num != 0) ? 13 : 12); } drawSpriteAnim(_iconsSprites, _iconsSpritesData, 11); - refreshScreen(false); + refreshScreen(); } void Menu::drawSettingsScreen() { - decodeLZW(_optionsBitmapData[_optionNum], _video->_frontLayer); + drawBitmap(_optionsBitmapData[_optionNum], _optionsBitmapSize[_optionNum]); drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x2A); drawSpriteAnim(_iconsSprites, _iconsSpritesData, (_settingNum == kSettingNum_Controls) ? 0x27 : 0x24); drawSpriteAnim(_iconsSprites, _iconsSpritesData, (_settingNum == kSettingNum_Difficulty) ? 0x26 : 0x23); drawSpriteAnim(_iconsSprites, _iconsSpritesData, (_settingNum == kSettingNum_Sound) ? 0x28 : 0x25); drawSprite(&_iconsSprites[0x29], _iconsSpritesData, (_settingNum == kSettingNum_Confirm) ? 1 : 0); - refreshScreen(true); + refreshScreen(); } void Menu::handleSettingsScreen(int num) { const uint8_t *data = &_optionData[num * 8]; num = data[5]; - if (num == 0) { + if (num == kCursor_Select) { if (_settingNum == kSettingNum_Controls) { playSound(kSound_0x78); _condMask = 0x10; @@ -809,29 +797,29 @@ void Menu::handleSettingsScreen(int num) { _condMask = 0x80; } return; - } else if (num == 1) { - if (_settingNum != kSettingNum_Confirm && _settingNum > 0 && 0) { // 'controls' not implemented + } else if (num == kCursor_Left) { + if (_settingNum != kSettingNum_Confirm && _settingNum > 1) { // 'controls' not implemented playSound(kSound_0x70); --_settingNum; _iconsSprites[0x27].num = 0; _iconsSprites[0x26].num = 0; _iconsSprites[0x28].num = 0; } - } else if (num == 2) { - if (_settingNum != kSettingNum_Confirm && _settingNum < 2 && 0) { // 'volume' not implemented + } else if (num == kCursor_Right) { + if (_settingNum != kSettingNum_Confirm && _settingNum < 2) { playSound(kSound_0x70); ++_settingNum; _iconsSprites[0x27].num = 0; _iconsSprites[0x26].num = 0; _iconsSprites[0x28].num = 0; } - } else if (num == 3) { + } else if (num == kCursor_Up) { if (_settingNum == kSettingNum_Confirm) { playSound(kSound_0x70); _settingNum = kSettingNum_Difficulty; _iconsSprites[0x26].num = 0; } - } else if (num == 4) { + } else if (num == kCursor_Down) { if (_settingNum != kSettingNum_Confirm) { playSound(kSound_0x70); } @@ -839,44 +827,439 @@ void Menu::handleSettingsScreen(int num) { } drawSettingsScreen(); _condMask = 8; - g_system->sleep(30); + g_system->sleep(kDelayMs); +} + +void Menu::drawControlsScreen() { + drawBitmap(_optionsBitmapData[_optionNum], _optionsBitmapSize[_optionNum]); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, (_controlsNum == 1) ? 0x2E : 0x2D); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, (_controlsNum == 0) ? 0x2C : 0x2B); + drawSprite(&_iconsSprites[0x2F], _iconsSpritesData, (_controlsNum == 2) ? 1 : 0); + refreshScreen(); +} + +void Menu::handleControlsScreen(int num) { + const uint8_t *data = &_optionData[num * 8]; + num = data[5]; + if (num == kCursor_Select) { + playSound(kSound_0x78); + if (_controlsNum == 0) { + _condMask = 0x10; + } else if (_controlsNum == 1) { + _condMask = 0x8; + } else if (_controlsNum == 2) { + _condMask = 0x80; + } + return; + } else if (num == kCursor_Left) { + if (_controlsNum == 1) { + playSound(kSound_0x70); + _controlsNum = 0; + _iconsSprites[0x2C].num = 0; + } + } else if (num == kCursor_Right) { + if (_controlsNum == 0) { + playSound(kSound_0x70); + _controlsNum = 1; + _iconsSprites[0x2E].num = 0; + } + } else if (num == kCursor_Up) { + if (_controlsNum == 2) { + playSound(kSound_0x70); + _controlsNum = 1; + _iconsSprites[0x2E].num = 0; + } + } else if (num == kCursor_Down) { + if (_controlsNum != 2) { + playSound(kSound_0x70); + _controlsNum = 2; + } + } + drawControlsScreen(); + _condMask = 0x20; + g_system->sleep(kDelayMs); +} + +void Menu::drawJoystickKeyCode(int num) { + const uint32_t code = READ_LE_UINT32(_config->players[_config->currentPlayer].controls + 4 * num); + if (code != 0) { + static const uint8_t xPos[] = { 20, 79, 138, 197 }; + int bit = 0; + for (; bit < 32; ++bit) { + if ((code & (1 << bit)) != 0) { + break; + } + } + const int code1 = (bit < 8) ? (41 + bit) : 40; + _video->drawStringCharacter(xPos[num], 111, code1, _res->_fontDefaultColor, _video->_frontLayer); + if ((code & ~(1 << bit)) != 0) { + for (; bit < 32; ++bit) { + if ((code & (1 << bit)) != 0) { + break; + } + } + const int code2 = (bit < 8) ? (41 + bit) : 40; + _video->drawStringCharacter(xPos[num] + 23, 111, code2, _res->_fontDefaultColor, _video->_frontLayer); + } + } +} + +void Menu::drawJoystickControlsScreen() { + drawBitmap(_optionsBitmapData[_optionNum], _optionsBitmapSize[_optionNum]); + drawSprite(&_iconsSprites[0x11], _iconsSpritesData, (_joystickControlsNum == 1) ? 2 : 3); + drawSprite(&_iconsSprites[0x11], _iconsSpritesData, 0); + drawSprite(&_iconsSprites[0x11], _iconsSpritesData, (_joystickControlsNum == 0) ? 0 : 1); + drawSprite(&_iconsSprites[0x11], _iconsSpritesData, (_joystickControlsNum == 2) ? 4 : 5); + drawSprite(&_iconsSprites[0x11], _iconsSpritesData, (_joystickControlsNum == 3) ? 6 : 7); + if (_joystickControlsNum <= 3) { + drawSprite(&_iconsSprites[0x11], _iconsSpritesData, _joystickControlsNum * 2); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x15); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x14); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x13); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x16); + } else if (_joystickControlsNum == 4) { + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x19); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x14); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x13); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x16); + } else if (_joystickControlsNum == 5) { + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x15); + drawSprite(&_iconsSprites[0x18], _iconsSpritesData, 0); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x13); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x16); + } else if (_joystickControlsNum == 6) { + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x15); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x14); + drawSprite(&_iconsSprites[0x17], _iconsSpritesData, 0); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x16); + } else if (_joystickControlsNum == 7) { + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x15); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x14); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x13); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x1A); + } else if (_joystickControlsNum == 8) { + drawSprite(&_iconsSprites[0x11], _iconsSpritesData, 4); + static const int joystickKeyCode = 0; + int mask = 0; + if (READ_LE_UINT32(_config->players[_config->currentPlayer].controls + 0x0) & joystickKeyCode) { + mask = 1; + } + if (READ_LE_UINT32(_config->players[_config->currentPlayer].controls + 0x4) & joystickKeyCode) { + mask |= 2; + } + if (READ_LE_UINT32(_config->players[_config->currentPlayer].controls + 0x8) & joystickKeyCode) { + mask |= 4; + } + if (READ_LE_UINT32(_config->players[_config->currentPlayer].controls + 0xC) & joystickKeyCode) { + mask |= 5; + } + const int flag = (((mask & 5) - 5) != 0) ? 0 : 1; + if (((mask & 1) != 0 && flag == 0) || _iconsSprites[0x19].num != 0) { + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x19); + } else { + drawSprite(&_iconsSprites[0x19], _iconsSpritesData, 0); + } + if ((mask & 2) == 0 || _iconsSprites[0x18].num == 0) { + drawSprite(&_iconsSprites[0x18], _iconsSpritesData, 0); + } else { + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x18); + } + if (((mask & 4) != 0 && flag == 0) || _iconsSprites[0x17].num != 0) { + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x17); + } else { + drawSprite(&_iconsSprites[0x17], _iconsSpritesData, 0); + } + if (flag == 0 || _iconsSprites[0x1A].num == 0) { + drawSprite(&_iconsSprites[0x1A], _iconsSpritesData, 0); + } else { + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x1A); + } + } + drawJoystickKeyCode(0); + drawJoystickKeyCode(1); + drawJoystickKeyCode(2); + drawJoystickKeyCode(3); + refreshScreen(); +} + +void Menu::handleJoystickControlsScreen(int num) { + const uint8_t *data = &_optionData[num * 8]; + num = data[5]; + if (num == 1) { + if (_joystickControlsNum == 0) { + playSound(kSound_0x70); + _joystickControlsNum = 1; + } else if (_joystickControlsNum == 2) { + playSound(kSound_0x70); + _joystickControlsNum = 0; + } else if (_joystickControlsNum == 5) { + playSound(kSound_0x70); + _joystickControlsNum = 4; + } else if (_joystickControlsNum == 6) { + playSound(kSound_0x70); + _joystickControlsNum = 5; + } else if (_joystickControlsNum == 7) { + playSound(kSound_0x70); + _joystickControlsNum = 6; + } else if (_joystickControlsNum == 8) { + _iconsSprites[0x19].num = 0; + _iconsSprites[0x18].num = 0; + _iconsSprites[0x17].num = 0; + _iconsSprites[0x1A].num = 0; + _joystickControlsNum = 2; + } + } else if (num == 2) { + if (_joystickControlsNum == 0) { + playSound(kSound_0x70); + _joystickControlsNum = 2; + } else if (_joystickControlsNum == 1) { + playSound(kSound_0x70); + _joystickControlsNum = 0; + } else if (_joystickControlsNum == 4) { + playSound(kSound_0x70); + _joystickControlsNum = 5; + } else if (_joystickControlsNum == 5) { + playSound(kSound_0x70); + _joystickControlsNum = 6; + } else if (_joystickControlsNum == 6) { + playSound(kSound_0x70); + _joystickControlsNum = 7; + } else if (_joystickControlsNum == 8) { + _iconsSprites[0x19].num = 0; + _iconsSprites[0x18].num = 0; + _iconsSprites[0x17].num = 0; + _iconsSprites[0x1A].num = 0; + _joystickControlsNum = 2; + } + } else if (num == 3) { + if (_joystickControlsNum <= 2) { + playSound(kSound_0x70); + _joystickControlsNum = 5; + } else if (_joystickControlsNum == 3) { + playSound(kSound_0x70); + _joystickControlsNum = 0; + } else if (_joystickControlsNum == 8) { + _iconsSprites[0x19].num = 0; + _iconsSprites[0x18].num = 0; + _iconsSprites[0x17].num = 0; + _iconsSprites[0x1A].num = 0; + _joystickControlsNum = 2; + } + } else if (num == 4) { + if (_joystickControlsNum != 3) { + playSound(kSound_0x70); + } + if (_joystickControlsNum <= 2) { + _joystickControlsNum = 3; + } else if (_joystickControlsNum > 3 && _joystickControlsNum <= 7) { + _joystickControlsNum = 0; + } + } + drawJoystickControlsScreen(); + if (_joystickControlsNum == 8) { + _condMask = 8; + } + g_system->sleep(kDelayMs); +} + +void Menu::drawKeyboardKeyCode(int num) { + for (int i = 0; i < 2; ++i) { + const uint8_t code = _config->players[_config->currentPlayer].controls[16 + 2 * num + i]; + if (code != 0) { + static const uint8_t xPos[] = { 20, 79, 138, 197 }; + const int chr = _video->findStringCharacterFontIndex(code); + if (chr != 255) { + _video->drawStringCharacter(xPos[num] + i * 23, 111, chr, _res->_fontDefaultColor, _video->_frontLayer); + } + } + } +} + +void Menu::drawKeyboardControlsScreen() { + drawBitmap(_optionsBitmapData[_optionNum], _optionsBitmapSize[_optionNum]); + for (int i = 1; i <= 7; ++i) { + drawSprite(&_iconsSprites[0x10], _iconsSpritesData, i); + } + if (_keyboardControlsNum < 3) { + drawSprite(&_iconsSprites[0x10], _iconsSpritesData, _keyboardControlsNum * 2); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x1D); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x1C); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x1B); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x1E); + } else if (_keyboardControlsNum == 4) { + drawSprite(&_iconsSprites[0x21], _iconsSpritesData, 0); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x1C); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x1B); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x1E); + } else if (_keyboardControlsNum == 5) { + drawSprite(&_iconsSprites[0x20], _iconsSpritesData, 0); + drawSprite(&_iconsSprites[0x1D], _iconsSpritesData, 0); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x1B); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x1E); + } else if (_keyboardControlsNum == 6) { + drawSprite(&_iconsSprites[0x1F], _iconsSpritesData, 0); + drawSprite(&_iconsSprites[0x1D], _iconsSpritesData, 0); + drawSprite(&_iconsSprites[0x1C], _iconsSpritesData, 0); + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x1E); + } else if (_keyboardControlsNum == 7) { + drawSprite(&_iconsSprites[0x22], _iconsSpritesData, 0); + drawSprite(&_iconsSprites[0x1D], _iconsSpritesData, 0); + drawSprite(&_iconsSprites[0x1C], _iconsSpritesData, 0); + drawSprite(&_iconsSprites[0x1B], _iconsSpritesData, 0); + } else if (_keyboardControlsNum == 8) { + drawSprite(&_iconsSprites[0x10], _iconsSpritesData, 4); + static const int keyboardMask = 0; + int mask = keyboardMask; + const int flag = (((keyboardMask & 5) - 5) != 0) ? 0 : 1; + if (((mask & 1) != 0 && flag == 0) || _iconsSprites[0x21].num != 0) { + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x21); + } else { + drawSprite(&_iconsSprites[0x21], _iconsSpritesData, 0); + } + if ((mask & 2) == 0 || _iconsSprites[0x20].num == 0) { + drawSprite(&_iconsSprites[0x20], _iconsSpritesData, 0); + } else { + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x20); + } + if (((mask & 4) != 0 && flag == 0) || _iconsSprites[0x1F].num != 0) { + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x1F); + } else { + drawSprite(&_iconsSprites[0x1F], _iconsSpritesData, 0); + } + if (flag == 0 || _iconsSprites[0x22].num == 0) { + drawSprite(&_iconsSprites[0x22], _iconsSpritesData, 0); + } else { + drawSpriteAnim(_iconsSprites, _iconsSpritesData, 0x22); + } + } + drawKeyboardKeyCode(0); + drawKeyboardKeyCode(1); + drawKeyboardKeyCode(2); + drawKeyboardKeyCode(3); + refreshScreen(); +} + +void Menu::handleKeyboardControlsScreen(int num) { + const uint8_t *data = &_optionData[num * 8]; + num = data[5]; + if (num == 1) { + if (_keyboardControlsNum == 0) { + playSound(kSound_0x70); + _keyboardControlsNum = 1; + } else if (_keyboardControlsNum == 2) { + playSound(kSound_0x70); + _keyboardControlsNum = 0; + } else if (_keyboardControlsNum == 5) { + playSound(kSound_0x70); + _keyboardControlsNum = 4; + } else if (_keyboardControlsNum == 6) { + playSound(kSound_0x70); + _keyboardControlsNum = 5; + } else if (_keyboardControlsNum == 7) { + playSound(kSound_0x70); + _keyboardControlsNum = 6; + } else if (_keyboardControlsNum == 8) { + _iconsSprites[0x21].num = 0; + _iconsSprites[0x20].num = 0; + _iconsSprites[0x1F].num = 0; + _iconsSprites[0x22].num = 0; + _keyboardControlsNum = 2; + } + } else if (num == 2) { + if (_keyboardControlsNum == 0) { + playSound(kSound_0x70); + _keyboardControlsNum = 2; + } else if (_keyboardControlsNum == 1) { + playSound(kSound_0x70); + _keyboardControlsNum = 0; + } else if (_keyboardControlsNum == 4) { + playSound(kSound_0x70); + _keyboardControlsNum = 5; + } else if (_keyboardControlsNum == 5) { + playSound(kSound_0x70); + _keyboardControlsNum = 6; + } else if (_keyboardControlsNum == 6) { + playSound(kSound_0x70); + _keyboardControlsNum = 7; + } else if (_keyboardControlsNum == 8) { + _iconsSprites[0x21].num = 0; + _iconsSprites[0x20].num = 0; + _iconsSprites[0x1F].num = 0; + _iconsSprites[0x22].num = 0; + _keyboardControlsNum = 2; + } + } else if (num == 3) { + if (_keyboardControlsNum <= 2) { + playSound(kSound_0x70); + _keyboardControlsNum = 5; + } else if (_keyboardControlsNum == 3) { + playSound(kSound_0x70); + _keyboardControlsNum = 0; + } else if (_keyboardControlsNum == 8) { + _iconsSprites[0x21].num = 0; + _iconsSprites[0x20].num = 0; + _iconsSprites[0x1F].num = 0; + _iconsSprites[0x22].num = 0; + _keyboardControlsNum = 2; + } + } else if (num == 4) { + if (_keyboardControlsNum == 3) { + playSound(kSound_0x70); + } + if (_keyboardControlsNum <= 2) { + _keyboardControlsNum = 3; + } else if (_keyboardControlsNum > 3 && _keyboardControlsNum <= 7) { + _keyboardControlsNum = 0; + } else if (_keyboardControlsNum == 8) { + _iconsSprites[0x21].num = 0; + _iconsSprites[0x20].num = 0; + _iconsSprites[0x1F].num = 0; + _iconsSprites[0x22].num = 0; + _keyboardControlsNum = 2; + } + } + drawKeyboardControlsScreen(); + if (_keyboardControlsNum == 8) { + _condMask = 8; + } + g_system->sleep(kDelayMs); } void Menu::drawDifficultyScreen() { - decodeLZW(_optionsBitmapData[_optionNum], _video->_frontLayer); + drawBitmap(_optionsBitmapData[_optionNum], _optionsBitmapSize[_optionNum]); for (int i = 0; i < 3; ++i) { if (i != _difficultyNum) { drawSprite(&_iconsSprites[0xF], _iconsSpritesData, i * 2); } } drawSprite(&_iconsSprites[0xF], _iconsSpritesData, _difficultyNum * 2 + 1); - refreshScreen(true); + refreshScreen(); } void Menu::handleDifficultyScreen(int num) { const uint8_t *data = &_optionData[num * 8]; num = data[5]; - if (num == 0) { + if (num == kCursor_Select) { playSound(kSound_0x78); _config->players[_config->currentPlayer].difficulty = _g->_difficulty = _difficultyNum; _condMask = 0x80; - } else if (num == 1) { + } else if (num == kCursor_Left) { if (_difficultyNum > 0) { playSound(kSound_0x70); --_difficultyNum; } - } else if (num == 2) { + } else if (num == kCursor_Right) { if (_difficultyNum < 2) { playSound(kSound_0x70); ++_difficultyNum; } } drawDifficultyScreen(); - g_system->sleep(30); + g_system->sleep(kDelayMs); } void Menu::drawSoundScreen() { - decodeLZW(_optionsBitmapData[_optionNum], _video->_frontLayer); + drawBitmap(_optionsBitmapData[_optionNum], _optionsBitmapSize[_optionNum]); drawSprite(&_iconsSprites[0x12], _iconsSpritesData, (_soundNum == kSoundNum_Stereo) ? 1 : 0); drawSprite(&_iconsSprites[0x12], _iconsSpritesData, (_soundNum == kSoundNum_Volume) ? 3 : 2); drawSprite(&_iconsSprites[0x12], _iconsSpritesData, (_soundNum == kSoundNum_Confirm) ? 5 : 4); @@ -884,13 +1267,13 @@ void Menu::drawSoundScreen() { drawSprite(&_iconsSprites[0x12], _iconsSpritesData, (_soundNum == kSoundNum_Cancel) ? 9 : 8); drawSprite(&_iconsSprites[0x12], _iconsSpritesData, (_soundNum == kSoundNum_Reset) ? 11 : 10); // volume bar - const int w = ((_g->_snd_masterVolume * 3) << 5) >> 7; + const int w = (_g->_snd_masterVolume * 96) / 128; for (int y = 0; y < 15; ++y) { memset(_video->_frontLayer + 18807 + 256 * y, 0xE0, w); } drawSprite(&_iconsSprites[0x12], _iconsSpritesData, 21); if (_soundNum == kSoundNum_Test) { -// drawSprite(&_iconsSprites[0x12], _iconsSpritesData, _soundTestNum); + drawSprite(&_iconsSprites[0x12], _iconsSpritesData, _soundTestSpriteNum); } if (_g->_snd_masterVolume != 0) { if (_config->players[_config->currentPlayer].stereo) { @@ -901,11 +1284,11 @@ void Menu::drawSoundScreen() { drawSprite(&_iconsSprites[0x12], _iconsSpritesData, 15); } } - if (0) { // (soundUnk1 != 0) && (_soundCounter & 1) - if (0) { // soundUnk1 == 1 + if ((_volumeState != 0) && (_soundCounter & 1) != 0) { + if (_volumeState == 1) { // decrease volume drawSprite(&_iconsSprites[0x12], _iconsSpritesData, 18); drawSprite(&_iconsSprites[0x12], _iconsSpritesData, 19); - } else { + } else { // increase volume drawSprite(&_iconsSprites[0x12], _iconsSpritesData, 17); drawSprite(&_iconsSprites[0x12], _iconsSpritesData, 20); } @@ -913,20 +1296,51 @@ void Menu::drawSoundScreen() { drawSprite(&_iconsSprites[0x12], _iconsSpritesData, 17); drawSprite(&_iconsSprites[0x12], _iconsSpritesData, 19); } - refreshScreen(true); + refreshScreen(); } void Menu::handleSoundScreen(int num) { + _volumeState = 0; + ++_soundCounter; const uint8_t *data = &_optionData[num * 8]; num = data[5]; - if (num == 0) { + if (num == kCursor_Select) { if (_soundNum == kSoundNum_Confirm) { playSound(kSound_0x78); _config->players[_config->currentPlayer].volume = _g->_snd_masterVolume; _condMask = 0x80; } else if (_soundNum == kSoundNum_Test) { - playSound(kSound_0x60); - // ... + SssObject *so = playSound(kSound_0x60); + int spriteNum = _soundTestSpriteNum = 7; + drawSoundScreen(); + if (so) { + int frames, panning = so->panning; + while ((frames = _g->getSoundPosition(so)) > 0) { + if (frames <= 20) { + if (_soundTestSpriteNum != 7) { + _soundTestSpriteNum = 7; + panning = 64; // center + } + } else if (frames <= 36) { + if (_soundTestSpriteNum != 23) { + _soundTestSpriteNum = 23; + panning = 128; // right + } + } else { // if (frames <= 49) + if (_soundTestSpriteNum != 22) { + _soundTestSpriteNum = 22; + panning = 0; // left + } + } + if (spriteNum != _soundTestSpriteNum) { + spriteNum = _soundTestSpriteNum; + _g->setSoundPanning(so, panning); + drawSoundScreen(); + } + g_system->sleep(kDelayMs); + } + } + _soundTestSpriteNum = 24; } else if (_soundNum == kSoundNum_Cancel) { playSound(kSound_0x80); _config->players[_config->currentPlayer].volume = _g->_snd_masterVolume = _soundVolume; @@ -935,63 +1349,65 @@ void Menu::handleSoundScreen(int num) { playSound(kSound_0x88); _config->players[_config->currentPlayer].volume = _g->_snd_masterVolume = Game::kDefaultSoundVolume; } - } else if (num == 1) { - if (_soundNum == 0) { - // ... - } else if (_soundNum == kSoundNum_Volume) { + } else if (num == kCursor_Left) { + if (_soundNum == kSoundNum_Volume) { if (_g->_snd_masterVolume > 0) { playSound(kSound_0x90); --_g->_snd_masterVolume; _config->players[_config->currentPlayer].volume = _g->_snd_masterVolume; + _volumeState = 1; _condMask = 8; } - } else if (_soundNum == 3) { + } else if (_soundNum == kSoundNum_Test) { playSound(kSound_0x70); - _soundNum = 4; - } else if (_soundNum == 4) { + _soundNum = kSoundNum_Cancel; + } else if (_soundNum == kSoundNum_Cancel) { playSound(kSound_0x70); - _soundNum = 2; + _soundNum = kSoundNum_Confirm; } - } else if (num == 2) { - if (_soundNum == 0) { - // ... - } else if (_soundNum == kSoundNum_Volume) { + } else if (num == kCursor_Right) { + if (_soundNum == kSoundNum_Volume) { if (_g->_snd_masterVolume < 128) { playSound(kSound_0x90); ++_g->_snd_masterVolume; _config->players[_config->currentPlayer].volume = _g->_snd_masterVolume; + _volumeState = 2; _condMask = 8; } } else if (_soundNum == 2) { playSound(kSound_0x70); - _soundNum = 4; + _soundNum = kSoundNum_Cancel; } else if (_soundNum == 4) { if (_g->_snd_masterVolume != 0) { playSound(kSound_0x70); - _soundNum = 3; } + _soundNum = kSoundNum_Test; } - } else if (num == 3) { + } else if (num == kCursor_Up) { if (_soundNum != kSoundNum_Volume) { playSound(kSound_0x70); } - if ((_soundNum >= 2 && _soundNum <= 4) || _soundNum == 5) { - _soundNum = 1; + if (_soundNum >= 2 && _soundNum <= 4) { + _soundNum = kSoundNum_Volume; + } else if (_soundNum == kSoundNum_Reset) { + _soundNum = kSoundNum_Cancel; } - } else if (num == 4) { - if (_soundNum != 5) { + } else if (num == kCursor_Down) { + if (_soundNum != kSoundNum_Reset) { playSound(kSound_0x70); } - if (_soundNum == 0) { - _soundNum = 1; - } else if (_soundNum == 1) { - _soundNum = 4; + if (_soundNum == kSoundNum_Stereo) { + _soundNum = kSoundNum_Volume; + } else if (_soundNum == kSoundNum_Volume) { + _soundNum = kSoundNum_Cancel; } else if (_soundNum >= 2 && _soundNum <= 4) { _soundNum = 5; } + } else { + _soundCounter = 0; } drawSoundScreen(); - g_system->sleep(30); + g_system->sleep(kDelayMs); } void Menu::changeToOption(int num) { @@ -1013,11 +1429,10 @@ void Menu::changeToOption(int num) { _config->players[_config->currentPlayer].levelNum = 0; _config->players[_config->currentPlayer].checkpointNum = 0; } else if (_optionNum == kMenu_CurrentGame + 1) { - // _config->players[_config->currentPlayer].levelNum = _g->_currentLevel; - // _config->players[_config->currentPlayer].checkpointNum = _g->_currentLevelCheckpoint; + // nothing to do } else if (_optionNum == kMenu_Load + 1) { _loadLevelButtonState = 0; - memcpy(_paletteBuffer, _optionsBitmapData[5] + _optionsBitmapSize[5], 768); + memcpy(_paletteBuffer, _optionsBitmapData[5] + _optionsBitmapSize[5], 192 * 3); memcpy(_paletteBuffer + 192 * 3, _levelsBitmapsData + _levelsBitmaps[_levelNum].palette, 64 * 3); g_system->setPalette(_paletteBuffer, 256, 6); drawLevelScreen(); @@ -1025,21 +1440,23 @@ void Menu::changeToOption(int num) { _loadCheckpointButtonState = 0; _checkpointNum = 0; setLevelCheckpoint(_config->currentPlayer); - memcpy(_paletteBuffer, _optionsBitmapData[6] + _optionsBitmapSize[6], 768); + memcpy(_paletteBuffer, _optionsBitmapData[6] + _optionsBitmapSize[6], 256 * 3); g_system->setPalette(_paletteBuffer, 256, 6); drawCheckpointScreen(); } else if (_optionNum == kMenu_Settings + 1) { - _settingNum = 1; - memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 768); + _settingNum = kSettingNum_Difficulty; + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); handleSettingsScreen(5); } else if (_optionNum == kMenu_Cutscenes + 1) { _loadCutsceneButtonState = 0; _cutsceneNum = 0; drawCutsceneScreen(); } else if (_optionsBitmapSize[_optionNum] != 0) { - decodeLZW(_optionsBitmapData[_optionNum], _video->_frontLayer); + drawBitmap(_optionsBitmapData[_optionNum], _optionsBitmapSize[_optionNum]); memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); - refreshScreen(true); + g_system->setPalette(_paletteBuffer, 256, 6); + refreshScreen(); } } @@ -1090,6 +1507,7 @@ void Menu::handleLoadLevel(int num) { } } drawLevelScreen(); + g_system->sleep(kDelayMs); } void Menu::handleLoadCheckpoint(int num) { @@ -1141,6 +1559,7 @@ void Menu::handleLoadCheckpoint(int num) { } } drawCheckpointScreen(); + g_system->sleep(kDelayMs); } void Menu::handleLoadCutscene(int num) { @@ -1164,6 +1583,8 @@ void Menu::handleLoadCutscene(int num) { playSound(kSound_0x78); _loadCutsceneButtonState = 2; if (!_paf->_skipCutscenes) { + _currentOptionButtonSound = 0; + _currentOptionButtonSprite = 0; const int num = _cutscenesBitmaps[_cutsceneIndexes[_cutsceneNum]].data; _paf->play(num); if (num == kPafAnimation_end) { @@ -1192,9 +1613,10 @@ void Menu::handleLoadCutscene(int num) { } } drawCutsceneScreen(); + g_system->sleep(kDelayMs); } -static bool matchInput(uint8_t menu, uint8_t type, uint8_t mask, const PlayerInput &inp, uint8_t optionMask) { +static bool matchInput(uint8_t type, uint8_t mask, const PlayerInput &inp, uint8_t optionMask) { if (type != 0) { if ((mask & 1) != 0 && inp.keyReleased(SYS_INP_RUN)) { return true; @@ -1225,7 +1647,7 @@ static bool matchInput(uint8_t menu, uint8_t type, uint8_t mask, const PlayerInp return false; } -void Menu::handleOptions() { +bool Menu::handleOptions() { _lastLevelNum = _config->players[_config->currentPlayer].lastLevelNum + 1; if (_lastLevelNum > _res->_datHdr.levelsCount) { _lastLevelNum = _res->_datHdr.levelsCount; @@ -1261,15 +1683,15 @@ void Menu::handleOptions() { // get transition from inputs and menu return code (_condMask) int num = -1; for (int i = 0; i < _res->_datHdr.menusCount; ++i) { - const uint8_t *data = _optionData + i * 8; - if (data[0] == _optionNum && matchInput(data[0], data[1] & 1, data[2], g_system->inp, _condMask)) { + const uint8_t *data = &_optionData[i * 8]; + if (data[0] == _optionNum && matchInput(data[1] & 1, data[2], g_system->inp, _condMask)) { num = i; break; } } _condMask = 0; if (num == -1) { - g_system->sleep(15); + g_system->sleep(kDelayMs); continue; } const uint8_t *data = &_optionData[num * 8]; @@ -1283,23 +1705,61 @@ void Menu::handleOptions() { _iconsSprites[0x27].num = 0; _iconsSprites[0x26].num = 0; _iconsSprites[0x28].num = 0; - memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 768); + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + _settingNum = kSettingNum_Difficulty; } handleSettingsScreen(num); break; - // case 1: // controls + case 1: + if (prevOptionNum != _optionNum) { + _iconsSprites[0x2C].num = 0; + _iconsSprites[0x2E].num = 0; + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + _controlsNum = 2; + } + handleControlsScreen(num); + break; + case 2: + if (prevOptionNum != _optionNum) { + _iconsSprites[0x19].num = 0; + _iconsSprites[0x18].num = 0; + _iconsSprites[0x17].num = 0; + _iconsSprites[0x1A].num = 0; + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + _joystickControlsNum = 1; + } + handleJoystickControlsScreen(num); + break; + case 3: + if (prevOptionNum != _optionNum) { + _iconsSprites[0x21].num = 0; + _iconsSprites[0x20].num = 0; + _iconsSprites[0x1F].num = 0; + _iconsSprites[0x22].num = 0; + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); + _keyboardControlsNum = 1; + } + handleKeyboardControlsScreen(num); + break; case 4: if (prevOptionNum != _optionNum) { - memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 768); + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); _difficultyNum = _config->players[_config->currentPlayer].difficulty; } handleDifficultyScreen(num); break; case 5: if (prevOptionNum != _optionNum) { - memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 768); - _soundNum = 2; + memcpy(_paletteBuffer, _optionsBitmapData[_optionNum] + _optionsBitmapSize[_optionNum], 256 * 3); + g_system->setPalette(_paletteBuffer, 256, 6); _soundVolume = _g->_snd_masterVolume; + _soundNum = kSoundNum_Confirm; + _soundCounter = 0; } handleSoundScreen(num); break; @@ -1334,9 +1794,11 @@ void Menu::handleOptions() { warning("Unhandled option %d %d", _optionNum, data[4]); break; } - if (_optionNum == kMenu_Quit + 1 || _optionNum == kMenu_NewGame + 1 || _optionNum == kMenu_CurrentGame + 1 || _optionNum == kMenu_ResumeGame) { - // 'setup.cfg' is saved when exiting the main loop + if (_optionNum == kMenu_Quit + 1) { break; + } else if (_optionNum == kMenu_NewGame + 1 || _optionNum == kMenu_CurrentGame + 1 || _optionNum == kMenu_ResumeGame) { + return true; } } + return false; } diff --git a/menu.h b/menu.h index d0bbc51..ce4741e 100644 --- a/menu.h +++ b/menu.h @@ -34,6 +34,7 @@ struct DatBitmapsGroup { struct Menu { enum { + kDelayMs = 30, kCheckpointLevelsCount = 8, kCutsceneIndexesCount = 22, // kPafAnimation_cinema + 1 kOptionsCount = 19 @@ -86,9 +87,15 @@ struct Menu { uint8_t _loadCutsceneButtonState; int _cutsceneIndexes[kCutsceneIndexesCount]; int _settingNum; + int _controlsNum; + int _joystickControlsNum; + int _keyboardControlsNum; int _difficultyNum; int _soundNum; uint8_t _soundVolume; + int _volumeState; + int _soundCounter; + int _soundTestSpriteNum; Menu(Game *g, PafPlayer *paf, Resource *res, Video *video); @@ -97,13 +104,15 @@ struct Menu { void loadData(); int getSoundNum(int num, int index = 0) const; - void playSound(int num); + SssObject *playSound(int num); + + void drawBitmap(const uint8_t *data, uint32_t size, bool setPalette = false); void drawSprite(const DatSpritesGroup *spriteGroup, const uint8_t *ptr, uint32_t num, int x = -1, int y = -1); void drawSpriteAnim(DatSpritesGroup *spriteGroup, const uint8_t *ptr, uint32_t num); void pafCallback(int frameNum, const uint8_t *frameData); - void refreshScreen(bool updatePalette); + void refreshScreen(); bool mainLoop(); @@ -122,6 +131,14 @@ struct Menu { void drawCutsceneScreen(); void drawSettingsScreen(); void handleSettingsScreen(int num); + void drawControlsScreen(); + void handleControlsScreen(int num); + void drawJoystickKeyCode(int num); + void drawJoystickControlsScreen(); + void handleJoystickControlsScreen(int num); + void drawKeyboardKeyCode(int num); + void drawKeyboardControlsScreen(); + void handleKeyboardControlsScreen(int num); void drawDifficultyScreen(); void handleDifficultyScreen(int num); void drawSoundScreen(); @@ -130,7 +147,7 @@ struct Menu { void handleLoadLevel(int num); void handleLoadCheckpoint(int num); void handleLoadCutscene(int num); - void handleOptions(); + bool handleOptions(); }; #endif // MENU_H__ diff --git a/mixer.cpp b/mixer.cpp index 15e983d..17002e8 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -29,6 +29,10 @@ void Mixer::queue(const int16_t *ptr, const int16_t *end, int panType, int panL, ++_mixingQueueSize; } +static int gain(int v) { + return v + (v / 8) + (v / 16); +} + template static void mixS16(int16_t *dst, const int16_t *src, int len, int panL, int panR) { @@ -38,10 +42,10 @@ static void mixS16(int16_t *dst, const int16_t *src, int len, int panL, int panR const int16_t sampleL = *src++; const int16_t sampleR = stereo ? *src++ : sampleL; if (panning != 1) { - dst[0] = CLIP(dst[0] + ((panL * sampleL) >> kPanBits), -32768, 32767); + dst[0] = CLIP(dst[0] + gain(((panL * sampleL) >> kPanBits)), -32768, 32767); } if (panning != 2) { - dst[1] = CLIP(dst[1] + ((panR * sampleR) >> kPanBits), -32768, 32767); + dst[1] = CLIP(dst[1] + gain(((panR * sampleR) >> kPanBits)), -32768, 32767); } } } diff --git a/monsters.cpp b/monsters.cpp index c24e7b4..2dcb5cd 100644 --- a/monsters.cpp +++ b/monsters.cpp @@ -240,12 +240,18 @@ int Game::mstTaskStopMonsterObject1(Task *t) { } MonsterObject1 *m = t->monster1; - // bugfix: original code meant to check bit 3 directly ? + // bugfix: original code likely meant to check bit 3 directly + // eg. the function should return if bit 3 is not set - // const uint8_t r = (m->flagsA5 == 0) ? 1 : 0; - // if ((r & 8) != 0) { - // return 0; - // } + // mov dl, [esi+MonsterObject1.flagsA5] + // test dl, dl + // setz al + // test al, 8 + // jnz short return_0 + + if ((m->flagsA5 & 8) == 0) { + warning("Unexpected flags 0x%x for stopMonsterObject1", m->flagsA5); + } const MstMonsterAreaAction *m48 = m->action; if (!m48) { @@ -291,8 +297,8 @@ bool Game::mstMonster1SetWalkingBounds(MonsterObject1 *m) { MstWalkPath *walkPath = &_res->_mstWalkPathData[indexWalkPath]; MstWalkNode *walkNode = walkPath->data; - int x = m->xMstPos; // ve - int y = m->yMstPos; // vd + int x = m->xMstPos; + int y = m->yMstPos; if (m->levelPosBounds_x1 >= 0) { if (x < m->levelPosBounds_x1) { x = m->levelPosBounds_x1; @@ -307,16 +313,16 @@ bool Game::mstMonster1SetWalkingBounds(MonsterObject1 *m) { } const uint32_t indexWalkBox = walkPath->data[0].walkBox; - const MstWalkBox *m34 = &_res->_mstWalkBoxData[indexWalkBox]; // vg - int xWalkBox = (m34->right - m34->left) / 2 + m34->left; // vc + const MstWalkBox *m34 = &_res->_mstWalkBoxData[indexWalkBox]; + int xWalkBox = (m34->right - m34->left) / 2 + m34->left; - int minDistance = 0x1000000; // vf + int minDistance = 0x1000000; int yWalkBox = y; uint32_t i = 0; for (; i < walkPath->count; ++i) { const uint32_t indexWalkBox = walkPath->data[i].walkBox; - const MstWalkBox *m34 = &_res->_mstWalkBoxData[indexWalkBox]; // vg + const MstWalkBox *m34 = &_res->_mstWalkBoxData[indexWalkBox]; if (!rect_contains(m34->left, m34->top, m34->right, m34->bottom, x, y)) { // find the closest box const int d1 = ABS(x - m34->left); @@ -342,11 +348,11 @@ bool Game::mstMonster1SetWalkingBounds(MonsterObject1 *m) { if (i == walkPath->count) { // calculate the yPos for the walkBox const uint32_t indexWalkBox = walkNode->walkBox; - const MstWalkBox *m34 = &_res->_mstWalkBoxData[indexWalkBox]; // vg + const MstWalkBox *m34 = &_res->_mstWalkBoxData[indexWalkBox]; if (y <= m34->bottom) { y = (m34->bottom - m34->top) / 2 + m34->top; } - yWalkBox = y; // vd + yWalkBox = y; } // find screenNum for level position @@ -655,7 +661,7 @@ void Game::mstTaskUpdateScreenPosition(Task *t) { const uint8_t *ptr = m->monsterInfos; if (ptr[946] & 4) { - const uint8_t *ptr1 = ptr + (o->flags0 & 0xFF) * 28; // va + const uint8_t *ptr1 = ptr + (o->flags0 & 0xFF) * kMonsterInfoSize; if (ptr1[0xE] != 0) { _mstTemp_x1 = m->xMstPos + (int8_t)ptr1[0xC]; _mstTemp_y1 = m->yMstPos + (int8_t)ptr1[0xD]; @@ -1267,7 +1273,7 @@ void Game::mstLvlObjectSetActionDirection(LvlObject *o, const uint8_t *ptr, uint } break; case 224: - o->directionKeyMask |= m->unkF8; + o->directionKeyMask |= m->goalDirectionKeyMask; break; default: o->directionKeyMask |= dirMask2; @@ -1752,7 +1758,7 @@ void Game::mstMonster1MoveTowardsGoal2(MonsterObject1 *m) { vc = (int8_t)p[0x8]; va = (int8_t)p[0x9]; } - int xPos = m->xMstPos; // vf + int xPos = m->xMstPos; if (dirMask & kDirectionKeyMaskLeft) { xPos -= vc; if (xPos < m->levelPosBounds_x1) { @@ -1764,7 +1770,7 @@ void Game::mstMonster1MoveTowardsGoal2(MonsterObject1 *m) { continue; } } - int yPos = m->yMstPos; // ve + int yPos = m->yMstPos; if (dirMask & kDirectionKeyMaskUp) { yPos -= va; if (yPos < m->levelPosBounds_y1) { @@ -1798,7 +1804,6 @@ void Game::mstMonster1MoveTowardsGoal2(MonsterObject1 *m) { m->targetLevelPos_y = yPos; p = _res->_mstMonsterInfos + m->m49Unk1->offsetMonsterInfo; if (p[0xE] != 0) { - bboxIndex = m->monster1Index; const int x1 = m->xMstPos + (int8_t)p[0xC]; const int y1 = m->yMstPos + (int8_t)p[0xD]; const int x2 = x1 + p[0xE] - 1; @@ -1841,7 +1846,6 @@ int Game::mstTaskStopMonster1(Task *t, MonsterObject1 *m) { const int yPosScreen = _res->_mstPointOffsets[_currentScreen].yOffset; const int xPosObj = o->xPos + _res->_mstPointOffsets[o->screenNum].xOffset; const int yPosObj = o->yPos + _res->_mstPointOffsets[o->screenNum].yOffset; - // this matches the original code but rect_intersects() could probably be used if (xPosObj < xPosScreen || xPosObj + o->width - 1 > xPosScreen + 255 || yPosObj < yPosScreen || yPosObj + o->height - 1 > yPosScreen + 191) { return mstTaskStopMonsterObject1(t); } @@ -1931,7 +1935,7 @@ int Game::mstMonster1FindWalkPathRect(MonsterObject1 *m, MstWalkPath *walkPath, _xMstPos3 = x; _yMstPos3 = y; const int num = (~m->flagsA5) & 1; - int minDistance = 0x40000000; // vg + int minDistance = 0x40000000; int ret = -1; int currentIndex = -1; int xDist = 0; @@ -2039,7 +2043,7 @@ bool Game::mstTestActionDirection(MonsterObject1 *m, int num) { LvlObject *o = m->o16; const uint8_t _al = _res->_mstActionDirectionData[num].unk0; const uint8_t _bl = _res->_mstActionDirectionData[num].unk2; - const uint8_t *var4 = m->monsterInfos + _al * 28; + const uint8_t *ptr = m->monsterInfos + _al * kMonsterInfoSize; const uint8_t _dl = (o->flags1 >> 4) & 3; uint8_t var8 = ((_dl & 1) != 0) ? 8 : 2; if (_dl & 2) { @@ -2091,7 +2095,7 @@ bool Game::mstTestActionDirection(MonsterObject1 *m, int num) { break; } } - directionKeyMask &= var4[2]; + directionKeyMask &= ptr[2]; if ((_bl & 0xE0) == 0x40) { directionKeyMask ^= kDirectionKeyMaskHorizontal; } @@ -2133,15 +2137,15 @@ bool Game::lvlObjectCollidesAndy1(LvlObject *o, int flags) const { bool Game::lvlObjectCollidesAndy2(LvlObject *o, int type) const { int x1, y1, x2, y2; if (type != 1 && type != 0x1000) { - x1 = o->xPos; // vg - y1 = o->yPos; // vf - x2 = x1 + o->width - 1; // vb - y2 = y1 + o->height - 1; // ve + x1 = o->xPos; + y1 = o->yPos; + x2 = x1 + o->width - 1; + y2 = y1 + o->height - 1; } else { - x1 = o->xPos + o->posTable[0].x; // vg - x2 = o->xPos + o->posTable[1].x; // vb - y1 = o->yPos + o->posTable[0].y; // vf - y2 = o->yPos + o->posTable[1].y; // ve + x1 = o->xPos + o->posTable[0].x; + x2 = o->xPos + o->posTable[1].x; + y1 = o->yPos + o->posTable[0].y; + y2 = o->yPos + o->posTable[1].y; if (x1 > x2) { SWAP(x1, x2); } @@ -2163,41 +2167,38 @@ bool Game::lvlObjectCollidesAndy2(LvlObject *o, int type) const { bool Game::lvlObjectCollidesAndy3(LvlObject *o, int type) const { int x1, y1, x2, y2; if (type != 1) { - x1 = o->xPos; // va - y1 = o->yPos; // vd - x2 = o->xPos + o->width - 1; // vg - y2 = o->yPos + o->height - 1; // vc + x1 = o->xPos; + y1 = o->yPos; + x2 = o->xPos + o->width - 1; + y2 = o->yPos + o->height - 1; } else { - x1 = o->xPos + o->posTable[0].x; // va - y1 = o->yPos + o->posTable[0].y; // vd - x2 = o->xPos + o->posTable[1].x; // vg - y2 = o->yPos + o->posTable[1].y; // vc + x1 = o->xPos + o->posTable[0].x; + y1 = o->yPos + o->posTable[0].y; + x2 = o->xPos + o->posTable[1].x; + y2 = o->yPos + o->posTable[1].y; if (x1 > x2) { SWAP(x1, x2); } if (y1 > y2) { SWAP(y1, y2); } - const int xPos = _andyObject->xPos + _andyObject->posTable[3].x; - const int yPos = _andyObject->yPos + _andyObject->posTable[3].y; - if (rect_contains(x1, y1, x2, y2, xPos, yPos)) { - return true; - } } - return false; + const int xPos = _andyObject->xPos + _andyObject->posTable[3].x; + const int yPos = _andyObject->yPos + _andyObject->posTable[3].y; + return rect_contains(x1, y1, x2, y2, xPos, yPos); } bool Game::lvlObjectCollidesAndy4(LvlObject *o, int type) const { int x1, y1, x2, y2; if (type != 1) { - x1 = o->xPos; // vd - y1 = o->yPos; // vf - x2 = o->xPos + o->width - 1; // vb + x1 = o->xPos; + y1 = o->yPos; + x2 = o->xPos + o->width - 1; y2 = o->yPos + o->height - 1; } else { - x1 = o->xPos + o->posTable[0].x; // vd - y1 = o->yPos + o->posTable[0].y; // vf - x2 = o->xPos + o->posTable[1].x; // vb + x1 = o->xPos + o->posTable[0].x; + y1 = o->yPos + o->posTable[0].y; + x2 = o->xPos + o->posTable[1].x; y2 = o->yPos + o->posTable[1].y; if (x1 > x2) { SWAP(x1, x2); @@ -2205,13 +2206,13 @@ bool Game::lvlObjectCollidesAndy4(LvlObject *o, int type) const { if (y1 > y2) { SWAP(y1, y2); } - static const uint8_t indexes[] = { 1, 2, 4, 5 }; - for (int i = 0; i < 4; ++i) { - const int xPos = _andyObject->xPos + _andyObject->posTable[indexes[i]].x; - const int yPos = _andyObject->yPos + _andyObject->posTable[indexes[i]].y; - if (rect_contains(x1, y1, x2, y2, xPos, yPos)) { - return true; - } + } + static const uint8_t indexes[] = { 1, 2, 4, 5 }; + for (int i = 0; i < 4; ++i) { + const int xPos = _andyObject->xPos + _andyObject->posTable[indexes[i]].x; + const int yPos = _andyObject->yPos + _andyObject->posTable[indexes[i]].y; + if (rect_contains(x1, y1, x2, y2, xPos, yPos)) { + return true; } } return false; @@ -2299,7 +2300,7 @@ int Game::mstUpdateTaskMonsterObject1(Task *t) { MonsterObject1 *_mstCurrentMonster1 = m; LvlObject *o = m->o16; const int num = o->flags0 & 0xFF; - const uint8_t *ptr = m->monsterInfos + num * 28; // vb + const uint8_t *ptr = m->monsterInfos + num * kMonsterInfoSize; int8_t a = ptr[6]; if (a != 0) { const int num = CLIP(m->lut4Index + a, 0, 17); @@ -2334,7 +2335,7 @@ int Game::mstUpdateTaskMonsterObject1(Task *t) { t->child->codeData = 0; t->child = 0; } - if ((m->flagsA5 & 8) != 0 && m->action && _mstActionNum != -1) { + if (_mstActionNum != -1 && (m->flagsA5 & 8) != 0 && m->action) { mstTaskStopMonsterObject1(_mstCurrentTask); return 0; } @@ -2425,13 +2426,13 @@ int Game::mstUpdateTaskMonsterObject1(Task *t) { } int var20 = -1; int indexUnk51; - if ((m->flagsA5 & 8) != 0 && m->action && m->action->indexUnk51 != kNone && m->monsterInfos == &_res->_mstMonsterInfos[m->action->unk0 * 948]) { + if ((m->flagsA5 & 8) != 0 && m->action && m->action->indexUnk51 != kNone && m->monsterInfos == &_res->_mstMonsterInfos[m->action->indexMonsterInfo * kMonsterInfoDataSize]) { indexUnk51 = m->action->indexUnk51; } else { indexUnk51 = vg->indexUnk51; } int vb = -1; - const MstShootIndex *var18 = &_res->_mstShootIndexData[indexUnk51]; // vg + const MstShootIndex *var18 = &_res->_mstShootIndexData[indexUnk51]; for (; var24 < var18->count; ++var24) { assert(m->shootActionIndex >= 0 && m->shootActionIndex < 9); const uint32_t indexUnk50Unk1 = var18->indexUnk50Unk1[var24 * 9 + m->shootActionIndex]; @@ -2474,7 +2475,7 @@ int Game::mstUpdateTaskMonsterObject1(Task *t) { if (var28 == dirMask) { continue; } - if (mstMonster1CheckLevelBounds(m, _mstTemp_x1, _mstTemp_y1, dirMask)) { + if (mstMonster1CheckLevelBounds(m, _mstTemp_x1, _mstTemp_y1, ve)) { continue; } } @@ -2517,7 +2518,7 @@ int Game::mstUpdateTaskMonsterObject1(Task *t) { const uint32_t indexUnk50Unk1 = var18->indexUnk50Unk1[vb * 9 + m->shootActionIndex]; MstShootAction *m50Unk1 = &_res->_mstShootData[var18->indexUnk50].data[indexUnk50Unk1]; mstTaskAttack(_mstCurrentTask, m50Unk1->codeData, 0x40); - _mstCurrentMonster1->unkF8 = m50Unk1->unk8; + _mstCurrentMonster1->goalDirectionKeyMask = m50Unk1->dirMask; _mstCurrentMonster1->shootSource = dir; _mstCurrentMonster1->shootDirection = var14->directionMask; _mstCurrentMonster1->directionKeyMask = _andyObject->directionKeyMask; @@ -2539,16 +2540,16 @@ int Game::mstUpdateTaskMonsterObject1(Task *t) { int x1, x2, y1, y2; switch (dir) { case 1: - x1 = m->xMstPos - c; // vd - x2 = m->xMstPos - a; // vf - y1 = m->yMstPos + b; // vg - y2 = m->yMstPos + d; // ve; + x1 = m->xMstPos - c; + x2 = m->xMstPos - a; + y1 = m->yMstPos + b; + y2 = m->yMstPos + d; break; case 2: - x1 = m->xMstPos + a; // vd - x2 = m->xMstPos + c; // vf - y1 = m->yMstPos - d; // vg - y2 = m->yMstPos - b; // ve + x1 = m->xMstPos + a; + x2 = m->xMstPos + c; + y1 = m->yMstPos - d; + y2 = m->yMstPos - b; break; case 3: x1 = m->xMstPos - c; @@ -2557,10 +2558,10 @@ int Game::mstUpdateTaskMonsterObject1(Task *t) { y2 = m->yMstPos - b; break; default: - x1 = m->xMstPos + a; // vd - x2 = m->xMstPos + c; // vf - y1 = m->yMstPos + b; // vg - y2 = m->yMstPos + d; // ve + x1 = m->xMstPos + a; + x2 = m->xMstPos + c; + y1 = m->yMstPos + b; + y2 = m->yMstPos + d; break; } @@ -3009,10 +3010,8 @@ void Game::mstRemoveMonsterObject2(Task *t, Task **tasksList) { void Game::mstRemoveMonsterObject1(Task *t, Task **tasksList) { MonsterObject1 *m = t->monster1; - if (_mstActionNum != -1) { - if ((m->flagsA5 & 8) != 0 && m->action) { - mstMonster1ClearChasingMonster(m); - } + if (_mstActionNum != -1 && (m->flagsA5 & 8) != 0 && m->action) { + mstMonster1ClearChasingMonster(m); } if (m->monsterInfos[946] & 4) { mstBoundingBoxClear(m, 0); @@ -3064,7 +3063,7 @@ int Game::mstTaskSetActionDirection(Task *t, int num, int delay) { LvlObject *o = m->o16; uint8_t var4 = _res->_mstActionDirectionData[num].unk0; uint8_t var8 = _res->_mstActionDirectionData[num].unk2; - const uint8_t *p = m->monsterInfos + var4 * 28; + const uint8_t *p = m->monsterInfos + var4 * kMonsterInfoSize; uint8_t _al = (o->flags1 >> 4) & 3; uint8_t _cl = ((_al & 1) != 0) ? 8 : 2; if (_al & 2) { @@ -3130,8 +3129,8 @@ int Game::mstTaskSetActionDirection(Task *t, int num, int delay) { } else if ((o->directionKeyMask & kDirectionKeyMaskDown) == 0) { va = 0; } - const int x1 = m->xMstPos + (int8_t)p[0xC]; - const int y1 = m->yMstPos + (int8_t)p[0xD]; + const int x1 = m->xMstPos + (int8_t)p[0xC] + ve; + const int y1 = m->yMstPos + (int8_t)p[0xD] + va; const int x2 = x1 + p[0xE] - 1; const int y2 = y1 + p[0xF] - 1; if ((var8 & 0xE0) != 0x60 && mstBoundingBoxCollides2(m->monster1Index, x1, y1, x2, y2) != 0) { @@ -3208,8 +3207,8 @@ void Game::updateTask(Task *t, int num, const uint8_t *codeData) { _tasksList = next; } } else { - t->codeData = codeData; - t->run = &Game::mstTask_main; + current->codeData = codeData; + current->run = &Game::mstTask_main; } } } @@ -3219,15 +3218,8 @@ void Game::updateTask(Task *t, int num, const uint8_t *codeData) { return; } if (codeData) { - t = findFreeTask(); + t = createTask(codeData); if (t) { - resetTask(t, codeData); - t->prevPtr = 0; - t->nextPtr = _tasksList; - if (_tasksList) { - _tasksList->prevPtr = t; - } - _tasksList = t; t->localVars[7] = num; } } @@ -3407,11 +3399,9 @@ int Game::getTaskAndyVar(int index, Task *t) const { AndyLvlObjectData *andyData = (AndyLvlObjectData *)getLvlObjectDataPtr(_andyObject, kObjectDataTypeAndy); if (andyData) { LvlObject *o = andyData->shootLvlObject; - if (o) { + if (o && o->dataPtr) { ShootLvlObjectData *data = (ShootLvlObjectData *)getLvlObjectDataPtr(o, kObjectDataTypeShoot); - if (data) { - return (data->type == 4) ? 1 : 0; - } + return (data->type == 4) ? 1 : 0; } } } @@ -3421,11 +3411,9 @@ int Game::getTaskAndyVar(int index, Task *t) const { AndyLvlObjectData *andyData = (AndyLvlObjectData *)getLvlObjectDataPtr(_andyObject, kObjectDataTypeAndy); if (andyData) { LvlObject *o = andyData->shootLvlObject; - if (o) { + if (o && o->dataPtr) { ShootLvlObjectData *data = (ShootLvlObjectData *)getLvlObjectDataPtr(o, kObjectDataTypeShoot); - if (data) { - return (data->type == 0) ? 1 : 0; - } + return (data->type == 0) ? 1 : 0; } } } @@ -3681,8 +3669,8 @@ int Game::mstTask_main(Task *t) { case 2: { // 2 - set_var_random_range const int num = READ_LE_UINT16(p + 2); MstOp2Data *m = &_res->_mstOp2Data[num]; - int a = getTaskVar(t, m->indexVar1, m->maskVars >> 4); // vb - int b = getTaskVar(t, m->indexVar2, m->maskVars & 15); // vg + int a = getTaskVar(t, m->indexVar1, m->maskVars >> 4); + int b = getTaskVar(t, m->indexVar2, m->maskVars & 15); if (a > b) { SWAP(a, b); } @@ -4180,8 +4168,8 @@ int Game::mstTask_main(Task *t) { int a = getTaskVar(t, op197Data->unk0, (mask >> 16) & 15); // var1C int b = getTaskVar(t, op197Data->unk2, (mask >> 12) & 15); // x2 int c = getTaskVar(t, op197Data->unk4, (mask >> 8) & 15); // var14 - int d = getTaskVar(t, op197Data->unk6, (mask >> 4) & 15); // vg - int e = getTaskVar(t, op197Data->unkE, mask & 15); // va + int d = getTaskVar(t, op197Data->unk6, (mask >> 4) & 15); + int e = getTaskVar(t, op197Data->unkE, mask & 15); const int screenNum = CLIP(e, -4, _res->_mstHdr.screensCount - 1); ret = mstOp49_setMovingBounds(a, b, c, d, screenNum, t, num); } @@ -4258,8 +4246,8 @@ int Game::mstTask_main(Task *t) { break; } assert(o); - int xPos = o->xPos + o->posTable[6].x; // vf - int yPos = o->yPos + o->posTable[6].y; // vd + int xPos = o->xPos + o->posTable[6].x; + int yPos = o->yPos + o->posTable[6].y; const uint16_t flags1 = o->flags1; if (flags1 & 0x10) { xPos -= (int8_t)p[2]; @@ -4404,8 +4392,8 @@ int Game::mstTask_main(Task *t) { int a = getTaskVar(t, m->indexVar1, (mask >> 16) & 15); // var1C int b = getTaskVar(t, m->indexVar2, (mask >> 12) & 15); // var20 int c = getTaskVar(t, m->indexVar3, (mask >> 8) & 15); // var14, vb - int d = getTaskVar(t, m->indexVar4, (mask >> 4) & 15); // vf - int e = getTaskVar(t, m->indexVar5, mask & 15); // va + int d = getTaskVar(t, m->indexVar4, (mask >> 4) & 15); + int e = getTaskVar(t, m->indexVar5, mask & 15); if (a > b) { SWAP(a, b); } @@ -4506,19 +4494,19 @@ int Game::mstTask_main(Task *t) { } } t->flags |= 0x80; - const int total = countRight + countLeft; // vb + const int total = countRight + countLeft; if (total >= m226Data->unk3) { break; } int vc = m226Data->unk3 - total; - int countType1 = m226Data->unk1; // vf + int countType1 = m226Data->unk1; if (countLeft >= countType1) { countType1 = 0; } else { countType1 -= countLeft; } - int countType2 = m226Data->unk2; // vg + int countType2 = m226Data->unk2; if (countRight >= countType2) { countType2 = 0; } else { @@ -4817,10 +4805,10 @@ int Game::mstTask_main(Task *t) { } void Game::mstOp26_removeMstTaskScreen(Task **tasksList, int screenNum) { - Task *current = *tasksList; // vg + Task *current = *tasksList; while (current) { - MonsterObject1 *m = current->monster1; // vc - Task *next = current->nextPtr; // ve + MonsterObject1 *m = current->monster1; + Task *next = current->nextPtr; if (m && m->o16->screenNum == screenNum) { if (_mstActionNum != -1 && (m->flagsA5 & 8) != 0 && m->action) { mstMonster1ClearChasingMonster(m); @@ -4934,7 +4922,7 @@ int Game::mstOp49_setMovingBounds(int a, int b, int c, int d, int screen, Task * } break; case 0: { // 0xFC - const uint8_t _al = m->unkF8; + const uint8_t _al = m->goalDirectionKeyMask; if (_al & 8) { m->goalDistance_x1 = -b; m->goalDistance_x2 = -a; @@ -5034,7 +5022,7 @@ int Game::mstOp49_setMovingBounds(int a, int b, int c, int d, int screen, Task * x2 = 255 - x; } const int y = MIN(_mstAndyScreenPosY, 191); - int y1, y2; // ve, var4 + int y1, y2; if (_mstAndyScreenPosY < 0) { y1 = y; y2 = y + 191; @@ -5080,6 +5068,7 @@ int Game::mstOp49_setMovingBounds(int a, int b, int c, int d, int screen, Task * m->targetLevelPos_x = -1; m->targetLevelPos_y = -1; mstBoundingBoxClear(m, 1); + p = _res->_mstMonsterInfos + m->m49Unk1->offsetMonsterInfo; if (p[0xE] != 0) { t->flags |= 0x80; mstTaskResetMonster1WalkPath(t); @@ -5169,7 +5158,7 @@ void Game::mstOp52() { assert(m->task->monster1 == m); Task *t = m->task; const int num = m->o16->flags0 & 0xFF; - if (m->monsterInfos[num * 28] != 0) { + if (m->monsterInfos[num * kMonsterInfoSize] != 0) { if (t->run != &Game::mstTask_monsterWait1 && t->run != &Game::mstTask_monsterWait4 && t->run != &Game::mstTask_monsterWait2 && t->run != &Game::mstTask_monsterWait3 && t->run != &Game::mstTask_monsterWait5 && t->run != &Game::mstTask_monsterWait6 && t->run != &Game::mstTask_monsterWait7 && t->run != &Game::mstTask_monsterWait8 && t->run != &Game::mstTask_monsterWait9 && t->run != &Game::mstTask_monsterWait10) { m->flagsA5 = (m->flagsA5 & ~0xF) | 6; mstTaskInitMonster1Type2(m->task, 1); @@ -5191,46 +5180,41 @@ void Game::mstOp52() { bool Game::mstHasMonsterInRange(const MstMonsterAction *m48, uint8_t flag) { for (int i = 0; i < 2; ++i) { for (uint32_t j = 0; j < m48->count[i]; ++j) { - uint32_t a = (i ^ flag); // * 32; // vd - uint32_t n = m48->data1[i][j]; // va + uint32_t a = (i ^ flag); // * 32; + uint32_t n = m48->data1[i][j]; if (_mstCollisionTable[a][n].count < m48->data2[i][j]) { return false; } } } - uint8_t _op54Data[kMaxMonsterObjects1]; - memset(_op54Data, 0, sizeof(_op54Data)); + bool flagTable[kMaxMonsterObjects1]; + memset(flagTable, 0, sizeof(flagTable)); int var24 = 0; //int var28 = 0; - int vf = 0; for (int i = 0; i < m48->areaCount; ++i) { const MstMonsterArea *m12 = &m48->area[i]; assert(m12->count == 1); MstMonsterAreaAction *m12u4 = m12->data; if (m12->unk0 != 0) { - uint8_t var1C = m12u4->unk18; - if (var1C != 2) { - vf = var1C; - } + const uint8_t var1C = m12u4->unk18; + int var4C = (var1C == 2) ? 0 : var1C; l1: - int var4C = vf; - int var8 = m12u4->xPos; int vb = var8; // xPos int var4 = m12u4->yPos; int vg = var4; // yPos - int va = vf ^ flag; + int va = var4C ^ flag; if (va == 1) { vb = -vb; } debug(kDebug_MONSTER, "mstHasMonsterInRange (unk0!=0) count:%d %d %d [%d,%d] screen:%d", m12->count, vb, vg, _mstPosXmin, _mstPosXmax, m12u4->screenNum); if (vb >= _mstPosXmin && vb <= _mstPosXmax) { - uint8_t var4D = _res->_mstMonsterInfos[m12u4->unk0 * kMonsterInfoDataSize + 946] & 2; + uint8_t var4D = _res->_mstMonsterInfos[m12u4->indexMonsterInfo * kMonsterInfoDataSize + 946] & 2; if (var4D == 0 || (vg >= _mstPosYmin && vg <= _mstPosYmax)) { - MstCollision *varC = &_mstCollisionTable[va][m12u4->unk0]; + MstCollision *varC = &_mstCollisionTable[va][m12u4->indexMonsterInfo]; vb += _mstAndyLevelPosX; const int xLevelPos = vb; vg += _mstAndyLevelPosY; @@ -5242,12 +5226,12 @@ bool Game::mstHasMonsterInRange(const MstMonsterAction *m48, uint8_t flag) { //MstCollision *var20 = varC; for (int j = 0; j < var10; ++j) { MonsterObject1 *m = varC->monster1[j]; - if (_op54Data[m->monster1Index] == 0 && (m12u4->screenNum < 0 || m->o16->screenNum == m12u4->screenNum)) { + if (!flagTable[m->monster1Index] && (m12u4->screenNum < 0 || m->o16->screenNum == m12u4->screenNum)) { int ve = yLevelPos - m->yMstPos; int va = ABS(ve); int vg = xLevelPos - m->xMstPos; int vc = ABS(vg); - if (vc > m48->unk0 || va > m48->unk2) { + if (vc > m48->xRange || va > m48->yRange) { continue; } if ((var8 || var4) && m->monsterInfos[944] != 10 && m->monsterInfos[944] != 16 && m->monsterInfos[944] != 9) { @@ -5282,7 +5266,7 @@ bool Game::mstHasMonsterInRange(const MstMonsterAction *m48, uint8_t flag) { if (var34 != -1) { const uint8_t num = varC->monster1[var34]->monster1Index; m12u4->monster1Index = num; - _op54Data[num] = 1; + flagTable[num] = true; debug(kDebug_MONSTER, "monster %d in range", num); ++var24; continue; @@ -5292,36 +5276,35 @@ bool Game::mstHasMonsterInRange(const MstMonsterAction *m48, uint8_t flag) { if (var1C != 2 || var4C == 1) { return false; } - vf = 1; - var4C = vf; + var4C = 1; goto l1; } //++var28; } //var28 = vf; - for (int i = vf; i < m48->areaCount; ++i) { + for (int i = 0; i < m48->areaCount; ++i) { MstMonsterArea *m12 = &m48->area[i]; assert(m12->count == 1); MstMonsterAreaAction *m12u4 = m12->data; if (m12->unk0 == 0) { - uint8_t var1C = m12u4->unk18; + const uint8_t var1C = m12u4->unk18; m12u4->monster1Index = 0xFF; int var4C = (var1C == 2) ? 0 : var1C; - int vd = var4C; l2: int var4 = m12u4->xPos; int vb = var4; int var8 = m12u4->yPos; int vg = var8; - int va = vd ^ flag; + + int va = var4C ^ flag; if (va == 1) { vb = -vb; } debug(kDebug_MONSTER, "mstHasMonsterInRange (unk0==0) count:%d %d %d [%d,%d] screen:%d", m12->count, vb, vg, _mstPosXmin, _mstPosXmax, m12u4->screenNum); if (vb >= _mstPosXmin && vb <= _mstPosXmax) { - uint8_t var4D = _res->_mstMonsterInfos[m12u4->unk0 * kMonsterInfoDataSize + 946] & 2; + uint8_t var4D = _res->_mstMonsterInfos[m12u4->indexMonsterInfo * kMonsterInfoDataSize + 946] & 2; if (var4D == 0 || (vg >= _mstPosYmin && vg <= _mstPosYmax)) { - MstCollision *varC = &_mstCollisionTable[va][m12u4->unk0]; + MstCollision *varC = &_mstCollisionTable[va][m12u4->indexMonsterInfo]; vb += _mstAndyLevelPosX; const int xLevelPos = vb; vg += _mstAndyLevelPosY; @@ -5332,12 +5315,12 @@ bool Game::mstHasMonsterInRange(const MstMonsterAction *m48, uint8_t flag) { int var10 = varC->count; for (int j = 0; j < var10; ++j) { MonsterObject1 *m = varC->monster1[j]; - if (_op54Data[m->monster1Index] == 0 && (m12u4->screenNum < 0 || m->o16->screenNum == m12u4->screenNum)) { + if (!flagTable[m->monster1Index] && (m12u4->screenNum < 0 || m->o16->screenNum == m12u4->screenNum)) { int ve = yLevelPos - m->yMstPos; int va = ABS(ve); int vg = xLevelPos - m->xMstPos; int vc = ABS(vg); - if (vc > m48->unk0 || va > m48->unk2) { + if (vc > m48->xRange || va > m48->yRange) { continue; } if ((var8 || var4) && m->monsterInfos[944] != 10 && m->monsterInfos[944] != 16 && m->monsterInfos[944] != 9) { @@ -5372,18 +5355,18 @@ bool Game::mstHasMonsterInRange(const MstMonsterAction *m48, uint8_t flag) { if (var34 != -1) { const uint8_t num = varC->monster1[var34]->monster1Index; m12u4->monster1Index = num; - _op54Data[num] = 1; + flagTable[num] = true; debug(kDebug_MONSTER, "monster %d in range", num); ++var24; continue; } } } - if (var1C == 2 && var4C != 1) { - vd = 1; - var4C = 1; - goto l2; + if (var1C != 2 || var4C == 1) { + continue; } + var4C = 1; + goto l2; } //++var28; } @@ -5462,15 +5445,17 @@ void Game::mstOp54() { _mstOp54Counter = 0; shuffleMstMonsterActionIndex(m43); } else { - memset(_mstOp54Table, 0, sizeof(_mstOp54Table)); - bool var4 = false; + bool flagTable[kMaxMonsterObjects1]; + memset(flagTable, 0, sizeof(flagTable)); + + bool found = false; uint32_t i = 0; for (; i < m43->dataCount; ++i) { uint8_t num = m43->data[i]; if ((num & 0x80) == 0) { - var4 = true; - if (_mstOp54Table[num] == 0) { - _mstOp54Table[num] = 1; + found = true; + if (!flagTable[num]) { + flagTable[num] = true; const uint32_t indexUnk48 = m43->indexUnk48[num]; MstMonsterAction *m48 = &_res->_mstMonsterActionData[indexUnk48]; if (mstUpdateInRange(m48)) { @@ -5483,16 +5468,14 @@ void Game::mstOp54() { assert(i < m43->dataCount); m43->data[i] |= 0x80; } else { - if (var4) { + if (found) { ++_mstOp54Counter; if (_mstOp54Counter <= 16) { return; } } _mstOp54Counter = 0; - if (m43->dataCount != 0) { - shuffleMstMonsterActionIndex(m43); - } + shuffleMstMonsterActionIndex(m43); } } } @@ -5921,7 +5904,6 @@ void Game::mstOp57_addWormHoleSprite(int x, int y, int screenNum) { ++spriteNum; } if (!found) { - found = true; if (spriteNum == 6) { ++_wormHoleSpritesCount; if (_wormHoleSpritesCount >= spriteNum) { @@ -5983,9 +5965,9 @@ void Game::mstOp57_addWormHoleSprite(int x, int y, int screenNum) { void Game::mstOp58_addLvlObject(Task *t, int num) { const MstOp211Data *dat = &_res->_mstOp211Data[num]; const int mask = dat->maskVars; - int xPos = getTaskVar(t, dat->indexVar1, (mask >> 8) & 15); // vb - int yPos = getTaskVar(t, dat->indexVar2, (mask >> 4) & 15); // ve - const uint8_t type = getTaskVar(t, dat->indexVar3, mask & 15); // va + int xPos = getTaskVar(t, dat->indexVar1, (mask >> 8) & 15); + int yPos = getTaskVar(t, dat->indexVar2, (mask >> 4) & 15); + const uint8_t type = getTaskVar(t, dat->indexVar3, mask & 15); LvlObject *o = 0; if (t->monster2) { o = t->monster2->o; @@ -6008,8 +5990,8 @@ void Game::mstOp58_addLvlObject(Task *t, int num) { yPos += o->yPos + o->posTable[7].y; screen = o->screenNum; } else if (type == 0xFF) { // -1 - xPos += _mstAndyScreenPosX; // vb - yPos += _mstAndyScreenPosY; // ve + xPos += _mstAndyScreenPosX; + yPos += _mstAndyScreenPosY; screen = _currentScreen; } const uint16_t flags = (dat->unk6 == -1 && o) ? o->flags2 : 0x3001; @@ -6141,11 +6123,11 @@ bool Game::mstSetCurrentPos(MonsterObject1 *m, int x, int y) { _mstCurrentPosY = y; const uint8_t *ptr = m->monsterInfos; const int32_t a = READ_LE_UINT32(ptr + 900); - int x1 = _mstAndyLevelPosX - a; // vc - int x2 = _mstAndyLevelPosX + a; // vf + int x1 = _mstAndyLevelPosX - a; + int x2 = _mstAndyLevelPosX + a; if (ptr[946] & 2) { // horizontal and vertical - int y1 = _mstAndyLevelPosY - a; // vb - int y2 = _mstAndyLevelPosY + a; // ve + int y1 = _mstAndyLevelPosY - a; + int y2 = _mstAndyLevelPosY + a; if (x > x1 && x < x2 && y > y1 && y < y2) { if (ABS(x - _mstAndyLevelPosX) > ABS(y - _mstAndyLevelPosY)) { if (x >= _mstAndyLevelPosX) { @@ -6236,7 +6218,7 @@ void Game::mstMonster1SetGoalHorizontal(MonsterObject1 *m) { } void Game::mstResetCollisionTable() { - const int count = MIN(_res->_mstHdr.infoMonster1Count, 32); + const int count = MIN(_res->_mstHdr.infoMonster1Count, kMaxMonsterObjects1); for (int i = 0; i < 2; ++i) { for (int j = 0; j < count; ++j) { _mstCollisionTable[i][j].count = 0; @@ -6253,7 +6235,7 @@ void Game::mstResetCollisionTable() { continue; } const int num = m->o16->flags0 & 0xFF; - if (m->monsterInfos[num * 28] != 0) { + if (m->monsterInfos[num * kMonsterInfoSize] != 0) { continue; } if (m->task->run == &Game::mstTask_monsterWait4) { @@ -6268,7 +6250,7 @@ void Game::mstResetCollisionTable() { const uint32_t offset = m->monsterInfos - _res->_mstMonsterInfos; assert(offset % kMonsterInfoDataSize == 0); const uint32_t num = offset / kMonsterInfoDataSize; - assert(num < 32); + assert(num < kMaxMonsterObjects1); const int dir = (m->xMstPos < _mstAndyLevelPosX) ? 1 : 0; const int count = _mstCollisionTable[dir][num].count; _mstCollisionTable[dir][num].monster1[count] = m; @@ -6363,7 +6345,7 @@ int Game::mstTaskInitMonster1Type1(Task *t) { } assert((uint32_t)m->indexUnk49Unk1 < m49->count1); m->m49Unk1 = &m49->data1[m->indexUnk49Unk1]; - int xDelta = (m34->right - x) / 4; // vf + int xDelta = (m34->right - x) / 4; m->goalDistance_x1 = x + xDelta; m->goalDistance_x2 = m34->right - xDelta; if (xDelta != 0) { @@ -6379,7 +6361,7 @@ int Game::mstTaskInitMonster1Type1(Task *t) { } int vf; if (m->monsterInfos[946] & 2) { - int yDelta = (m34->bottom - y) / 4; // vf + int yDelta = (m34->bottom - y) / 4; m->goalDistance_y1 = y + yDelta; m->goalDistance_y2 = m34->bottom - yDelta; if (yDelta != 0) { @@ -6443,6 +6425,7 @@ int Game::mstTaskInitMonster1Type1(Task *t) { m->targetLevelPos_x = -1; m->targetLevelPos_y = -1; mstBoundingBoxClear(m, 1); + p = _res->_mstMonsterInfos + m->m49Unk1->offsetMonsterInfo; if (p[0xE] != 0) { t->flags |= 0x80; mstTaskResetMonster1WalkPath(t); @@ -6607,6 +6590,7 @@ int Game::mstTaskInitMonster1Type2(Task *t, int flag) { m->targetLevelPos_x = -1; m->targetLevelPos_y = -1; mstBoundingBoxClear(m, 1); + p = _res->_mstMonsterInfos + m->m49Unk1->offsetMonsterInfo; if (p[0xE] != 0) { t->flags |= 0x80; mstTaskResetMonster1WalkPath(t); @@ -6663,9 +6647,9 @@ void Game::mstOp67_addMonster(Task *currentTask, int x1, int x2, int y1, int y2, } int objScreen = (screen < 0) ? _currentScreen : screen; - LvlObject *o = 0; // vf - MonsterObject2 *mo = 0; // ve - MonsterObject1 *m = 0; // vg + LvlObject *o = 0; + MonsterObject2 *mo = 0; + MonsterObject1 *m = 0; if (arg1C != -128) { if (_mstVars[30] > kMaxMonsterObjects1) { @@ -6680,7 +6664,7 @@ void Game::mstOp67_addMonster(Task *currentTask, int x1, int x2, int y1, int y2, if (count >= _mstVars[30]) { return; } - if (arg1C < 0) { // vd + if (arg1C < 0) { const MstBehaviorIndex *m42 = &_res->_mstBehaviorIndexData[arg24]; if (m42->dataCount == 0) { arg1C = m42->data[0]; @@ -6710,7 +6694,7 @@ void Game::mstOp67_addMonster(Task *currentTask, int x1, int x2, int y1, int y2, MstBehavior *m46 = &_res->_mstBehaviorData[indexBehavior]; m->m46 = m46; assert((uint32_t)arg20 < m46->count); - MstBehaviorState *behaviorState = &m46->data[arg20]; // vc + MstBehaviorState *behaviorState = &m46->data[arg20]; m->behaviorState = behaviorState; m->monsterInfos = _res->_mstMonsterInfos + behaviorState->indexMonsterInfo * kMonsterInfoDataSize; @@ -6767,15 +6751,11 @@ void Game::mstOp67_addMonster(Task *currentTask, int x1, int x2, int y1, int y2, mo->flags24 = 0; - uint8_t _cl = mo->monster2Info->type; - uint16_t anim = mo->monster2Info->anim; - - o = addLvlObject((_cl >> 7) & 1, x1, y1, objScreen, (_cl & 0x7F), anim, o_flags1, o_flags2, 0, 0); + const uint8_t type = mo->monster2Info->type; + const uint16_t anim = mo->monster2Info->anim; + o = addLvlObject((type >> 7) & 1, x1, y1, objScreen, (type & 0x7F), anim, o_flags1, o_flags2, 0, 0); if (!o) { - mo->monster2Info = 0; - if (mo->o) { - mo->o->dataPtr = 0; - } + mstMonster2ResetData(mo); return; } mo->o = o; @@ -6789,10 +6769,7 @@ void Game::mstOp67_addMonster(Task *currentTask, int x1, int x2, int y1, int y2, if (mo) { Task *t = findFreeTask(); if (!t) { - mo->monster2Info = 0; - if (mo->o) { - mo->o->dataPtr = 0; - } + mstMonster2ResetData(mo); removeLvlObject2(o); return; } @@ -7119,7 +7096,7 @@ int Game::mstTask_monsterWait11(Task *t) { debug(kDebug_MONSTER, "mstTask_monsterWait11 t %p", t); MonsterObject1 *m = t->monster1; const int num = m->o16->flags0 & 0xFF; - if (m->monsterInfos[num * 28] == 0) { + if (m->monsterInfos[num * kMonsterInfoSize] == 0) { mstTaskResetMonster1Direction(t); } return 1; diff --git a/paf.cpp b/paf.cpp index 0254e5f..7d1047a 100644 --- a/paf.cpp +++ b/paf.cpp @@ -44,6 +44,8 @@ PafPlayer::PafPlayer(FileSystem *fs) _audioQueue = _audioQueueTail = 0; _playedMask = 0; memset(&_pafCb, 0, sizeof(_pafCb)); + _volume = 128; + _frameMs = kFrameDuration; } PafPlayer::~PafPlayer() { @@ -51,6 +53,10 @@ PafPlayer::~PafPlayer() { closePaf(_fs, &_file); } +void PafPlayer::setVolume(int volume) { + _volume = volume; +} + void PafPlayer::preload(int num) { debug(kDebug_PAF, "preload %d", num); assert(num >= 0 && num < kMaxVideosCount); @@ -130,7 +136,7 @@ bool PafPlayer::readPafHeader() { warning("readPafHeader() Unexpected signature"); return false; } - _pafHdr.frameRate = READ_LE_UINT32(_bufferBlock + 0x88); + _pafHdr.frameDuration = READ_LE_UINT32(_bufferBlock + 0x88); _pafHdr.startOffset = READ_LE_UINT32(_bufferBlock + 0xA4); _pafHdr.preloadFrameBlocksCount = READ_LE_UINT32(_bufferBlock + 0x9C); _pafHdr.readBufferSize = READ_LE_UINT32(_bufferBlock + 0x98); @@ -375,10 +381,11 @@ void PafPlayer::decodeVideoFrameOp4(const uint8_t *src) { } } -static void decodeAudioFrame2205(const uint8_t *src, int len, int16_t *dst) { +static void decodeAudioFrame2205(const uint8_t *src, int len, int16_t *dst, int volume) { static const int offset = 256 * sizeof(int16_t); for (int i = 0; i < len * 2; ++i) { // stereo - dst[i] = READ_LE_UINT16(src + src[offset + i] * sizeof(int16_t)); + const int16_t sample = READ_LE_UINT16(src + src[offset + i] * sizeof(int16_t)); + dst[i] = CLIP((sample * volume + 64) >> 7, -32768, 32767); } } @@ -402,10 +409,10 @@ void PafPlayer::decodeAudioFrame(const uint8_t *src, uint32_t offset, uint32_t s if (sq) { sq->offset = 0; sq->size = count * kAudioSamples * 2; - sq->buffer = (int16_t *)calloc(sq->size, sizeof(int16_t)); + sq->buffer = (int16_t *)malloc(sq->size * sizeof(int16_t)); if (sq->buffer) { for (int i = 0; i < count; ++i) { - decodeAudioFrame2205(src + _audioBufferOffsetRd + i * kAudioStrideSize, kAudioSamples, sq->buffer + i * kAudioSamples * 2); + decodeAudioFrame2205(src + _audioBufferOffsetRd + i * kAudioStrideSize, kAudioSamples, sq->buffer + i * kAudioSamples * 2, _volume); } } sq->next = 0; @@ -420,8 +427,9 @@ void PafPlayer::decodeAudioFrame(const uint8_t *src, uint32_t offset, uint32_t s _audioQueueTail = sq; g_system->unlockAudio(); } + + _audioBufferOffsetRd += count * kAudioStrideSize; } - _audioBufferOffsetRd += count * kAudioStrideSize; if (_audioBufferOffsetWr == _flushAudioSize) { _audioBufferOffsetWr = 0; _audioBufferOffsetRd = 0; @@ -446,7 +454,7 @@ void PafPlayer::mix(int16_t *buf, int samples) { _audioQueueTail = 0; } if (samples > 0) { - warning("PafPlayer::mix() soundQueue underrun %d", samples); + debug(kDebug_PAF, "audioQueue underrun %d", samples); } } @@ -457,7 +465,7 @@ static void mixAudio(void *userdata, int16_t *buf, int len) { void PafPlayer::mainLoop() { _file.seek(_videoOffset + _pafHdr.startOffset, SEEK_SET); for (int i = 0; i < 4; ++i) { - memset(_pageBuffers[i], 0, kVideoWidth * kVideoHeight); + memset(_pageBuffers[i], 0, kPageBufferSize); } memset(_paletteBuffer, 0, sizeof(_paletteBuffer)); _paletteChanged = true; @@ -472,8 +480,9 @@ void PafPlayer::mainLoop() { prevAudioCb = g_system->setAudioCallback(audioCb); } - const uint32_t framesPerSec = (_demuxAudioFrameBlocks != 0) ? kFramesPerSec : 15; - uint32_t frameTime = g_system->getTimeStamp() + 1000 / framesPerSec; + // keep original frame rate for audio + const uint32_t frameMs = (_demuxAudioFrameBlocks != 0) ? _pafHdr.frameDuration : (_pafHdr.frameDuration * _frameMs / kFrameDuration); + uint32_t frameTime = g_system->getTimeStamp() + frameMs; uint32_t blocksCountForFrame = _pafHdr.preloadFrameBlocksCount; for (int i = 0; i < (int)_pafHdr.framesCount; ++i) { @@ -496,12 +505,13 @@ void PafPlayer::mainLoop() { // decode video data decodeVideoFrame(_demuxVideoFrameBlocks + _pafHdr.framesOffsetTable[i]); - if (_pafCb.proc) { - _pafCb.proc(_pafCb.userdata, i, _pageBuffers[_currentPageBuffer]); + if (_pafCb.frameProc) { + _pafCb.frameProc(_pafCb.userdata, i, _pageBuffers[_currentPageBuffer]); } else { g_system->copyRect(0, 0, kVideoWidth, kVideoHeight, _pageBuffers[_currentPageBuffer], kVideoWidth); } if (_paletteChanged) { + _paletteChanged = false; g_system->setPalette(_paletteBuffer, 256, 6); } g_system->updateScreen(false); @@ -512,13 +522,17 @@ void PafPlayer::mainLoop() { const int delay = MAX(10, frameTime - g_system->getTimeStamp()); g_system->sleep(delay); - frameTime = g_system->getTimeStamp() + 1000 / framesPerSec; + frameTime = g_system->getTimeStamp() + frameMs; // set next decoding video page ++_currentPageBuffer; _currentPageBuffer &= 3; } + if (_pafCb.endProc) { + _pafCb.endProc(_pafCb.userdata); + } + // restore audio callback if (_demuxAudioFrameBlocks) { g_system->setAudioCallback(prevAudioCb); diff --git a/paf.h b/paf.h index 3afc709..5582cd0 100644 --- a/paf.h +++ b/paf.h @@ -7,6 +7,7 @@ #define PAF_PLAYER_H__ #include "intern.h" +#include "defs.h" #include "fileio.h" struct PafHeader { @@ -20,7 +21,7 @@ struct PafHeader { uint32_t readBufferSize; int32_t maxVideoFrameBlocksCount; int32_t maxAudioFrameBlocksCount; - int32_t frameRate; + int32_t frameDuration; }; // names taken from the PSX filenames @@ -61,7 +62,8 @@ struct PafAudioQueue { }; struct PafCallback { - void (*proc)(void *userdata, int num, const uint8_t *frame); + void (*frameProc)(void *userdata, int num, const uint8_t *frame); + void (*endProc)(void *userdata); void *userdata; }; @@ -73,7 +75,6 @@ struct PafPlayer { kVideoWidth = 256, kVideoHeight = 192, kPageBufferSize = 256 * 256, - kFramesPerSec = 10, // 10hz kAudioSamples = 2205, kAudioStrideSize = 4922 // 256 * sizeof(int16_t) + 2205 * 2 }; @@ -97,10 +98,14 @@ struct PafPlayer { uint32_t _flushAudioSize; uint32_t _playedMask; PafCallback _pafCb; + int _volume; + int _frameMs; PafPlayer(FileSystem *fs); ~PafPlayer(); + void setVolume(int volume); + void preload(int num); void play(int num); void unload(int num = -1); diff --git a/resource.cpp b/resource.cpp index 2f395a8..6ff9f1b 100644 --- a/resource.cpp +++ b/resource.cpp @@ -142,6 +142,7 @@ Resource::Resource(FileSystem *fs) _loadingImageBuffer = 0; _fontBuffer = 0; + _fontDefaultColor = 0; _menuBuffer0 = 0; _menuBuffer1 = 0; @@ -234,6 +235,12 @@ void Resource::loadSetupDat() { } else { memcpy(_fontBuffer, _loadingImageBuffer + offset, kFontSize); } + for (int i = 0; i < kFontSize; ++i) { + _fontDefaultColor = _fontBuffer[i]; + if (_fontDefaultColor != 0) { + break; + } + } } } assert(_datHdr.yesNoQuitImage == hintsCount - 3); @@ -241,23 +248,26 @@ void Resource::loadSetupDat() { } bool Resource::loadDatHintImage(int num, uint8_t *dst, uint8_t *pal) { + const int size = _datHdr.hintsImageSizeTable[num]; + if (size == 0) { + return false; + } + const int offset = _datHdr.hintsImageOffsetTable[num]; + assert(size <= 256 * 192); + _datFile->seek(offset, SEEK_SET); + _datFile->read(dst, size); if (!_isPsx) { - const int offset = _datHdr.hintsImageOffsetTable[num]; - const int size = _datHdr.hintsImageSizeTable[num]; - assert(size == 256 * 192); - _datFile->seek(offset, SEEK_SET); - _datFile->read(dst, size); if (_datHdr.version == 11) { _datFile->seek(offset + fioAlignSizeTo2048(size), SEEK_SET); // align to next sector } _datFile->read(pal, 768); - return true; } - return false; + return true; } bool Resource::loadDatLoadingImage(uint8_t *dst, uint8_t *pal) { - if (!_isPsx && _loadingImageBuffer) { + assert(!_isPsx); + if (_loadingImageBuffer) { const uint32_t bufferSize = READ_LE_UINT32(_loadingImageBuffer); const int size = decodeLZW(_loadingImageBuffer + 8, dst); assert(size == 256 * 192); @@ -927,7 +937,6 @@ void Resource::loadSssData(File *fp, const uint32_t baseOffset) { } // _sssPreloadInfosData = data; } - // data += _sssHdr.preloadInfoCount * 8; _sssPreloadInfosData.allocate(_sssHdr.preloadInfoCount); for (int i = 0; i < _sssHdr.preloadInfoCount; ++i) { _sssPreloadInfosData[i].count = fp->readUint32(); @@ -1578,8 +1587,8 @@ void Resource::loadMstData(File *fp) { _mstMonsterActionData.allocate(_mstHdr.monsterActionDataCount); for (int i = 0; i < _mstHdr.monsterActionDataCount; ++i) { MstMonsterAction *m = &_mstMonsterActionData[i]; - m->unk0 = fp->readUint16(); - m->unk2 = fp->readUint16(); + m->xRange = fp->readUint16(); + m->yRange = fp->readUint16(); m->unk4 = fp->readByte(); m->direction = fp->readByte(); m->unk6 = fp->readByte(); @@ -1627,7 +1636,7 @@ void Resource::loadMstData(File *fp) { for (uint32_t k = 0; k < m12[j].count; ++k) { uint8_t data[28]; fp->read(data, sizeof(data)); - m12[j].data[k].unk0 = READ_LE_UINT32(data); + m12[j].data[k].indexMonsterInfo = READ_LE_UINT32(data); m12[j].data[k].indexUnk51 = READ_LE_UINT32(data + 0x4); m12[j].data[k].xPos = READ_LE_UINT32(data + 0x8); m12[j].data[k].yPos = READ_LE_UINT32(data + 0xC); @@ -1678,7 +1687,7 @@ void Resource::loadMstData(File *fp) { _mstMovingBoundsData[i].data1[j].unkF = fp->readByte(); const uint32_t num = _mstMovingBoundsData[i].data1[j].unk4; assert(num < 32); - _mstMovingBoundsData[i].data1[j].offsetMonsterInfo = start * kMonsterInfoDataSize + num * 28; + _mstMovingBoundsData[i].data1[j].offsetMonsterInfo = start * kMonsterInfoDataSize + num * kMonsterInfoSize; bytesRead += 16; } if (_mstMovingBoundsData[i].indexDataCount != 0) { @@ -1701,7 +1710,7 @@ void Resource::loadMstData(File *fp) { for (uint32_t j = 0; j < _mstShootData[i].count; ++j) { _mstShootData[i].data[j].codeData = fp->readUint32(); _mstShootData[i].data[j].unk4 = fp->readUint32(); - _mstShootData[i].data[j].unk8 = fp->readUint32(); + _mstShootData[i].data[j].dirMask = fp->readUint32(); _mstShootData[i].data[j].xPos = fp->readUint32(); _mstShootData[i].data[j].yPos = fp->readUint32(); _mstShootData[i].data[j].width = fp->readUint32(); @@ -2069,3 +2078,20 @@ bool Resource::readSetupCfg(SetupConfig *config) { } return false; } + +void Resource::setDefaultsSetupCfg(SetupConfig *config, int num) { + assert(num >= 0 && num < 4); + memset(config->players[num].progress, 0, 10); + config->players[num].levelNum = 0; + config->players[num].checkpointNum = 0; + config->players[num].cutscenesMask = 0; + memset(config->players[num].controls, 0, 32); + config->players[num].controls[0x0] = 0x11; + config->players[num].controls[0x4] = 0x22; + config->players[num].controls[0x8] = 0x84; + config->players[num].controls[0xC] = 0x48; + config->players[num].difficulty = 1; + config->players[num].stereo = 1; + config->players[num].volume = 128; + config->players[num].lastLevelNum = 0; +} diff --git a/resource.h b/resource.h index 7d56433..2370e8d 100644 --- a/resource.h +++ b/resource.h @@ -39,10 +39,10 @@ struct LvlScreenVector { }; struct LvlScreenState { - uint8_t s0; - uint8_t s1; - uint8_t s2; - uint8_t s3; // maskData + uint8_t s0; // current state + uint8_t s1; // states count + uint8_t s2; // lvlObjects initialized + uint8_t s3; // current mask }; struct LvlBackgroundData { @@ -217,7 +217,7 @@ struct MstAttackBox { // u47 }; // sizeof == 8 struct MstMonsterAreaAction { - uint32_t unk0; // 0x0, indexes _mstMonsterInfos + uint32_t indexMonsterInfo; // 0x0, indexes _mstMonsterInfos uint32_t indexUnk51; // 0x4 int32_t xPos; // 0x8 int32_t yPos; // 0xC @@ -236,8 +236,8 @@ struct MstMonsterArea { }; // sizeof == 12 struct MstMonsterAction { // u48 - uint16_t unk0; - uint16_t unk2; + uint16_t xRange; + uint16_t yRange; uint8_t unk4; uint8_t direction; uint8_t unk6; @@ -278,7 +278,7 @@ struct MstMovingBounds { // u49 struct MstShootAction { // u50u1 uint32_t codeData; uint32_t unk4; - uint32_t unk8; + uint32_t dirMask; uint32_t xPos; // C uint32_t yPos; // 10 uint32_t width; // 14 @@ -565,6 +565,7 @@ struct Resource { uint8_t *_loadingImageBuffer; uint8_t *_fontBuffer; + uint8_t _fontDefaultColor; uint8_t *_menuBuffer0; uint8_t *_menuBuffer1; uint32_t _menuBuffersOffset; @@ -692,6 +693,7 @@ struct Resource { bool writeSetupCfg(const SetupConfig *config); bool readSetupCfg(SetupConfig *config); + void setDefaultsSetupCfg(SetupConfig *config, int num); }; #endif // RESOURCE_H__ diff --git a/scaler.h b/scaler.h index 695da8c..aa3ed69 100644 --- a/scaler.h +++ b/scaler.h @@ -10,10 +10,7 @@ typedef void (*ScaleProc32)(int factor, uint32_t *dst, int dstPitch, const uint32_t *src, int srcPitch, int w, int h); -#define SCALER_TAG 1 - struct Scaler { - uint32_t tag; const char *name; int factorMin, factorMax; ScaleProc32 scale; diff --git a/scaler_nearest.cpp b/scaler_nearest.cpp index fdfc5e5..e595775 100644 --- a/scaler_nearest.cpp +++ b/scaler_nearest.cpp @@ -40,7 +40,6 @@ static void scale_nearest(int factor, uint32_t *dst, int dstPitch, const uint32_ } const Scaler scaler_nearest = { - SCALER_TAG, "nearest", 2, 3, scale_nearest diff --git a/scaler_xbr.cpp b/scaler_xbr.cpp index 7406700..a90c546 100644 --- a/scaler_xbr.cpp +++ b/scaler_xbr.cpp @@ -34,7 +34,6 @@ static void scale_xbr(int factor, uint32_t *dst, int dstPitch, const uint32_t *s } const Scaler scaler_xbr = { - SCALER_TAG, "xbr", 2, 4, scale_xbr diff --git a/sound.cpp b/sound.cpp index 6e9eb12..2924201 100644 --- a/sound.cpp +++ b/sound.cpp @@ -10,8 +10,6 @@ enum { kFlagNoCode = 1 << 2 // no bytecode }; -static const bool kLimitSounds = false; // limit the number of active playing sounds - // if x < 90, lut[x] ~= x / 2 // if x > 90, lut[x] ~= 45 + (x - 90) * 2 static const uint8_t _volumeRampTable[129] = { @@ -26,28 +24,8 @@ static const uint8_t _volumeRampTable[129] = { 0x80 }; -static uint32_t sssGroupValue(uint8_t source, uint8_t mask, SssInfo *s) { - uint32_t value = 0; - assert(source < 3); // 0,1,2 - - // bits 20..24 - value = source; - // bits 24..32 - value |= mask << 4; - - // bits 16..20 - value <<= 4; - value |= s->sampleIndex & 15; - - // bits 12..16 - value <<= 4; - value |= s->concurrencyMask; - - // bits 0..12 - value <<= 12; - value |= (s->sssBankIndex & 0xFFF); - - return value; +static uint32_t sssGroupValue(uint8_t source, uint8_t mask, const SssInfo *s) { + return (mask << 24) | (source << 20) | ((s->sampleIndex & 15) << 16) | (s->concurrencyMask << 12) | (s->sssBankIndex & 0xFFF); } static bool compareSssGroup(uint32_t flags_a, uint32_t flags_b) { @@ -56,7 +34,7 @@ static bool compareSssGroup(uint32_t flags_a, uint32_t flags_b) { // the original code possibly used a structure with bit fields that was optimized by the compiler as a uint32_t if (((flags_a >> 20) & 15) == ((flags_b >> 20) & 15)) { // source : 0,1,2 (Andy, monster1, monster2) if ((flags_a & 0xFFF) == (flags_b & 0xFFF)) { // bank index - return (flags_a >> 24) == (flags_b >> 24); // sample index bit 0..31, used as a mask lut[][] |= 1 << bit + return (flags_a >> 24) == (flags_b >> 24); // sample index, used as a mask lut[][] |= 1 << index } } return false; @@ -86,12 +64,14 @@ static uint32_t *getSssGroupPtr(Resource *res, int num, uint32_t flags) { void Game::muteSound() { MixerLock ml(&_mix); _snd_muted = true; + _snd_bufferOffset = _snd_bufferSize = 0; _mix._mixingQueueSize = 0; } void Game::unmuteSound() { MixerLock ml(&_mix); _snd_muted = false; + _snd_bufferOffset = _snd_bufferSize = 0; _mix._mixingQueueSize = 0; } @@ -100,7 +80,18 @@ void Game::resetSound() { clearSoundObjects(); } -SssObject *Game::findLowestRankSoundObject() const { +int Game::getSoundPosition(const SssObject *so) { + MixerLock ml(&_mix); + return so->pcm ? so->pcmFramesCount : -1; +} + +void Game::setSoundPanning(SssObject *so, int panning) { + MixerLock ml(&_mix); + so->panning = panning; + setSoundObjectPanning(so); +} + +SssObject *Game::findLowPrioritySoundObject() const { SssObject *so = 0; if (_playingSssObjectsCount >= _playingSssObjectsMax && _sssObjectsList1) { so = _sssObjectsList1; @@ -132,9 +123,9 @@ void Game::removeSoundObjectFromList(SssObject *so) { } --_playingSssObjectsCount; - if (kLimitSounds) { - if (_lowRankSssObject == so || (_playingSssObjectsCount < _playingSssObjectsMax && _lowRankSssObject)) { - _lowRankSssObject = findLowestRankSoundObject(); + if (_playingSssObjectsMax > 0) { + if (_lowPrioritySssObject == so || (_playingSssObjectsCount < _playingSssObjectsMax && _lowPrioritySssObject)) { + _lowPrioritySssObject = findLowPrioritySoundObject(); } } } else { @@ -311,9 +302,9 @@ void Game::sssOp17_pauseSound(SssObject *so) { } --_playingSssObjectsCount; - if (kLimitSounds) { - if (so == _lowRankSssObject || (_playingSssObjectsCount < _playingSssObjectsMax && _lowRankSssObject)) { - _lowRankSssObject = findLowestRankSoundObject(); + if (_playingSssObjectsMax > 0) { + if (so == _lowPrioritySssObject || (_playingSssObjectsCount < _playingSssObjectsMax && _lowPrioritySssObject)) { + _lowPrioritySssObject = findLowPrioritySoundObject(); } } } else { @@ -686,14 +677,15 @@ void Game::prependSoundObjectToList(SssObject *so) { _sssObjectsList2 = so; } else { debug(kDebug_SOUND, "Adding so %p to list1 flags 0x%x", so, so->flags); - SssObject *stopSo = so; // vf + SssObject *stopSo = so; if (so->pcm && so->pcm->ptr) { - if (kLimitSounds && _playingSssObjectsCount >= _playingSssObjectsMax) { - if (so->currentPriority > _lowRankSssObject->currentPriority) { + if (_playingSssObjectsMax > 0 && _playingSssObjectsCount >= _playingSssObjectsMax) { + if (so->currentPriority > _lowPrioritySssObject->currentPriority) { - stopSo = _lowRankSssObject; - SssObject *next = _lowRankSssObject->nextPtr; // vd - SssObject *prev = _lowRankSssObject->prevPtr; // vc + stopSo = _lowPrioritySssObject; + debug(kDebug_SOUND, "Removing so %p priority %d", stopSo, stopSo->priority); + SssObject *next = _lowPrioritySssObject->nextPtr; + SssObject *prev = _lowPrioritySssObject->prevPtr; so->nextPtr = next; so->prevPtr = prev; @@ -704,10 +696,10 @@ void Game::prependSoundObjectToList(SssObject *so) { if (prev) { prev->nextPtr = so; } else { - assert(so == _sssObjectsList1); + assert(stopSo == _sssObjectsList1); _sssObjectsList1 = so; } - _lowRankSssObject = findLowestRankSoundObject(); + _lowPrioritySssObject = findLowPrioritySoundObject(); } } else { stopSo = 0; @@ -719,13 +711,13 @@ void Game::prependSoundObjectToList(SssObject *so) { _sssObjectsList1->prevPtr = so; } _sssObjectsList1 = so; - if (kLimitSounds) { + if (_playingSssObjectsMax > 0) { if (_playingSssObjectsCount < _playingSssObjectsMax) { - _lowRankSssObject = 0; - } else if (!_lowRankSssObject) { - _lowRankSssObject = findLowestRankSoundObject(); - } else if (so->currentPriority < _lowRankSssObject->currentPriority) { - _lowRankSssObject = so; + _lowPrioritySssObject = 0; + } else if (!_lowPrioritySssObject) { + _lowPrioritySssObject = findLowPrioritySoundObject(); + } else if (so->currentPriority < _lowPrioritySssObject->currentPriority) { + _lowPrioritySssObject = so; } } } @@ -904,10 +896,10 @@ SssObject *Game::startSoundObject(int bankIndex, int sampleIndex, uint32_t flags return 0; } -void Game::playSoundObject(SssInfo *s, int source, int mask) { +SssObject *Game::playSoundObject(SssInfo *s, int source, int mask) { debug(kDebug_SOUND, "playSoundObject num %d lut 0x%x mask 0x%x", s->sssBankIndex, source, mask); if (_sssDisabled) { - return; + return 0; } const int filterIndex = _res->_sssBanksData[s->sssBankIndex].sssFilter; SssFilter *filter = &_res->_sssFilters[filterIndex]; @@ -950,7 +942,9 @@ void Game::playSoundObject(SssInfo *s, int source, int mask) { SssObject *so = &_sssObjectsTable[i]; if (so->pcm != 0 && so->filter == filter) { so->currentPriority = CLIP(va + so->priority, 0, 7); - setLowPrioritySoundObject(so); + if (_playingSssObjectsMax > 0) { + setLowPrioritySoundObject(so); + } } } } @@ -962,41 +956,42 @@ void Game::playSoundObject(SssInfo *s, int source, int mask) { *sssGroupPtr3 |= mask; uint32_t *sssGroupPtr2 = getSssGroupPtr(_res, 2, ve); if (*sssGroupPtr2 & mask) { - return; + return 0; } *sssGroupPtr2 |= mask; } else if (_al & 1) { const uint32_t mask = 1 << (ve >> 24); uint32_t *sssGroupPtr1 = getSssGroupPtr(_res, 1, ve); if (*sssGroupPtr1 & mask) { - return; + return 0; } *sssGroupPtr1 |= mask; } else if (_al & 4) { for (SssObject *so = _sssObjectsList1; so; so = so->nextPtr) { if (compareSssGroup(so->flags0, ve)) { - return; + return 0; } } for (SssObject *so = _sssObjectsList2; so; so = so->nextPtr) { if (compareSssGroup(so->flags0, ve)) { - return; + return 0; } } } - createSoundObject(s->sssBankIndex, s->sampleIndex, ve); + return createSoundObject(s->sssBankIndex, s->sampleIndex, ve); } void Game::clearSoundObjects() { memset(_sssObjectsTable, 0, sizeof(_sssObjectsTable)); _sssObjectsList1 = 0; _sssObjectsList2 = 0; - _lowRankSssObject = 0; + _lowPrioritySssObject = 0; for (int i = 0; i < kMaxSssObjects; ++i) { _sssObjectsTable[i].num = i; } _sssObjectsCount = 0; _playingSssObjectsCount = 0; + _snd_bufferOffset = _snd_bufferSize = 0; _mix._mixingQueueSize = 0; if (_res->_sssHdr.infosDataCount != 0) { const int size = _res->_sssHdr.banksDataCount * sizeof(uint32_t); @@ -1011,9 +1006,7 @@ void Game::clearSoundObjects() { void Game::setLowPrioritySoundObject(SssObject *so) { if ((so->flags & kFlagPaused) == 0) { - if (kLimitSounds) { - _lowRankSssObject = findLowestRankSoundObject(); - } + _lowPrioritySssObject = findLowPrioritySoundObject(); } } @@ -1052,15 +1045,19 @@ void Game::setSoundObjectPanning(SssObject *so) { volume = 0; panning = kDefaultSoundPanning; priority = 0; - } else { - panning = CLIP(so->panning, 0, 128); + } else if (so->panning < 0) { + panning = 0; + volume >>= 2; + priority /= 2; + } else if (so->panning > 128) { + panning = 128; volume >>= 2; priority /= 2; } if (so->currentPriority != priority) { so->currentPriority = priority; - if (kLimitSounds) { - _lowRankSssObject = findLowestRankSoundObject(); + if (_playingSssObjectsMax > 0) { + _lowPrioritySssObject = findLowPrioritySoundObject(); } } } else { @@ -1069,10 +1066,11 @@ void Game::setSoundObjectPanning(SssObject *so) { if (so->pcm == 0) { return; } - if (volume < 0 || volume >= (int)ARRAYSIZE(_volumeRampTable)) { + if ((uint32_t)volume >= ARRAYSIZE(_volumeRampTable)) { warning("Out of bounds volume %d (filter %d volume %d)", volume, (so->filter->volumeCurrent >> 16), so->volume); so->panL = 0; so->panR = 0; + so->panType = 0; return; } int vd = _volumeRampTable[volume]; // 0..128 @@ -1194,7 +1192,7 @@ void Game::queueSoundObjectsPcmStride() { if (so->currentPcmPtr >= end) { continue; } - if (so->panL == 0 && so->panR == 0) { + if ((so->panL == 0 && so->panR == 0) || so->panType == 0) { continue; } _mix.queue(so->currentPcmPtr, end, so->panType, so->panL, so->panR, so->stereo); diff --git a/staticres.cpp b/staticres.cpp index a3190fb..884ef4a 100644 --- a/staticres.cpp +++ b/staticres.cpp @@ -27,11 +27,7 @@ const uint8_t Game::_pointRandomizeShiftTable[] = { 0x1A, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00 + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x20 }; const uint8_t Game::_pointSrcIndex2Table[] = { diff --git a/system.h b/system.h index d6efecd..3509453 100644 --- a/system.h +++ b/system.h @@ -48,7 +48,8 @@ struct System { virtual void setScaler(const char *name, int multiplier) = 0; virtual void setGamma(float gamma) = 0; - virtual void setPalette(const uint8_t *pal, int n, int depth = 8) = 0; + virtual void setPalette(const uint8_t *pal, int n, int depth) = 0; + virtual void clearPalette() = 0; virtual void copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch) = 0; virtual void copyYuv(int w, int h, const uint8_t *y, int ypitch, const uint8_t *u, int upitch, const uint8_t *v, int vpitch) = 0; virtual void fillRect(int x, int y, int w, int h, uint8_t color) = 0; @@ -67,6 +68,11 @@ struct System { virtual AudioCallback setAudioCallback(AudioCallback callback) = 0; }; +extern void System_earlyInit(); +extern void System_printLog(FILE *, const char *s); +extern void System_fatalError(const char *s); +extern bool System_hasCommandLine(); + extern System *const g_system; #endif // SYSTEM_H__ diff --git a/system_psp.cpp b/system_psp.cpp index d41dded..d91db9f 100644 --- a/system_psp.cpp +++ b/system_psp.cpp @@ -25,6 +25,7 @@ struct System_PSP : System { virtual void setScaler(const char *name, int multiplier); virtual void setGamma(float gamma); virtual void setPalette(const uint8_t *pal, int n, int depth); + virtual void clearPalette(); virtual void copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch); virtual void copyYuv(int w, int h, const uint8_t *y, int ypitch, const uint8_t *u, int upitch, const uint8_t *v, int vpitch); virtual void fillRect(int x, int y, int w, int h, uint8_t color); @@ -65,7 +66,7 @@ static uint8_t __attribute__((aligned(16))) _texture[256 * 256]; static uint32_t __attribute__((aligned(16))) _clut2[256]; static uint8_t __attribute__((aligned(16))) _texture2[256 * 256]; -PSP_MODULE_INFO("Heart of Darkness", 0, 2, 8); +PSP_MODULE_INFO("Heart of Darkness", 0, 2, 9); PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER); struct Vertex { @@ -109,6 +110,10 @@ void System_fatalError(const char *s) { sceKernelExitGame(); } +bool System_hasCommandLine() { + return false; +} + static int exitCallback(int arg1, int arg2, void *common) { g_system->inp.quit = true; return 0; @@ -200,6 +205,13 @@ void System_PSP::setPalette(const uint8_t *pal, int n, int depth) { sceKernelDcacheWritebackRange(_clut, sizeof(_clut)); } +void System_PSP::clearPalette() { + for (int i = 0; i < 256; ++i) { + _clut[i] = GU_RGBA(0, 0, 0, 255); + } + sceKernelDcacheWritebackRange(_clut, sizeof(_clut)); +} + void System_PSP::copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch) { uint8_t *p = _texture + y * GAME_W + x; if (w == GAME_W && w == pitch) { diff --git a/system_sdl2.cpp b/system_sdl2.cpp index 548f68c..0239263 100644 --- a/system_sdl2.cpp +++ b/system_sdl2.cpp @@ -66,6 +66,7 @@ struct System_SDL2 : System { virtual void setScaler(const char *name, int multiplier); virtual void setGamma(float gamma); virtual void setPalette(const uint8_t *pal, int n, int depth); + virtual void clearPalette(); virtual void copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch); virtual void copyYuv(int w, int h, const uint8_t *y, int ypitch, const uint8_t *u, int upitch, const uint8_t *v, int vpitch); virtual void fillRect(int x, int y, int w, int h, uint8_t color); @@ -91,11 +92,24 @@ struct System_SDL2 : System { static System_SDL2 system_sdl2; System *const g_system = &system_sdl2; +void System_printLog(FILE *fp, const char *s) { + if (fp == stderr) { + fprintf(stderr, "WARNING: %s\n", s); + } else { + fprintf(fp, "%s\n", s); + } +} + void System_fatalError(const char *s) { + fprintf(stderr, "ERROR: %s\n", s); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Heart of Darkness", s, system_sdl2._window); exit(-1); } +bool System_hasCommandLine() { + return true; +} + System_SDL2::System_SDL2() : _offscreenLut(0), _offscreenRgb(0), _window(0), _renderer(0), _texture(0), _backgroundTexture(0), _fmt(0), _widescreenTexture(0), @@ -126,11 +140,12 @@ void System_SDL2::init(const char *title, int w, int h, bool fullscreen, bool wi } memset(_offscreenLut, 0, offscreenSize); prepareScaledGfx(title, fullscreen, widescreen, yuv); + + SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt"); _joystick = 0; _controller = 0; const int count = SDL_NumJoysticks(); if (count > 0) { - SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt"); for (int i = 0; i < count; ++i) { if (SDL_IsGameController(i)) { _controller = SDL_GameControllerOpen(i); @@ -332,6 +347,10 @@ void System_SDL2::setPalette(const uint8_t *pal, int n, int depth) { } } +void System_SDL2::clearPalette() { + memset(_pal, 0, sizeof(_pal)); +} + void System_SDL2::copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch) { assert(x >= 0 && x + w <= _screenW && y >= 0 && y + h <= _screenH); if (w == pitch && w == _screenW) { @@ -811,16 +830,11 @@ void System_SDL2::updateKeys(PlayerInput *inp) { } void System_SDL2::prepareScaledGfx(const char *caption, bool fullscreen, bool widescreen, bool yuv) { - int flags = 0; - if (fullscreen) { - flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; - } else { - flags |= SDL_WINDOW_RESIZABLE; - } _texW = _screenW * _scalerMultiplier; _texH = _screenH * _scalerMultiplier; const int windowW = widescreen ? _texH * 16 / 9 : _texW; const int windowH = _texH; + const int flags = fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_RESIZABLE; _window = SDL_CreateWindow(caption, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowW, windowH, flags); SDL_Surface *icon = SDL_LoadBMP(kIconBmp); if (icon) { diff --git a/system_wii.cpp b/system_wii.cpp index c83d09a..e7d416f 100644 --- a/system_wii.cpp +++ b/system_wii.cpp @@ -2,6 +2,8 @@ #include #include +#include + #include #include #include @@ -33,6 +35,7 @@ struct System_Wii : System { virtual void setScaler(const char *name, int multiplier); virtual void setGamma(float gamma); virtual void setPalette(const uint8_t *pal, int n, int depth); + virtual void clearPalette(); virtual void copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch); virtual void copyYuv(int w, int h, const uint8_t *y, int ypitch, const uint8_t *u, int upitch, const uint8_t *v, int vpitch); virtual void fillRect(int x, int y, int w, int h, uint8_t color); @@ -81,6 +84,10 @@ static int16_t __attribute__((aligned(32))) _resample[DMA_BUFFER_SAMPLES * 2]; static uint8_t __attribute__((aligned(32))) _dma[2][DMA_BUFFER_SIZE]; static int _current_dma; +void System_earlyInit() { + fatInitDefault(); +} + void System_fatalError(const char *s) { GXRModeObj *rmodeObj = system_wii._rmodeObj; if (!rmodeObj) { @@ -96,6 +103,10 @@ void System_fatalError(const char *s) { void System_printLog(FILE *fp, const char *s) { } +bool System_hasCommandLine() { + return false; +} + System_Wii::System_Wii() { _rmodeObj = 0; } @@ -144,6 +155,9 @@ void System_Wii::destroy() { _xfb[0] = 0; free(MEM_K1_TO_K0(_xfb[1])); _xfb[1] = 0; + + fatUnmount("sd:/"); + fatUnmount("usb:/"); } void System_Wii::setScaler(const char *name, int multiplier) { @@ -176,6 +190,12 @@ void System_Wii::setPalette(const uint8_t *pal, int n, int depth) { GX_LoadTlut(&_tlutObj, GX_TLUT0); } +void System_Wii::clearPalette() { + memset(_clut, 0, sizeof(_clut)); + DCFlushRange(_clut, sizeof(_clut)); + GX_LoadTlut(&_tlutObj, GX_TLUT0); +} + void System_Wii::copyRect(int x, int y, int w, int h, const uint8_t *buf, int pitch) { uint64_t *dst = (uint64_t *)_texture + y * GAME_W + x; uint64_t *src = (uint64_t *)buf; diff --git a/util.cpp b/util.cpp index dbc01a6..8a3be0d 100644 --- a/util.cpp +++ b/util.cpp @@ -21,14 +21,10 @@ void debug(int mask, const char *msg, ...) { va_start(va, msg); vsprintf(buf, msg, va); va_end(va); - printf("%s\n", buf); - fflush(stdout); #ifdef __ANDROID__ __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "%s", buf); #endif -#ifdef PSP System_printLog(stdout, buf); -#endif } } @@ -38,12 +34,8 @@ void error(const char *msg, ...) { va_start(va, msg); vsprintf(buf, msg, va); va_end(va); - fprintf(stderr, "ERROR: %s!\n", buf); #ifdef __ANDROID__ __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", buf); -#endif -#ifdef PSP - System_printLog(stderr, buf); #endif System_fatalError(buf); } @@ -54,11 +46,8 @@ void warning(const char *msg, ...) { va_start(va, msg); vsprintf(buf, msg, va); va_end(va); - fprintf(stderr, "WARNING: %s!\n", buf); #ifdef __ANDROID__ __android_log_print(ANDROID_LOG_WARN, LOG_TAG, "%s", buf); #endif -#ifdef PSP System_printLog(stderr, buf); -#endif } diff --git a/video.cpp b/video.cpp index 8616043..f12cd9c 100644 --- a/video.cpp +++ b/video.cpp @@ -43,19 +43,17 @@ Video::~Video() { free(_mdec.planes[kOutputPlaneCr].ptr); } -void Video::init(bool mdec) { - if (mdec) { - static const int w = (W + 15) & ~15; - static const int h = (H + 15) & ~15; - static const int w2 = w / 2; - static const int h2 = h / 2; - _mdec.planes[kOutputPlaneY].ptr = (uint8_t *)malloc(w * h); - _mdec.planes[kOutputPlaneY].pitch = w; - _mdec.planes[kOutputPlaneCb].ptr = (uint8_t *)malloc(w2 * h2); - _mdec.planes[kOutputPlaneCb].pitch = w2; - _mdec.planes[kOutputPlaneCr].ptr = (uint8_t *)malloc(w2 * h2); - _mdec.planes[kOutputPlaneCr].pitch = w2; - } +void Video::initPsx() { + static const int w = (W + 15) & ~15; + static const int h = (H + 15) & ~15; + static const int w2 = w / 2; + static const int h2 = h / 2; + _mdec.planes[kOutputPlaneY].ptr = (uint8_t *)malloc(w * h); + _mdec.planes[kOutputPlaneY].pitch = w; + _mdec.planes[kOutputPlaneCb].ptr = (uint8_t *)malloc(w2 * h2); + _mdec.planes[kOutputPlaneCb].pitch = w2; + _mdec.planes[kOutputPlaneCr].ptr = (uint8_t *)malloc(w2 * h2); + _mdec.planes[kOutputPlaneCr].pitch = w2; } static int colorBrightness(int r, int g, int b) { @@ -66,17 +64,17 @@ void Video::updateGamePalette(const uint16_t *pal) { for (int i = 0; i < 256 * 3; ++i) { _palette[i] = pal[i] >> 8; } - g_system->setPalette(_palette, 256); + g_system->setPalette(_palette, 256, 8); } void Video::updateGameDisplay(uint8_t *buf) { g_system->copyRect(0, 0, W, H, buf, 256); if (_mdec.planes[kOutputPlaneY].ptr) { - updateYuvDisplay(&_mdec); + updateYuvDisplay(); } } -void Video::updateYuvDisplay(MdecOutput *mdec) { +void Video::updateYuvDisplay() { g_system->copyYuv(Video::W, Video::H, _mdec.planes[0].ptr, _mdec.planes[0].pitch, _mdec.planes[1].ptr, _mdec.planes[1].pitch, _mdec.planes[2].ptr, _mdec.planes[2].pitch); } @@ -93,7 +91,7 @@ void Video::clearBackBuffer() { void Video::clearPalette() { memset(_palette, 0, sizeof(_palette)); - g_system->setPalette(_palette, 256); + g_system->clearPalette(); } void Video::decodeSPR(const uint8_t *src, uint8_t *dst, int x, int y, uint8_t flags, uint16_t spr_w, uint16_t spr_h) { @@ -450,10 +448,10 @@ void Video::drawStringCharacter(int x, int y, uint8_t chr, uint8_t color, uint8_ void Video::drawString(const char *s, int x, int y, uint8_t color, uint8_t *dst) { for (int i = 0; s[i]; ++i) { uint8_t chr = s[i]; - if (chr >= 'a' && chr <= 'z') { - chr += 'A' - 'a'; - } if (chr != ' ') { + if (chr >= 'a' && chr <= 'z') { + chr += 'A' - 'a'; + } chr = findStringCharacterFontIndex(chr); if (chr == 255) { continue; @@ -477,11 +475,14 @@ uint8_t Video::findWhiteColor() const { return color; } -void Video::decodeBackgroundPsx(const uint8_t *src, const int size, int w, int h, int x, int y) { +void Video::decodeBackgroundPsx(const uint8_t *src, int size, int w, int h, int x, int y) { _mdec.x = x; _mdec.y = y; _mdec.w = w; _mdec.h = h; + if (size < 0) { // size not available + size = w * h * sizeof(uint16_t); + } decodeMDEC(src, size, 0, 0, w, h, &_mdec); copyYuvBackBuffer(); } diff --git a/video.h b/video.h index 25507e2..59b6023 100644 --- a/video.h +++ b/video.h @@ -52,17 +52,17 @@ struct Video { Video(); ~Video(); - void init(bool mdec); + void initPsx(); void updateGamePalette(const uint16_t *pal); void updateGameDisplay(uint8_t *buf); - void updateYuvDisplay(MdecOutput *mdec); + void updateYuvDisplay(); void copyYuvBackBuffer(); void updateScreen(); void clearBackBuffer(); void clearPalette(); static void decodeRLE(const uint8_t *src, uint8_t *dst, int size); - void decodeSPR(const uint8_t *src, uint8_t *dst, int x, int y, uint8_t flags, uint16_t spr_w, uint16_t spr_h); + static void decodeSPR(const uint8_t *src, uint8_t *dst, int x, int y, uint8_t flags, uint16_t spr_w, uint16_t spr_h); int computeLineOutCode(int x, int y); bool clipLineCoords(int &x1, int &y1, int &x2, int &y2); void drawLine(int x1, int y1, int x2, int y2, uint8_t color);