diff --git a/README.txt b/README.txt index 24d10da..ddf53f4 100644 --- a/README.txt +++ b/README.txt @@ -1,6 +1,6 @@ hode README -Release version: 0.2.0 +Release version: 0.2.1 ------------------------------------------------------------------------------- diff --git a/andy.cpp b/andy.cpp index 445484b..608091e 100644 --- a/andy.cpp +++ b/andy.cpp @@ -1569,9 +1569,8 @@ void Game::updateAndyObject(LvlObject *ptr) { ash = (LvlAnimSeqHeader *)(dat->animsInfoData + ah->seqOffset) + currentAnimFrame; asfh = &asfh[count]; - const uint8_t *bitmap = _res->getLvlSpriteFramePtr(dat, ash->firstFrame); - int w = READ_LE_UINT16(bitmap + 2); - int h = READ_LE_UINT16(bitmap + 4); + uint16_t w, h; + _res->getLvlSpriteFramePtr(dat, ash->firstFrame, &w, &h); ptr->flags1 = ((ptr->flags1 & 0x30) ^ ((asfh->unk5 & 3) << 4)) | (ptr->flags1 & ~0x30); int type = (ptr->flags1 >> 4) & 3; @@ -1598,7 +1597,8 @@ void Game::updateAndyObject(LvlObject *ptr) { } else { sameAnim: - const uint8_t *frame1 = _res->getLvlSpriteFramePtr(dat, ash->firstFrame); + uint16_t frame1_w, frame1_h; + _res->getLvlSpriteFramePtr(dat, ash->firstFrame, &frame1_w, &frame1_h); ++currentAnimFrame; if (currentAnimFrame >= ah->seqCount) { @@ -1607,10 +1607,11 @@ void Game::updateAndyObject(LvlObject *ptr) { ash = (LvlAnimSeqHeader *)(dat->animsInfoData + ah->seqOffset) + currentAnimFrame; - const uint8_t *frame2 = _res->getLvlSpriteFramePtr(dat, ash->firstFrame); + uint16_t frame2_w, frame2_h; + _res->getLvlSpriteFramePtr(dat, ash->firstFrame, &frame2_w, &frame2_h); - int dw = READ_LE_UINT16(frame2 + 2) - READ_LE_UINT16(frame1 + 2); - int dh = READ_LE_UINT16(frame2 + 4) - READ_LE_UINT16(frame1 + 4); + int dw = frame2_w - frame1_w; + int dh = frame2_h - frame1_h; const int type = (ptr->flags1 >> 4) & 3; switch (type) { @@ -1647,10 +1648,7 @@ void Game::updateAndyObject(LvlObject *ptr) { ptr->currentSprite = ash->firstFrame; - ptr->bitmapBits = _res->getLvlSpriteFramePtr(dat, ash->firstFrame); - - ptr->width = READ_LE_UINT16(ptr->bitmapBits + 2); - ptr->height = READ_LE_UINT16(ptr->bitmapBits + 4); + ptr->bitmapBits = _res->getLvlSpriteFramePtr(dat, ash->firstFrame, &ptr->width, &ptr->height); LvlSprHotspotData *hs = ((LvlSprHotspotData *)dat->hotspotsData) + ash->firstFrame; diff --git a/defs.h b/defs.h index 4be614b..3fbfee4 100644 --- a/defs.h +++ b/defs.h @@ -15,6 +15,7 @@ enum { enum { kNone = 0xFFFFFFFF, // (uint32_t)-1 + kNoScreen = 0xFF, // (uint8_t)-1 kLvlAnimHdrOffset = 0x2C, kMaxScreens = 40, kMaxSpriteTypes = 32, @@ -119,8 +120,6 @@ struct LvlObjectData { uint8_t refCount; // 0xA uint8_t frame; // 0xB uint16_t anim; // 0xC - uint8_t unkE; - uint8_t unkF; uint8_t *animsInfoData; // 0x10, LevelSprAnimInfo uint8_t *movesData; // 0x14, LvlSprMoveData uint8_t *framesData; // 0x18 @@ -154,13 +153,11 @@ struct LvlObject { uint8_t actionKeyMask; uint8_t directionKeyMask; uint16_t currentSprite; - uint16_t currentSound; - uint8_t unk26; - uint8_t unk27; - const uint8_t *bitmapBits; - int (Game::*callbackFuncPtr)(LvlObject *ptr); - void *dataPtr; - SssObject *sssObject; // 0x34 + uint16_t currentSound; // 24 + const uint8_t *bitmapBits; // 28 + int (Game::*callbackFuncPtr)(LvlObject *ptr); // 2C + void *dataPtr; // 30 + SssObject *sssObject; // 34 LvlObjectData *levelData0x2988; Point16_t posTable[8]; LvlObject *nextPtr; diff --git a/fs_posix.cpp b/fs_posix.cpp index 3bb0259..0957c0a 100644 --- a/fs_posix.cpp +++ b/fs_posix.cpp @@ -8,6 +8,7 @@ static const char *_suffixes[] = { "setup.dat", + "setup.dax", ".paf", "_hod.lvl", "_hod.sss", diff --git a/game.cpp b/game.cpp index 23e78df..e623111 100644 --- a/game.cpp +++ b/game.cpp @@ -38,7 +38,7 @@ Game::Game(System *system, const char *dataPath, uint32_t cheats) { _plasmaExplosionObject = 0; _plasmaCannonObject = 0; memset(_spritesTable, 0, sizeof(_spritesTable)); - memset(_spriteListPtrTable, 0, sizeof(_spriteListPtrTable)); + memset(_typeSpritesList, 0, sizeof(_typeSpritesList)); _directionKeyMask = 0; _actionKeyMask = 0; @@ -64,7 +64,7 @@ Game::Game(System *system, const char *dataPath, uint32_t cheats) { _mstOriginPosX = Video::W / 2; _mstOriginPosY = Video::H / 2; memset(_declaredLvlObjectsList, 0, sizeof(_declaredLvlObjectsList)); - _declaredLvlObjectsListHead = 0; + _declaredLvlObjectsNextPtr = 0; _declaredLvlObjectsListCount = 0; memset(_animBackgroundDataTable, 0, sizeof(_animBackgroundDataTable)); @@ -90,7 +90,7 @@ Game::~Game() { } void Game::resetShootLvlObjectDataTable() { - _shootLvlObjectDataList = &_shootLvlObjectDataTable[0]; + _shootLvlObjectDataNextPtr = &_shootLvlObjectDataTable[0]; for (int i = 0; i < kMaxShootLvlObjectData - 1; ++i) { _shootLvlObjectDataTable[i].nextPtr = &_shootLvlObjectDataTable[i + 1]; } @@ -99,8 +99,8 @@ void Game::resetShootLvlObjectDataTable() { void Game::clearShootLvlObjectData(LvlObject *ptr) { ShootLvlObjectData *dat = (ShootLvlObjectData *)getLvlObjectDataPtr(ptr, kObjectDataTypeShoot); - dat->nextPtr = _shootLvlObjectDataList; - _shootLvlObjectDataList = dat; + dat->nextPtr = _shootLvlObjectDataNextPtr; + _shootLvlObjectDataNextPtr = dat; ptr->dataPtr = 0; } @@ -287,7 +287,7 @@ 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) { MixerLock ml(&_mix); - if (num < _res->_sssHdr.infosDataCount) { + if (!_res->_isPsx && 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); @@ -318,7 +318,11 @@ void Game::setupBackgroundBitmap() { if (lvl->backgroundBitmapId != 0xFFFF) { playSound(lvl->backgroundBitmapId, 0, 0, 3); } - decodeLZW(pic, _video->_backgroundLayer); + if (_res->_isPsx) { + assert(READ_LE_UINT16(pic + 4) == 0x3800); + } else { + decodeLZW(pic, _video->_backgroundLayer); + } if (lvl->shadowCount != 0) { decodeShadowScreenMask(lvl); } @@ -329,12 +333,10 @@ void Game::setupBackgroundBitmap() { } void Game::addToSpriteList(LvlObject *ptr) { - Sprite *spr = _spritesListNextPtr; + Sprite *spr = _spritesNextPtr; if (spr) { - uint8_t rightScreenId = _res->_screensGrid[_res->_currentScreenResourceNum * 4 + kPosRightScreen]; - uint8_t topScreenId = _res->_screensGrid[_res->_currentScreenResourceNum * 4 + kPosTopScreen]; - uint8_t bottomScreenId = _res->_screensGrid[_res->_currentScreenResourceNum * 4 + kPosBottomScreen]; - uint8_t leftScreenId = _res->_screensGrid[_res->_currentScreenResourceNum * 4 + kPosLeftScreen]; + const uint8_t num = _res->_currentScreenResourceNum; + const uint8_t *grid = _res->_screensGrid[num]; LvlObjectData *dat = ptr->levelData0x2988; LvlAnimHeader *ah = (LvlAnimHeader *)(dat->animsInfoData + kLvlAnimHdrOffset) + ptr->anim; @@ -345,15 +347,15 @@ void Game::addToSpriteList(LvlObject *ptr) { int index = ptr->screenNum; spr->xPos = ptr->xPos; spr->yPos = ptr->yPos; - if (index == topScreenId) { + if (index == grid[kPosTopScreen]) { spr->yPos -= Video::H; - } else if (index == bottomScreenId) { + } else if (index == grid[kPosBottomScreen]) { spr->yPos += Video::H; - } else if (index == rightScreenId) { + } else if (index == grid[kPosRightScreen]) { spr->xPos += Video::W; - } else if (index == leftScreenId) { + } else if (index == grid[kPosLeftScreen]) { spr->xPos -= Video::W; - } else if (index != _res->_currentScreenResourceNum) { + } else if (index != num) { return; } if (spr->xPos >= Video::W || spr->xPos + ptr->width < 0) { @@ -368,32 +370,32 @@ void Game::addToSpriteList(LvlObject *ptr) { } if (READ_LE_UINT16(ptr->bitmapBits) > 8) { spr->bitmapBits = ptr->bitmapBits; - _spritesListNextPtr = spr->nextPtr; + _spritesNextPtr = spr->nextPtr; index = (ptr->flags2 & 31); - spr->nextPtr = _spriteListPtrTable[index]; - _spriteListPtrTable[index] = spr; + spr->nextPtr = _typeSpritesList[index]; + _typeSpritesList[index] = spr; } } } int16_t Game::calcScreenMaskDy(int16_t xPos, int16_t yPos, int num) { if (xPos < 0) { - xPos += 256; - num = _res->_screensGrid[num * 4 + kPosLeftScreen]; - } else if (xPos >= 256) { - xPos -= 256; - num = _res->_screensGrid[num * 4 + kPosRightScreen]; - } - if (num != 0xFF && yPos < 0) { - yPos += 192; - num = _res->_screensGrid[num * 4 + kPosTopScreen]; - } else if (yPos >= 192) { - assert(num != 0xFF); - yPos -= 192; - num = _res->_screensGrid[num * 4 + kPosBottomScreen]; + xPos += Video::W; + num = _res->_screensGrid[num][kPosLeftScreen]; + } else if (xPos >= Video::W) { + xPos -= Video::W; + num = _res->_screensGrid[num][kPosRightScreen]; + } + if (num != kNoScreen && yPos < 0) { + yPos += Video::H; + num = _res->_screensGrid[num][kPosTopScreen]; + } else if (yPos >= Video::H) { + assert(num != kNoScreen); + yPos -= Video::H; + num = _res->_screensGrid[num][kPosBottomScreen]; } uint8_t var1 = 0xFF - (yPos & 7); - if (num == 0xFF) { + if (num == kNoScreen) { return var1; } int vg = screenMaskOffset(_res->_screensBasePos[num].u + xPos, _res->_screensBasePos[num].v + yPos); @@ -412,24 +414,18 @@ int16_t Game::calcScreenMaskDy(int16_t xPos, int16_t yPos, int num) { } else { return 0; } - int _dl = 1; // screen - while (_res->_screensGrid[_res->_currentScreenResourceNum * 4 + _dl - 1] != num) { - ++_dl; - if (_dl >= 4) { - if (num == _res->_currentScreenResourceNum) { - break; - } - return (int8_t)(var1 + 4); - } + int _dl = _res->findScreenGridIndex(num); + if (_dl < 0) { + return (int8_t)(var1 + 4); } const uint8_t *p = _res->_resLevelData0x470CTablePtrData + (xPos & 7); return (int8_t)(var1 + p[_screenPosTable[_dl][vf] * 8]); } void Game::setupScreenPosTable(uint8_t num) { - const uint8_t *src = &_res->_screensGrid[num * 4]; + const uint8_t *src = _res->_screensGrid[num]; for (int i = 0; i < 4; ++i) { - if (src[i] != 0xFF) { + if (src[i] != kNoScreen) { int index = _res->_resLvlScreenBackgroundDataTable[src[i]].currentMaskId; const uint8_t *p = _res->getLvlScreenPosDataPtr(src[i] * 4 + index); if (p) { @@ -449,7 +445,7 @@ void Game::setupScreenPosTable(uint8_t num) { } void Game::setupScreenMask(uint8_t num) { - if (num == 0xFF) { + if (num == kNoScreen) { return; } int mask = _res->_resLvlScreenBackgroundDataTable[num].currentMaskId; @@ -482,7 +478,7 @@ void Game::resetScreenMask() { } void Game::setScreenMaskRectHelper(int x1, int y1, int x2, int y2, int screenNum) { - if (screenNum != 0xFF) { + if (screenNum != kNoScreen) { int index = _res->_resLvlScreenBackgroundDataTable[screenNum].currentMaskId; const uint8_t *p = _res->getLvlScreenPosDataPtr(screenNum * 4 + index); @@ -494,13 +490,13 @@ void Game::setScreenMaskRectHelper(int x1, int y1, int x2, int y2, int screenNum const int x = x1 - _res->_screensBasePos[screenNum].u; const int y = y1 - _res->_screensBasePos[screenNum].v; - const int u = _res->_screensBasePos[screenNum].u + 256; + const int u = _res->_screensBasePos[screenNum].u + Video::W; if (x2 < u) { ++w; } const uint8_t *src = _screenTempMaskBuffer + screenGridOffset(x, y); - uint8_t *dst = _screenMaskBuffer + screenMaskOffset(y1, x1); + uint8_t *dst = _screenMaskBuffer + screenMaskOffset(x1, y1); for (int i = 0; i < h; ++i) { memcpy(dst, src, w); src += 32; @@ -512,13 +508,13 @@ void Game::setScreenMaskRectHelper(int x1, int y1, int x2, int y2, int screenNum void Game::setScreenMaskRect(int x1, int y1, int x2, int y2, int screenNum) { const int u = _res->_screensBasePos[screenNum].u; const int v = _res->_screensBasePos[screenNum].v; - const int topScreen = _res->_screensGrid[screenNum * 4 + kPosTopScreen]; - if (x1 < u || y1 < v || y2 >= v + 192) { - if (topScreen != 255) { - const int u2 = _res->_screensBasePos[topScreen].u; - const int v2 = _res->_screensBasePos[topScreen].v; - if (x1 >= u2 && y1 >= v2 && y2 < v + 192) { - setScreenMaskRectHelper(u2, y1, x2, v2 + 192, topScreen); + const int topScreenNum = _res->_screensGrid[screenNum][kPosTopScreen]; + if (x1 < u || y1 < v || y2 >= v + Video::H) { + if (topScreenNum != kNoScreen) { + const int u2 = _res->_screensBasePos[topScreenNum].u; + const int v2 = _res->_screensBasePos[topScreenNum].v; + if (x1 >= u2 && y1 >= v2 && y2 < v + Video::H) { + setScreenMaskRectHelper(x1, y1, x2, v2 + Video::H, topScreenNum); } } } @@ -563,10 +559,7 @@ void Game::setupLvlObjectBitmap(LvlObject *ptr) { ptr->flags1 = merge_bits(ptr->flags1, ash->flags1, 8); ptr->currentSprite = ash->firstFrame; - ptr->bitmapBits = _res->getLvlSpriteFramePtr(dat, ash->firstFrame); - - ptr->width = READ_LE_UINT16(ptr->bitmapBits + 2); - ptr->height = READ_LE_UINT16(ptr->bitmapBits + 4); + ptr->bitmapBits = _res->getLvlSpriteFramePtr(dat, ash->firstFrame, &ptr->width, &ptr->height); const int w = ptr->width - 1; const int h = ptr->height - 1; @@ -744,9 +737,9 @@ void Game::destroyLvlObject(LvlObject *o) { assert(o); if (o->type == 8) { _res->decLvlSpriteDataRefCounter(o); - o->nextPtr = _declaredLvlObjectsListHead; + o->nextPtr = _declaredLvlObjectsNextPtr; --_declaredLvlObjectsListCount; - _declaredLvlObjectsListHead = o; + _declaredLvlObjectsNextPtr = o; switch (o->spriteNum) { case 0: case 2: @@ -912,13 +905,29 @@ int Game::testPlasmaCannonPointsDirection(int x1, int y1, int x2, int y2) { return 1; } -void Game::preloadLevelScreenData(int num, int prev) { - _res->loadLvlScreenBackgroundData(num); +void Game::preloadLevelScreenData(uint8_t num, uint8_t prev) { + assert(num != kNoScreen); + if (!_res->isLvlBackgroundDataLoaded(num)) { + _res->loadLvlScreenBackgroundData(num); + } + if (0) { + const uint8_t leftScreen = _res->_screensGrid[num][kPosLeftScreen]; + if (leftScreen != kNoScreen && !_res->isLvlBackgroundDataLoaded(leftScreen)) { + _res->loadLvlScreenBackgroundData(leftScreen); + } + const uint8_t rightScreen = _res->_screensGrid[num][kPosRightScreen]; + if (rightScreen != kNoScreen && !_res->isLvlBackgroundDataLoaded(rightScreen)) { + _res->loadLvlScreenBackgroundData(rightScreen); + } + for (unsigned int i = 0; i < kMaxScreens; ++i) { + if (_res->_resLevelData0x2B88SizeTable[i] != 0) { + if (i != num && i != leftScreen && i != rightScreen) { + _res->unloadLvlScreenBackgroundData(i); + } + } + } + } loadLevelScreenSounds(num); - - // we should also - - // load the adjacent left and right screens - // unload previous screens } void Game::loadLevelScreenSounds(int num) { @@ -962,9 +971,9 @@ void Game::clearLvlObjectsList0() { LvlObject *next = ptr->nextPtr; if (ptr->type == 8) { _res->decLvlSpriteDataRefCounter(ptr); - ptr->nextPtr = _declaredLvlObjectsListHead; + ptr->nextPtr = _declaredLvlObjectsNextPtr; --_declaredLvlObjectsListCount; - _declaredLvlObjectsListHead = ptr; + _declaredLvlObjectsNextPtr = ptr; switch (ptr->spriteNum) { case 0: case 2: @@ -1003,9 +1012,9 @@ void Game::clearLvlObjectsList1() { LvlObject *next = ptr->nextPtr; if (ptr->type == 8) { _res->decLvlSpriteDataRefCounter(ptr); - ptr->nextPtr = _declaredLvlObjectsListHead; + ptr->nextPtr = _declaredLvlObjectsNextPtr; --_declaredLvlObjectsListCount; - _declaredLvlObjectsListHead = ptr; + _declaredLvlObjectsNextPtr = ptr; switch (ptr->spriteNum) { case 0: case 2: @@ -1035,9 +1044,9 @@ void Game::clearLvlObjectsList2() { LvlObject *next = ptr->nextPtr; if (ptr->type == 8) { _res->decLvlSpriteDataRefCounter(ptr); - ptr->nextPtr = _declaredLvlObjectsListHead; + ptr->nextPtr = _declaredLvlObjectsNextPtr; --_declaredLvlObjectsListCount; - _declaredLvlObjectsListHead = ptr; + _declaredLvlObjectsNextPtr = ptr; switch (ptr->spriteNum) { case 0: case 2: @@ -1067,9 +1076,9 @@ void Game::clearLvlObjectsList3() { LvlObject *next = ptr->nextPtr; if (ptr->type == 8) { _res->decLvlSpriteDataRefCounter(ptr); - ptr->nextPtr = _declaredLvlObjectsListHead; + ptr->nextPtr = _declaredLvlObjectsNextPtr; --_declaredLvlObjectsListCount; - _declaredLvlObjectsListHead = ptr; + _declaredLvlObjectsNextPtr = ptr; switch (ptr->spriteNum) { case 0: case 2: @@ -1095,9 +1104,9 @@ void Game::clearLvlObjectsList3() { LvlObject *Game::addLvlObjectToList0(int num) { if (_res->_resLevelData0x2988PtrTable[num] != 0 && _declaredLvlObjectsListCount < kMaxLvlObjects) { - assert(_declaredLvlObjectsListHead); - LvlObject *ptr = _declaredLvlObjectsListHead; - _declaredLvlObjectsListHead = _declaredLvlObjectsListHead->nextPtr; + assert(_declaredLvlObjectsNextPtr); + LvlObject *ptr = _declaredLvlObjectsNextPtr; + _declaredLvlObjectsNextPtr = _declaredLvlObjectsNextPtr->nextPtr; ++_declaredLvlObjectsListCount; ptr->spriteNum = num; ptr->type = 8; @@ -1116,9 +1125,9 @@ LvlObject *Game::addLvlObjectToList0(int num) { LvlObject *Game::addLvlObjectToList1(int type, int num) { if ((type != 8 || _res->_resLevelData0x2988PtrTable[num] != 0) && _declaredLvlObjectsListCount < kMaxLvlObjects) { - assert(_declaredLvlObjectsListHead); - LvlObject *ptr = _declaredLvlObjectsListHead; - _declaredLvlObjectsListHead = _declaredLvlObjectsListHead->nextPtr; + assert(_declaredLvlObjectsNextPtr); + LvlObject *ptr = _declaredLvlObjectsNextPtr; + _declaredLvlObjectsNextPtr = _declaredLvlObjectsNextPtr->nextPtr; ++_declaredLvlObjectsListCount; ptr->spriteNum = num; ptr->type = type; @@ -1139,9 +1148,9 @@ LvlObject *Game::addLvlObjectToList1(int type, int num) { LvlObject *Game::addLvlObjectToList2(int num) { if (_res->_resLevelData0x2988PtrTable[num] != 0 && _declaredLvlObjectsListCount < kMaxLvlObjects) { - assert(_declaredLvlObjectsListHead); - LvlObject *ptr = _declaredLvlObjectsListHead; - _declaredLvlObjectsListHead = _declaredLvlObjectsListHead->nextPtr; + assert(_declaredLvlObjectsNextPtr); + LvlObject *ptr = _declaredLvlObjectsNextPtr; + _declaredLvlObjectsNextPtr = _declaredLvlObjectsNextPtr->nextPtr; ++_declaredLvlObjectsListCount; ptr->spriteNum = num; ptr->type = 8; @@ -1160,9 +1169,9 @@ LvlObject *Game::addLvlObjectToList2(int num) { LvlObject *Game::addLvlObjectToList3(int num) { if (_res->_resLevelData0x2988PtrTable[num] != 0 && _declaredLvlObjectsListCount < kMaxLvlObjects) { - assert(_declaredLvlObjectsListHead); - LvlObject *ptr = _declaredLvlObjectsListHead; - _declaredLvlObjectsListHead = _declaredLvlObjectsListHead->nextPtr; + assert(_declaredLvlObjectsNextPtr); + LvlObject *ptr = _declaredLvlObjectsNextPtr; + _declaredLvlObjectsNextPtr = _declaredLvlObjectsNextPtr->nextPtr; ++_declaredLvlObjectsListCount; ptr->spriteNum = num; ptr->type = 8; @@ -1210,8 +1219,8 @@ void Game::removeLvlObject2(LvlObject *o) { o->dataPtr = 0; if (o->type == 8) { _res->decLvlSpriteDataRefCounter(o); - o->nextPtr = _declaredLvlObjectsListHead; - _declaredLvlObjectsListHead = o; + o->nextPtr = _declaredLvlObjectsNextPtr; + _declaredLvlObjectsNextPtr = o; --_declaredLvlObjectsListCount; } else { switch (o->spriteNum) { @@ -1277,8 +1286,8 @@ void Game::setupAndyLvlObject() { ptr->directionKeyMask = 0; ptr->actionKeyMask = 0; _currentScreen = dat->screenNum; - _currentLeftScreen = _res->_screensGrid[_currentScreen * 4 + kPosLeftScreen]; - _currentRightScreen = _res->_screensGrid[_currentScreen * 4 + kPosRightScreen]; + _currentLeftScreen = _res->_screensGrid[_currentScreen][kPosLeftScreen]; + _currentRightScreen = _res->_screensGrid[_currentScreen][kPosRightScreen]; ptr->frame = 0; setupLvlObjectBitmap(ptr); AndyLvlObjectData *dataPtr = (AndyLvlObjectData *)getLvlObjectDataPtr(ptr, kObjectDataTypeAndy); @@ -1297,7 +1306,10 @@ void Game::updateScreenHelper(int num) { case 0: { AnimBackgroundData *p = (AnimBackgroundData *)getLvlObjectDataPtr(ptr, kObjectDataTypeAnimBackgroundData); uint8_t *data = _res->_resLvlScreenBackgroundDataTable[num].backgroundAnimationTable[ptr->dataNum]; - assert(data); + if (!data) { + warning("No AnimBackgroundData num %d screen %d", ptr->dataNum, num); + break; + } p->framesCount = READ_LE_UINT16(data); data += 2; ptr->currentSound = READ_LE_UINT16(data); data += 2; p->currentSpriteData = p->otherSpriteData = data; @@ -1307,6 +1319,10 @@ void Game::updateScreenHelper(int num) { break; case 1: { uint8_t *data = _res->_resLvlScreenBackgroundDataTable[num].backgroundSoundTable[ptr->dataNum]; + if (!data) { + warning("No SoundBackgroundData num %d screen %d", ptr->dataNum, num); + break; + } ptr->currentSound = READ_LE_UINT16(data); data += 2; ptr->dataPtr = data; } @@ -1362,13 +1378,13 @@ void Game::resetDisplay() { _levelRestartCounter = 0; _fadePalette = false; memset(_video->_fadePaletteBuffer, 0, sizeof(_video->_fadePaletteBuffer)); -// _snd_masterVolume = _plyConfigTable[_plyConfigNumber].soundVolume; + _snd_masterVolume = kDefaultSoundVolume; // _plyConfigTable[_plyConfigNumber].soundVolume; } void Game::updateScreen(uint8_t num) { uint8_t i, prev; - if (num == 0xFF) { + if (num == kNoScreen) { return; } prev = _res->_currentScreenResourceNum; @@ -1379,27 +1395,27 @@ void Game::updateScreen(uint8_t num) { --_res->_screensState[num].s1; } callLevel_postScreenUpdate(num); - i = _res->_screensGrid[num * 4 + kPosTopScreen]; - if (i != 0xFF && prev != i) { + i = _res->_screensGrid[num][kPosTopScreen]; + if (i != kNoScreen && prev != i) { callLevel_preScreenUpdate(i); setupScreenMask(i); callLevel_postScreenUpdate(i); } - i = _res->_screensGrid[num * 4 + kPosRightScreen]; - if (i != 0xFF && _res->_resLevelData0x2B88SizeTable[i] != 0 && prev != i) { + i = _res->_screensGrid[num][kPosRightScreen]; + if (i != kNoScreen && _res->_resLevelData0x2B88SizeTable[i] != 0 && prev != i) { updateScreenHelper(i); callLevel_preScreenUpdate(i); setupScreenMask(i); callLevel_postScreenUpdate(i); } - i = _res->_screensGrid[num * 4 + kPosBottomScreen]; - if (i != 0xFF && prev != i) { + i = _res->_screensGrid[num][kPosBottomScreen]; + if (i != kNoScreen && prev != i) { callLevel_preScreenUpdate(i); setupScreenMask(i); callLevel_postScreenUpdate(i); } - i = _res->_screensGrid[num * 4 + kPosLeftScreen]; - if (i != 0xFF && _res->_resLevelData0x2B88SizeTable[i] != 0 && prev != i) { + i = _res->_screensGrid[num][kPosLeftScreen]; + if (i != kNoScreen && _res->_resLevelData0x2B88SizeTable[i] != 0 && prev != i) { updateScreenHelper(i); callLevel_preScreenUpdate(i); setupScreenMask(i); @@ -1444,12 +1460,12 @@ void Game::restartLevel() { resetSound(); } const int screenNum = _level->getCheckpointData(_level->_checkpoint)->screenNum; - preloadLevelScreenData(screenNum, 0xFF); + preloadLevelScreenData(screenNum, kNoScreen); _andyObject->levelData0x2988 = _res->_resLevelData0x2988PtrTable[_andyObject->spriteNum]; memset(_video->_backgroundLayer, 0, Video::W * Video::H); resetScreen(); if (_andyObject->screenNum != screenNum) { - preloadLevelScreenData(_andyObject->screenNum, 0xFF); + preloadLevelScreenData(_andyObject->screenNum, kNoScreen); } updateScreen(_andyObject->screenNum); } @@ -1498,21 +1514,21 @@ int8_t Game::updateLvlObjectScreen(LvlObject *ptr) { int yPos = ptr->yPos + ptr->posTable[3].y; uint8_t num = ptr->screenNum; if (xPos < 0) { - ptr->screenNum = _res->_screensGrid[num * 4 + kPosLeftScreen]; - ptr->xPos = xPosPrev + 256; - } else if (xPos > 256) { - ptr->screenNum = _res->_screensGrid[num * 4 + kPosRightScreen]; - ptr->xPos = xPosPrev - 256; - } - if (yPos < 0 && ptr->screenNum != 0xFF) { - ptr->screenNum = _res->_screensGrid[ptr->screenNum * 4 + kPosTopScreen]; - ptr->yPos = yPosPrev + 192; - } else if (yPos > 192) { - assert(ptr->screenNum != 0xFF); - ptr->screenNum = _res->_screensGrid[ptr->screenNum * 4 + kPosBottomScreen]; - ptr->yPos = yPosPrev - 192; - } - if (ptr->screenNum == 0xFF) { + ptr->screenNum = _res->_screensGrid[num][kPosLeftScreen]; + ptr->xPos = xPosPrev + Video::W; + } else if (xPos > Video::W) { + ptr->screenNum = _res->_screensGrid[num][kPosRightScreen]; + ptr->xPos = xPosPrev - Video::W; + } + if (yPos < 0 && ptr->screenNum != kNoScreen) { + ptr->screenNum = _res->_screensGrid[ptr->screenNum][kPosTopScreen]; + ptr->yPos = yPosPrev + Video::H; + } else if (yPos > Video::H) { + assert(ptr->screenNum != kNoScreen); + ptr->screenNum = _res->_screensGrid[ptr->screenNum][kPosBottomScreen]; + ptr->yPos = yPosPrev - Video::H; + } + if (ptr->screenNum == kNoScreen) { debug(kDebug_GAME, "Changing screen from -1 to %d, pos=%d,%d (%d,%d)", num, xPos, yPos, xPosPrev, yPosPrev); ptr->screenNum = num; ptr->xPos = xPosPrev; @@ -1529,8 +1545,8 @@ int8_t Game::updateLvlObjectScreen(LvlObject *ptr) { } } _currentScreen = ptr->screenNum; - _currentLeftScreen = _res->_screensGrid[_currentScreen * 4 + kPosLeftScreen]; - _currentRightScreen = _res->_screensGrid[_currentScreen * 4 + kPosRightScreen]; + _currentLeftScreen = _res->_screensGrid[_currentScreen][kPosLeftScreen]; + _currentRightScreen = _res->_screensGrid[_currentScreen][kPosRightScreen]; return ret; } @@ -1996,21 +2012,21 @@ void Game::drawScreen() { // redraw background animation sprites LvlBackgroundData *dat = &_res->_resLvlScreenBackgroundDataTable[_res->_currentScreenResourceNum]; - for (Sprite *spr = _spriteListPtrTable[0]; spr; spr = spr->nextPtr) { + for (Sprite *spr = _typeSpritesList[0]; spr; spr = spr->nextPtr) { if ((spr->num & 0x1F) == 0) { _video->decodeSPR(spr->bitmapBits, _video->_backgroundLayer, spr->xPos, spr->yPos, 0); } } memset(_video->_shadowLayer, 0, Video::W * Video::H + 1); for (int i = 1; i < 8; ++i) { - for (Sprite *spr = _spriteListPtrTable[i]; spr; spr = spr->nextPtr) { + for (Sprite *spr = _typeSpritesList[i]; spr; spr = spr->nextPtr) { if ((spr->num & 0x2000) != 0) { _video->decodeSPR(spr->bitmapBits, _video->_shadowLayer, spr->xPos, spr->yPos, (spr->num >> 0xE) & 3); } } } for (int i = 1; i < 4; ++i) { - for (Sprite *spr = _spriteListPtrTable[i]; spr; spr = spr->nextPtr) { + for (Sprite *spr = _typeSpritesList[i]; spr; spr = spr->nextPtr) { if ((spr->num & 0x1000) != 0) { _video->decodeSPR(spr->bitmapBits, _video->_frontLayer, spr->xPos, spr->yPos, (spr->num >> 0xE) & 3); } @@ -2022,14 +2038,14 @@ void Game::drawScreen() { } } for (int i = 4; i < 8; ++i) { - for (Sprite *spr = _spriteListPtrTable[i]; spr; spr = spr->nextPtr) { + for (Sprite *spr = _typeSpritesList[i]; spr; spr = spr->nextPtr) { if ((spr->num & 0x1000) != 0) { _video->decodeSPR(spr->bitmapBits, _video->_frontLayer, spr->xPos, spr->yPos, (spr->num >> 0xE) & 3); } } } for (int i = 0; i < 24; ++i) { - for (Sprite *spr = _spriteListPtrTable[i]; spr; spr = spr->nextPtr) { + for (Sprite *spr = _typeSpritesList[i]; spr; spr = spr->nextPtr) { if ((spr->num & 0x2000) != 0) { _video->decodeSPR(spr->bitmapBits, _video->_shadowLayer, spr->xPos, spr->yPos, (spr->num >> 0xE) & 3); } @@ -2048,7 +2064,7 @@ void Game::drawScreen() { _shadowScreenMasksTable[i].shadowPalettePtr); } for (int i = 1; i < 12; ++i) { - for (Sprite *spr = _spriteListPtrTable[i]; spr; spr = spr->nextPtr) { + for (Sprite *spr = _typeSpritesList[i]; spr; spr = spr->nextPtr) { if ((spr->num & 0x1000) != 0) { _video->decodeSPR(spr->bitmapBits, _video->_frontLayer, spr->xPos, spr->yPos, (spr->num >> 0xE) & 3); } @@ -2060,7 +2076,7 @@ void Game::drawScreen() { } } for (int i = 12; i <= 24; ++i) { - for (Sprite *spr = _spriteListPtrTable[i]; spr; spr = spr->nextPtr) { + for (Sprite *spr = _typeSpritesList[i]; spr; spr = spr->nextPtr) { if ((spr->num & 0x1000) != 0) { _video->decodeSPR(spr->bitmapBits, _video->_frontLayer, spr->xPos, spr->yPos, (spr->num >> 0xE) & 3); } @@ -2081,7 +2097,7 @@ void Game::mainLoop(int level, int checkpoint, bool levelChanged) { _mstAndyCurrentScreenNum = -1; _rnd.initTable(); initMstCode(); - preloadLevelScreenData(_level->getCheckpointData(_level->_checkpoint)->screenNum, 0xFF); + preloadLevelScreenData(_level->getCheckpointData(_level->_checkpoint)->screenNum, kNoScreen); memset(_level->_screenCounterTable, 0, sizeof(_level->_screenCounterTable)); clearDeclaredLvlObjectsList(); initLvlObjects(); @@ -2090,8 +2106,8 @@ void Game::mainLoop(int level, int checkpoint, bool levelChanged) { _res->_screensState[i].s2 = 0; } _res->_currentScreenResourceNum = _andyObject->screenNum; - _currentRightScreen = _res->_screensGrid[_res->_currentScreenResourceNum * 4 + kPosRightScreen]; - _currentLeftScreen = _res->_screensGrid[_res->_currentScreenResourceNum * 4 + kPosLeftScreen]; + _currentRightScreen = _res->_screensGrid[_res->_currentScreenResourceNum][kPosRightScreen]; + _currentLeftScreen = _res->_screensGrid[_res->_currentScreenResourceNum][kPosLeftScreen]; if (!_mstDisabled) { startMstCode(); } @@ -2100,6 +2116,9 @@ void Game::mainLoop(int level, int checkpoint, bool levelChanged) { _paf->preload(num); _paf->play(num); _paf->unload(num); + if (_system->inp.quit) { + return; + } } if (_res->_sssHdr.infosDataCount != 0) { resetSound(); @@ -2206,16 +2225,16 @@ LvlObject *Game::updateAnimatedLvlObjectType0(LvlObject *ptr) { playSound(ptr->currentSound, ptr, 0, 3); ptr->currentSound = 0xFFFF; } - Sprite *spr = _spritesListNextPtr; + Sprite *spr = _spritesNextPtr; if (spr && READ_LE_UINT16(vf + 2) > 8) { spr->xPos = vf[0]; spr->yPos = vf[1]; spr->bitmapBits = vf + 2; spr->num = ptr->flags2; const int index = spr->num & 0x1F; - _spritesListNextPtr = spr->nextPtr; - spr->nextPtr = _spriteListPtrTable[index]; - _spriteListPtrTable[index] = spr; + _spritesNextPtr = spr->nextPtr; + spr->nextPtr = _typeSpritesList[index]; + _typeSpritesList[index] = spr; } } int16_t soundNum = -1; @@ -2249,7 +2268,7 @@ LvlObject *Game::updateAnimatedLvlObjectType0(LvlObject *ptr) { break; case 4: ++vg->currentFrame; - if (vg->currentFrame < vg->framesCount) { // original uses '<=' (oob) + if (vg->currentFrame < vg->framesCount) { // bugfix: original uses '<=' (out of bounds) vg->currentSpriteData = va; soundNum = READ_LE_UINT16(va); } else { @@ -2269,16 +2288,16 @@ LvlObject *Game::updateAnimatedLvlObjectType0(LvlObject *ptr) { } va = vg->currentSpriteData + 2; // vg if (_res->_currentScreenResourceNum == ptr->screenNum) { - Sprite *spr = _spritesListNextPtr; + Sprite *spr = _spritesNextPtr; if (spr && READ_LE_UINT16(va + 2) > 8) { spr->bitmapBits = va + 2; spr->xPos = va[0]; spr->yPos = va[1]; - _spritesListNextPtr = spr->nextPtr; + _spritesNextPtr = spr->nextPtr; spr->num = ptr->flags2; const int index = spr->num & 0x1F; - spr->nextPtr = _spriteListPtrTable[index]; - _spriteListPtrTable[index] = spr; + spr->nextPtr = _typeSpritesList[index]; + _typeSpritesList[index] = spr; } } ptr->objectUpdateType = 1; @@ -2327,16 +2346,16 @@ LvlObject *Game::updateAnimatedLvlObjectType1(LvlObject *ptr) { ptr->currentSound = 0xFFFF; } uint8_t *data = (uint8_t *)getLvlObjectDataPtr(ptr, kObjectDataTypeLvlBackgroundSound); - Sprite *spr = _spritesListNextPtr; + Sprite *spr = _spritesNextPtr; if (spr && READ_LE_UINT16(data + 2) > 8) { spr->bitmapBits = data + 2; spr->xPos = data[0]; spr->yPos = data[1]; - _spritesListNextPtr = spr->nextPtr; + _spritesNextPtr = spr->nextPtr; spr->num = ptr->flags2; const int index = spr->num & 0x1F; - spr->nextPtr = _spriteListPtrTable[index]; - _spriteListPtrTable[index] = spr; + spr->nextPtr = _typeSpritesList[index]; + _typeSpritesList[index] = spr; } } } @@ -2381,16 +2400,16 @@ LvlObject *Game::updateAnimatedLvlObjectType2(LvlObject *ptr) { int vd = (ptr->flags1 >> 4) & 0xFF; int vc = (ash->flags1 >> 4) & 0xFF; vc = (((vc ^ vd) & 3) << 14) | ptr->flags2; - Sprite *spr = _spritesListNextPtr; + Sprite *spr = _spritesNextPtr; if (spr && READ_LE_UINT16(vf) > 8) { spr->yPos = ptr->yPos; spr->xPos = ptr->xPos; spr->bitmapBits = vf; spr->num = vc; const int index = spr->num & 0x1F; - _spritesListNextPtr = spr->nextPtr; - spr->nextPtr = _spriteListPtrTable[index]; - _spriteListPtrTable[index] = spr; + _spritesNextPtr = spr->nextPtr; + spr->nextPtr = _typeSpritesList[index]; + _typeSpritesList[index] = spr; } } if (ptr->spriteNum <= 15 || ptr->dataPtr == 0) { @@ -2464,8 +2483,8 @@ void Game::updateAnimatedLvlObjectsLeftRightCurrentScreens() { ptr = ptr->nextPtr; } } - int index = _res->_screensGrid[_res->_currentScreenResourceNum * 4 + kPosRightScreen]; - if (index != 0xFF && _res->_screensState[index].s2 != 0) { + int index = _res->_screensGrid[_res->_currentScreenResourceNum][kPosRightScreen]; + if (index != kNoScreen && _res->_screensState[index].s2 != 0) { ptr = _screenLvlObjectsList[index]; while (ptr) { if (ptr->screenState == 0xFF || ptr->screenState == _res->_screensState[index].s0) { @@ -2475,8 +2494,8 @@ void Game::updateAnimatedLvlObjectsLeftRightCurrentScreens() { } } } - index = _res->_screensGrid[_res->_currentScreenResourceNum * 4 + kPosLeftScreen]; - if (index != 0xFF && _res->_screensState[index].s2 != 0) { + index = _res->_screensGrid[_res->_currentScreenResourceNum][kPosLeftScreen]; + if (index != kNoScreen && _res->_screensState[index].s2 != 0) { ptr = _screenLvlObjectsList[index]; while (ptr) { if (ptr->screenState == 0xFF || ptr->screenState == _res->_screensState[index].s0) { @@ -2628,8 +2647,8 @@ void Game::updateInput() { } void Game::levelMainLoop() { - memset(_spriteListPtrTable, 0, sizeof(_spriteListPtrTable)); - _spritesListNextPtr = &_spritesTable[0]; + memset(_typeSpritesList, 0, sizeof(_typeSpritesList)); + _spritesNextPtr = &_spritesTable[0]; for (int i = 0; i < kMaxSprites - 1; ++i) { _spritesTable[i].nextPtr = &_spritesTable[i + 1]; } @@ -2647,10 +2666,10 @@ void Game::levelMainLoop() { restartLevel(); } else { callLevel_postScreenUpdate(_res->_currentScreenResourceNum); - if (_currentLeftScreen != 0xFF) { + if (_currentLeftScreen != kNoScreen) { callLevel_postScreenUpdate(_currentLeftScreen); } - if (_currentRightScreen != 0xFF) { + if (_currentRightScreen != kNoScreen) { callLevel_postScreenUpdate(_currentRightScreen); } } @@ -2676,7 +2695,7 @@ void Game::levelMainLoop() { } } if (_res->_sssHdr.infosDataCount != 0) { - // original code appears to have a dedicated thread for sound, that main thread/loop signals + // sound thread signaling } if (_video->_paletteNeedRefresh) { _video->_paletteNeedRefresh = false; @@ -3220,12 +3239,12 @@ void Game::setupSpecialPowers(LvlObject *ptr) { if (!vf->shootLvlObject) { LvlObject *vd = declareLvlObject(8, 3); vf->shootLvlObject = vd; - vd->dataPtr = _shootLvlObjectDataList; - if (_shootLvlObjectDataList) { - _shootLvlObjectDataList = _shootLvlObjectDataList->nextPtr; + vd->dataPtr = _shootLvlObjectDataNextPtr; + if (_shootLvlObjectDataNextPtr) { + _shootLvlObjectDataNextPtr = _shootLvlObjectDataNextPtr->nextPtr; memset(vd->dataPtr, 0, sizeof(ShootLvlObjectData)); } else { - warning("Nothing free in _shootLvlObjectDataList"); + warning("Nothing free in _shootLvlObjectDataNextPtr"); } vd->xPos = ptr->xPos; vd->yPos = ptr->yPos; @@ -3267,12 +3286,12 @@ void Game::setupSpecialPowers(LvlObject *ptr) { if (!vf->shootLvlObject) { LvlObject *vd = declareLvlObject(8, 3); vf->shootLvlObject = vd; - vd->dataPtr = _shootLvlObjectDataList; - if (_shootLvlObjectDataList) { - _shootLvlObjectDataList = _shootLvlObjectDataList->nextPtr; + vd->dataPtr = _shootLvlObjectDataNextPtr; + if (_shootLvlObjectDataNextPtr) { + _shootLvlObjectDataNextPtr = _shootLvlObjectDataNextPtr->nextPtr; memset(vd->dataPtr, 0, sizeof(ShootLvlObjectData)); } else { - warning("Nothing free in _shootLvlObjectDataList"); + warning("Nothing free in _shootLvlObjectDataNextPtr"); } vd->xPos = ptr->xPos; vd->yPos = ptr->yPos; @@ -3307,12 +3326,12 @@ void Game::setupSpecialPowers(LvlObject *ptr) { if (!vf->shootLvlObject) { LvlObject *vd = declareLvlObject(8, 3); vf->shootLvlObject = vd; - vd->dataPtr = _shootLvlObjectDataList; - if (_shootLvlObjectDataList) { - _shootLvlObjectDataList = _shootLvlObjectDataList->nextPtr; + vd->dataPtr = _shootLvlObjectDataNextPtr; + if (_shootLvlObjectDataNextPtr) { + _shootLvlObjectDataNextPtr = _shootLvlObjectDataNextPtr->nextPtr; memset(vd->dataPtr, 0, sizeof(ShootLvlObjectData)); } else { - warning("Nothing free in _shootLvlObjectDataList"); + warning("Nothing free in _shootLvlObjectDataNextPtr"); } vd->xPos = ptr->xPos; vd->yPos = ptr->yPos; @@ -3504,10 +3523,10 @@ int Game::lvlObjectType7Callback(LvlObject *ptr) { o->anim = 12; } o->frame = 0; - if (dat->xPosShoot >= 256) { + if (dat->xPosShoot >= Video::W) { dat->xPosShoot -= _res->_screensBasePos[ptr->screenNum].u; } - if (dat->yPosShoot >= 192) { + if (dat->yPosShoot >= Video::H) { dat->yPosShoot -= _res->_screensBasePos[ptr->screenNum].v; } setupLvlObjectBitmap(o); @@ -3521,10 +3540,10 @@ int Game::lvlObjectType7Callback(LvlObject *ptr) { ptr->anim = 3; } ptr->frame = 0; - if (dat->xPosShoot >= 256) { + if (dat->xPosShoot >= Video::W) { dat->xPosShoot -= _res->_screensBasePos[ptr->screenNum].u; } - if (dat->yPosShoot >= 192) { + if (dat->yPosShoot >= Video::H) { dat->yPosShoot -= _res->_screensBasePos[ptr->screenNum].v; } setupLvlObjectBitmap(ptr); @@ -3645,9 +3664,9 @@ int Game::lvlObjectList3Callback(LvlObject *o) { } if (o->type == 8) { _res->decLvlSpriteDataRefCounter(o); - o->nextPtr = _declaredLvlObjectsListHead; + o->nextPtr = _declaredLvlObjectsNextPtr; --_declaredLvlObjectsListCount; - _declaredLvlObjectsListHead = o; + _declaredLvlObjectsNextPtr = o; switch (o->spriteNum) { case 0: case 2: @@ -3681,8 +3700,73 @@ int Game::lvlObjectList3Callback(LvlObject *o) { } void Game::lvlObjectSpecialPowersCallbackHelper1(LvlObject *o) { - warning("lvlObjectSpecialPowersCallbackHelper1 unimplemented"); - // TODO + int xPos = o->xPos + o->posTable[3].x; + int yPos = o->yPos + o->posTable[3].y; + ShootLvlObjectData *dat = (ShootLvlObjectData *)getLvlObjectDataPtr(o, kObjectDataTypeShoot); + const uint8_t val = dat->unk3; + if (val == 0x80) { + dat->xPosShoot = xPos; + dat->yPosShoot = yPos; + } + uint8_t screenNum = o->screenNum; + if (xPos < 0) { + xPos += Video::W; + screenNum = _res->_screensGrid[screenNum][kPosLeftScreen]; + } else if (xPos >= Video::W) { + xPos -= Video::W; + screenNum = _res->_screensGrid[screenNum][kPosRightScreen]; + } + if (screenNum != kNoScreen && yPos < 0) { + yPos += Video::H; + screenNum = _res->_screensGrid[screenNum][kPosTopScreen]; + } else if (yPos >= Video::H) { + assert(screenNum != kNoScreen); + yPos -= Video::H; + screenNum = _res->_screensGrid[screenNum][kPosBottomScreen]; + } + int8_t dy = 255 - (yPos & 7); + if (screenNum != kNoScreen) { + const int xLevelPos = _res->_screensBasePos[screenNum].u + xPos; + const int yLevelPos = _res->_screensBasePos[screenNum].v + yPos + 8; + int offset = screenMaskOffset(xLevelPos, yLevelPos); + if (_screenMaskBuffer[offset] & 1) { + dy = -8; + goto set_dat03; + } else if (_screenMaskBuffer[offset + 512] & 1) { + const int vg = screenGridOffset(xPos, yPos); + int i = _res->findScreenGridIndex(screenNum); + if (i < 0) { + goto set_dat03; + } + const uint8_t *p = _res->_resLevelData0x470CTablePtrData + (xPos & 7); + dy += (int8_t)p[_screenPosTable[i][vg] * 8]; + goto set_dat03; + } else if (_screenMaskBuffer[offset - 1024] & 1) { + dy -= 16; + goto set_dat03; + } else { + dy = val; + if (val < 0x18) { + dat->unk3 = val + 4; + } + goto set_dxpos; + } + } +set_dat03: + if (val == 0x18) { + dat->unk0 = 6; + } else { + dat->unk3 = 8; + } +set_dxpos: + if (dat->unk0 != 6 && dat->unk3 == 0x80) { + dat->yPosShoot += dy; + setLvlObjectPosRelativeToPoint(o, 3, dat->xPosShoot, dat->yPosShoot); + } else { + dat->unk3 = 0x80; + dat->dxPos = 0; + dat->dyPos = 0; + } } uint8_t Game::lvlObjectSpecialPowersCallbackScreen(LvlObject *o) { @@ -3702,31 +3786,31 @@ uint8_t Game::lvlObjectSpecialPowersCallbackScreen(LvlObject *o) { int var20; int var24 = xPos; if (xPos < 0) { - xPos += 256; - var20 = -256; + xPos += Video::W; + var20 = -Video::W; var24 = xPos; - screenNum = _res->_screensGrid[screenNum * 4 + 3]; - } else if (xPos >= 256) { - xPos -= 256; - var20 = 256; + screenNum = _res->_screensGrid[screenNum][kPosLeftScreen]; + } else if (xPos >= Video::W) { + xPos -= Video::W; + var20 = Video::W; var24 = xPos; - screenNum = _res->_screensGrid[screenNum * 4 + 1]; + screenNum = _res->_screensGrid[screenNum][kPosRightScreen]; } else { var20 = 0; } - if (screenNum != 0xFF && yPos < 0) { - yPos += 192; - var1C = -192; - screenNum = _res->_screensGrid[screenNum * 4 + 0]; - } else if (yPos >= 192) { - assert(screenNum != 0xFF); - yPos -= 192; - var1C = 192; - screenNum = _res->_screensGrid[screenNum * 4 + 2]; + if (screenNum != kNoScreen && yPos < 0) { + yPos += Video::H; + var1C = -Video::H; + screenNum = _res->_screensGrid[screenNum][kPosTopScreen]; + } else if (yPos >= Video::H) { + assert(screenNum != kNoScreen); + yPos -= Video::H; + var1C = Video::H; + screenNum = _res->_screensGrid[screenNum][kPosBottomScreen]; } else { var1C = 0; } - if (screenNum == 0xFF) { + if (screenNum == kNoScreen) { return 0; } uint8_t var2C, _bl; @@ -3818,16 +3902,10 @@ uint8_t Game::lvlObjectSpecialPowersCallbackScreen(LvlObject *o) { if (_bl != 2 && _bl != 4 && _bl != 7) { return var30; } - var2C = 0; - while (_res->_screensGrid[_res->_currentScreenResourceNum * 4 + var2C] != screenNum) { - ++var2C; - if (var2C >= 4) { - if (o->screenNum != _res->_currentScreenResourceNum) { - dat->yPosShoot += 4; - return var30; - } - break; - } + var2C = _res->findScreenGridIndex(screenNum); + if (var2C < 0) { + dat->yPosShoot += 4; + return var30; } const int vc = (o->posTable[3].x + o->xPos) & 7; const uint8_t *p = _res->_resLevelData0x470CTablePtrData + vc; @@ -3886,10 +3964,10 @@ int Game::lvlObjectSpecialPowersCallback(LvlObject *o) { } } else { o->anim = p[0]; - if (dat->xPosShoot >= 256) { + if (dat->xPosShoot >= Video::W) { dat->xPosShoot -= _res->_screensBasePos[o->screenNum].u; } - if (dat->yPosShoot >= 192) { + if (dat->yPosShoot >= Video::H) { dat->yPosShoot -= _res->_screensBasePos[o->screenNum].v; } if (dat->o && (dat->o->actionKeyMask & 7) == 7) { @@ -4041,23 +4119,23 @@ int Game::setLvlObjectPosInScreenGrid(LvlObject *o, int pos) { int numPrev = o->screenNum; int screenNum = o->screenNum; if (x < 0) { - o->screenNum = _res->_screensGrid[screenNum * 4 + kPosLeftScreen]; - o->xPos = xPrev + 256; - } else if (x >= 256) { - o->screenNum = _res->_screensGrid[screenNum * 4 + kPosRightScreen]; - o->xPos = xPrev - 256; + o->screenNum = _res->_screensGrid[screenNum][kPosLeftScreen]; + o->xPos = xPrev + Video::W; + } else if (x >= Video::W) { + o->screenNum = _res->_screensGrid[screenNum][kPosRightScreen]; + o->xPos = xPrev - Video::W; } screenNum = o->screenNum; - if (y < 0 && screenNum != 0xFF) { - o->screenNum = _res->_screensGrid[screenNum * 4 + kPosTopScreen]; - o->yPos = yPrev + 192; - } else if (y >= 192) { - assert(screenNum != 0xFF); - o->screenNum = _res->_screensGrid[screenNum * 4 + kPosBottomScreen]; - o->yPos = yPrev - 192; + if (y < 0 && screenNum != kNoScreen) { + o->screenNum = _res->_screensGrid[screenNum][kPosTopScreen]; + o->yPos = yPrev + Video::H; + } else if (y >= Video::H) { + assert(screenNum != kNoScreen); + o->screenNum = _res->_screensGrid[screenNum][kPosBottomScreen]; + o->yPos = yPrev - Video::H; } screenNum = o->screenNum; - if (screenNum == 0xFF) { + if (screenNum == kNoScreen) { o->xPos = xPrev; o->yPos = yPrev; o->screenNum = numPrev; @@ -4072,9 +4150,9 @@ 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(_declaredLvlObjectsListHead); - LvlObject *ptr = _declaredLvlObjectsListHead; - _declaredLvlObjectsListHead = _declaredLvlObjectsListHead->nextPtr; + assert(_declaredLvlObjectsNextPtr); + LvlObject *ptr = _declaredLvlObjectsNextPtr; + _declaredLvlObjectsNextPtr = _declaredLvlObjectsNextPtr->nextPtr; assert(ptr); ++_declaredLvlObjectsListCount; ptr->spriteNum = num; @@ -4099,7 +4177,7 @@ void Game::clearDeclaredLvlObjectsList() { _declaredLvlObjectsList[i].nextPtr = &_declaredLvlObjectsList[i + 1]; } _declaredLvlObjectsList[kMaxLvlObjects - 1].nextPtr = 0; - _declaredLvlObjectsListHead = &_declaredLvlObjectsList[0]; + _declaredLvlObjectsNextPtr = &_declaredLvlObjectsList[0]; _declaredLvlObjectsListCount = 0; } @@ -4225,17 +4303,153 @@ void Game::setLavaAndyAnimation(int yPos) { } } -void Game::updateSwitchesLar(int count, uint8_t *switchesData, BoundingBox *r) { +void Game::updateGatesLar(LvlObject *o, uint8_t *p, int num) { + uint32_t mask = 1 << num; // ve + uint8_t _cl = p[0] & 15; + if (_cl >= 3) { + if ((o->flags0 & 0x1F) == 0) { + if (p[3] == 0) { + if (_cl == 3) { + p[0] = (p[0] & ~0xB) | 4; + p[3] = p[1]; + o->directionKeyMask = 1; + o->actionKeyMask = 0; + } else { + p[0] = (p[0] & ~0xC) | 3; + p[3] = p[2]; + o->directionKeyMask = 4; + o->actionKeyMask = 0; + } + } else { + --p[3]; + o->directionKeyMask = 0; + o->actionKeyMask = 0; + } + } + } else { + num = p[1]; + if ((p[1] | p[2]) != 0) { + uint8_t _dl = p[0] >> 4; + if (_cl != _dl) { + uint8_t _al = (p[0] & 0xF0) | _dl; + p[0] = _al; + if (_al & 0xF0) { + p[3] = p[1]; + } else { + p[3] = p[2]; + } + } + if (p[3] == 0) { + if (p[0] & 0xF) { + o->directionKeyMask = 1; + _mstAndyVarMask &= ~mask; + } else { + o->directionKeyMask = 4; + _mstAndyVarMask |= mask; + } + _mstLevelGatesMask |= mask; + } else { + --p[3]; + o->actionKeyMask = 0; + o->directionKeyMask = 0; + } + } else { + uint8_t _dl = p[0] >> 4; + if (_cl != _dl) { + if (p[3] != 0) { + --p[3]; + } else { + uint8_t _al = (p[0] & 0xF0) | _dl; + p[0] = _al; + if (_al & 0xF0) { + o->directionKeyMask = 1; + _mstAndyVarMask &= ~mask; + } else { + o->directionKeyMask = 4; + _mstAndyVarMask |= mask; + } + _mstLevelGatesMask |= mask; + if (o->screenNum != _currentScreen && o->screenNum != _currentLeftScreen && o->screenNum != _currentRightScreen) { + o->actionKeyMask = 1; + } else { + o->actionKeyMask = 0; + } + } + } + } + } + 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 + if (x1 < 0) { + x1 = 0; + } + if (y1 < 0) { + y1 = 0; + } + uint32_t offset = screenMaskOffset(_res->_screensBasePos[o->screenNum].u + x1, _res->_screensBasePos[o->screenNum].v + y1); + if (h1 < 0) { + h1 = -h1; + for (int i = 0; i < h1 / 8; ++i) { + memset(_screenMaskBuffer + offset, 0, 4); + offset += 512; + } + } else { + for (int i = 0; i < h1 / 8; ++i) { + memset(_screenMaskBuffer + offset, 2, 4); + offset += 512; + } + } + if (o->screenNum == _currentScreen || (o->screenNum == _currentRightScreen && _res->_resLevelData0x2B88SizeTable[_currentRightScreen] != 0) || (o->screenNum == _currentLeftScreen && _res->_resLevelData0x2B88SizeTable[_currentLeftScreen] != 0)) { + if (o->levelData0x2988) { + 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 + if (x2 < 0) { + x2 = 0; + } + if (y2 < 0) { + y2 = 0; + } + offset = screenMaskOffset(_res->_screensBasePos[o->screenNum].u + x2, _res->_screensBasePos[o->screenNum].v + y2); + if (h2 < 0) { + h2 = -h2; + for (int i = 0; i < h2 / 8; ++i) { + memset(_screenMaskBuffer + offset, 0, 4); + offset += 512; + } + } else { + for (int i = 0; i < h2 / 8; ++i) { + memset(_screenMaskBuffer + offset, 2, 4); + offset += 512; + } + } + // gate closing on Andy + if (o->screenNum == _res->_currentScreenResourceNum && o->directionKeyMask == 4) { + if ((o->flags0 & 0x1F) == 1 && (o->flags0 & 0xE0) == 0x40) { + if (!_hideAndyObjectFlag && (_mstFlags & 0x80000000) == 0) { + if (clipLvlObjectsBoundingBox(_andyObject, o, 132)) { + setAndySpecialAnimation(0xA1); + } + } + } + } +} + +void Game::updateSwitchesLar(int count, uint8_t *switchesData, BoundingBox *switchesBoundingBox, uint8_t *gatesData) { for (int i = 0; i < count; ++i) { switchesData[i * 4 + 1] &= ~0x40; } for (int i = 0; i < count; ++i) { if (_andyObject->screenNum == switchesData[i * 4]) { if ((switchesData[i * 4 + 1] & 0x10) == 0x10) { // can be actioned by a spectre - updateSwitchesLar_checkSpectre(i, &switchesData[i * 4], &r[i]); + updateSwitchesLar_checkSpectre(i, &switchesData[i * 4], &switchesBoundingBox[i], gatesData); } AndyLvlObjectData *data = (AndyLvlObjectData *)getLvlObjectDataPtr(_andyObject, kObjectDataTypeAndy); - updateSwitchesLar_checkAndy(i, &switchesData[i * 4], &data->boundingBox, &r[i]); + updateSwitchesLar_checkAndy(i, &switchesData[i * 4], &data->boundingBox, &switchesBoundingBox[i], gatesData); } } for (int i = 0; i < count; ++i) { @@ -4249,7 +4463,7 @@ void Game::updateSwitchesLar(int count, uint8_t *switchesData, BoundingBox *r) { } } -void Game::updateSwitchesLar_checkSpectre(int num, uint8_t *p, BoundingBox *r) { +void Game::updateSwitchesLar_checkSpectre(int num, uint8_t *p, BoundingBox *r, uint8_t *gatesData) { bool found = false; for (LvlObject *o = _lvlObjectsList1; o && !found; o = o->nextPtr) { if (o->screenNum != p[0]) { @@ -4267,153 +4481,119 @@ void Game::updateSwitchesLar_checkSpectre(int num, uint8_t *p, BoundingBox *r) { uint8_t *vf; if ((p[1] & 0x40) == 0 && clipBoundingBox(r, &b)) { found = true; - if ((p[2] & 0x80) == 0 && !updateSwitchesLar_toggle(true, p[2], p[0], num, (p[1] >> 5) & 1)) { + if ((p[2] & 0x80) == 0 && !updateSwitchesLar_toggle(true, p[2], p[0], num, (p[1] >> 5) & 1, r)) { continue; } p[1] |= 0x40; if ((p[1] & 0x8) != 0) { continue; } - if (_currentLevel == kLvl_lar2) { - vf = &Game::_lar2_gatesData[p[3] * 4]; - } else { - vf = &Game::_lar1_gatesData[p[3] * 4]; - } + vf = &gatesData[p[3] * 4]; uint8_t _al = (p[1] >> 1) & 1; uint8_t _bl = (vf[0] >> 4); - if (_bl == _al) { - continue; - } - _bl = (_al << 4) | (vf[0] & 15); - vf[0] = _bl; - uint8_t _cl = (p[1] >> 5) & 1; - if (_cl != 1 || _al != _cl) { - continue; + if (_bl != _al) { + _bl = (_al << 4) | (vf[0] & 15); + vf[0] = _bl; + const uint8_t _cl = (p[1] >> 5) & 1; + if (_cl == 1 && _al == _cl) { + vf[3] = 4; + } } - vf[3] = 4; } else { if ((p[1] & 0xC) == 0 && (p[1] & 0x80) != 0) { - if (_currentLevel == kLvl_lar2) { - vf = &Game::_lar2_gatesData[p[3] * 4]; - } else { - vf = &Game::_lar1_gatesData[p[3] * 4]; - } + vf = &gatesData[p[3] * 4]; uint8_t _al = ((~p[1]) >> 1) & 1; uint8_t _bl = (vf[0] >> 4); - if (_bl == _al) { - continue; - } - _bl = (_al << 4) | (vf[0] & 15); - vf[0] = _bl; - uint8_t _cl = (p[1] >> 5) & 1; - if (_cl != 1 || _al != _cl) { - continue; + if (_bl != _al) { + _bl = (_al << 4) | (vf[0] & 15); + vf[0] = _bl; + const uint8_t _cl = (p[1] >> 5) & 1; + if (_cl == 1 && _al == _cl) { + vf[3] = 4; + } } - vf[3] = 4; } } } } -int Game::updateSwitchesLar_checkAndy(int num, uint8_t *p, BoundingBox *b1, BoundingBox *b2) { +int Game::updateSwitchesLar_checkAndy(int num, uint8_t *p, BoundingBox *b1, BoundingBox *b2, uint8_t *gatesData) { int ret = 0; //const uint8_t flags = _andyObject->flags0 & 0x1F; - if ((p[1] & 0x40) == 0) { - ret = clipBoundingBox(b1, b2); - if (ret) { - if ((p[1] & 1) == 0) { // switch already actioned - return ret; - } - const int flag = (p[1] >> 5) & 1; - uint8_t _al = clipAndyLvlObjectLar(b1, b2, flag); - _al = updateSwitchesLar_toggle(_al, p[2], p[0], num, flag); - p[1] = ((_al & 1) << 6) | (p[1] & ~0x40); - _al = p[1]; - if ((_al & 0x40) == 0) { - return ret; - } - ret = 1; - if ((_al & 8) != 0) { - if (_al & 2) { - _al = p[3]; - } else { - _al = -p[3]; - } - int _bl, i; - if (_al < 0) { - i = (-_al) * 6; - updateScreenMaskLar(&_lar1_maskData[i], 0); - _bl = 5; - } else { - i = _al * 6; - updateScreenMaskLar(&_lar1_maskData[i], 1); - _bl = 2; - } - LvlObject *o = findLvlObject2(0, _lar1_maskData[i + 5], _lar1_maskData[i + 4]); - if (o) { - o->objectUpdateType = _bl; - } - return ret; - } - uint8_t _cl = (_al >> 5) & 1; - _al = (_al >> 1) & 1; - uint8_t *vg; - if (_currentLevel == kLvl_lar2) { - vg = &Game::_lar2_gatesData[p[3] * 4]; + if ((p[1] & 0x40) == 0 && (ret = clipBoundingBox(b1, b2)) != 0) { + if ((p[1] & 1) == 0) { // switch already actioned + return ret; + } + const int flag = (p[1] >> 5) & 1; + uint8_t _al = clipAndyLvlObjectLar(b1, b2, flag); + _al = updateSwitchesLar_toggle(_al, p[2], p[0], num, flag, b2); + _al = ((_al & 1) << 6) | (p[1] & ~0x40); + p[1] = _al; + if ((_al & 0x40) == 0) { + return ret; + } + ret = 1; + if ((_al & 8) != 0) { + if (_al & 2) { + _al = p[3]; } else { - vg = &Game::_lar1_gatesData[p[3] * 4]; + _al = -p[3]; } - uint8_t _dl = vg[0]; - uint8_t _bl = _dl >> 4; - if (_bl == _al) { - return ret; + int _bl, i; + if (_al < 0) { + i = (-_al) * 6; + updateScreenMaskLar(&_lar1_maskData[i], 0); + _bl = 5; + } else { + i = _al * 6; + updateScreenMaskLar(&_lar1_maskData[i], 1); + _bl = 2; } - _bl = (_al << 4) | (_dl & 15); - vg[0] = _bl; - if (_cl != 1 || _al != _cl) { - return ret; + LvlObject *o = findLvlObject2(0, _lar1_maskData[i + 5], _lar1_maskData[i + 4]); + if (o) { + o->objectUpdateType = _bl; } - vg[3] = 4; return ret; } + const uint8_t _cl = (_al >> 5) & 1; + _al = (_al >> 1) & 1; + p = &gatesData[p[3] * 4]; + uint8_t _bl = p[0] >> 4; + if (_bl != _al) { + _bl = (_al << 4) | (p[0] & 0xF); + p[0] = _bl; + if (_cl == 1 && _al == _cl) { + p[3] = 4; + } + } + return ret; } if ((p[1] & 0xC) == 0 && (p[1] & 0x80) != 0) { - if (_currentLevel == kLvl_lar2) { - p = &Game::_lar2_gatesData[p[3] * 4]; - } else { - p = &Game::_lar1_gatesData[p[3] * 4]; - } + p = &gatesData[p[3] * 4]; + const uint8_t _cl = (p[1] >> 5) & 1; uint8_t _al = ((~p[1]) >> 1) & 1; - uint8_t _cl = (p[1] >> 5) & 1; + uint8_t _bl = p[0] >> 4; - if (_bl == _al) { - return ret; - } - _bl = (_al << 4) | (p[0] & 0xF); - p[0] = _bl; - if (_cl != 1 || _al != _cl) { - return ret; + if (_bl != _al) { + _bl = (_al << 4) | (p[0] & 0xF); + p[0] = _bl; + if (_cl == 1 && _al == _cl) { + p[3] = 4; + } } - p[3] = 4; } return ret; } -int Game::updateSwitchesLar_toggle(bool flag, uint8_t dataNum, int screenNum, int boxNum, int anim) { +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 if ((dataNum & 0x80) == 0) { - BoundingBox *box; - if (_currentLevel == kLvl_lar2) { - box = &Game::_lar2_bboxData[boxNum]; - } else { - box = &Game::_lar1_bboxData[boxNum]; - } const int dy = box->y2 - box->y1; const int dx = box->x2 - box->x1; if (dx >= dy) { - ret = 0; + ret = 1; } else { const uint8_t _dl = ((_andyObject->flags1) >> 4) & 3; if (anim != _dl) { @@ -4433,7 +4613,7 @@ int Game::updateSwitchesLar_toggle(bool flag, uint8_t dataNum, int screenNum, in ret = (_andyObject->anim == 224) ? 1 : 0; } if (ret) { - LvlObject *o = findLvlObject(0, dataNum, screenNum); + LvlObject *o = findLvlObject2(0, dataNum, screenNum); if (o) { o->objectUpdateType = 7; } @@ -4519,7 +4699,7 @@ void Game::updateWormHoleSprites() { int xOffset = 0; for (int j = 0; j < 11; ++j) { uint8_t _al = (*flags >> (j * 2)) & 3; - if (_al != 0 && _spritesListNextPtr != 0) { + if (_al != 0 && _spritesNextPtr != 0) { const int xPos = spr->xPos + xOffset + 12; const int yPos = spr->yPos + yOffset + 16; if (rect_contains(spr->rect1_x1, spr->rect1_y1, spr->rect1_x2, spr->rect1_y2, xPos, yPos)) { @@ -4534,15 +4714,15 @@ void Game::updateWormHoleSprites() { tmp.yPos -= 16; } if (READ_LE_UINT16(tmp.bitmapBits) != 8) { - Sprite *spr = _spritesListNextPtr; + Sprite *spr = _spritesNextPtr; spr->xPos = tmp.xPos; spr->yPos = tmp.yPos; spr->bitmapBits = tmp.bitmapBits; spr->num = tmp.flags2 & 0x3FFF; const int index = spr->num & 0x1F; - _spritesListNextPtr = spr->nextPtr; - spr->nextPtr = _spriteListPtrTable[index]; - _spriteListPtrTable[index] = spr; + _spritesNextPtr = spr->nextPtr; + spr->nextPtr = _typeSpritesList[index]; + _typeSpritesList[index] = spr; } } xOffset += 24; diff --git a/game.h b/game.h index 01afba7..5a5dd24 100644 --- a/game.h +++ b/game.h @@ -83,10 +83,6 @@ struct Game { static const uint8_t _lar1_spritesData[]; static const int16_t *_lar_screenMaskOffsets[]; static uint8_t _lar1_maskData[]; - static uint8_t _lar1_gatesData[]; - static uint8_t _lar2_gatesData[]; - static BoundingBox _lar1_bboxData[]; - static BoundingBox _lar2_bboxData[]; Level *_level; Mixer _mix; @@ -111,8 +107,8 @@ struct Game { int _currentLevelCheckpoint; bool _endLevel; Sprite _spritesTable[kMaxSprites]; - Sprite *_spritesListNextPtr; // pointer to the next free entry - Sprite *_spriteListPtrTable[kMaxSpriteTypes]; + Sprite *_spritesNextPtr; // pointer to the next free entry + Sprite *_typeSpritesList[kMaxSpriteTypes]; uint8_t _directionKeyMask; uint8_t _actionKeyMask; uint8_t _currentRightScreen; @@ -122,7 +118,7 @@ struct Game { bool _fadePalette; bool _hideAndyObjectFlag; ShootLvlObjectData _shootLvlObjectDataTable[kMaxShootLvlObjectData]; - ShootLvlObjectData *_shootLvlObjectDataList; // pointer to the next free entry + ShootLvlObjectData *_shootLvlObjectDataNextPtr; // pointer to the next free entry LvlObject *_lvlObjectsList0; LvlObject *_lvlObjectsList1; LvlObject *_lvlObjectsList2; @@ -182,7 +178,7 @@ struct Game { uint8_t _mstOp54Table[32]; bool _mstDisabled; LvlObject _declaredLvlObjectsList[kMaxLvlObjects]; - LvlObject *_declaredLvlObjectsListHead; // pointer to the next free entry + LvlObject *_declaredLvlObjectsNextPtr; // pointer to the next free entry int _declaredLvlObjectsListCount; AndyLvlObjectData _andyObjectScreenData; AnimBackgroundData _animBackgroundDataTable[kMaxBackgroundAnims]; @@ -275,7 +271,7 @@ struct Game { void destroyLvlObject(LvlObject *o); void setupPlasmaCannonPoints(LvlObject *ptr); int testPlasmaCannonPointsDirection(int x1, int y1, int x2, int y2); - void preloadLevelScreenData(int num, int prev); + void preloadLevelScreenData(uint8_t num, uint8_t prev); void loadLevelScreenSounds(int num); void setLvlObjectPosRelativeToObject(LvlObject *ptr1, int num1, LvlObject *ptr2, int num2); void setLvlObjectPosRelativeToPoint(LvlObject *ptr, int num, int x, int y); @@ -360,10 +356,11 @@ struct Game { LvlObject *findLvlObjectType2(int spriteNum, int screenNum); LvlObject *findLvlObjectBoundingBox(BoundingBox *box); void setLavaAndyAnimation(int yPos); - void updateSwitchesLar(int count, uint8_t *data, BoundingBox *r); - void updateSwitchesLar_checkSpectre(int num, uint8_t *p1, BoundingBox *r); - int updateSwitchesLar_checkAndy(int num, uint8_t *p1, BoundingBox *b, BoundingBox *r); - int updateSwitchesLar_toggle(bool flag, uint8_t dataNum, int screenNum, int boxNum, int anim); + void updateGatesLar(LvlObject *o, uint8_t *p, int num); + void updateSwitchesLar(int count, uint8_t *data, BoundingBox *r, uint8_t *gatesData); + void updateSwitchesLar_checkSpectre(int num, uint8_t *p1, BoundingBox *r, uint8_t *gatesData); + int updateSwitchesLar_checkAndy(int num, uint8_t *p1, BoundingBox *b, BoundingBox *r, uint8_t *gatesData); + int updateSwitchesLar_toggle(bool flag, uint8_t dataNum, int screenNum, int switchNum, int anim, const BoundingBox *switchBoundingBox); void updateScreenMaskLar(uint8_t *p, uint8_t flag); int clipAndyLvlObjectLar(BoundingBox *a, BoundingBox *b, bool flag); void resetWormHoleSprites(); @@ -381,9 +378,6 @@ struct Game { int objectUpdate_rock_case3(LvlObject *o); int objectUpdate_rock_case4(LvlObject *o); - // level7_lar1.cpp - void updateGatesLar(LvlObject *o, uint8_t *p, int num); - // monsters.cpp void mstMonster1ResetData(MonsterObject1 *m); void mstMonster1ResetWalkPath(MonsterObject1 *m); @@ -395,7 +389,7 @@ struct Game { void mstMonster1SetScreenPosition(MonsterObject1 *m); bool mstMonster1SetWalkingBounds(MonsterObject1 *m); bool mstMonster1UpdateWalkPath(MonsterObject1 *m); - void initMonsterObject2_firefly(MonsterObject2 *m); + void mstMonster2InitFirefly(MonsterObject2 *m); void mstMonster2ResetData(MonsterObject2 *m); uint32_t mstMonster1GetNextWalkCode(MonsterObject1 *m); int mstTaskSetNextWalkCode(Task *t); @@ -408,7 +402,7 @@ struct Game { void mstTaskSetMonster2ScreenPosition(Task *t); int getMstDistance(int y, const AndyShootData *p) const; void mstTaskUpdateScreenPosition(Task *t); - void shuffleMstUnk43(MstUnk43 *p); + void shuffleMstMonsterActionIndex(MstMonsterActionIndex *p); void initMstCode(); void resetMstCode(); diff --git a/intern.h b/intern.h index ebb9e4b..7e396c5 100644 --- a/intern.h +++ b/intern.h @@ -81,13 +81,7 @@ inline T ABS(T t) { template inline T CLIP(T t, T tmin, T tmax) { - if (t < tmin) { - return tmin; - } else if (t > tmax) { - return tmax; - } else { - return t; - } + return (t < tmin ? tmin : (t > tmax ? tmax : t)); } template diff --git a/level3_pwr1.cpp b/level3_pwr1.cpp index a30abbf..c7efc80 100644 --- a/level3_pwr1.cpp +++ b/level3_pwr1.cpp @@ -238,6 +238,7 @@ void Level_pwr1::postScreenUpdate_pwr1_screen23() { case 2: ++_screenCounterTable[23]; if (_screenCounterTable[23] == 26) { + _res->_screensState[23].s0 = 1; _res->_resLvlScreenBackgroundDataTable[23].currentMaskId = 1; _res->_resLvlScreenBackgroundDataTable[23].currentBackgroundId = 1; _g->setupScreenMask(23); @@ -261,15 +262,18 @@ void Level_pwr1::postScreenUpdate_pwr1_screen23() { } void Level_pwr1::postScreenUpdate_pwr1_screen27() { - if (_res->_screensState[27].s0 != 0) { + switch (_res->_screensState[27].s0) { + case 2: ++_screenCounterTable[27]; if (_screenCounterTable[27] == 37) { + _res->_screensState[27].s0 = 1; _res->_resLvlScreenBackgroundDataTable[27].currentMaskId = 1; _res->_resLvlScreenBackgroundDataTable[27].currentBackgroundId = 1; _g->setupScreenMask(27); } - } else if (_res->_currentScreenResourceNum == 27) { - if ((_andyObject->flags0 & 0x1F) == 6) { + break; + case 0: + if (_res->_currentScreenResourceNum == 27 && (_andyObject->flags0 & 0x1F) == 6) { BoundingBox b1; b1.x1 = _andyObject->xPos + _andyObject->posTable[7].x - 3; b1.x2 = _andyObject->xPos + _andyObject->posTable[7].x + 4; @@ -283,6 +287,7 @@ void Level_pwr1::postScreenUpdate_pwr1_screen27() { } } } + break; } } @@ -406,7 +411,7 @@ void Level_pwr1::preScreenUpdate_pwr1_screen23() { void Level_pwr1::preScreenUpdate_pwr1_screen24() { if (_res->_currentScreenResourceNum == 24) { - if (_res->_screensState[27].s0 != 0) { // +0x6C + if (_res->_screensState[27].s0 != 0) { if (_checkpoint == 6) { _checkpoint = 7; } diff --git a/level4_isld.cpp b/level4_isld.cpp index d0b6f31..ddba328 100644 --- a/level4_isld.cpp +++ b/level4_isld.cpp @@ -412,7 +412,7 @@ void Level_isld::tick() { void Level_isld::terminate() { if (!_paf->_skipCutscenes) { - // original calls preload()... + // bugfix: original calls preload() _paf->unload(kPafAnimation_IslandAndyFalling); } } diff --git a/level5_lava.cpp b/level5_lava.cpp index 25e8dd1..5c0a503 100644 --- a/level5_lava.cpp +++ b/level5_lava.cpp @@ -146,8 +146,8 @@ void Level_lava::postScreenUpdate_lava_screen2_addLvlObjects(const uint8_t *p) { do { LvlObject *ptr = 0; if (_g->_declaredLvlObjectsListCount < Game::kMaxLvlObjects) { - ptr = _g->_declaredLvlObjectsListHead; - _g->_declaredLvlObjectsListHead = _g->_declaredLvlObjectsListHead->nextPtr; + ptr = _g->_declaredLvlObjectsNextPtr; + _g->_declaredLvlObjectsNextPtr = _g->_declaredLvlObjectsNextPtr->nextPtr; ++_g->_declaredLvlObjectsListCount; ptr->spriteNum = 22; ptr->type = 8; diff --git a/level7_lar1.cpp b/level7_lar1.cpp index 41acdf0..2430682 100644 --- a/level7_lar1.cpp +++ b/level7_lar1.cpp @@ -78,14 +78,14 @@ Level *Level_lar1_create() { return new Level_lar1; } -uint8_t Game::_lar1_gatesData[13 * 4] = { +static uint8_t _lar1_gatesData[13 * 4] = { 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x32, 0x09, 0x02, 0x00, 0x32, 0x0E, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }; -BoundingBox Game::_lar1_bboxData[24] = { +static BoundingBox _lar1_switchesBbox[24] = { { 203, 162, 213, 166 }, { 68, 86, 78, 90 }, { 195, 58, 205, 62 }, @@ -112,7 +112,7 @@ BoundingBox Game::_lar1_bboxData[24] = { { 32, 145, 44, 173 } }; -static uint8_t _lar1_switchesData[24 * 4] = { +static uint8_t _lar1_switchesData[24 * 4] = { // screenNum,state,spriteNum,gateNum 0x04, 0x07, 0x01, 0x00, 0x05, 0x01, 0x01, 0x01, 0x08, 0x0F, 0x02, 0x00, 0x08, 0x07, 0x03, 0x04, 0x08, 0x07, 0xFF, 0x05, 0x08, 0x07, 0x04, 0x04, 0x09, 0x27, 0xFF, 0x06, 0x09, 0x29, 0x03, 0x02, 0x09, 0x29, 0xFF, 0x03, 0x09, 0x29, 0xFF, 0x04, 0x0A, 0x0B, 0x04, 0x02, 0x0A, 0x0B, 0xFF, 0x03, @@ -139,142 +139,6 @@ static void setLvlObjectUpdateType3_lar1(Game *g, int screenNum) { } } -void Game::updateGatesLar(LvlObject *o, uint8_t *p, int num) { - uint32_t mask = 1 << num; // ve - uint8_t _cl = p[0] & 15; - if (_cl >= 3) { - if ((o->flags0 & 0x1F) == 0) { - if (p[3] == 0) { - if (_cl == 3) { - p[0] = (p[0] & ~0xB) | 4; - p[3] = p[1]; - o->directionKeyMask = 1; - o->actionKeyMask = 0; - } else { - p[0] = (p[0] & ~0xC) | 3; - p[3] = p[2]; - o->directionKeyMask = 4; - o->actionKeyMask = 0; - } - } else { - --p[3]; - o->directionKeyMask = 0; - o->actionKeyMask = 0; - } - } - } else { - num = p[1]; - if ((p[1] | p[2]) != 0) { - uint8_t _dl = p[0] >> 4; - if (_cl != _dl) { - uint8_t _al = (p[0] & 0xF0) | _dl; - p[0] = _al; - if (_al & 0xF0) { - p[3] = p[1]; - } else { - p[3] = p[2]; - } - } - if (p[3] == 0) { - if (p[0] & 0xF) { - o->directionKeyMask = 1; - _mstAndyVarMask &= ~mask; - } else { - o->directionKeyMask = 4; - _mstAndyVarMask |= mask; - } - _mstLevelGatesMask |= mask; - } else { - --p[3]; - o->actionKeyMask = 0; - o->directionKeyMask = 0; - } - } else { - uint8_t _dl = p[0] >> 4; - if (_cl != _dl) { - if (p[3] != 0) { - --p[3]; - } else { - uint8_t _al = (p[0] & 0xF0) | _dl; - p[0] = _al; - if (_al & 0xF0) { - o->directionKeyMask = 1; - _mstAndyVarMask &= ~mask; - } else { - o->directionKeyMask = 4; - _mstAndyVarMask |= mask; - } - _mstLevelGatesMask |= mask; - if (o->screenNum != _currentScreen && o->screenNum != _currentLeftScreen && o->screenNum != _currentRightScreen) { - o->actionKeyMask = 1; - } else { - o->actionKeyMask = 0; - } - } - } - } - } - 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 - if (x1 < 0) { - x1 = 0; - } - if (y1 < 0) { - y1 = 0; - } - uint32_t offset = screenMaskOffset(_res->_screensBasePos[o->screenNum].u + x1, _res->_screensBasePos[o->screenNum].v + y1); - if (h1 < 0) { - h1 = -h1; - for (int i = 0; i < h1 / 8; ++i) { - memset(_screenMaskBuffer + offset, 0, 4); - offset += 512; - } - } else { - for (int i = 0; i < h1 / 8; ++i) { - memset(_screenMaskBuffer + offset, 2, 4); - offset += 512; - } - } - if (o->screenNum == _currentScreen || (o->screenNum == _currentRightScreen && _res->_resLevelData0x2B88SizeTable[_currentRightScreen] != 0) || (o->screenNum == _currentLeftScreen && _res->_resLevelData0x2B88SizeTable[_currentLeftScreen] != 0)) { - if (o->levelData0x2988) { - 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 - if (x2 < 0) { - x2 = 0; - } - if (y2 < 0) { - y2 = 0; - } - offset = screenMaskOffset(_res->_screensBasePos[o->screenNum].u + x2, _res->_screensBasePos[o->screenNum].v + y2); - if (h2 < 0) { - h2 = -h2; - for (int i = 0; i < h2 / 8; ++i) { - memset(_screenMaskBuffer + offset, 0, 4); - offset += 512; - } - } else { - for (int i = 0; i < h2 / 8; ++i) { - memset(_screenMaskBuffer + offset, 2, 4); - offset += 512; - } - } - // gate closing on Andy - if (o->screenNum == _res->_currentScreenResourceNum && o->directionKeyMask == 4) { - if ((o->flags0 & 0x1F) == 1 && (o->flags0 & 0xE0) == 0x40) { - if (!_hideAndyObjectFlag && (_mstFlags & 0x80000000) == 0) { - if (clipLvlObjectsBoundingBox(_andyObject, o, 132)) { - setAndySpecialAnimation(0xA1); - } - } - } - } -} - void Level_lar1::postScreenUpdate_lar1_screen0() { switch (_res->_screensState[0].s0) { case 0: @@ -347,24 +211,24 @@ void Level_lar1::postScreenUpdate_lar1_screen3() { void Level_lar1::postScreenUpdate_lar1_screen4() { LvlObject *o = _g->findLvlObject(2, 0, 4); - _g->updateGatesLar(o, &Game::_lar1_gatesData[0 * 4], 0); + _g->updateGatesLar(o, &_lar1_gatesData[0 * 4], 0); } void Level_lar1::postScreenUpdate_lar1_screen5() { LvlObject *o1 = _g->findLvlObject(2, 0, 5); - _g->updateGatesLar(o1, &Game::_lar1_gatesData[1 * 4], 1); + _g->updateGatesLar(o1, &_lar1_gatesData[1 * 4], 1); LvlObject *o2 = _g->findLvlObject(2, 1, 5); - _g->updateGatesLar(o2, &Game::_lar1_gatesData[2 * 4], 2); + _g->updateGatesLar(o2, &_lar1_gatesData[2 * 4], 2); LvlObject *o3 = _g->findLvlObject(2, 2, 5); - _g->updateGatesLar(o3, &Game::_lar1_gatesData[3 * 4], 3); + _g->updateGatesLar(o3, &_lar1_gatesData[3 * 4], 3); if (_res->_currentScreenResourceNum == 5) { if (_checkpoint >= 1 && _checkpoint <= 3) { _checkpoint = 2; BoundingBox b = { 194, 0, 255, 88 }; AndyLvlObjectData *data = (AndyLvlObjectData *)_g->getLvlObjectDataPtr(_andyObject, kObjectDataTypeAndy); - if (_g->clipBoundingBox(&b, &data->boundingBox) && (Game::_lar1_gatesData[0x18] & 0xF0) == 0x10) { + if (_g->clipBoundingBox(&b, &data->boundingBox) && (_lar1_gatesData[0x18] & 0xF0) == 0x10) { _checkpoint = 2; - _screenCounterTable[26] = (Game::_lar1_gatesData[0x1C] < 16) ? 1 : 3; + _screenCounterTable[26] = (_lar1_gatesData[0x1C] < 16) ? 1 : 3; } } } @@ -372,18 +236,18 @@ void Level_lar1::postScreenUpdate_lar1_screen5() { void Level_lar1::postScreenUpdate_lar1_screen8() { LvlObject *o1 = _g->findLvlObject(2, 0, 8); - _g->updateGatesLar(o1, &Game::_lar1_gatesData[4 * 4], 4); + _g->updateGatesLar(o1, &_lar1_gatesData[4 * 4], 4); LvlObject *o2 = _g->findLvlObject(2, 1, 8); - _g->updateGatesLar(o2, &Game::_lar1_gatesData[5 * 4], 5); + _g->updateGatesLar(o2, &_lar1_gatesData[5 * 4], 5); if (_res->_currentScreenResourceNum == 8) { if (_checkpoint >= 1 && _checkpoint <= 3) { BoundingBox b = { 104, 0, 255, 80 }; AndyLvlObjectData *data = (AndyLvlObjectData *)_g->getLvlObjectDataPtr(_andyObject, kObjectDataTypeAndy); if (_g->clipBoundingBox(&b, &data->boundingBox)) { _checkpoint = 3; - const int a = (Game::_lar1_gatesData[0x18] & 0xF0) != 0 ? 5 : 4; + const int a = (_lar1_gatesData[0x18] & 0xF0) != 0 ? 5 : 4; _screenCounterTable[26] = a; - if ((Game::_lar1_gatesData[0x1C] & 0xF0) == 0x10) { + if ((_lar1_gatesData[0x1C] & 0xF0) == 0x10) { _screenCounterTable[26] = a + 2; } } @@ -393,7 +257,7 @@ void Level_lar1::postScreenUpdate_lar1_screen8() { void Level_lar1::postScreenUpdate_lar1_screen9() { LvlObject *o = _g->findLvlObject(2, 0, 9); - _g->updateGatesLar(o, &Game::_lar1_gatesData[6 * 4], 6); + _g->updateGatesLar(o, &_lar1_gatesData[6 * 4], 6); } void Level_lar1::postScreenUpdate_lar1_screen12() { @@ -462,7 +326,7 @@ void Level_lar1::postScreenUpdate_lar1_screen12() { void Level_lar1::postScreenUpdate_lar1_screen13() { LvlObject *o = _g->findLvlObject(2, 0, 13); - _g->updateGatesLar(o, &Game::_lar1_gatesData[7 * 4], 7); + _g->updateGatesLar(o, &_lar1_gatesData[7 * 4], 7); } void Level_lar1::postScreenUpdate_lar1_screen14() { @@ -532,24 +396,24 @@ void Level_lar1::postScreenUpdate_lar1_screen14() { } } LvlObject *o = _g->findLvlObject(2, 0, 14); - _g->updateGatesLar(o, &Game::_lar1_gatesData[8 * 4], 8); + _g->updateGatesLar(o, &_lar1_gatesData[8 * 4], 8); } void Level_lar1::postScreenUpdate_lar1_screen15() { LvlObject *o = _g->findLvlObject(2, 0, 15); - _g->updateGatesLar(o, &Game::_lar1_gatesData[9 * 4], 9); + _g->updateGatesLar(o, &_lar1_gatesData[9 * 4], 9); } void Level_lar1::postScreenUpdate_lar1_screen16() { LvlObject *o = _g->findLvlObject(2, 0, 16); - _g->updateGatesLar(o, &Game::_lar1_gatesData[10 * 4], 10); + _g->updateGatesLar(o, &_lar1_gatesData[10 * 4], 10); } void Level_lar1::postScreenUpdate_lar1_screen18() { LvlObject *o1 = _g->findLvlObject(2, 0, 18); - _g->updateGatesLar(o1, &Game::_lar1_gatesData[11 * 4], 11); + _g->updateGatesLar(o1, &_lar1_gatesData[11 * 4], 11); LvlObject *o2 = _g->findLvlObject(2, 1, 18); - _g->updateGatesLar(o2, &Game::_lar1_gatesData[12 * 4], 12); + _g->updateGatesLar(o2, &_lar1_gatesData[12 * 4], 12); if ((_lar1_switchesData[0x59] & 0x40) == 0 && (_lar1_switchesData[0x59] & 0x80) != 0) { if ((_lar1_switchesData[0x4D] & 1) == 0) { _lar1_switchesData[0x4D] |= 1; @@ -721,9 +585,9 @@ void Level_lar1::preScreenUpdate_lar1_screen2() { void Level_lar1::preScreenUpdate_lar1_screen6() { if (_res->_currentScreenResourceNum == 6) { if (_checkpoint >= 1 && _checkpoint <= 3) { - if ((Game::_lar1_gatesData[0x18] & 0xF0) == 0) { + if ((_lar1_gatesData[0x18] & 0xF0) == 0) { _checkpoint = 2; - _screenCounterTable[26] = ((Game::_lar1_gatesData[0x1C] & 0xF0) != 0) ? 2 : 0; + _screenCounterTable[26] = ((_lar1_gatesData[0x1C] & 0xF0) != 0) ? 2 : 0; } } } @@ -744,7 +608,7 @@ void Level_lar1::preScreenUpdate_lar1_screen10() { void Level_lar1::preScreenUpdate_lar1_screen11() { if (_res->_currentScreenResourceNum == 11) { if (_checkpoint >= 2 && _checkpoint <= 3) { - if ((Game::_lar1_gatesData[0x1C] & 0xF) == 1 && (Game::_lar1_gatesData[0x18] & 0xF) == 1) { + if ((_lar1_gatesData[0x1C] & 0xF) == 1 && (_lar1_gatesData[0x18] & 0xF) == 1) { _checkpoint = 4; } } @@ -814,8 +678,8 @@ void Level_lar1::preScreenUpdate_lar1_screen17() { void Level_lar1::preScreenUpdate_lar1_screen18() { if (_checkpoint >= 7) { - Game::_lar1_gatesData[0x30] &= 0xF; - Game::_lar1_gatesData[0x30] |= 0x10; + _lar1_gatesData[0x30] &= 0xF; + _lar1_gatesData[0x30] |= 0x10; } if (_res->_currentScreenResourceNum == 18) { setLvlObjectUpdateType3_lar1(_g, 18); @@ -861,8 +725,8 @@ void Level_lar1::preScreenUpdate_lar1_screen23() { if (_res->_currentScreenResourceNum == 23) { setLvlObjectUpdateType3_lar1(_g, 23); if (_g->_plasmaCannonFlags & 2) { - Game::_lar1_gatesData[0x28] &= 0xF; - Game::_lar1_gatesData[0x28] |= 0x10; + _lar1_gatesData[0x28] &= 0xF; + _lar1_gatesData[0x28] |= 0x10; } } } @@ -941,7 +805,7 @@ void Level_lar1::terminate() { } void Level_lar1::tick() { - _g->updateSwitchesLar(24, _lar1_switchesData, Game::_lar1_bboxData); + _g->updateSwitchesLar(24, _lar1_switchesData, _lar1_switchesBbox, _lar1_gatesData); _g->updateWormHoleSprites(); if (_screenCounterTable[19] != 0) { _g->_plasmaCannonFlags |= 2; @@ -965,9 +829,10 @@ void Level_lar1::setupScreenCheckpoint_lar1_screen24_initGates() { } static const uint8_t data[] = { 0, 1, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; for (int i = _lar1_setupScreen24Data[num * 3 + 1]; i < 13; ++i) { - const uint8_t _al = (data[i] << 4) | 2; - Game::_lar1_gatesData[i * 4] = _al; - const uint32_t mask = 1 << i; + const int j = i; + const uint8_t _al = (data[j] << 4) | 2; + _lar1_gatesData[j * 4] = _al; + const uint32_t mask = 1 << j; if (_al & 0xF0) { _g->_mstAndyVarMask &= ~mask; } else { @@ -976,9 +841,10 @@ void Level_lar1::setupScreenCheckpoint_lar1_screen24_initGates() { _g->_mstLevelGatesMask |= mask; } for (int i = _lar1_setupScreen24Data[num * 3 + 1]; i != 0; --i) { - const uint8_t _al = (((data[i] == 0) ? 1 : 0) << 4) | 2; - Game::_lar1_gatesData[i * 4] = _al; - const uint32_t mask = 1 << i; + const int j = i - 1; + const uint8_t _al = (((data[j] == 0) ? 1 : 0) << 4) | 2; + _lar1_gatesData[j * 4] = _al; + const uint32_t mask = 1 << j; if (_al & 0xF0) { _g->_mstAndyVarMask &= ~mask; } else { @@ -986,10 +852,10 @@ void Level_lar1::setupScreenCheckpoint_lar1_screen24_initGates() { } _g->_mstLevelGatesMask |= mask; } - Game::_lar1_gatesData[2] &= 0xF; - Game::_lar1_gatesData[2] |= 0x30; - Game::_lar1_gatesData[3] &= 0xF; - Game::_lar1_gatesData[3] |= 0x30; + _lar1_gatesData[2] &= 0xF; + _lar1_gatesData[2] |= 0x30; + _lar1_gatesData[3] &= 0xF; + _lar1_gatesData[3] |= 0x30; } void Level_lar1::setupScreenCheckpoint_lar1_screen24_initAndy(int num) { @@ -1012,8 +878,8 @@ void Level_lar1::setupScreenCheckpoint_lar1_screen24_initAndy(int num) { uint8_t _al = *p++; num = data2[i]; _al <<= 4; - _al |= Game::_lar1_gatesData[num * 4] & 15; - Game::_lar1_gatesData[num * 4] = _al; + _al |= _lar1_gatesData[num * 4] & 15; + _lar1_gatesData[num * 4] = _al; const uint32_t mask = 1 << num; if (_al & 0xF0) { _g->_mstAndyVarMask &= ~mask; diff --git a/level8_lar2.cpp b/level8_lar2.cpp index e4dc114..c7ed8d0 100644 --- a/level8_lar2.cpp +++ b/level8_lar2.cpp @@ -69,19 +69,13 @@ Level *Level_lar2_create() { return new Level_lar2; } -uint8_t Game::_lar2_gatesData[10 * 4] = { +static uint8_t _lar2_gatesData[10 * 4] = { 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }; -static const uint8_t _lar2_setupScreen19Data[13 * 3] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x05, 0x02, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x0A, 0x0C, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -BoundingBox Game::_lar2_bboxData[13] = { +static BoundingBox _lar2_switchesBbox[13] = { { 210, 155, 220, 159 }, { 224, 146, 234, 150 }, { 193, 84, 203, 88 }, @@ -97,19 +91,25 @@ BoundingBox Game::_lar2_bboxData[13] = { { 16, 164, 26, 168 } }; -static uint8_t _lar2_switchesData[13 * 4] = { +static uint8_t _lar2_switchesData[13 * 4] = { // screenNum,state,spriteNum,gateNum 0x03, 0x07, 0x00, 0x01, 0x0A, 0x07, 0x00, 0x04, 0x09, 0x03, 0x00, 0x07, 0x08, 0x03, 0x00, 0x07, 0x0B, 0x17, 0x00, 0x06, 0x0B, 0x15, 0xFF, 0x05, 0x0B, 0x15, 0x01, 0x06, 0x0B, 0x17, 0xFF, 0x05, 0x0B, 0x17, 0x02, 0x06, 0x0D, 0x05, 0x00, 0x09, 0x0D, 0x07, 0xFF, 0x08, 0x0D, 0x05, 0x01, 0x08, 0x0D, 0x07, 0xFF, 0x09 }; +static const uint8_t _lar2_setupScreen19Data[13 * 3] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x05, 0x02, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x09, 0x0C, 0x00, 0x0A, 0x0C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + bool Level_lar2::postScreenUpdate_lar2_screen2_updateGateSwitches(BoundingBox *b) { bool ret = false; BoundingBox b1 = { 121, 158, 131, 162 }; if (_g->clipBoundingBox(&b1, b)) { ret = true; - Game::_lar2_gatesData[0] &= 0xF; + _lar2_gatesData[0] &= 0xF; LvlObject *o = _g->findLvlObject2(0, 0, 2); if (o) { o->objectUpdateType = 7; @@ -118,7 +118,7 @@ bool Level_lar2::postScreenUpdate_lar2_screen2_updateGateSwitches(BoundingBox *b BoundingBox b2 = { 170, 158, 180, 162 }; if (_g->clipBoundingBox(&b2, b)) { ret = true; - Game::_lar2_gatesData[0] &= 0xF; + _lar2_gatesData[0] &= 0xF; LvlObject *o = _g->findLvlObject2(0, 1, 2); if (o) { o->objectUpdateType = 7; @@ -127,7 +127,7 @@ bool Level_lar2::postScreenUpdate_lar2_screen2_updateGateSwitches(BoundingBox *b BoundingBox b3 = { 215, 158, 225, 162 }; if (_g->clipBoundingBox(&b3, b)) { ret = true; - Game::_lar2_gatesData[0] &= 0xF; + _lar2_gatesData[0] &= 0xF; LvlObject *o = _g->findLvlObject2(0, 2, 2); if (o) { o->objectUpdateType = 7; @@ -138,7 +138,7 @@ bool Level_lar2::postScreenUpdate_lar2_screen2_updateGateSwitches(BoundingBox *b void Level_lar2::postScreenUpdate_lar2_screen2() { LvlObject *o = _g->findLvlObject(2, 0, 2); - _g->updateGatesLar(o, Game::_lar2_gatesData, 0); + _g->updateGatesLar(o, _lar2_gatesData, 0); if (_res->_currentScreenResourceNum == 2) { bool ret = false; for (LvlObject *o = _g->_lvlObjectsList1; o; o = o->nextPtr) { @@ -162,7 +162,7 @@ void Level_lar2::postScreenUpdate_lar2_screen2() { o->objectUpdateType = 7; } if (!ret) { - Game::_lar2_gatesData[0] = (Game::_lar2_gatesData[0] & 0xF) | 0x10; + _lar2_gatesData[0] = (_lar2_gatesData[0] & 0xF) | 0x10; } } } @@ -171,12 +171,12 @@ void Level_lar2::postScreenUpdate_lar2_screen2() { void Level_lar2::postScreenUpdate_lar2_screen3() { LvlObject *o = _g->findLvlObject(2, 0, 3); - _g->updateGatesLar(o, Game::_lar2_gatesData + 4, 1); + _g->updateGatesLar(o, _lar2_gatesData + 4, 1); } void Level_lar2::postScreenUpdate_lar2_screen4() { if (_g->_currentLevelCheckpoint == 8 && _checkpoint == 9) { - Game::_lar2_gatesData[8] = (Game::_lar2_gatesData[8] & 0xF) | 0x10; + _lar2_gatesData[8] = (_lar2_gatesData[8] & 0xF) | 0x10; if (!_paf->_skipCutscenes) { _paf->play(18); _paf->unload(18); @@ -186,15 +186,15 @@ void Level_lar2::postScreenUpdate_lar2_screen4() { } } LvlObject *o = _g->findLvlObject(2, 0, 4); - _g->updateGatesLar(o, Game::_lar2_gatesData + 8, 2); + _g->updateGatesLar(o, _lar2_gatesData + 8, 2); } void Level_lar2::postScreenUpdate_lar2_screen5() { if (_g->_currentLevelCheckpoint == 7 && _checkpoint == 8) { - Game::_lar2_gatesData[0xC] &= 0xF; + _lar2_gatesData[0xC] &= 0xF; } LvlObject *o = _g->findLvlObject(2, 0, 5); - _g->updateGatesLar(o, Game::_lar2_gatesData + 0xC, 3); + _g->updateGatesLar(o, _lar2_gatesData + 0xC, 3); } void Level_lar2::postScreenUpdate_lar2_screen6() { @@ -241,58 +241,53 @@ void Level_lar2::postScreenUpdate_lar2_screen7() { void Level_lar2::postScreenUpdate_lar2_screen8() { LvlObject *o = _g->findLvlObject(2, 0, 8); - _g->updateGatesLar(o, Game::_lar2_gatesData + 0x1C, 7); + _g->updateGatesLar(o, _lar2_gatesData + 0x1C, 7); } void Level_lar2::postScreenUpdate_lar2_screen10() { LvlObject *o = _g->findLvlObject(2, 0, 10); - _g->updateGatesLar(o, Game::_lar2_gatesData + 0x10, 4); + _g->updateGatesLar(o, _lar2_gatesData + 0x10, 4); } void Level_lar2::postScreenUpdate_lar2_screen11() { LvlObject *o = _g->findLvlObject(2, 0, 11); - _g->updateGatesLar(o, Game::_lar2_gatesData + 0x14, 5); + _g->updateGatesLar(o, _lar2_gatesData + 0x14, 5); o = _g->findLvlObject(2, 1, 11); - _g->updateGatesLar(o, Game::_lar2_gatesData + 0x18, 6); - uint8_t *p = _lar2_switchesData + 0x18; + _g->updateGatesLar(o, _lar2_gatesData + 0x18, 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] & ~0x40) | 1; - p = _lar2_switchesData + 0x1C; - _lar2_switchesData[0x1D] = (_lar2_switchesData[0x1D] & ~0x40) | 1; + _lar2_switchesData[0x19] = (_lar2_switchesData[0x19] | 1) & ~0x40; + offset = 0x1C; + _lar2_switchesData[0x1D] = (_lar2_switchesData[0x1D] | 1) & ~0x40; } - if ((p[1] & 1) == 0 && (p[1] & 0x40) != 0) { + if ((_lar2_switchesData[offset + 1] & 1) == 0 && (_lar2_switchesData[offset + 1] & 0x40) != 0) { if ((_lar2_switchesData[0x21] & 1) != 0) { goto next; } - _lar2_switchesData[0x21] |= 1; - _lar2_switchesData[0x21] &= ~0x40; + _lar2_switchesData[0x21] = (_lar2_switchesData[0x21] | 1) & ~0x40; } - if ((_lar2_switchesData[0x21] & 1) == 0 && (_lar2_switchesData[0x21] & 0x40) != 0 && (p[1] & 1) == 0) { - p[1] &= ~0x40; - p[1] |= 1; - _lar2_switchesData[0x1D] |= 1; - _lar2_switchesData[0x1D] &= ~0x40; - p = _lar2_switchesData + 0x1C; + if ((_lar2_switchesData[0x21] & 1) == 0 && (_lar2_switchesData[0x21] & 0x40) != 0 && (_lar2_switchesData[offset + 1] & 1) == 0) { + _lar2_switchesData[offset + 1] = (_lar2_switchesData[offset + 1] | 1) & ~0x40; + _lar2_switchesData[0x1D] = (_lar2_switchesData[0x1D] | 1) & ~0x40; + offset = 0x1C; } next: - if ((p[1] & 1) == 0 && (p[1] & 0x40) != 0 && (_lar2_switchesData[0x11] & 1) == 0) { - _lar2_switchesData[0x11] |= 1; - _lar2_switchesData[0x11] &= ~0x40; - _lar2_switchesData[0x15] |= 1; - _lar2_switchesData[0x15] &= ~0x40; + if ((_lar2_switchesData[offset + 1] & 1) == 0 && (_lar2_switchesData[offset + 1] & 0x40) != 0 && (_lar2_switchesData[0x11] & 1) == 0) { + _lar2_switchesData[0x11] = (_lar2_switchesData[0x11] | 1) & ~0x40; + _lar2_switchesData[0x15] = (_lar2_switchesData[0x15] | 1) & ~0X40; } } void Level_lar2::postScreenUpdate_lar2_screen12() { LvlObject *o = _g->findLvlObject(2, 0, 12); - _g->updateGatesLar(o, Game::_lar2_gatesData + 0x20, 8); + _g->updateGatesLar(o, _lar2_gatesData + 0x20, 8); o = _g->findLvlObject(2, 1, 12); - _g->updateGatesLar(o, Game::_lar2_gatesData + 0x24, 9); + _g->updateGatesLar(o, _lar2_gatesData + 0x24, 9); if (_res->_currentScreenResourceNum == 12) { BoundingBox b1 = { 65, 84, 75, 88 }; AndyLvlObjectData *data = (AndyLvlObjectData *)_g->getLvlObjectDataPtr(_andyObject, kObjectDataTypeAndy); if (_g->clipBoundingBox(&b1, &data->boundingBox)) { - Game::_lar2_gatesData[0x20] &= 0xF; + _lar2_gatesData[0x20] &= 0xF; o = _g->findLvlObject2(0, 0, 12); if (o) { o->objectUpdateType = 7; @@ -300,7 +295,7 @@ void Level_lar2::postScreenUpdate_lar2_screen12() { } else { BoundingBox b2 = { 65, 163, 75, 167 }; if (_g->clipBoundingBox(&b2, &data->boundingBox)) { - Game::_lar2_gatesData[0x24] &= 0xF; + _lar2_gatesData[0x24] &= 0xF; o = _g->findLvlObject2(0, 1, 12); if (o) { o->objectUpdateType = 7; @@ -313,19 +308,15 @@ void Level_lar2::postScreenUpdate_lar2_screen12() { void Level_lar2::postScreenUpdate_lar2_screen13() { if (_res->_currentScreenResourceNum == 13) { - const uint8_t *p = &_lar2_switchesData[0x2C]; - if ((_lar2_switchesData[0x25] & 1) == 0 && (_lar2_switchesData[0x25] & 0x40) != 0) { - if ((_lar2_switchesData[0x2D] & 1) == 0) { - p = &_lar2_switchesData[0x30]; - _lar2_switchesData[0x2D] &= ~0x40; - _lar2_switchesData[0x31] = (_lar2_switchesData[0x31] | 1) & ~0x40; - } + int offset = 0x2C; + if ((_lar2_switchesData[0x25] & 1) == 0 && (_lar2_switchesData[0x25] & 0x40) != 0 && (_lar2_switchesData[0x2D] & 1) == 0) { + offset = 0x30; + _lar2_switchesData[0x2D] = (_lar2_switchesData[0x2D] | 1) & ~0x40; + _lar2_switchesData[0x31] = (_lar2_switchesData[0x31] | 1) & ~0x40; } - if ((p[1] & 1) == 0 && (p[1] & 0x40) != 0) { - if ((_lar2_switchesData[0x25] & 1) == 0) { - _lar2_switchesData[0x25] = (_lar2_switchesData[0x25] | 1) & ~0x40; - _lar2_switchesData[0x29] = (_lar2_switchesData[0x29] | 1) & ~0x40; - } + if ((_lar2_switchesData[offset + 1] & 1) == 0 && (_lar2_switchesData[offset + 1] & 0x40) != 0 && (_lar2_switchesData[0x25] & 1) == 0) { + _lar2_switchesData[0x25] = (_lar2_switchesData[0x25] | 1) & ~0x40; + _lar2_switchesData[0x29] = (_lar2_switchesData[0x29] | 1) & ~0x40; } } } @@ -386,7 +377,7 @@ void Level_lar2::postScreenUpdate(int num) { void Level_lar2::preScreenUpdate_lar2_screen2() { LvlObject *o = _g->findLvlObject(2, 0, 2); - _g->updateGatesLar(o, Game::_lar2_gatesData, 1); + _g->updateGatesLar(o, _lar2_gatesData, 1); if (_res->_currentScreenResourceNum == 2) { if (_checkpoint == 0) { _checkpoint = 1; @@ -400,9 +391,9 @@ void Level_lar2::preScreenUpdate_lar2_screen4() { _checkpoint = 2; } if (_checkpoint >= 2) { - Game::_lar2_gatesData[4] &= 0xF; + _lar2_gatesData[4] &= 0xF; if (_checkpoint == 8) { - Game::_lar2_gatesData[8] &= 0xF; + _lar2_gatesData[8] &= 0xF; if (!_paf->_skipCutscenes) { _paf->preload(18); } @@ -414,9 +405,9 @@ void Level_lar2::preScreenUpdate_lar2_screen4() { void Level_lar2::preScreenUpdate_lar2_screen5() { if (_res->_currentScreenResourceNum == 5) { if (_checkpoint == 7) { - Game::_lar2_gatesData[0xC] = (Game::_lar2_gatesData[0xC] & 0xF) | 0x10; + _lar2_gatesData[0xC] = (_lar2_gatesData[0xC] & 0xF) | 0x10; } else if (_checkpoint >= 3) { - Game::_lar2_gatesData[0xC] &= 0xF; + _lar2_gatesData[0xC] &= 0xF; } } } @@ -429,7 +420,7 @@ void Level_lar2::preScreenUpdate_lar2_screen6() { if (!_paf->_skipCutscenes) { if (_checkpoint == 3) { _paf->preload(15); - Game::_lar2_gatesData[0xC] &= 0xF; + _lar2_gatesData[0xC] &= 0xF; } else if (_checkpoint == 6) { _paf->preload(17); } @@ -460,16 +451,16 @@ void Level_lar2::preScreenUpdate_lar2_screen7() { } void Level_lar2::preScreenUpdate_lar2_screen8() { - if (_res->_currentScreenResourceNum == 8 && Game::_lar2_gatesData[0x1E] > 1) { - Game::_lar2_gatesData[0x1E] = 1; + if (_res->_currentScreenResourceNum == 8 && _lar2_gatesData[0x1E] > 1) { + _lar2_gatesData[0x1E] = 1; } LvlObject *o = _g->findLvlObject(2, 0, 8); - _g->updateGatesLar(o, Game::_lar2_gatesData + 0x1C, 7); + _g->updateGatesLar(o, _lar2_gatesData + 0x1C, 7); } void Level_lar2::preScreenUpdate_lar2_screen9() { if (_res->_currentScreenResourceNum == 9) { - Game::_lar2_gatesData[0x1E] = 0x24; + _lar2_gatesData[0x1E] = 0x24; } } @@ -525,7 +516,7 @@ void Level_lar2::preScreenUpdate(int num) { } void Level_lar2::tick() { - _g->updateSwitchesLar(13, _lar2_switchesData, Game::_lar2_bboxData); + _g->updateSwitchesLar(13, _lar2_switchesData, _lar2_switchesBbox, _lar2_gatesData); } void Level_lar2::setupScreenCheckpoint_lar2_screen19() { @@ -546,9 +537,9 @@ void Level_lar2::setupScreenCheckpoint_lar2_screen19() { const int gateIndex = _lar2_setupScreen19Data[_checkpoint * 3]; for (int i = gateIndex; i < 10; ++i) { const int num = i; - Game::_lar2_gatesData[num * 4] = (data[num] << 4) | 2; + _lar2_gatesData[num * 4] = (data[num] << 4) | 2; const uint32_t mask = 1 << num; - if (Game::_lar2_gatesData[num * 4] & 0xF0) { + if (_lar2_gatesData[num * 4] & 0xF0) { _g->_mstAndyVarMask &= ~mask; } else { _g->_mstAndyVarMask |= mask; @@ -557,9 +548,9 @@ void Level_lar2::setupScreenCheckpoint_lar2_screen19() { } for (int i = gateIndex; i != 0; --i) { const int num = i - 1; - Game::_lar2_gatesData[num * 4] = ((data[num] == 0) ? 16 : 0) | 2; + _lar2_gatesData[num * 4] = (((data[num] == 0) ? 1 : 0) << 4) | 2; const uint32_t mask = 1 << num; - if (Game::_lar2_gatesData[num * 4] & 0xF0) { + if (_lar2_gatesData[num * 4] & 0xF0) { _g->_mstAndyVarMask &= ~mask; } else { _g->_mstAndyVarMask |= mask; diff --git a/main.cpp b/main.cpp index bdf5107..d386153 100644 --- a/main.cpp +++ b/main.cpp @@ -90,7 +90,9 @@ static int handleConfigIni(void *userdata, const char *section, const char *name // fprintf(stdout, "config.ini: section '%s' name '%s' value '%s'\n", section, name, value); if (strcmp(section, "engine") == 0) { if (strcmp(name, "disable_paf") == 0) { - g->_paf->_skipCutscenes = configBool(value); + if (!g->_paf->_skipCutscenes) { // .paf file not found + g->_paf->_skipCutscenes = configBool(value); + } } else if (strcmp(name, "disable_mst") == 0) { g->_mstDisabled = configBool(value); } else if (strcmp(name, "disable_sss") == 0) { diff --git a/mixer.cpp b/mixer.cpp index e92edae..ba6eab0 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -41,23 +41,14 @@ static void mixS16(int16_t *dst, const int16_t *src, int len, int panL, int panR static const int kPanBits = 14; // 0..16384 - if (stereo) { - for (int j = 0; j < len; j += 2, dst += 2, src += 2) { - if (panning != 1) { - dst[0] = CLIP(dst[0] + ((panL * src[0]) >> kPanBits), -32768, 32767); - } - if (panning != 2) { - dst[1] = CLIP(dst[1] + ((panR * src[1]) >> kPanBits), -32768, 32767); - } + for (int j = 0; j < len; j += 2, dst += 2) { + 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); } - } else { - for (int j = 0; j < len; j += 2, dst += 2, ++src) { - if (panning != 1) { - dst[0] = CLIP(dst[0] + ((panL * src[0]) >> kPanBits), -32768, 32767); - } - if (panning != 2) { - dst[1] = CLIP(dst[1] + ((panR * src[0]) >> kPanBits), -32768, 32767); - } + if (panning != 2) { + dst[1] = CLIP(dst[1] + ((panR * sampleR) >> kPanBits), -32768, 32767); } } } diff --git a/monsters.cpp b/monsters.cpp index 941e428..ac55d1e 100644 --- a/monsters.cpp +++ b/monsters.cpp @@ -86,7 +86,7 @@ void Game::mstMonster1ResetData(MonsterObject1 *m) { } } -void Game::initMonsterObject2_firefly(MonsterObject2 *m) { +void Game::mstMonster2InitFirefly(MonsterObject2 *m) { LvlObject *o = m->o; m->x1 = _res->_mstPointOffsets[o->screenNum].xOffset; m->y1 = _res->_mstPointOffsets[o->screenNum].yOffset; @@ -242,7 +242,7 @@ int Game::mstTaskStopMonsterObject1(Task *t) { } MonsterObject1 *m = t->monster1; - // original code probably meant to check bit 3 directly + // bugfix: original code meant to check bit 3 directly ? // const uint8_t r = (m->flagsA5 == 0) ? 1 : 0; // if ((r & 8) != 0) { @@ -784,7 +784,7 @@ void Game::mstTaskUpdateScreenPosition(Task *t) { } } -void Game::shuffleMstUnk43(MstUnk43 *p) { +void Game::shuffleMstMonsterActionIndex(MstMonsterActionIndex *p) { for (uint32_t i = 0; i < p->dataCount; ++i) { p->data[i] &= 0x7F; } @@ -829,8 +829,8 @@ void Game::resetMstCode() { shuffleArray(_res->_mstWalkCodeData[i].data, count); } } - for (int i = 0; i < _res->_mstHdr.unk0x24; ++i) { - shuffleMstUnk43(&_res->_mstUnk43[i]); + for (int i = 0; i < _res->_mstHdr.monsterActionIndexDataCount; ++i) { + shuffleMstMonsterActionIndex(&_res->_mstMonsterActionIndexData[i]); } _mstOp67_x1 = -256; _mstOp67_x2 = -256; @@ -839,7 +839,7 @@ void Game::resetMstCode() { memset(_mstVars, 0, sizeof(_mstVars)); memset(_tasksTable, 0, sizeof(_tasksTable)); _m43Num3 = _m43Num1 = _m43Num2 = _mstActionNum = -1; - _mstOp54Counter = 0; // not reset in the original, causes uninitialized reads at the beginning of 'fort' + _mstOp54Counter = 0; // bugfix: not reset in the original, causes uninitialized reads at the beginning of 'fort' _executeMstLogicPrevCounter = _executeMstLogicCounter = 0; // _mstUnk8 = 0; _specialAnimFlag = false; @@ -847,12 +847,12 @@ void Game::resetMstCode() { _mstBoundingBoxesCount = 0; _mstOp67_y1 = 0; _mstOp67_y2 = 0; - _mstOp67_screenNum = 0xFF; + _mstOp67_screenNum = kNoScreen; _mstOp68_x1 = 256; _mstOp68_x2 = 256; _mstOp68_y1 = 0; _mstOp68_y2 = 0; - _mstOp68_screenNum = 255; + _mstOp68_screenNum = kNoScreen; _mstLevelGatesMask = 0; // _mstLevelGatesTestMask = 0xFFFFFFFF; _mstAndyVarMask = 0; @@ -2809,14 +2809,13 @@ int Game::mstUpdateTaskMonsterObject2(Task *t) { } LvlObject *o = m->o; MstInfoMonster2 *monster2Info = m->monster2Info; - uint8_t _bl = monster2Info->shootMask; - if (_bl != _dl) { + const uint8_t _bl = monster2Info->shootMask; + if ((_bl & _dl) != 0) { for (int i = 0; i < _andyShootsCount; ++i) { AndyShootData *p = &_andyShootsTable[i]; if (p->type == 2 && (_bl & 1) == 0) { continue; - } - if (p->type == 1 && (_bl & 2) == 0) { + } else if (p->type == 1 && (_bl & 2) == 0) { continue; } if (o->screenNum != _currentScreen || p->o->screenNum != _currentScreen) { @@ -4380,8 +4379,8 @@ int Game::mstTask_main(Task *t) { break; case 215: { // 62 if (_m43Num3 != -1) { - assert(_m43Num3 < _res->_mstHdr.unk0x24); - shuffleMstUnk43(&_res->_mstUnk43[_m43Num3]); + assert(_m43Num3 < _res->_mstHdr.monsterActionIndexDataCount); + shuffleMstMonsterActionIndex(&_res->_mstMonsterActionIndexData[_m43Num3]); } _mstOp54Counter = 0; } @@ -4390,8 +4389,8 @@ int Game::mstTask_main(Task *t) { const int16_t num = READ_LE_UINT16(p + 2); if (_m43Num3 != num) { _m43Num3 = num; - assert(num >= 0 && num < _res->_mstHdr.unk0x24); - shuffleMstUnk43(&_res->_mstUnk43[num]); + assert(num >= 0 && num < _res->_mstHdr.monsterActionIndexDataCount); + shuffleMstMonsterActionIndex(&_res->_mstMonsterActionIndexData[num]); _mstOp54Counter = 0; } } @@ -4401,8 +4400,8 @@ int Game::mstTask_main(Task *t) { if (num != _m43Num1) { _m43Num1 = num; _m43Num2 = num; - assert(num >= 0 && num < _res->_mstHdr.unk0x24); - shuffleMstUnk43(&_res->_mstUnk43[num]); + assert(num >= 0 && num < _res->_mstHdr.monsterActionIndexDataCount); + shuffleMstMonsterActionIndex(&_res->_mstMonsterActionIndexData[num]); } } break; @@ -5455,17 +5454,17 @@ void Game::mstOp54() { if (_mstActionNum != -1) { return; } - MstUnk43 *m43 = 0; + MstMonsterActionIndex *m43 = 0; if (_mstFlags & 0x20000000) { if (_m43Num2 == -1) { return; } - m43 = &_res->_mstUnk43[_m43Num2]; + m43 = &_res->_mstMonsterActionIndexData[_m43Num2]; } else { if (_m43Num3 == -1) { return; } - m43 = &_res->_mstUnk43[_m43Num3]; + m43 = &_res->_mstMonsterActionIndexData[_m43Num3]; _m43Num2 = _m43Num1; } const int x = MIN(_mstAndyScreenPosX, 255); @@ -5496,7 +5495,7 @@ void Game::mstOp54() { return; } _mstOp54Counter = 0; - shuffleMstUnk43(m43); + shuffleMstMonsterActionIndex(m43); } else { memset(_mstOp54Table, 0, sizeof(_mstOp54Table)); bool var4 = false; @@ -5527,7 +5526,7 @@ void Game::mstOp54() { } _mstOp54Counter = 0; if (m43->dataCount != 0) { - shuffleMstUnk43(m43); + shuffleMstMonsterActionIndex(m43); } } } @@ -6066,9 +6065,9 @@ void Game::mstOp58_addLvlObject(Task *t, int num) { void Game::mstOp59_addShootSpecialPowers(int x, int y, int screenNum, int type, uint16_t flags) { LvlObject *o = addLvlObjectToList0(3); if (o) { - o->dataPtr = _shootLvlObjectDataList; - if (_shootLvlObjectDataList) { - _shootLvlObjectDataList = _shootLvlObjectDataList->nextPtr; + o->dataPtr = _shootLvlObjectDataNextPtr; + if (_shootLvlObjectDataNextPtr) { + _shootLvlObjectDataNextPtr = _shootLvlObjectDataNextPtr->nextPtr; memset(o->dataPtr, 0, sizeof(ShootLvlObjectData)); } ShootLvlObjectData *s = (ShootLvlObjectData *)o->dataPtr; @@ -6095,9 +6094,9 @@ void Game::mstOp59_addShootSpecialPowers(int x, int y, int screenNum, int type, void Game::mstOp59_addShootFireball(int x, int y, int screenNum, int pos, int type, uint16_t flags) { LvlObject *o = addLvlObjectToList2(7); if (o) { - o->dataPtr = _shootLvlObjectDataList; - if (_shootLvlObjectDataList) { - _shootLvlObjectDataList = _shootLvlObjectDataList->nextPtr; + o->dataPtr = _shootLvlObjectDataNextPtr; + if (_shootLvlObjectDataNextPtr) { + _shootLvlObjectDataNextPtr = _shootLvlObjectDataNextPtr->nextPtr; memset(o->dataPtr, 0, sizeof(ShootLvlObjectData)); } ShootLvlObjectData *s = (ShootLvlObjectData *)o->dataPtr; @@ -6857,7 +6856,7 @@ void Game::mstOp67_addMonster(Task *currentTask, int x1, int x2, int y1, int y2, assert(codeData != kNone); resetTask(t, _res->_mstCodeData + codeData * 4); if (_currentLevel == kLvl_fort && mo->monster2Info->type == 27) { - initMonsterObject2_firefly(mo); + mstMonster2InitFirefly(mo); } } else { Task *t = findFreeTask(); diff --git a/paf.cpp b/paf.cpp index 65f364a..8bb7c69 100644 --- a/paf.cpp +++ b/paf.cpp @@ -241,7 +241,7 @@ uint8_t *PafPlayer::getVideoPageOffset(uint8_t a, uint8_t b) { const int x = b & 0x7F; const int y = ((a & 0x3F) << 1) | ((b >> 7) & 1); const int page = (a & 0xC0) >> 6; - return _pageBuffers[page] + y * 2 * 256 + x * 2; + return _pageBuffers[page] + (y * kVideoWidth + x) * 2; } void PafPlayer::decodeVideoFrameOp0(const uint8_t *base, const uint8_t *src, uint8_t code) { @@ -264,7 +264,7 @@ void PafPlayer::decodeVideoFrameOp0(const uint8_t *base, const uint8_t *src, uin pafCopy4x4h(dst, src); src += 16; if ((offset & 0x3F) == 0) { - dst += 256 * 3; + dst += kVideoWidth * 3; } dst += 4; } while (offset < end); @@ -278,10 +278,10 @@ void PafPlayer::decodeVideoFrameOp0(const uint8_t *base, const uint8_t *src, uin pafCopy4x4v(dst, src2); ++count; if ((count & 0x3F) == 0) { - dst += 256 * 3; + dst += kVideoWidth * 3; } dst += 4; - } while (count < 256 * 192 / 16); + } while (count < kVideoWidth * kVideoHeight / 16); const uint32_t opcodesSize = READ_LE_UINT16(src); src += 4; @@ -294,8 +294,8 @@ void PafPlayer::decodeVideoFrameOp0(const uint8_t *base, const uint8_t *src, uin const uint8_t *src2 = 0; dst = _pageBuffers[_currentPageBuffer]; - for (int y = 0; y < 192; y += 4, dst += 256 * 3) { - for (int x = 0; x < 256; x += 4, dst += 4) { + for (int y = 0; y < kVideoHeight; y += 4, dst += kVideoWidth * 3) { + for (int x = 0; x < kVideoWidth; x += 4, dst += 4) { if ((x & 4) == 0) { opcodes = updateSequences[*opcodesData >> 4]; } else { @@ -303,7 +303,7 @@ void PafPlayer::decodeVideoFrameOp0(const uint8_t *base, const uint8_t *src, uin ++opcodesData; } while (*opcodes) { - uint32_t offset = 256 * 2; + uint32_t offset = kVideoWidth * 2; const int code = *opcodes++; switch (code) { case 2: @@ -313,7 +313,7 @@ void PafPlayer::decodeVideoFrameOp0(const uint8_t *base, const uint8_t *src, uin case 4: mask = *src++; pafCopyColorMask(mask >> 4, dst + offset, color); - offset += 256; + offset += kVideoWidth; pafCopyColorMask(mask & 15, dst + offset, color); break; case 5: @@ -323,7 +323,7 @@ void PafPlayer::decodeVideoFrameOp0(const uint8_t *base, const uint8_t *src, uin case 7: mask = *src++; pafCopySrcMask(mask >> 4, dst + offset, src2 + offset); - offset += 256; + offset += kVideoWidth; pafCopySrcMask(mask & 15, dst + offset, src2 + offset); break; } @@ -364,6 +364,16 @@ void PafPlayer::decodeVideoFrameOp4(const uint8_t *src) { } } +static void decodeAudioFrame2205(const uint8_t *src, int len, int16_t *dst) { + + int offset = 256 * sizeof(int16_t); + + for (int i = 0; i < len; ++i) { + *dst++ = READ_LE_UINT16(src + src[offset++] * sizeof(int16_t)); + *dst++ = READ_LE_UINT16(src + src[offset++] * sizeof(int16_t)); + } +} + void PafPlayer::decodeAudioFrame(const uint8_t *src, uint32_t offset, uint32_t size) { assert(size == _pafHdr.readBufferSize); @@ -381,7 +391,7 @@ void PafPlayer::decodeAudioFrame(const uint8_t *src, uint32_t offset, uint32_t s sq->buffer = (int16_t *)calloc(sq->size, sizeof(int16_t)); if (sq->buffer) { for (int i = 0; i < count; ++i) { - decodeAudioFrame2205(src + _audioBufferOffsetRd + i * kAudioStrideSize, sq->buffer + i * kAudioSamples * 2); + decodeAudioFrame2205(src + _audioBufferOffsetRd + i * kAudioStrideSize, kAudioSamples, sq->buffer + i * kAudioSamples * 2); } } sq->next = 0; @@ -404,20 +414,6 @@ void PafPlayer::decodeAudioFrame(const uint8_t *src, uint32_t offset, uint32_t s } } -void PafPlayer::decodeAudioFrame2205(const uint8_t *src, int16_t *dst) { - - const uint8_t *samples = src; - src += 256 * sizeof(int16_t); - - for (int i = 0; i < kAudioSamples; ++i) { - for (int channel = 0; channel < 2; ++channel) { - const uint8_t num = *src++; - const int16_t pcm = READ_LE_UINT16(samples + num * sizeof(int16_t)); - *dst++ = pcm; - } - } -} - void PafPlayer::mix(int16_t *buf, int samples) { while (_audioQueue && samples > 0) { assert(_audioQueue->size != 0); @@ -481,7 +477,7 @@ void PafPlayer::mainLoop() { // decode video data decodeVideoFrame(_demuxVideoFrameBlocks + _pafHdr.framesOffsetTable[i]); _system->setPalette(_paletteBuffer, 256, 6); - _system->copyRect(0, 0, kVideoWidth, kVideoHeight, _pageBuffers[_currentPageBuffer], 256); + _system->copyRect(0, 0, kVideoWidth, kVideoHeight, _pageBuffers[_currentPageBuffer], kVideoWidth); _system->updateScreen(false); _system->processEvents(); if (_system->inp.quit || _system->inp.keyPressed(SYS_INP_ESC)) { diff --git a/paf.h b/paf.h index d9cb49f..7dfd139 100644 --- a/paf.h +++ b/paf.h @@ -110,7 +110,6 @@ struct PafPlayer { void decodeVideoFrameOp4(const uint8_t *src); void decodeAudioFrame(const uint8_t *src, uint32_t offset, uint32_t size); - void decodeAudioFrame2205(const uint8_t *src, int16_t *dst); void mix(int16_t *buf, int samples); void mainLoop(); diff --git a/resource.cpp b/resource.cpp index 9650882..75206f1 100644 --- a/resource.cpp +++ b/resource.cpp @@ -11,6 +11,7 @@ #include "util.h" static const char *_setupDat = "SETUP.DAT"; +static const char *_setupDax = "SETUP.DAX"; static const char *_prefixes[] = { "rock", @@ -56,7 +57,7 @@ static int readBytesAlign(File *f, uint8_t *buf, int len) { } Resource::Resource(const char *dataPath) - : _fs(dataPath) { + : _fs(dataPath), _isPsx(false) { memset(_screensGrid, 0, sizeof(_screensGrid)); memset(_screensBasePos, 0, sizeof(_screensBasePos)); @@ -66,6 +67,7 @@ Resource::Resource(const char *dataPath) _resLevelData0x470CTable = 0; _resLevelData0x470CTablePtrHdr = 0; _resLevelData0x470CTablePtrData = 0; + _lvlSssOffset = 0; // sprites memset(_resLevelData0x2988SizeTable, 0, sizeof(_resLevelData0x2988SizeTable)); @@ -113,8 +115,11 @@ Resource::~Resource() { bool Resource::sectorAlignedGameData() { FILE *fp = _fs.openFile(_setupDat); if (!fp) { - error("Unable to open '%s'", _setupDat); - return false; + fp = _fs.openFile(_setupDax); + if (!fp) { + error("Unable to open '%s' or '%s'", _setupDat, _setupDax); + return false; + } } bool ret = false; uint8_t buf[2048]; @@ -126,7 +131,9 @@ bool Resource::sectorAlignedGameData() { } void Resource::loadSetupDat() { - openDat(_fs, _setupDat, _datFile); + if (!openDat(_fs, _setupDat, _datFile)) { + _isPsx = openDat(_fs, _setupDax, _datFile); + } _datHdr.version = _datFile->readUint32(); if (_datHdr.version != 10 && _datHdr.version != 11) { @@ -161,19 +168,21 @@ void Resource::loadSetupDat() { uint32_t offset = 0; - // loading image - uint32_t size = READ_LE_UINT32(_loadingImageBuffer + offset); offset += 8; - offset += size + 768; + if (!_isPsx) { + // loading image + uint32_t size = READ_LE_UINT32(_loadingImageBuffer + offset); offset += 8; + offset += size + 768; - // loading animation - size = READ_LE_UINT32(_loadingImageBuffer + offset + 8); offset += 16; - offset += size; + // loading animation + size = READ_LE_UINT32(_loadingImageBuffer + offset + 8); offset += 16; + offset += size; + } // font static const int kFontSize = 16 * 16 * 64; _fontBuffer = (uint8_t *)malloc(kFontSize); if (_fontBuffer) { - size = READ_LE_UINT32(_loadingImageBuffer + offset); offset += 4; + /* size = READ_LE_UINT32(_loadingImageBuffer + offset); */ offset += 4; if (_datHdr.version == 11) { const uint32_t uncompressedSize = decodeLZW(_loadingImageBuffer + offset, _fontBuffer); assert(uncompressedSize == kFontSize); @@ -188,6 +197,9 @@ void Resource::loadSetupDat() { void Resource::loadDatHintImage(int num, uint8_t *dst, uint8_t *pal) { + if (_isPsx) { + return; + } const int offset = _datHdr.hintsImageOffsetTable[num]; const int size = _datHdr.hintsImageSizeTable[num]; assert(size == 256 * 192); @@ -254,77 +266,58 @@ void Resource::loadLevelData(int levelNum) { snprintf(filename, sizeof(filename), "%s_HOD.SSS", levelName); if (openDat(_fs, filename, _sssFile)) { loadSssData(_sssFile); + } else if (_isPsx) { + assert((_lvlSssOffset & 0x7FF) == 0); + _lvlFile->seek(_lvlSssOffset, SEEK_SET); + loadSssData(_lvlFile, _lvlSssOffset); } else { warning("Unable to open '%s'", filename); memset(&_sssHdr, 0, sizeof(_sssHdr)); } } -void Resource::loadLvlScreenGridData(int num) { - _lvlFile->seekAlign(0x8 + num * 4); - _lvlFile->read(&_screensGrid[num * 4], 4); -} - -void Resource::loadLvlScreenVectorData(int num) { - _lvlFile->seekAlign(0xA8 + num * 8); - LvlScreenVector *dat = &_screensBasePos[num]; - dat->u = _lvlFile->readUint32(); - dat->v = _lvlFile->readUint32(); -} - -void Resource::loadLvlScreenStateData(int num) { - _lvlFile->seekAlign(0x1E8 + num * 4); - LvlScreenState *dat = &_screensState[num]; - dat->s0 = _lvlFile->readByte(); - dat->s1 = _lvlFile->readByte(); - dat->s2 = _lvlFile->readByte(); - dat->s3 = _lvlFile->readByte(); -} - -void Resource::loadLvlScreenObjectData(int num) { - _lvlFile->seekAlign(0x288 + num * 96); - LvlObject *dat = &_resLvlScreenObjectDataTable[num]; - - dat->xPos = _lvlFile->readUint32(); - dat->yPos = _lvlFile->readUint32(); - dat->screenNum = _lvlFile->readByte(); - dat->screenState = _lvlFile->readByte(); - dat->dataNum = _lvlFile->readByte(); - dat->frame = _lvlFile->readByte(); - dat->anim = _lvlFile->readUint16(); - dat->type = _lvlFile->readByte(); - dat->spriteNum = _lvlFile->readByte(); - dat->flags0 = _lvlFile->readUint16(); - dat->flags1 = _lvlFile->readUint16(); - dat->flags2 = _lvlFile->readUint16(); - dat->objectUpdateType = _lvlFile->readByte(); - dat->hitCount = _lvlFile->readByte(); - const uint32_t objRef = _lvlFile->readUint32(); +void Resource::loadLvlScreenObjectData(LvlObject *dat, const uint8_t *src) { + const uint8_t *start = src; + dat->xPos = READ_LE_UINT32(src); src += 4; + dat->yPos = READ_LE_UINT32(src); src += 4; + dat->screenNum = *src++; + dat->screenState = *src++; + dat->dataNum = *src++; + dat->frame = *src++; + dat->anim = READ_LE_UINT16(src); src += 2; + dat->type = *src++; + dat->spriteNum = *src++; + dat->flags0 = READ_LE_UINT16(src); src += 2; + dat->flags1 = READ_LE_UINT16(src); src += 2; + dat->flags2 = READ_LE_UINT16(src); src += 2; + dat->objectUpdateType = *src++; + dat->hitCount = *src++; + const uint32_t objRef = READ_LE_UINT32(src); src += 4; if (objRef) { dat->childPtr = &_dummyObject; - debug(kDebug_RESOURCE, "loadLvlObj num %d linkObjRef 0x%x", num, objRef); - } - dat->width = _lvlFile->readUint16(); - dat->height = _lvlFile->readUint16(); - dat->directionKeyMask = _lvlFile->readByte(); - dat->actionKeyMask = _lvlFile->readByte(); - dat->currentSprite = _lvlFile->readUint16(); - dat->currentSound = _lvlFile->readUint16(); - dat->unk26 = _lvlFile->readByte(); - dat->unk27 = _lvlFile->readByte(); - dat->bitmapBits = 0; _lvlFile->readUint32(); - dat->callbackFuncPtr = 0; _lvlFile->readUint32(); - dat->dataPtr = 0; _lvlFile->readUint32(); - dat->sssObject = 0; _lvlFile->readUint32(); - dat->levelData0x2988 = 0; _lvlFile->readUint32(); + debug(kDebug_RESOURCE, "loadLvlObj dat %p linkObjRef 0x%x", dat, objRef); + } + dat->width = READ_LE_UINT16(src); src += 2; + dat->height = READ_LE_UINT16(src); src += 2; + dat->directionKeyMask = *src++; + dat->actionKeyMask = *src++; + dat->currentSprite = READ_LE_UINT16(src); src += 2; + dat->currentSound = READ_LE_UINT16(src); src += 2; + src += 2; // 0x26 + dat->bitmapBits = 0; src += 4; + dat->callbackFuncPtr = 0; src += 4; + dat->dataPtr = 0; src += 4; + dat->sssObject = 0; src += 4; + dat->levelData0x2988 = 0; src += 4; for (int i = 0; i < 8; ++i) { - dat->posTable[i].x = _lvlFile->readUint16(); - dat->posTable[i].y = _lvlFile->readUint16(); + dat->posTable[i].x = READ_LE_UINT16(src); src += 2; + dat->posTable[i].y = READ_LE_UINT16(src); src += 2; } - dat->nextPtr = 0; _lvlFile->readUint32(); + dat->nextPtr = 0; src += 4; + assert((src - start) == 96); } -static uint32_t resFixPointersLevelData0x2988(uint8_t *src, uint8_t *ptr, LvlObjectData *dat) { +static uint32_t resFixPointersLevelData0x2988(uint8_t *src, uint8_t *ptr, LvlObjectData *dat, bool isPsx) { uint8_t *base = src; dat->unk0 = *src++; @@ -336,8 +329,7 @@ static uint32_t resFixPointersLevelData0x2988(uint8_t *src, uint8_t *ptr, LvlObj dat->refCount = *src++; dat->frame = *src++; dat->anim = READ_LE_UINT16(src); src += 2; - dat->unkE = *src++; - dat->unkF = *src++; + src += 2; // 0xE src += 4; // 0x10 uint32_t movesDataOffset = READ_LE_UINT32(src); src += 4; // 0x14 src += 4; // 0x18 @@ -391,6 +383,22 @@ static uint32_t resFixPointersLevelData0x2988(uint8_t *src, uint8_t *ptr, LvlObj dat->coordsOffsetsTable = 0; } + if (dat->unk0 == 1) { // fixed size offset table + assert(isPsx); + dat->framesOffsetsTable = (uint8_t *)malloc(dat->framesCount * sizeof(uint32_t)); + uint32_t framesOffset = 6 * dat->framesCount; + if (READ_LE_UINT16(dat->framesData + framesOffset) == 0) { + framesOffset += 2; + } + for (int i = 0; i < dat->framesCount; ++i) { + const int size = READ_LE_UINT16(dat->framesData + i * 6); + WRITE_LE_UINT32(dat->framesOffsetsTable + i * sizeof(uint32_t), framesOffset); + framesOffset += size; + } + dat->coordsOffsetsTable = ptr; + return 0; + } + uint32_t framesOffset = 0; for (int i = 0; i < dat->framesCount; ++i) { const int size = READ_LE_UINT16(dat->framesData + framesOffset); @@ -408,19 +416,23 @@ static uint32_t resFixPointersLevelData0x2988(uint8_t *src, uint8_t *ptr, LvlObj } void Resource::loadLvlSpriteData(int num) { + assert((unsigned int)num < kMaxSpriteTypes); + static const uint32_t baseOffset = 0x2988; + uint8_t buf[4 * 3]; _lvlFile->seekAlign(baseOffset + num * 16); - const uint32_t offset = _lvlFile->readUint32(); - const uint32_t size = _lvlFile->readUint32(); - const uint32_t readSize = _lvlFile->readUint32(); - uint8_t *ptr = (uint8_t *)calloc(size, 1); - _lvlFile->seek(offset, SEEK_SET); + _lvlFile->read(buf, sizeof(buf)); + const uint32_t offset = READ_LE_UINT32(&buf[0]); + const uint32_t size = READ_LE_UINT32(&buf[4]); + const uint32_t readSize = READ_LE_UINT32(&buf[8]); + assert(readSize <= size); + uint8_t *ptr = (uint8_t *)malloc(size); + _lvlFile->seek(_isPsx ? _lvlSssOffset + offset : offset, SEEK_SET); _lvlFile->read(ptr, readSize); LvlObjectData *dat = &_resLevelData0x2988Table[num]; - const uint32_t readOffsetsSize = resFixPointersLevelData0x2988(ptr, ptr + readSize, dat); - assert(readSize <= size); + const uint32_t readOffsetsSize = resFixPointersLevelData0x2988(ptr, ptr + readSize, dat, _isPsx); const uint32_t allocatedOffsetsSize = size - readSize; assert(allocatedOffsetsSize == readOffsetsSize); @@ -450,6 +462,8 @@ void Resource::loadLvlScreenMaskData() { _lvlFile->read(_resLevelData0x470CTable, size); _resLevelData0x470CTablePtrHdr = _resLevelData0x470CTable; _resLevelData0x470CTablePtrData = _resLevelData0x470CTable + (kMaxScreens * 4) * (2 * sizeof(uint32_t)); + // .sss is embedded in .lvl on PSX + _lvlSssOffset = offset + fioAlignSizeTo2048(size); } static const uint32_t _lvlTag = 0x484F4400; // 'HOD\x00' @@ -473,17 +487,31 @@ void Resource::loadLvlData(File *fp) { _lvlHdr.spritesCount = _lvlFile->readByte(); debug(kDebug_RESOURCE, "Resource::loadLvlData() %d %d %d %d", _lvlHdr.screensCount, _lvlHdr.staticLvlObjectsCount, _lvlHdr.otherLvlObjectsCount, _lvlHdr.spritesCount); + _lvlFile->seekAlign(0x8); for (int i = 0; i < _lvlHdr.screensCount; ++i) { - loadLvlScreenGridData(i); + _lvlFile->read(_screensGrid[i], 4); } + _lvlFile->seekAlign(0xA8); for (int i = 0; i < _lvlHdr.screensCount; ++i) { - loadLvlScreenVectorData(i); + LvlScreenVector *dat = &_screensBasePos[i]; + dat->u = _lvlFile->readUint32(); + dat->v = _lvlFile->readUint32(); } + _lvlFile->seekAlign(0x1E8); for (int i = 0; i < _lvlHdr.screensCount; ++i) { - loadLvlScreenStateData(i); + LvlScreenState *dat = &_screensState[i]; + dat->s0 = _lvlFile->readByte(); + dat->s1 = _lvlFile->readByte(); + dat->s2 = _lvlFile->readByte(); + dat->s3 = _lvlFile->readByte(); } - for (int i = 0; i < (0x2988 - 0x288) / 96; ++i) { - loadLvlScreenObjectData(i); + _lvlFile->seekAlign(0x288); + static const int kSizeOfLvlObject = 96; + for (int i = 0; i < (0x2988 - 0x288) / kSizeOfLvlObject; ++i) { + LvlObject *dat = &_resLvlScreenObjectDataTable[i]; + uint8_t buf[kSizeOfLvlObject]; + _lvlFile->read(buf, kSizeOfLvlObject); + loadLvlScreenObjectData(dat, buf); } loadLvlScreenMaskData(); @@ -504,12 +532,17 @@ void Resource::unloadLvlData() { unloadLvlScreenBackgroundData(i); } for (unsigned int i = 0; i < kMaxSpriteTypes; ++i) { + LvlObjectData *dat = &_resLevelData0x2988Table[i]; + if (dat->unk0 == 1) { + free(dat->framesOffsetsTable); + dat->framesOffsetsTable = 0; + } free(_resLvlSpriteDataPtrTable[i]); _resLvlSpriteDataPtrTable[i] = 0; } } -static uint32_t resFixPointersLevelData0x2B88(const uint8_t *src, uint8_t *ptr, uint8_t *offsetsPtr, LvlBackgroundData *dat) { +static uint32_t resFixPointersLevelData0x2B88(const uint8_t *src, uint8_t *ptr, uint8_t *offsetsPtr, LvlBackgroundData *dat, bool isPsx) { const uint8_t *start = src; dat->backgroundCount = *src++; @@ -525,7 +558,7 @@ static uint32_t resFixPointersLevelData0x2B88(const uint8_t *src, uint8_t *ptr, dat->dataUnk45Count = *src++; dat->unkB = *src++; dat->backgroundPaletteId = READ_LE_UINT16(src); src += 2; - dat->backgroundBitmapId = READ_LE_UINT16(src); src += 2; + dat->backgroundBitmapId = READ_LE_UINT16(src); src += 2; for (int i = 0; i < 4; ++i) { const uint32_t offs = READ_LE_UINT32(src); src += 4; dat->backgroundPaletteTable[i] = (offs != 0) ? ptr + offs : 0; @@ -546,20 +579,16 @@ static uint32_t resFixPointersLevelData0x2B88(const uint8_t *src, uint8_t *ptr, const uint32_t offs = READ_LE_UINT32(src); src += 4; dat->backgroundSoundTable[i] = (offs != 0) ? ptr + offs : 0; } - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 8; ++i) { const uint32_t offs = READ_LE_UINT32(src); src += 4; dat->backgroundAnimationTable[i] = (offs != 0) ? ptr + offs : 0; } - for (int i = 0; i < 4; ++i) { - const uint32_t offs = READ_LE_UINT32(src); src += 4; - dat->dataUnk4Table[i] = (offs != 0) ? ptr + offs : 0; - } uint32_t offsetsSize = 0; for (int i = 0; i < 4; ++i) { const uint32_t offs = READ_LE_UINT32(src); src += 4; if (offs != 0) { dat->backgroundLvlObjectDataTable[i] = (LvlObjectData *)malloc(sizeof(LvlObjectData)); - offsetsSize += resFixPointersLevelData0x2988(ptr + offs, offsetsPtr + offsetsSize, dat->backgroundLvlObjectDataTable[i]); + offsetsSize += resFixPointersLevelData0x2988(ptr + offs, offsetsPtr + offsetsSize, dat->backgroundLvlObjectDataTable[i], isPsx); } else { dat->backgroundLvlObjectDataTable[i] = 0; } @@ -577,21 +606,22 @@ void Resource::loadLvlScreenBackgroundData(int num) { static const uint32_t baseOffset = 0x2B88; + uint8_t buf[4 * 3]; _lvlFile->seekAlign(baseOffset + num * 16); - const uint32_t offset = _lvlFile->readUint32(); - const uint32_t size = _lvlFile->readUint32(); - const uint32_t readSize = _lvlFile->readUint32(); - uint8_t *ptr = (uint8_t *)calloc(size, 1); - _lvlFile->seek(offset, SEEK_SET); + _lvlFile->read(buf, sizeof(buf)); + const uint32_t offset = READ_LE_UINT32(&buf[0]); + const uint32_t size = READ_LE_UINT32(&buf[4]); + const uint32_t readSize = READ_LE_UINT32(&buf[8]); + assert(readSize <= size); + uint8_t *ptr = (uint8_t *)malloc(size); + _lvlFile->seek(_isPsx ? _lvlSssOffset + offset : offset, SEEK_SET); _lvlFile->read(ptr, readSize); + uint8_t hdr[160]; _lvlFile->seekAlign(baseOffset + kMaxScreens * 16 + num * 160); - uint8_t buf[160]; - _lvlFile->read(buf, 160); + _lvlFile->read(hdr, 160); LvlBackgroundData *dat = &_resLvlScreenBackgroundDataTable[num]; - const uint32_t readOffsetsSize = resFixPointersLevelData0x2B88(buf, ptr, ptr + readSize, dat); - - assert(size >= readSize); + const uint32_t readOffsetsSize = resFixPointersLevelData0x2B88(hdr, ptr, ptr + readSize, dat, _isPsx); const uint32_t allocatedOffsetsSize = size - readSize; assert(allocatedOffsetsSize == readOffsetsSize); @@ -604,6 +634,12 @@ void Resource::unloadLvlScreenBackgroundData(int num) { free(_resLvlScreenBackgroundDataPtrTable[num]); _resLvlScreenBackgroundDataPtrTable[num] = 0; _resLevelData0x2B88SizeTable[num] = 0; + + LvlBackgroundData *dat = &_resLvlScreenBackgroundDataTable[num]; + for (int i = 0; i < 4; ++i) { + free(dat->backgroundLvlObjectDataTable[i]); + } + memset(dat, 0, sizeof(LvlBackgroundData)); } } @@ -629,8 +665,16 @@ void Resource::decLvlSpriteDataRefCounter(LvlObject *ptr) { } } -const uint8_t *Resource::getLvlSpriteFramePtr(LvlObjectData *dat, int frame) const { +const uint8_t *Resource::getLvlSpriteFramePtr(LvlObjectData *dat, int frame, uint16_t *w, uint16_t *h) const { assert(frame < dat->framesCount); + const uint8_t *p = dat->framesData; + if (dat->unk0 == 1) { + p += frame * 6; + } else { + p += READ_LE_UINT32(dat->framesOffsetsTable + frame * sizeof(uint32_t)); + } + *w = READ_LE_UINT16(p + 2); + *h = READ_LE_UINT16(p + 4); return dat->framesData + READ_LE_UINT32(dat->framesOffsetsTable + frame * sizeof(uint32_t)); } @@ -639,9 +683,21 @@ const uint8_t *Resource::getLvlSpriteCoordPtr(LvlObjectData *dat, int num) const return dat->coordsData + READ_LE_UINT32(dat->coordsOffsetsTable + num * sizeof(uint32_t)); } +int Resource::findScreenGridIndex(int screenNum) const { + for (int i = 0; i < 4; ++i) { + if (_screensGrid[_currentScreenResourceNum][i] == screenNum) { + return i; + } + } + if (_currentScreenResourceNum == screenNum) { + return 4; + } + return -1; +} + void Resource::loadSssData(File *fp, const uint32_t baseOffset) { - assert(fp == _sssFile || fp == _datFile); + assert(fp == _sssFile || fp == _datFile || fp == _lvlFile); if (_sssHdr.bufferSize != 0) { const int count = MIN(_sssHdr.pcmCount, _sssHdr.preloadPcmCount); @@ -795,7 +851,7 @@ void Resource::loadSssData(File *fp, const uint32_t baseOffset) { bytesRead += kSizeOfPreloadInfoData_V10 * count; for (int j = 0; j < count; ++j) { const int len = READ_LE_UINT32(p + j * kSizeOfPreloadInfoData_V10 + 0x1C) * 4; - bytesRead += skipBytesAlign(_sssFile, len); + bytesRead += skipBytesAlign(fp, len); } free(p); } @@ -811,7 +867,7 @@ void Resource::loadSssData(File *fp, const uint32_t baseOffset) { static const int8_t lengths[8] = { 2, 1, 1, 2, 2, 1, 1, 1 }; for (int k = 0; k < 8; ++k) { const int len = READ_LE_UINT32(p + j * kSizeOfPreloadInfoData_V6 + offsets[k]) * lengths[k]; - bytesRead += skipBytesAlign(_sssFile, len); + bytesRead += skipBytesAlign(fp, len); } } free(p); @@ -832,7 +888,7 @@ void Resource::loadSssData(File *fp, const uint32_t baseOffset) { assert((_sssPcmTable[i].totalSize % _sssPcmTable[i].strideSize) == 0); assert(_sssPcmTable[i].totalSize == _sssPcmTable[i].strideSize * _sssPcmTable[i].strideCount); if (sssPcmOffset != 0) { - assert(_sssPcmTable[i].offset == 0x2800); // .dat + assert(fp != _datFile || _sssPcmTable[i].offset == 0x2800); // .dat _sssPcmTable[i].offset += sssPcmOffset; sssPcmOffset += _sssPcmTable[i].totalSize; } @@ -961,28 +1017,23 @@ uint32_t Resource::getSssPcmSize(const SssPcm *pcm) const { return (pcm->strideSize - 256 * sizeof(int16_t)) * pcm->strideCount * sizeof(int16_t); } -void Resource::loadSssPcm(File *fp, int num) { - if (_sssPcmTable[num].ptr) { - return; - } - SssPcm *pcm = &_sssPcmTable[num]; +void Resource::loadSssPcm(File *fp, SssPcm *pcm) { + assert(!pcm->ptr); const uint32_t decompressedSize = getSssPcmSize(pcm); if (decompressedSize != 0) { - debug(kDebug_SOUND, "Loading PCM %d decompressedSize %d", num, decompressedSize); + debug(kDebug_SOUND, "Loading PCM %p decompressedSize %d", pcm, decompressedSize); int16_t *p = (int16_t *)malloc(decompressedSize); if (!p) { - warning("Failed to allocate %d bytes for PCM %d", decompressedSize, num); + warning("Failed to allocate %d bytes for PCM", decompressedSize); return; } pcm->ptr = p; fp->seek(pcm->offset, SEEK_SET); for (int i = 0; i < pcm->strideCount; ++i) { - int16_t lut[256]; - for (int j = 0; j < 256; ++j) { - lut[j] = fp->readUint16(); - } - for (uint32_t j = 256 * sizeof(int16_t); j < pcm->strideSize; ++j) { - *p++ = lut[fp->readByte()]; + uint8_t samples[256 * sizeof(int16_t)]; + fp->read(samples, sizeof(samples)); + for (unsigned int j = 256 * sizeof(int16_t); j < pcm->strideSize; ++j) { + *p++ = READ_LE_UINT16(samples + fp->readByte() * sizeof(int16_t)); } } assert((p - pcm->ptr) * sizeof(int16_t) == decompressedSize); @@ -1033,9 +1084,9 @@ void Resource::loadMstData(File *fp) { _mstHdr.movingBoundsIndexDataCount = fp->readUint32(); _mstHdr.levelCheckpointCodeDataCount = fp->readUint32(); _mstHdr.screenAreaDataCount = fp->readUint32(); - _mstHdr.unk0x1C = fp->readUint32(); + _mstHdr.screenAreaIndexDataCount = fp->readUint32(); _mstHdr.behaviorIndexDataCount = fp->readUint32(); - _mstHdr.unk0x24 = fp->readUint32(); + _mstHdr.monsterActionIndexDataCount = fp->readUint32(); _mstHdr.walkPathDataCount = fp->readUint32(); _mstHdr.infoMonster2Count = fp->readUint32(); _mstHdr.behaviorDataCount = fp->readUint32(); @@ -1138,15 +1189,15 @@ void Resource::loadMstData(File *fp) { bytesRead += 36; } - _mstUnk39.allocate(_mstHdr.unk0x1C); - for (int i = 0; i < _mstHdr.unk0x1C; ++i) { - _mstUnk39[i] = fp->readUint32(); + _mstScreenAreaByValueIndexData.allocate(_mstHdr.screenAreaIndexDataCount); + for (int i = 0; i < _mstHdr.screenAreaIndexDataCount; ++i) { + _mstScreenAreaByValueIndexData[i] = fp->readUint32(); bytesRead += 4; } - _mstUnk40.allocate(_mstHdr.screensCount); + _mstScreenAreaByPosIndexData.allocate(_mstHdr.screensCount); for (int i = 0; i < _mstHdr.screensCount; ++i) { - _mstUnk40[i] = fp->readUint32(); + _mstScreenAreaByPosIndexData[i] = fp->readUint32(); bytesRead += 4; } @@ -1174,22 +1225,22 @@ void Resource::loadMstData(File *fp) { bytesRead += readBytesAlign(fp, _mstBehaviorIndexData[i].data, _mstBehaviorIndexData[i].dataCount); } - _mstUnk43.allocate(_mstHdr.unk0x24); - for (int i = 0; i < _mstHdr.unk0x24; ++i) { + _mstMonsterActionIndexData.allocate(_mstHdr.monsterActionIndexDataCount); + for (int i = 0; i < _mstHdr.monsterActionIndexDataCount; ++i) { fp->readUint32(); - _mstUnk43[i].count1 = fp->readUint32(); - _mstUnk43[i].indexUnk48 = (uint32_t *)malloc(_mstUnk43[i].count1 * sizeof(uint32_t)); + _mstMonsterActionIndexData[i].count1 = fp->readUint32(); + _mstMonsterActionIndexData[i].indexUnk48 = (uint32_t *)malloc(_mstMonsterActionIndexData[i].count1 * sizeof(uint32_t)); fp->readUint32(); - _mstUnk43[i].dataCount = fp->readUint32(); - _mstUnk43[i].data = (uint8_t *)malloc(_mstUnk43[i].dataCount); + _mstMonsterActionIndexData[i].dataCount = fp->readUint32(); + _mstMonsterActionIndexData[i].data = (uint8_t *)malloc(_mstMonsterActionIndexData[i].dataCount); bytesRead += 16; } - for (int i = 0; i < _mstHdr.unk0x24; ++i) { - for (uint32_t j = 0; j < _mstUnk43[i].count1; ++j) { - _mstUnk43[i].indexUnk48[j] = fp->readUint32(); + for (int i = 0; i < _mstHdr.monsterActionIndexDataCount; ++i) { + for (uint32_t j = 0; j < _mstMonsterActionIndexData[i].count1; ++j) { + _mstMonsterActionIndexData[i].indexUnk48[j] = fp->readUint32(); bytesRead += 4; } - bytesRead += readBytesAlign(fp, _mstUnk43[i].data, _mstUnk43[i].dataCount); + bytesRead += readBytesAlign(fp, _mstMonsterActionIndexData[i].data, _mstMonsterActionIndexData[i].dataCount); } _mstWalkPathData.allocate(_mstHdr.walkPathDataCount); @@ -1589,11 +1640,11 @@ void Resource::unloadMstData() { free(_mstBehaviorIndexData[i].data); _mstBehaviorIndexData[i].data = 0; } - for (int i = 0; i < _mstHdr.unk0x24; ++i) { - free(_mstUnk43[i].indexUnk48); - _mstUnk43[i].indexUnk48 = 0; - free(_mstUnk43[i].data); - _mstUnk43[i].data = 0; + for (int i = 0; i < _mstHdr.monsterActionIndexDataCount; ++i) { + free(_mstMonsterActionIndexData[i].indexUnk48); + _mstMonsterActionIndexData[i].indexUnk48 = 0; + free(_mstMonsterActionIndexData[i].data); + _mstMonsterActionIndexData[i].data = 0; } for (int i = 0; i < _mstHdr.walkPathDataCount; ++i) { free(_mstWalkPathData[i].data); @@ -1644,7 +1695,7 @@ void Resource::unloadMstData() { } const MstScreenArea *Resource::findMstCodeForPos(int num, int xPos, int yPos) const { - uint32_t i = _mstUnk40[num]; + uint32_t i = _mstScreenAreaByPosIndexData[num]; while (i != kNone) { const MstScreenArea *msac = &_mstScreenAreaData[i]; if (msac->x1 <= xPos && msac->x2 >= xPos && msac->unk0x1D != 0 && msac->y1 <= yPos && msac->y2 >= yPos) { @@ -1656,7 +1707,7 @@ const MstScreenArea *Resource::findMstCodeForPos(int num, int xPos, int yPos) co } void Resource::flagMstCodeForPos(int num, uint8_t value) { - uint32_t i = _mstUnk39[num]; + uint32_t i = _mstScreenAreaByValueIndexData[num]; while (i != kNone) { MstScreenArea *msac = &_mstScreenAreaData[i]; msac->unk0x1D = value; diff --git a/resource.h b/resource.h index 91ea0d4..2072318 100644 --- a/resource.h +++ b/resource.h @@ -65,8 +65,7 @@ struct LvlBackgroundData { uint8_t *dataUnk0Table[4]; // unused uint8_t *backgroundMaskTable[4]; uint8_t *backgroundSoundTable[4]; - uint8_t *backgroundAnimationTable[4]; - uint8_t *dataUnk4Table[4]; // unused + uint8_t *backgroundAnimationTable[8]; LvlObjectData *backgroundLvlObjectDataTable[4]; uint8_t *dataUnk6Table[4]; // unused }; @@ -79,9 +78,9 @@ struct MstHdr { int movingBoundsIndexDataCount; // 10 int levelCheckpointCodeDataCount; // 14 int screenAreaDataCount; // 18 - int unk0x1C; // mstUnk39DataCount + int screenAreaIndexDataCount; // 1C int behaviorIndexDataCount; // 20 - int unk0x24; // mstUnk43DataCount + int monsterActionIndexDataCount; // 24 int walkPathDataCount; // 28 int infoMonster2Count; // 2C int behaviorDataCount; // 30 @@ -117,10 +116,10 @@ struct MstScreenArea { int32_t x2; // 4 int32_t y1; // 8 int32_t y2; // 0xC - uint32_t nextByPos; // 0x10 _mstUnk40 + uint32_t nextByPos; // 0x10 _mstScreenAreaByPosIndexData uint32_t prev; // 0x14 unused - uint32_t nextByValue; // 0x18 indexUnk39 - uint8_t unk0x1C; // 0x1C indexUnk39 + uint32_t nextByValue; // 0x18 _mstScreenAreaByValueIndexData + uint8_t unk0x1C; // 0x1C _mstScreenAreaByValueIndexData uint8_t unk0x1D; // 0x1D value uint16_t unk0x1E; // 0x1E unused uint32_t codeData; // 0x20, offset _mstCodeData @@ -154,7 +153,7 @@ struct MstBehaviorIndex { // u42 uint32_t dataCount; // C }; // sizeof == 16 -struct MstUnk43 { // MstMonsterActionIndex +struct MstMonsterActionIndex { // u43 uint32_t *indexUnk48; // indexes _mstMonsterActionData uint32_t count1; // 4 uint8_t *data; // 8 lut - indexes .indexUnk48 @@ -529,6 +528,8 @@ struct Resource { SssHdr _sssHdr; File *_sssFile; + bool _isPsx; + uint8_t *_loadingImageBuffer; uint8_t *_fontBuffer; uint8_t *_menuBuffer0; @@ -537,12 +538,13 @@ struct Resource { uint8_t _currentScreenResourceNum; - uint8_t _screensGrid[kMaxScreens * 4]; + uint8_t _screensGrid[kMaxScreens][4]; LvlScreenVector _screensBasePos[kMaxScreens]; LvlScreenState _screensState[kMaxScreens]; uint8_t *_resLevelData0x470CTable; uint8_t *_resLevelData0x470CTablePtrHdr; uint8_t *_resLevelData0x470CTablePtrData; + uint32_t _lvlSssOffset; uint32_t _resLevelData0x2B88SizeTable[kMaxScreens]; uint32_t _resLevelData0x2988SizeTable[kMaxSpriteTypes]; LvlObjectData _resLevelData0x2988Table[kMaxScreens]; @@ -575,11 +577,11 @@ struct Resource { uint32_t _mstTickCodeData; ResStruct _mstLevelCheckpointCodeData; ResStruct _mstScreenAreaData; - ResStruct _mstUnk39; // indexes _mstScreenAreaData - ResStruct _mstUnk40; // indexes _mstScreenAreaData + ResStruct _mstScreenAreaByValueIndexData; + ResStruct _mstScreenAreaByPosIndexData; ResStruct _mstUnk41; ResStruct _mstBehaviorIndexData; - ResStruct _mstUnk43; + ResStruct _mstMonsterActionIndexData; ResStruct _mstWalkPathData; ResStruct _mstInfoMonster2Data; ResStruct _mstBehaviorData; @@ -614,10 +616,7 @@ struct Resource { void loadLevelData(int levelNum); - void loadLvlScreenGridData(int num); - void loadLvlScreenVectorData(int num); - void loadLvlScreenStateData(int num); - void loadLvlScreenObjectData(int num); + void loadLvlScreenObjectData(LvlObject *dat, const uint8_t *src); void loadLvlData(File *fp); void unloadLvlData(); void loadLvlSpriteData(int num); @@ -630,13 +629,14 @@ struct Resource { bool isLvlBackgroundDataLoaded(int num) const; void incLvlSpriteDataRefCounter(LvlObject *ptr); void decLvlSpriteDataRefCounter(LvlObject *ptr); - const uint8_t *getLvlSpriteFramePtr(LvlObjectData *dat, int frame) const; + const uint8_t *getLvlSpriteFramePtr(LvlObjectData *dat, int frame, uint16_t *w, uint16_t *h) const; const uint8_t *getLvlSpriteCoordPtr(LvlObjectData *dat, int num) const; + int findScreenGridIndex(int screenNum) const; void loadSssData(File *fp, const uint32_t baseOffset = 0); void unloadSssData(); void checkSssCode(const uint8_t *buf, int size) const; - void loadSssPcm(File *fp, int num); + void loadSssPcm(File *fp, SssPcm *pcm); uint32_t getSssPcmSize(const SssPcm *pcm) const; void clearSssGroup3(); void resetSssFilters(); diff --git a/sound.cpp b/sound.cpp index c4d1e66..7d24315 100644 --- a/sound.cpp +++ b/sound.cpp @@ -878,14 +878,16 @@ SssObject *Game::startSoundObject(int bankIndex, int sampleIndex, uint32_t flags SssSample *sample = &_res->_sssSamplesData[sampleNum]; // original loads the PCM data in a seperate thread - _res->loadSssPcm(_res->_sssFile, sample->pcm); + SssPcm *pcm = &_res->_sssPcmTable[sample->pcm]; + if (!pcm->ptr) { + _res->loadSssPcm(_res->_sssFile, pcm); + } if (sample->framesCount != 0) { SssFilter *filter = &_res->_sssFilters[bank->sssFilter]; const int priority = CLIP(filter->priorityCurrent + sample->initPriority, 0, 7); uint32_t flags1 = flags & 0xFFF0F000; flags1 |= ((sampleIndex & 0xF) << 16) | (bankIndex & 0xFFF); - SssPcm *pcm = &_res->_sssPcmTable[sample->pcm]; SssObject *so = addSoundObject(pcm, priority, flags1, flags); if (so) { if (sample->codeOffset1 == kNone && sample->codeOffset2 == kNone && sample->codeOffset3 == kNone && sample->codeOffset4 == kNone) { @@ -941,7 +943,7 @@ SssObject *Game::startSoundObject(int bankIndex, int sampleIndex, uint32_t flags tmpObj.lvlObject = _currentSoundLvlObject; tmpObj.panningPtr = 0; debug(kDebug_SOUND, "startSoundObject dpcm %d", sample->pcm); - tmpObj.pcm = &_res->_sssPcmTable[sample->pcm]; + tmpObj.pcm = pcm; if (sample->codeOffset1 != kNone) { const uint8_t *code = _res->_sssCodeData + sample->codeOffset1; executeSssCode(&tmpObj, code, true); diff --git a/staticres.cpp b/staticres.cpp index 103226c..a3190fb 100644 --- a/staticres.cpp +++ b/staticres.cpp @@ -663,7 +663,7 @@ uint8_t Game::_lar1_maskData[15 * 6] = { 0x58, 0x60, 0x12, 0x00, 0x04, 0x00, 0xC0, 0x30, 0x17, 0x00 }; -const uint8_t Video::_fontCharactersTable[78] = { +const uint8_t Video::_fontCharactersTable[39 * 2] = { 0x30, 0x00, 0x31, 0x01, 0x32, 0x02, 0x33, 0x03, 0x34, 0x04, 0x35, 0x05, 0x36, 0x06, 0x37, 0x07, 0x38, 0x08, 0x39, 0x09, 0x41, 0x0a, 0x42, 0x0b, 0x43, 0x0c, 0x44, 0x0d, 0x45, 0x0e, 0x46, 0x0f, 0x47, 0x10, 0x48, 0x11, 0x49, 0x12, 0x4a, 0x13, 0x4b, 0x14, 0x4c, 0x15, 0x4d, 0x16, 0x4e, 0x17, diff --git a/system_sdl2.cpp b/system_sdl2.cpp index 9700c53..decb3a7 100644 --- a/system_sdl2.cpp +++ b/system_sdl2.cpp @@ -181,51 +181,19 @@ void System_SDL2::destroy() { } } - -static void blur_h(int radius, const uint32_t *src, int srcPitch, int w, int h, const SDL_PixelFormat *fmt, uint32_t *dst, int dstPitch) { +template +static void blur(int radius, const uint32_t *src, int srcPitch, int w, int h, const SDL_PixelFormat *fmt, uint32_t *dst, int dstPitch) { const int count = 2 * radius + 1; - for (int y = 0; y < h; ++y) { - - uint32_t r = 0; - uint32_t g = 0; - uint32_t b = 0; - - uint32_t color; - - for (int x = -radius; x <= radius; ++x) { - color = src[MAX(x, 0)]; - r += (color & fmt->Rmask) >> fmt->Rshift; - g += (color & fmt->Gmask) >> fmt->Gshift; - b += (color & fmt->Bmask) >> fmt->Bshift; - } - dst[0] = ((r / count) << fmt->Rshift) | ((g / count) << fmt->Gshift) | ((b / count) << fmt->Bshift); - - for (int x = 1; x < w; ++x) { - color = src[MIN(x + radius, w - 1)]; - r += (color & fmt->Rmask) >> fmt->Rshift; - g += (color & fmt->Gmask) >> fmt->Gshift; - b += (color & fmt->Bmask) >> fmt->Bshift; + const uint32_t rmask = fmt->Rmask; + const uint32_t rshift = fmt->Rshift; + const uint32_t gmask = fmt->Gmask; + const uint32_t gshift = fmt->Gshift; + const uint32_t bmask = fmt->Bmask; + const uint32_t bshift = fmt->Bshift; - color = src[MAX(x - radius - 1, 0)]; - r -= (color & fmt->Rmask) >> fmt->Rshift; - g -= (color & fmt->Gmask) >> fmt->Gshift; - b -= (color & fmt->Bmask) >> fmt->Bshift; - - dst[x] = ((r / count) << fmt->Rshift) | ((g / count) << fmt->Gshift) | ((b / count) << fmt->Bshift); - } - - src += srcPitch; - dst += dstPitch; - } -} - -static void blur_v(int radius, const uint32_t *src, int srcPitch, int w, int h, const SDL_PixelFormat *fmt, uint32_t *dst, int dstPitch) { - - const int count = 2 * radius + 1; - - for (int x = 0; x < w; ++x) { + for (int j = 0; j < (vertical ? w : h); ++j) { uint32_t r = 0; uint32_t g = 0; @@ -233,30 +201,48 @@ static void blur_v(int radius, const uint32_t *src, int srcPitch, int w, int h, uint32_t color; - for (int y = -radius; y <= radius; ++y) { - color = src[MAX(y, 0) * srcPitch]; - r += (color & fmt->Rmask) >> fmt->Rshift; - g += (color & fmt->Gmask) >> fmt->Gshift; - b += (color & fmt->Bmask) >> fmt->Bshift; + for (int i = -radius; i <= radius; ++i) { + if (vertical) { + color = src[MAX(i, 0) * srcPitch]; + } else { + color = src[MAX(i, 0)]; + } + r += (color & rmask) >> rshift; + g += (color & gmask) >> gshift; + b += (color & bmask) >> bshift; } - dst[0] = ((r / count) << fmt->Rshift) | ((g / count) << fmt->Gshift) | ((b / count) << fmt->Bshift); - - for (int y = 1; y < h; ++y) { - color = src[MIN(y + radius, h - 1) * srcPitch]; - r += (color & fmt->Rmask) >> fmt->Rshift; - g += (color & fmt->Gmask) >> fmt->Gshift; - b += (color & fmt->Bmask) >> fmt->Bshift; - - color = src[MAX(y - radius - 1, 0) * srcPitch]; - r -= (color & fmt->Rmask) >> fmt->Rshift; - g -= (color & fmt->Gmask) >> fmt->Gshift; - b -= (color & fmt->Bmask) >> fmt->Bshift; - - dst[y * dstPitch] = ((r / count) << fmt->Rshift) | ((g / count) << fmt->Gshift) | ((b / count) << fmt->Bshift); + color = ((r / count) << rshift) | ((g / count) << gshift) | ((b / count) << bshift); + dst[0] = color; + + for (int i = 1; i < (vertical ? h : w); ++i) { + if (vertical) { + color = src[MIN(i + radius, h - 1) * srcPitch]; + } else { + color = src[MIN(i + radius, w - 1)]; + } + r += (color & rmask) >> rshift; + g += (color & gmask) >> gshift; + b += (color & bmask) >> bshift; + + if (vertical) { + color = src[MAX(i - radius - 1, 0) * srcPitch]; + } else { + color = src[MAX(i - radius - 1, 0)]; + } + r -= (color & rmask) >> rshift; + g -= (color & gmask) >> gshift; + b -= (color & bmask) >> bshift; + + color = ((r / count) << rshift) | ((g / count) << gshift) | ((b / count) << bshift); + if (vertical) { + dst[i * srcPitch] = color; + } else { + dst[i] = color; + } } - ++src; - ++dst; + src += vertical ? 1 : srcPitch; + dst += vertical ? 1 : dstPitch; } } @@ -271,8 +257,8 @@ void System_SDL2::copyRectWidescreen(int w, int h, const uint8_t *buf, const uin if (SDL_LockTexture(_widescreenTexture, 0, &ptr, &pitch) == 0) { assert((pitch & 3) == 0); - uint32_t *src = (uint32_t *)malloc(w * sizeof(uint32_t) * h * sizeof(uint32_t)); - uint32_t *tmp = (uint32_t *)malloc(w * sizeof(uint32_t) * h * sizeof(uint32_t)); + uint32_t *src = (uint32_t *)malloc(w * h * sizeof(uint32_t)); + uint32_t *tmp = (uint32_t *)malloc(w * h * sizeof(uint32_t)); uint32_t *dst = (uint32_t *)ptr; if (src && tmp) { @@ -281,8 +267,10 @@ void System_SDL2::copyRectWidescreen(int w, int h, const uint8_t *buf, const uin src[i] = SDL_MapRGB(_fmt, _gammaLut[pal[color * 3]], _gammaLut[pal[color * 3 + 1]], _gammaLut[pal[color * 3 + 2]]); } static const int radius = 8; - blur_h(radius, src, w, w, h, _fmt, tmp, w); - blur_v(radius, tmp, w, w, h, _fmt, dst, pitch / sizeof(uint32_t)); + // horizontal pass + blur(radius, src, w, w, h, _fmt, tmp, w); + // vertical pass + blur(radius, tmp, w, w, h, _fmt, dst, pitch / sizeof(uint32_t)); } free(src); @@ -396,11 +384,8 @@ void System_SDL2::updateScreen(bool drawWidescreen) { } } uint32_t *p = (_scalerMultiplier == 1) ? dst : _offscreenRgb; - for (int y = 0; y < h; ++y) { - for (int x = 0; x < w; ++x) { - p[x] = _pal[src[y * w + x]]; - } - p += w; + for (int i = 0; i < w * h; ++i) { + p[i] = _pal[src[i]]; } if (_scalerMultiplier != 1) { _scaler->scale(_scalerMultiplier, dst, dstPitch, _offscreenRgb, srcPitch, w, h); @@ -698,25 +683,24 @@ void System_SDL2::setupDefaultKeyMappings() { addKeyMapping(SDL_SCANCODE_RETURN, SYS_INP_JUMP); addKeyMapping(SDL_SCANCODE_LCTRL, SYS_INP_RUN); -// addKeyMapping(SDL_SCANCODE_f, SYS_INP_RUN); + addKeyMapping(SDL_SCANCODE_F, SYS_INP_RUN); // addKeyMapping(SDL_SCANCODE_LALT, SYS_INP_JUMP); -// addKeyMapping(SDL_SCANCODE_g, SYS_INP_JUMP); + addKeyMapping(SDL_SCANCODE_G, SYS_INP_JUMP); addKeyMapping(SDL_SCANCODE_LSHIFT, SYS_INP_SHOOT); -// addKeyMapping(SDL_SCANCODE_h, SYS_INP_SHOOT); -// addKeyMapping(SDL_SCANCODE_d, SYS_INP_SHOOT | SYS_INP_RUN); -// addKeyMapping(SDL_SCANCODE_SPACE, SYS_INP_SHOOT | SYS_INP_RUN); + addKeyMapping(SDL_SCANCODE_H, SYS_INP_SHOOT); + addKeyMapping(SDL_SCANCODE_D, SYS_INP_SHOOT | SYS_INP_RUN); + addKeyMapping(SDL_SCANCODE_SPACE, SYS_INP_SHOOT | SYS_INP_RUN); addKeyMapping(SDL_SCANCODE_ESCAPE, SYS_INP_ESC); } void System_SDL2::updateKeys(PlayerInput *inp) { inp->prevMask = inp->mask; + inp->mask = 0; const uint8_t *keyState = SDL_GetKeyboardState(NULL); for (int i = 0; i < _keyMappingsCount; ++i) { - KeyMapping *keyMap = &_keyMappings[i]; + const KeyMapping *keyMap = &_keyMappings[i]; if (keyState[keyMap->keyCode]) { inp->mask |= keyMap->mask; - } else { - inp->mask &= ~keyMap->mask; } } inp->mask |= pad.mask; diff --git a/video.cpp b/video.cpp index 5c9bed2..6b8b69d 100644 --- a/video.cpp +++ b/video.cpp @@ -6,6 +6,7 @@ #include "video.h" #include "system.h" +static const bool kUseShadowColorLut = false; static const bool _findBlackColor = false; Video::Video(System *system) @@ -24,7 +25,11 @@ Video::Video(System *system) _spr.y = 0; _spr.w = W; _spr.h = H; - _shadowColorLookupTable = (uint8_t *)malloc(256 * 256); // shadowLayer, frontLayer + if (kUseShadowColorLut) { + _shadowColorLookupTable = (uint8_t *)malloc(256 * 256); // shadowLayer, frontLayer + } else { + _shadowColorLookupTable = 0; + } _shadowScreenMaskBuffer = (uint8_t *)malloc(256 * 192 * 2 + 256 * 4); _transformShadowBuffer = 0; _transformShadowLayerDelta = 0; @@ -241,39 +246,36 @@ bool Video::clipLineCoords(int &x1, int &y1, int &x2, int &y2) { int mask1 = computeLineOutCode(x2, y2); while (1) { const int mask2 = computeLineOutCode(x1, y1); - int mask = mask2; if (mask2 == 0 && mask1 == 0) { break; } - if ((mask1 & mask) != 0) { + if ((mask1 & mask2) != 0) { return true; } - if (mask & 1) { // (x < _drawLine.x1) + if (mask2 & 1) { // (x < _drawLine.x1) y1 += (y2 - y1) * (_drawLine.x1 - x1) / (x2 - x1); x1 = _drawLine.x1; continue; } - mask >>= 8; - if (mask & 1) { // (y < _drawLine.y1) + if (mask2 & 0x100) { // (y < _drawLine.y1) x1 += (x2 - x1) * (_drawLine.y1 - y1) / (y2 - y1); y1 = _drawLine.y1; continue; } - mask >>= 8; - if (mask & 1) { // (x > _drawLine.x2) + if (mask2 & 0x10000) { // (x > _drawLine.x2) y1 += (y2 - y1) * (_drawLine.x2 - x1) / (x2 - x1); x1 = _drawLine.x2; continue; } - mask >>= 8; - if (mask & 1) { // (y > _drawLine.y2) + if (mask2 & 0x1000000) { // (y > _drawLine.y2) x1 += (x2 - x1) * (_drawLine.y2 - y1) / (y2 - y1); y1 = _drawLine.y2; continue; } SWAP(x1, x2); SWAP(y1, y2); - SWAP(mask, mask1); + assert(mask2 == 0); + mask1 = 0; } return false; } @@ -348,10 +350,7 @@ void Video::drawLine(int x1, int y1, int x2, int y2) { } static uint8_t lookupColor(uint8_t a, uint8_t b, const uint8_t *lut) { - // if (a < 144) return b; - // else if (b < 144) return lut[b]; - // else return b; - return (a < 144) ? b : lut[b]; + return (a >= 144 && b < 144) ? lut[b] : b; } void Video::applyShadowColors(int x, int y, int src_w, int src_h, int dst_pitch, int src_pitch, uint8_t *dst1, uint8_t *dst2, uint8_t *src1, uint8_t *src2) { @@ -430,8 +429,8 @@ void Video::buildShadowColorLookupTable(const uint8_t *src, uint8_t *dst) { // returns the font index uint8_t Video::findStringCharacterFontIndex(uint8_t chr) const { - // the original code seems to ignore the last 3 entries - for (int i = 0; i < 36 * 2; i += 2) { + // bugfix: the original code seems to ignore the last 3 entries + for (int i = 0; i < 39 * 2; i += 2) { if (_fontCharactersTable[i] == chr) { return _fontCharactersTable[i + 1]; }