diff --git a/engines/startrek/awaymission.cpp b/engines/startrek/awaymission.cpp index 73526eeaa2a..77576d295c3 100644 --- a/engines/startrek/awaymission.cpp +++ b/engines/startrek/awaymission.cpp @@ -158,10 +158,10 @@ void StarTrekEngine::handleAwayMissionEvents() { _gfx->incPaletteFadeLevel(); break; case TREKEVENT_LBUTTONDOWN: - if (_awayMission.field1d != 0) - break; + //if (_awayMission.field1d != 0) // FIXME: uncomment + // break; switch (_awayMission.mapFileLoaded) { - case 0: + case 1: if (_awayMission.field1c == 0) { _kirkObject->sprite.drawMode = 1; // Hide these objects for function call below? _spockObject->sprite.drawMode = 1; @@ -178,11 +178,9 @@ void StarTrekEngine::handleAwayMissionEvents() { Common::String animFilename = getCrewmanAnimFilename(0, "walk"); Common::Point mousePos = _gfx->getMousePos(); - // objectWalkToPosition(0, animFilename, _kirkObject->pos.x, _kirkObject->pos.y, mousePos.x, mousePos.y); + objectWalkToPosition(0, animFilename, _kirkObject->pos.x, _kirkObject->pos.y, mousePos.x, mousePos.y); } break; - case 1: - break; case 2: break; case 3: @@ -232,6 +230,17 @@ Room *StarTrekEngine::getRoom() { } void StarTrekEngine::runAwayMissionCycle() { + // TODO +} + +/** + * Returns true if the given position in the room is solid (not walkable). + * Reads from a ".map" file which has a bit for each position in the room, which is true + * when that position is solid. + */ +bool StarTrekEngine::isPositionSolid(int16 x, int16 y) { + _mapFile->seek((y * SCREEN_WIDTH + x) / 8, SEEK_SET); + return _mapFile->readByte() & (0x80 >> (x % 8)); } } diff --git a/engines/startrek/awaymission.h b/engines/startrek/awaymission.h index 290e5e39f51..f2a9ca68c4f 100644 --- a/engines/startrek/awaymission.h +++ b/engines/startrek/awaymission.h @@ -28,7 +28,7 @@ struct AwayMission { int16 mouseX; int16 mouseY; byte field1c; - byte field1d; + byte field1d; // Set while beaming in? bool redshirtDead; byte mapFileLoaded; int8 field25[4]; diff --git a/engines/startrek/object.h b/engines/startrek/object.h index d9b16da8752..d1cd8fb649d 100644 --- a/engines/startrek/object.h +++ b/engines/startrek/object.h @@ -54,21 +54,25 @@ struct Object { uint16 field72; uint16 field74; uint16 field76; - uint16 iwSrcPosition; - uint16 iwDestPosition; - uint16 field7c; - uint16 field7e; - uint16 field80; - uint16 field82; - uint16 field84; - uint16 field86; - uint16 field88; - uint16 field8a; - uint16 field8c; - uint16 field8e; + int16 iwSrcPosition; + int16 iwDestPosition; + + // Fixed-point position values (16.16) used while walking. + uint32 granularPosX; + uint32 granularPosY; + + // Fixed-point speed values (16.16). + uint32 speedX; + uint32 speedY; + + Common::Point dest; // Position object is walking toward uint16 field90; byte field92; - char direction; // Can 'n', 's', 'e', 'w', or 0 for uninitialized? + + // Can 'n', 's', 'e', 'w', or 0 for uninitialized? + // Can also be capitalized? + char direction; + uint16 field94; uint16 field96; char animationString[9]; diff --git a/engines/startrek/startrek.cpp b/engines/startrek/startrek.cpp index 346cb910819..9cafd443651 100644 --- a/engines/startrek/startrek.cpp +++ b/engines/startrek/startrek.cpp @@ -100,7 +100,7 @@ Common::Error StarTrekEngine::run() { _gameMode = -1; _lastGameMode = -1; - runGameMode(GAMEMODE_BEAMDOWN); + runGameMode(GAMEMODE_AWAYMISSION); return Common::kNoError; @@ -381,6 +381,43 @@ int StarTrekEngine::loadObjectAnim(int objectIndex, const Common::String &animNa return objectIndex; } +/** + * Tries to make an object walk to a position. + * Returns true if successful in initiating the walk. + */ +bool StarTrekEngine::objectWalkToPosition(int objectIndex, const Common::String &animFile, int16 srcX, int16 srcY, int16 destX, int16 destY) { + debugC(6, "Obj %d: walk from (%d,%d) to (%d,%d)", objectIndex, srcX, srcY, destX, destY); + + Object *object = &_objectList[objectIndex]; + + object->field64 = 0; + if (isPositionSolid(destX, destY)) + return false; + + if (object->spriteDrawn) + releaseAnim(object); + else + _gfx->addSprite(&object->sprite); + + object->spriteDrawn = true; + object->animType = 1; + object->frameToStartNextAnim = _frameIndex + 1; + strcpy(object->animationString2, animFile.c_str()); + + object->dest.x = destX; + object->dest.y = destY; + object->field92 = 0; + object->field64 = 0; + + object->iwDestPosition = -1; + object->iwSrcPosition = -1; + + // TODO: if (directPathExists(srcX, srcY, destX, destY)) { + + chooseObjectDirectionForWalking(object, srcX, srcY, destX, destY); + updateObjectPositionWhileWalking(object, (object->granularPosX + 0x8000) >> 16, (object->granularPosY + 0x8000) >> 16); +} + void StarTrekEngine::updateObjectAnimations() { for (int i = 0; i < MAX_OBJECTS; i++) { Object *object = &_objectList[i]; @@ -388,7 +425,7 @@ void StarTrekEngine::updateObjectAnimations() { continue; switch (object->animType) { - case 0: + case 0: // Not walking? case 2: if (_frameIndex >= object->frameToStartNextAnim) { int nextAnimIndex = 0; // TODO: "chooseNextAnimFrame" function @@ -439,8 +476,60 @@ void StarTrekEngine::updateObjectAnimations() { } } break; - case 1: // TODO - warning("Unimplemented anim type %d", object->animType); + case 1: // Walking + if (_frameIndex < object->frameToStartNextAnim) + break; + /* + if (i == 0) // TODO: Kirk only + sub_22c2d(object->pos.x, object->pos.y); + */ + if (object->field90 != 0) { + Sprite *sprite = &object->sprite; + int loops; + if (getObjectScaleAtPosition((object->granularPosY + 0x8000) >> 16) < 0xa0) + loops = 1; + else + loops = 2; + for (int k = 0; k < loops; k++) { + if (object->field90 == 0) + break; + object->field90--; + uint32 newX = object->granularPosX + object->speedX; + uint32 newY = object->granularPosY + object->speedY; + if ((object->field90 & 3) == 0) { + sprite->bitmap.reset(); + updateObjectPositionWhileWalking(object, (newX + 0x8000) >> 16, (newY + 0x8000) >> 16); + object->field92++; + } + + object->granularPosX = newX; + object->granularPosY = newY; + object->frameToStartNextAnim = _frameIndex; + } + } + else { // object->field90 == 0 + if (object->iwSrcPosition == -1) { + if (object->field64 != 0) { + object->field64 = 0; + //addCommand(COMMAND_12, object->field66 & 0xff, 0, 0); + } + + object->sprite.bitmap.reset(); + updateObjectPositionWhileWalking(object, (object->granularPosX + 0x8000) >> 16, (object->granularPosY + 0x8000) >> 16); + initStandAnim(i); + } + else { // object->iwSrcPosition != -1 + if (object->iwSrcPosition == object->iwDestPosition) { + object->animationString2[strlen(object->animationString2) - 1] = '\0'; + object->iwDestPosition = -1; + object->iwSrcPosition = -1; + // sub_11677(object->pos.x, object->pos.y, object->dest.x, object->dest.y); + } + else { + + } + } + } break; default: error("Invalid anim type."); @@ -477,7 +566,7 @@ void StarTrekEngine::objectFunc1() { } } -void StarTrekEngine::drawObjectToScreen(Object *object, const Common::String &_animName, uint16 x, uint16 y, uint16 scale, bool addSprite) { +void StarTrekEngine::drawObjectToScreen(Object *object, const Common::String &_animName, int16 x, int16 y, uint16 scale, bool addSprite) { Common::String animFilename = _animName; if (_animName.hasPrefixIgnoreCase("stnd") /* && word_45d20 == -1 */) // TODO animFilename += 'j'; @@ -571,6 +660,86 @@ void StarTrekEngine::initStandAnim(int objectIndex) { object->animType = 0; } +void StarTrekEngine::updateObjectPositionWhileWalking(Object *object, int16 x, int16 y) { + object->scale = getObjectScaleAtPosition(y); + Common::String animName = Common::String::format("%s%02d", object->animationString2, object->field92 & 7); + object->sprite.setBitmap(loadAnimationFrame(animName, object->scale)); + + memset(object->animationString4, 0, 10); + strncpy(object->animationString4, animName.c_str(), 9); + + Sprite *sprite = &object->sprite; + sprite->drawPriority = _gfx->getPriValue(0, y); + sprite->pos.x = x; + sprite->pos.y = y; + sprite->bitmapChanged = true; + + object->frameToStartNextAnim = _frameIndex; + object->pos.x = x; + object->pos.y = y; +} + +/** + * Chooses a value for the object's speed and direction, based on a source position and + * a destination position it's walking to. + */ +void StarTrekEngine::chooseObjectDirectionForWalking(Object *object, int16 srcX, int16 srcY, int16 destX, int16 destY) { + object->granularPosX = srcX << 16; + object->granularPosY = srcY << 16; + + int16 distX = destX - srcX; + int16 distY = destY - srcY; + int16 absDistX = abs(distX); + int16 absDistY = abs(distY); + + if (absDistX > absDistY) { + char d; + if (distX > 0) + d = 'E'; + else + d = 'W'; + + // Append direction to animation string + object->animationString2[strlen(object->animationString2) + 1] = '\0'; + object->animationString2[strlen(object->animationString2)] = d; + + object->direction = d; + object->field90 = absDistX; + + if (distX != 0) { + if (distX > 0) + object->speedX = 1 << 16; + else + object->speedX = -1 << 16; // 0xffff0000 + + object->speedY = (distY << 16) / absDistX; + } + } + else { + char d; + if (distY > 0) + d = 'S'; + else + d = 'N'; + + // Append direction to animation string + object->animationString2[strlen(object->animationString2) + 1] = '\0'; + object->animationString2[strlen(object->animationString2)] = d; + + object->direction = d; + object->field90 = absDistY; + + if (distY != 0) { + if (distY > 0) + object->speedY = 1 << 16; + else + object->speedY = -1 << 16; // 0xffff0000 + + object->speedX = (distX << 16) / absDistY; + } + } +} + SharedPtr StarTrekEngine::loadAnimationFrame(const Common::String &filename, uint16 scale) { SharedPtr bitmapToReturn; diff --git a/engines/startrek/startrek.h b/engines/startrek/startrek.h index 52157f4a0c5..68a9d51218d 100644 --- a/engines/startrek/startrek.h +++ b/engines/startrek/startrek.h @@ -99,7 +99,8 @@ struct TrekEvent { enum Commands { COMMAND_TICK = 0, - COMMAND_CLICKED_ON_OBJECT + COMMAND_CLICKED_ON_OBJECT = 1, + COMMAND_12 = 12 }; struct Command { @@ -134,6 +135,8 @@ private: uint16 getObjectScaleAtPosition(int16 y); void runAwayMissionCycle(); + bool isPositionSolid(int16 x, int16 y); + public: Room *getRoom(); @@ -153,13 +156,15 @@ public: // Objects void initObjects(); int loadObjectAnim(int objectIndex, const Common::String &animName, int16 x, int16 y, uint16 arg8); - bool objectWalkToPosition(int objectIndex, Common::Point src, Common::Point dest); + bool objectWalkToPosition(int objectIndex, const Common::String &animFile, int16 srcX, int16 srcY, int16 destX, int16 destY); void updateObjectAnimations(); void removeObjectFromScreen(int objectIndex); void objectFunc1(); - void drawObjectToScreen(Object *object, const Common::String &animName, uint16 field5e, uint16 field60, uint16 arg8, bool addSprite); + void drawObjectToScreen(Object *object, const Common::String &animName, int16 x, int16 y, uint16 scale, bool addSprite); void releaseAnim(Object *object); void initStandAnim(int objectIndex); + void updateObjectPositionWhileWalking(Object *object, int16 x, int16 y); + void chooseObjectDirectionForWalking(Object *object, int16 srcX, int16 srcY, int16 destX, int16 destY); SharedPtr loadAnimationFrame(const Common::String &filename, uint16 arg2); Common::String getCrewmanAnimFilename(int objectIndex, const Common::String &basename);