aboutsummaryrefslogtreecommitdiff
path: root/engines/startrek
diff options
context:
space:
mode:
authorMatthew Stewart2018-05-30 21:06:31 -0400
committerEugene Sandulenko2018-08-09 08:37:30 +0200
commitfe5658ca175810f7ea6cbcaa078e6fc86faf36f1 (patch)
treea5e392c93e9acc72453d88d0782a8837b6ecdf81 /engines/startrek
parent1290b7ea0298dc6a565e2593ecb703710d051830 (diff)
downloadscummvm-rg350-fe5658ca175810f7ea6cbcaa078e6fc86faf36f1.tar.gz
scummvm-rg350-fe5658ca175810f7ea6cbcaa078e6fc86faf36f1.tar.bz2
scummvm-rg350-fe5658ca175810f7ea6cbcaa078e6fc86faf36f1.zip
STARTREK: Mission 1 finished
Diffstat (limited to 'engines/startrek')
-rw-r--r--engines/startrek/awaymission.cpp9
-rw-r--r--engines/startrek/awaymission.h8
-rw-r--r--engines/startrek/menu.cpp11
-rw-r--r--engines/startrek/room.cpp41
-rw-r--r--engines/startrek/room.h41
-rw-r--r--engines/startrek/rooms/demon1.cpp6
-rw-r--r--engines/startrek/rooms/demon4.cpp498
-rw-r--r--engines/startrek/rooms/function_map.h40
-rw-r--r--engines/startrek/sprite.cpp7
-rw-r--r--engines/startrek/sprite.h1
-rw-r--r--engines/startrek/startrek.h1
-rw-r--r--engines/startrek/text.h2
12 files changed, 638 insertions, 27 deletions
diff --git a/engines/startrek/awaymission.cpp b/engines/startrek/awaymission.cpp
index e0232009ff..4a604b9e7e 100644
--- a/engines/startrek/awaymission.cpp
+++ b/engines/startrek/awaymission.cpp
@@ -38,6 +38,7 @@ void StarTrekEngine::initAwayMission() {
_sound->loadMusicFile("ground");
loadRoom(_missionToLoad, _roomIndexToLoad);
+ _roomIndexToLoad = -1;
// Load crew positions for beaming in
initAwayCrewPositions(4);
@@ -45,6 +46,14 @@ void StarTrekEngine::initAwayMission() {
void StarTrekEngine::runAwayMission() {
while (true) {
+ // Original game manipulates the stack when the room changes to return execution
+ // to this point. Instead of doing that, just check if a variable is set.
+ if (_roomIndexToLoad != -1 && _spawnIndexToLoad != -1) {
+ loadRoomIndex(_roomIndexToLoad, _spawnIndexToLoad);
+ _roomIndexToLoad = -1;
+ _spawnIndexToLoad = -1;
+ }
+
handleAwayMissionEvents();
Common::Point mousePos = _gfx->getMousePos();
diff --git a/engines/startrek/awaymission.h b/engines/startrek/awaymission.h
index 0ad2946c23..5029c8cad1 100644
--- a/engines/startrek/awaymission.h
+++ b/engines/startrek/awaymission.h
@@ -55,6 +55,7 @@ struct AwayMission {
struct {
bool wasRudeToPrelate; // 0x29
bool insultedStephen; // 0x2b
+ bool field2d; // 0x2d
bool beatKlingons; // 0x2f
bool tookKlingonHand; // 0x31
@@ -75,17 +76,18 @@ struct AwayMission {
byte field41; // 0x41
bool foundMiner; // 0x43
bool field45; // 0x45
- bool field47; // 0x47
+ bool gaveSkullToNauian; // 0x47
bool warpsDisabled; // 0x48
bool boulder1Gone; // 0x49
bool boulder2Gone; // 0x4a
bool boulder3Gone; // 0x4b
bool boulder4Gone; // 0x4c
bool doorOpened; // 0x4d
- bool field4e; // 0x4e
+ bool solvedSunPuzzle; // 0x4e
byte itemsTakenFromCase; // 0x4f
bool gotBerries; // 0x50
bool madeHypoDytoxin; // 0x51
+ bool metNauian; // 0x53
bool gavePointsForDytoxin; // 0x54
bool lookedAtComputer; // 0x55
byte field56; // 0x56
@@ -93,7 +95,7 @@ struct AwayMission {
} demon;
};
- int16 missionScore;
+ int16 missionScore; // 0x58
};
// Size: 0x129 bytes
diff --git a/engines/startrek/menu.cpp b/engines/startrek/menu.cpp
index d6929d0d5c..1f67fb288c 100644
--- a/engines/startrek/menu.cpp
+++ b/engines/startrek/menu.cpp
@@ -653,7 +653,6 @@ int StarTrekEngine::handleMenuEvents(uint32 ticksUntilClickingEnabled, bool arg4
switch(event.type) {
case TREKEVENT_TICK: {
- case TREKEVENT_MOUSEMOVE: // FIXME: actual game only uses TICK event here
Common::Point mousePos = _gfx->getMousePos();
int buttonIndex = getMenuButtonAt(_activeMenu->sprites, _activeMenu->numButtons, mousePos.x, mousePos.y);
if (buttonIndex != -1) {
@@ -676,11 +675,11 @@ int StarTrekEngine::handleMenuEvents(uint32 ticksUntilClickingEnabled, bool arg4
}
// Not added: updating mouse position (scummvm handles that)
- // sub_10492();
- // sub_10A91();
+ // sub_10492(); // TODO
+ // updateActorAnimations(); // TODO: uncomment and fix animations under textboxes
_gfx->drawAllSprites();
- // sub_10BE7();
- // sub_2A4B1();
+ // sub_10BE7(); // TODO
+ _sound->checkLoopMusic();
if (_finishedPlayingSpeech != 0) {
_finishedPlayingSpeech = 0;
@@ -688,7 +687,7 @@ int StarTrekEngine::handleMenuEvents(uint32 ticksUntilClickingEnabled, bool arg4
return TEXTBUTTON_SPEECH_DONE;
}
}
- // sub_1E88C();
+ _gfx->incPaletteFadeLevel();
_frameIndex++;
if (ticksUntilClickingEnabled != 0 && _clockTicks >= tickWhenClickingEnabled)
diff --git a/engines/startrek/room.cpp b/engines/startrek/room.cpp
index 7110c4d559..2a8f5e6c6f 100644
--- a/engines/startrek/room.cpp
+++ b/engines/startrek/room.cpp
@@ -236,17 +236,24 @@ void Room::loadRoomIndex(int roomIndex, int spawnIndex) {
if (_vm->_awayMission.crewDownBitset != 0)
return;
- _vm->loadRoomIndex(roomIndex, spawnIndex);
+ _vm->_missionToLoad = _vm->_missionName;
+ _vm->_roomIndexToLoad = roomIndex;
+ _vm->_spawnIndexToLoad = spawnIndex;
- // This room has now been deleted, don't do anything else here.
- // FIXME: this could a bit dangerous since this is generally called from room-specific
- // code, which isn't guaranteed to do nothing afterward. Original game would
- // manipulate the stack to jump directly back to the start of "runAwayMission"...
+ // WORKAROUND: original game manipulates the stack to return directly to the start of
+ // "runAwayMission". Instead, we set some variables and the room will be changed
+ // later. (We wouldn't want to delete the room we're currently in...)
}
void Room::loseItem(int item) {
assert(item >= ITEMS_START && item < ITEMS_END);
_vm->_itemList[item - ITEMS_START].have = false;
+
+ if (_vm->_awayMission.activeAction == ACTION_USE && _vm->_awayMission.activeObject == item) {
+ _vm->_awayMission.activeAction = ACTION_WALK;
+ _vm->chooseMouseBitmapForAction(ACTION_WALK, false);
+ _vm->hideInventoryIcons();
+ }
}
void Room::walkCrewman(int actorIndex, int16 destX, int16 destY, uint16 finishedAnimActionParam) {
@@ -286,6 +293,30 @@ void Room::playMidiMusicTracks(int startTrack, int loopTrack) {
_vm->playMidiMusicTracks(startTrack, loopTrack);
}
+void Room::endMission(int16 score, int16 arg1, int16 arg2) {
+ _vm->_awayMission.disableInput = true;
+
+ for (int i = 0; i < (_vm->_awayMission.redshirtDead ? 3 : 4); i++) {
+ Actor *actor = &_vm->_actorList[i];
+ Common::String anim = _vm->getCrewmanAnimFilename(i, "teled");
+ _vm->loadActorAnimWithRoomScaling(i, anim, actor->sprite.pos.x, actor->sprite.pos.y);
+ }
+
+ _vm->_kirkActor->animationString[0] = '\0';
+ _vm->_spockActor->animationString[0] = '\0';
+ _vm->_mccoyActor->animationString[0] = '\0';
+ _vm->_redshirtActor->animationString[0] = '\0';
+
+ playSoundEffectIndex(8);
+
+ while (_vm->_kirkActor->spriteDrawn)
+ _vm->handleAwayMissionEvents();
+
+ _vm->_awayMission.disableInput = false;
+
+ // TODO: game mode switch
+}
+
void Room::showGameOverMenu() {
_vm->showGameOverMenu();
}
diff --git a/engines/startrek/room.h b/engines/startrek/room.h
index 027dbd6ae5..4dd6e05d71 100644
--- a/engines/startrek/room.h
+++ b/engines/startrek/room.h
@@ -103,6 +103,7 @@ private:
int showText(int speaker, int text); // Cmd 0x03
int showText(int text); // Cmd 0x03
void giveItem(int item); // Cmd 0x04
+ // Command 0x05: "demon4ShowSunPuzzle"
void loadRoomIndex(int roomIndex, int spawnIndex); // Cmd 0x06
void loseItem(int item); // Cmd 0x07
void walkCrewman(int actorIndex, int16 destX, int16 destY, uint16 finishedAnimActionParam);// Cmd 0x08
@@ -111,6 +112,7 @@ private:
Common::Point getActorPos(int actorIndex); // Cmd 0x0d
void playSoundEffectIndex(int soundEffect); // Cmd 0x0f
void playMidiMusicTracks(int startTrack, int loopTrack); // Cmd 0x10
+ void endMission(int16 score, int16 arg2, int16 arg3); // Cmd 0x11
void showGameOverMenu(); // Cmd 0x12
void playVoc(Common::String filename); // Cmd 0x15
@@ -310,9 +312,26 @@ public:
void demon4FinishedAnimation1();
void demon4FinishedAnimation2();
void demon4FinishedAnimation3();
+ void demon4Timer0Expired();
+ void demon4Timer1Expired();
+ void demon4CrewmanReachedBeamoutPosition();
+ void demon4Timer2Expired();
+ void demon4Timer3Expired();
+ void demon4Timer4Expired();
+ void demon4Timer5Expired();
+ void demon4Timer6Expired();
+ void demon4UsePhaserOnNauian();
+ void demon4UseMetalOnSecurityEquipment();
+ void demon4KirkReachedSecurityEquipment();
+ void demon4KirkFinishedUsingSecurityEquipment();
+ void demon4UseMetalOnNauian();
+ void demon4KirkReachedNauian();
+ void demon4UseSkullOnNauian();
+ void demon4KirkReachedNauianWithSkull();
void demon4UsePhaserOnPanel();
void demon4UsePhaserOnPattern();
void demon4UsePhaserOnMccoy();
+ void demon4TalkToNauian();
void demon4LookAtPattern();
void demon4LookAtAlien();
void demon4LookAnywhere();
@@ -330,6 +349,22 @@ public:
void demon4UseRedshirtOnPanel();
void demon4UseCrewmanOnPanel();
void demon4CrewmanReachedPanel();
+ bool demon4ShowSunPuzzle();
+ void demon4TalkToKirk();
+ void demon4TalkToMccoy();
+ void demon4TalkToSpock();
+ void demon4TalkToRedshirt();
+ void demon4UseSTricorderOnChamber();
+ void demon4UseSTricorderOnPattern();
+ void demon4UseMTricorderOnPattern();
+ void demon4UseSTricorderOnPanel();
+ void demon4UseMTricorderOnPanel();
+ void demon4UseSTricorderOnAnything();
+ void demon4UseMTricorderOnAnything();
+ void demon4UseSTricorderOnNauian();
+ void demon4UseMTricorderOnNauian();
+ void demon4UseSTricorderOnSecurityEquipment();
+ void demon4UseMTricorderOnSecurityEquipment();
// DEMON5
void demon5Tick1();
@@ -461,7 +496,11 @@ private:
} demon3;
struct {
- bool cb; // 0xcb
+ bool triedToShootNauian; // 0xca
+ bool nauianEmerged; // 0xcb
+ bool disabledSecurity; // 0xcc
+ bool cd; // 0xcd
+ byte crewReadyToBeamOut; // 0xce
int16 crewmanUsingPanel; // 0xcf
} demon4;
diff --git a/engines/startrek/rooms/demon1.cpp b/engines/startrek/rooms/demon1.cpp
index 325f13c843..a5c42d33d0 100644
--- a/engines/startrek/rooms/demon1.cpp
+++ b/engines/startrek/rooms/demon1.cpp
@@ -381,8 +381,10 @@ void Room::demon1UseSTricorderOnHand() {
}
void Room::demon1UseSTricorderOnKlingon1() {
- // NOTE: it sets up the stack, but doesn't call the function...
- //loadActorAnim2(OBJECT_SPOCK, "sscann", -1, -1, 0);
+ // BUGFIX: Original game sets up the stack for this function call, but doesn't
+ // actually call the function...
+ loadActorAnim2(OBJECT_SPOCK, "sscann", -1, -1, 0);
+
playSoundEffectIndex(0x04);
if (_roomVar.demon1.numKlingonsKilled == 3 && !_vm->_awayMission.demon.tookKlingonHand && _rdfData[0xcf] != 1) {
diff --git a/engines/startrek/rooms/demon4.cpp b/engines/startrek/rooms/demon4.cpp
index 52286327ea..8f2e310c9e 100644
--- a/engines/startrek/rooms/demon4.cpp
+++ b/engines/startrek/rooms/demon4.cpp
@@ -24,18 +24,21 @@
namespace StarTrek {
+// TODO: this room should have animations on computer terminals, but this isn't where
+// they're implemented. Could be related to ".BAN" files which rooms can load?
+
void Room::demon4Tick1() {
playVoc("DEM4LOOP");
if (!_vm->_awayMission.demon.healedMiner)
_vm->_awayMission.demon.minerDead = true;
- if (_vm->_awayMission.demon.field4e) {
+ if (_vm->_awayMission.demon.solvedSunPuzzle) {
loadActorAnim(10, "bxrise2", 0x122, 0x91, 0);
loadActorAnim(8, "stpout2", 0x107, 0x92, 0);
- _roomVar.demon4.cb = true;
+ _roomVar.demon4.nauianEmerged = true;
- if ((_vm->_awayMission.demon.itemsTakenFromCase & 0x10) && !_vm->_awayMission.demon.field47)
+ if ((_vm->_awayMission.demon.itemsTakenFromCase & 0x10) && !_vm->_awayMission.demon.gaveSkullToNauian)
_vm->_awayMission.timers[6] = 20;
}
@@ -45,14 +48,164 @@ void Room::demon4Tick1() {
}
}
+// Alien emerged
void Room::demon4FinishedAnimation1() {
- // TODO
+ loadActorAnim(8, "stpout", 0x107, 0x92, 5);
+ _roomVar.demon4.nauianEmerged = true;
+ if (_vm->_awayMission.demon.itemsTakenFromCase & 0x10)
+ _vm->_awayMission.timers[6] = 45;
}
void Room::demon4FinishedAnimation2() {
+ if (!_roomVar.demon4.cd) {
+ _roomVar.demon4.cd = true;
+ showText(TX_DEM4N011);
+ }
+
+ showGameOverMenu();
+
+ // WORKAROUND: original game has the below line; however, it's never executed anyway
+ // since the game over menu manipulates the stack. Here, the menu could delete this
+ // room object, so it should be the last statement...
+ //_vm->_awayMission.disableInput = false;
}
void Room::demon4FinishedAnimation3() {
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_034);
+ showText(TX_SPEAKER_KIRK, TX_DEM4_010);
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_035);
+ showText(TX_SPEAKER_SPOCK, TX_DEM4_030);
+
+ _vm->_awayMission.disableInput = true;
+ _vm->_awayMission.missionScore += 5;
+ _vm->_awayMission.timers[1] = 20;
+}
+
+// Just solved sun puzzle
+void Room::demon4Timer0Expired() {
+ loadActorAnim(10, "bxrise", 0x122, 0x91, 1);
+ _vm->_awayMission.crewDirectionsAfterWalk[OBJECT_KIRK] = DIR_E;
+ loadActorStandAnim(OBJECT_KIRK);
+ playVoc("SE2POWER");
+}
+
+// Mission end
+void Room::demon4Timer1Expired() {
+ showText(TX_SPEAKER_KIRK, TX_DEM4_011);
+
+ walkCrewman(OBJECT_KIRK, 0xbe, 0xa5, 4);
+ walkCrewman(OBJECT_SPOCK, 0xb4, 0x9b, 4);
+ walkCrewman(OBJECT_MCCOY, 0xc8, 0x9b, 4);
+
+ if (!_vm->_awayMission.redshirtDead)
+ walkCrewman(OBJECT_REDSHIRT, 0xc1, 0x91, 4);
+ else
+ _roomVar.demon4.crewReadyToBeamOut++;
+}
+
+void Room::demon4CrewmanReachedBeamoutPosition() {
+ _roomVar.demon4.crewReadyToBeamOut++;
+ if (_roomVar.demon4.crewReadyToBeamOut != 4)
+ return;
+
+ if (!_vm->_awayMission.demon.insultedStephen)
+ _vm->_awayMission.missionScore += 3;
+ if (!_vm->_awayMission.redshirtDead)
+ _vm->_awayMission.missionScore += 2;
+
+ endMission(_vm->_awayMission.missionScore, 0x24, 0);
+}
+
+void Room::demon4Timer2Expired() {
+ loadActorAnim2(OBJECT_SPOCK, "skille", -1, -1, 0);
+}
+
+void Room::demon4Timer3Expired() {
+ loadActorAnim2(OBJECT_REDSHIRT, "rkille", -1, -1, 0);
+}
+
+void Room::demon4Timer4Expired() {
+ loadActorAnim2(OBJECT_MCCOY, "mkille", -1, -1, 0);
+}
+
+void Room::demon4Timer5Expired() {
+ loadActorAnim2(OBJECT_KIRK, "kkille", -1, -1, 2);
+}
+
+void Room::demon4Timer6Expired() {
+ showText(TX_SPEAKER_MCCOY, TX_DEM4_017);
+}
+
+void Room::demon4UsePhaserOnNauian() {
+ if (!_roomVar.demon4.triedToShootNauian) { // Lenient the first time
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_033);
+ _roomVar.demon4.triedToShootNauian = true;
+ }
+ else { // Murdery the second time
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_032);
+ loadActorAnim2(10, "bxfire", 0, 0, 2);
+ playVoc("V0SPOCKT");
+ _vm->_awayMission.disableInput = true;
+ _vm->_awayMission.timers[2] = 7;
+ _vm->_awayMission.timers[3] = 8;
+ _vm->_awayMission.timers[4] = 7;
+ _vm->_awayMission.timers[5] = 8;
+ }
+}
+
+void Room::demon4UseMetalOnSecurityEquipment() {
+ _vm->_awayMission.disableInput = true;
+ walkCrewman(OBJECT_KIRK, 0xf5, 0x90, 5);
+}
+
+void Room::demon4KirkReachedSecurityEquipment() {
+ loadActorAnim2(OBJECT_KIRK, "kusemn", -1, -1, 4);
+}
+
+void Room::demon4KirkFinishedUsingSecurityEquipment() {
+ _vm->_awayMission.disableInput = false;
+ showText(TX_DEM4N014);
+}
+
+void Room::demon4UseMetalOnNauian() {
+ walkCrewman(OBJECT_KIRK, 0xe9, 0x90, 1);
+ _vm->_awayMission.crewDirectionsAfterWalk[OBJECT_KIRK] = DIR_E;
+}
+
+void Room::demon4KirkReachedNauian() {
+ loadActorAnim2(8, "usekey", 0x107, 0x8e, 3);
+ loseItem(OBJECT_IMETAL);
+ _vm->_awayMission.missionScore += 2;
+ _vm->_awayMission.demon.itemsTakenFromCase &= ~1;
+}
+
+void Room::demon4UseSkullOnNauian() {
+ walkCrewman(OBJECT_KIRK, 0xe9, 0x90, 2);
+}
+
+void Room::demon4KirkReachedNauianWithSkull() {
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_036);
+
+ const int choices[] = { TX_SPEAKER_KIRK, TX_DEM4_006, TX_DEM4_003, TX_DEM4_005, TX_BLANK };
+ int choice = showText(choices);
+
+ switch (choice) {
+ case 0:
+ _vm->_awayMission.missionScore++;
+ loadActorAnim2(8, "takesk", 0x107, 0x8e, 0);
+ loseItem(OBJECT_ISKULL);
+ _vm->_awayMission.demon.itemsTakenFromCase &= ~16; // BUG: skull reappears in case? Can abuse for infinite ponits?
+ _vm->_awayMission.demon.gaveSkullToNauian = true;
+ break;
+
+ case 1:
+ case 2:
+ break;
+
+ default:
+ showText(TX_DIALOG_ERROR);
+ break;
+ }
}
void Room::demon4UsePhaserOnPanel() {
@@ -67,9 +220,77 @@ void Room::demon4UsePhaserOnMccoy() {
showText(TX_SPEAKER_MCCOY, TX_DEM4_018);
}
+void Room::demon4TalkToNauian() {
+ _vm->_awayMission.disableInput = false;
+
+ if (!_vm->_awayMission.demon.metNauian) {
+ _vm->_awayMission.demon.metNauian = true;
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_044);
+
+ const int choices[] = { TX_SPEAKER_KIRK, TX_DEM4_002, TX_DEM4_004, TX_DEM4_009, TX_BLANK };
+ int choice = showText(choices);
+
+ switch (choice) {
+ case 0:
+ _vm->_awayMission.demon.field2d = true;
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_042);
+ break;
+
+ case 1:
+ break;
+
+ case 2:
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_039);
+ break;
+
+ default:
+ showText(TX_DIALOG_ERROR);
+ break;
+ }
+
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_043);
+
+ const int choices2[] = { TX_SPEAKER_KIRK, TX_DEM4_008, TX_DEM4_007, TX_BLANK };
+ choice = showText(choices2);
+
+ switch (choice) {
+ case 0:
+ _vm->_awayMission.demon.field2d = true;
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_041);
+ break;
+ case 1:
+ break;
+ default:
+ showText(TX_DIALOG_ERROR);
+ break;
+ }
+
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_040);
+
+ if (_roomVar.demon4.disabledSecurity) { // Impossible condition?
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_037);
+
+ // BUGFIX: Originally all of these used no audio, despite the files existing
+ // (being used elsewhere).
+ showText(TX_SPEAKER_KIRK, TX_DEM4_010);
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_035);
+ showText(TX_SPEAKER_SPOCK, TX_DEM4_030);
+
+ _vm->_awayMission.disableInput = true;
+ _vm->_awayMission.missionScore += 5;
+ _vm->_awayMission.timers[1] = 20;
+ }
+ else {
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_038);
+ }
+ }
+ else {
+ showText(TX_SPEAKER_NAUIAN, TX_DEM4_031);
+ }
+}
+
void Room::demon4LookAtPattern() {
showText(TX_DEM4N002);
-
}
void Room::demon4LookAtAlien() {
@@ -133,7 +354,7 @@ void Room::demon4UseRedshirtOnPanel() {
}
void Room::demon4UseCrewmanOnPanel() {
- if (_vm->_awayMission.demon.field4e)
+ if (_vm->_awayMission.demon.solvedSunPuzzle)
return;
walkCrewman(_roomVar.demon4.crewmanUsingPanel, 0xda, 0x83, 3);
_vm->_awayMission.crewDirectionsAfterWalk[_roomVar.demon4.crewmanUsingPanel] = DIR_N;
@@ -141,7 +362,270 @@ void Room::demon4UseCrewmanOnPanel() {
}
void Room::demon4CrewmanReachedPanel() {
- // TODO: puzzle implementation
+ if (demon4ShowSunPuzzle()) {
+ _vm->_awayMission.demon.solvedSunPuzzle = true;
+ loadActorAnim(9, "ctrl", 0, 0, 0);
+ _vm->_awayMission.missionScore += 3;
+ _vm->_awayMission.timers[0] = 10;
+ }
+ else
+ showText(TX_DEM4N013);
+
+ walkCrewman(_roomVar.demon4.crewmanUsingPanel, 0xae, 0x93, 0);
+ _vm->_awayMission.disableInput = false;
+}
+
+bool Room::demon4ShowSunPuzzle() {
+ bool solved = false;
+
+ int sliderY = 17;
+ int sliderR = -17;
+ int sliderB = 17;
+
+ _vm->_gfx->fadeoutScreen();
+ _vm->_sound->stopAllVocSounds();
+
+ _vm->_gfx->pushSprites();
+ _vm->_gfx->setBackgroundImage(_vm->_gfx->loadBitmap("machineb"));
+ _vm->_gfx->copyBackgroundScreen();
+ _vm->_gfx->clearPri();
+
+ Sprite sprites[21];
+
+ for (int i = 0; i < 21; i++) {
+ _vm->_gfx->addSprite(&sprites[i]);
+ }
+
+ sprites[0].setBitmap(_vm->_gfx->loadBitmap("levery"));
+ sprites[1].setBitmap(_vm->_gfx->loadBitmap("leverr"));
+ sprites[2].setBitmap(_vm->_gfx->loadBitmap("leverb"));
+
+ SharedPtr<Bitmap> lightyBitmap = _vm->_gfx->loadBitmap("lighty");
+ SharedPtr<Bitmap> lightrBitmap = _vm->_gfx->loadBitmap("lightr");
+ SharedPtr<Bitmap> lightbBitmap = _vm->_gfx->loadBitmap("lightb");
+
+ for (int i = 3; i < 9; i++)
+ sprites[i].bitmap = lightyBitmap;
+ for (int i = 9; i < 15; i++)
+ sprites[i].bitmap = lightrBitmap;
+ for (int i = 15; i < 21; i++)
+ sprites[i].bitmap = lightbBitmap;
+
+ Sprite doneButtonSprite;
+ _vm->_gfx->addSprite(&doneButtonSprite);
+ doneButtonSprite.setXYAndPriority(0x104, 0x64, 2);
+ doneButtonSprite.setBitmap(_vm->_gfx->loadBitmap("donebutt"));
+ // BUGFIX: use draw mode 2 so the entire button is clickable (not just non-transparent
+ // pixels)
+ doneButtonSprite.drawMode = 2;
+
+ _vm->_gfx->fadeinScreen();
+
+ bool continueLoop = true;
+ bool sliderChanged = true;
+
+ while (continueLoop) {
+ if (sliderChanged) {
+ sprites[0].setXYAndPriority(0xa0, sliderY + 0x75, 14);
+ sprites[1].setXYAndPriority(0xa8, sliderR + 0x75, 14);
+ sprites[2].setXYAndPriority(0xb0, sliderB + 0x75, 14);
+
+ int var56 = 0x82;
+ int var58 = 0x83;
+ int var5a = 3;
+ int numSprites = abs(sliderY) / 3;
+ for (int i = 0; i < 6; i++) {
+ sprites[i + var5a].setXYAndPriority(var58, var56, 14);
+ }
+ var56 -= 6;
+ for (int i = 0; i < numSprites; i++) {
+ sprites[i + var5a].setXYAndPriority(var58, var56, 14);
+ var56 -= 6;
+ }
+
+ var56 = 0x82;
+ var58 = 0x8b;
+ var5a = 9;
+ numSprites = abs(sliderR) / 3;
+ for (int i = 0; i < 6; i++) {
+ sprites[i + var5a].setXYAndPriority(var58, var56, 14);
+ }
+ var56 -= 6;
+ for (int i = 0; i < numSprites; i++) {
+ sprites[i + var5a].setXYAndPriority(var58, var56, 14);
+ var56 -= 6;
+ }
+
+ var56 = 0x82;
+ var58 = 0x93;
+ var5a = 15;
+ numSprites = abs(sliderB) / 3;
+ for (int i = 0; i < 6; i++) {
+ sprites[i + var5a].setXYAndPriority(var58, var56, 14);
+ }
+ var56 -= 6;
+ for (int i = 0; i < numSprites; i++) {
+ sprites[i + var5a].setXYAndPriority(var58, var56, 14);
+ var56 -= 6;
+ }
+
+ sliderChanged = false;
+ }
+
+ TrekEvent event;
+ if (!_vm->popNextEvent(&event))
+ continue;
+
+ switch (event.type) {
+ case TREKEVENT_LBUTTONDOWN: {
+lclick:
+ Common::Point mousePos = _vm->_gfx->getMousePos();
+ if (_vm->_gfx->getSpriteAt(mousePos) == &doneButtonSprite)
+ goto done;
+ else {
+ if (mousePos.y >= 0x64 && mousePos.y <= 0x86) {
+ if (mousePos.x >= 0xa0 && mousePos.x <= 0xa6)
+ sliderY = mousePos.y - 0x75;
+ else if (mousePos.x >= 0xa8 && mousePos.x <= 0xae)
+ sliderR = mousePos.y - 0x75;
+ else if (mousePos.x >= 0xb0 && mousePos.x <= 0xb6)
+ sliderB = mousePos.y - 0x75;
+ sliderChanged = true;
+ }
+ }
+ break;
+ }
+
+ case TREKEVENT_RBUTTONDOWN:
+done:
+ if (abs(sliderY) <= 2 && abs(sliderR) <= 2 && abs(sliderB) <= 2)
+ solved = true;
+ else
+ solved = false;
+ continueLoop = false;
+ break;
+
+ case TREKEVENT_KEYDOWN:
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_ESCAPE:
+ case Common::KEYCODE_F2:
+ goto done;
+
+ case Common::KEYCODE_RETURN:
+ case Common::KEYCODE_KP_ENTER:
+ case Common::KEYCODE_F1:
+ goto lclick;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ _vm->_gfx->drawAllSprites();
+ }
+
+ _vm->_gfx->fadeoutScreen();
+ _vm->_gfx->popSprites();
+ _vm->_gfx->loadPri(_vm->_screenName);
+ _vm->_gfx->setBackgroundImage(_vm->_gfx->loadBitmap(_vm->_screenName));
+ _vm->_gfx->copyBackgroundScreen();
+ _vm->_gfx->forceDrawAllSprites();
+
+ return solved;
+}
+
+void Room::demon4TalkToKirk() {
+ showText(TX_SPEAKER_KIRK, TX_DEM4_001);
+}
+
+void Room::demon4TalkToMccoy() {
+ if (_roomVar.demon4.nauianEmerged)
+ showText(TX_SPEAKER_MCCOY, TX_DEM4_019);
+ else
+ showText(TX_SPEAKER_MCCOY, TX_DEM4_015);
+}
+
+void Room::demon4TalkToSpock() {
+ if (_roomVar.demon4.nauianEmerged)
+ showText(TX_SPEAKER_SPOCK, TX_DEM4_022);
+ else
+ showText(TX_SPEAKER_SPOCK, TX_DEM4_024);
+}
+
+void Room::demon4TalkToRedshirt() {
+ if (_roomVar.demon4.nauianEmerged)
+ showText(TX_SPEAKER_EVERTS, TX_DEM4_047);
+ else
+ showText(TX_SPEAKER_EVERTS, TX_DEM4_046);
+}
+
+void Room::demon4UseSTricorderOnChamber() {
+ loadActorAnim2(OBJECT_SPOCK, "sscane", -1, -1, 0);
+ playSoundEffectIndex(4);
+ showText(TX_SPEAKER_SPOCK, TX_DEM4_012);
+}
+
+void Room::demon4UseSTricorderOnPattern() {
+ loadActorAnim2(OBJECT_SPOCK, "sscane", -1, -1, 0);
+ playSoundEffectIndex(4);
+ showText(TX_SPEAKER_SPOCK, TX_DEM4_014);
+ showText(TX_SPEAKER_SPOCK, TX_DEM4_025);
+}
+
+void Room::demon4UseMTricorderOnPattern() {
+ showText(TX_SPEAKER_MCCOY, TX_DEM4_021);
+}
+
+void Room::demon4UseSTricorderOnPanel() {
+ loadActorAnim2(OBJECT_SPOCK, "sscane", -1, -1, 0);
+ playSoundEffectIndex(4);
+ showText(TX_SPEAKER_SPOCK, TX_DEM4_027);
+}
+
+void Room::demon4UseMTricorderOnPanel() {
+ loadActorAnim2(OBJECT_MCCOY, "mscane", -1, -1, 0);
+ playSoundEffectIndex(4);
+ showText(TX_SPEAKER_MCCOY, TX_DEM4_027); // BUG: Uses spock's voice (though speaker says "Mccoy")
+}
+
+void Room::demon4UseSTricorderOnAnything() {
+ loadActorAnim2(OBJECT_SPOCK, "sscane", -1, -1, 0);
+ playSoundEffectIndex(4);
+ showText(TX_SPEAKER_SPOCK, TX_DEM4_023);
+}
+
+void Room::demon4UseMTricorderOnAnything() {
+ loadActorAnim2(OBJECT_MCCOY, "mscane", -1, -1, 0);
+ playSoundEffectIndex(4);
+ showText(TX_SPEAKER_MCCOY, TX_DEM4_020);
+}
+
+void Room::demon4UseSTricorderOnNauian() {
+ loadActorAnim2(OBJECT_SPOCK, "sscane", -1, -1, 0);
+ playSoundEffectIndex(4);
+ showText(TX_SPEAKER_SPOCK, TX_DEM4_029);
+}
+
+void Room::demon4UseMTricorderOnNauian() {
+ loadActorAnim2(OBJECT_MCCOY, "mscane", -1, -1, 0);
+ playSoundEffectIndex(4);
+ showText(TX_SPEAKER_SPOCK, TX_DEM4_029); // BUG: Uses spock's voice (speaker says "Spock" too)
+}
+
+void Room::demon4UseSTricorderOnSecurityEquipment() {
+ loadActorAnim2(OBJECT_SPOCK, "sscane", -1, -1, 0);
+ playSoundEffectIndex(4);
+ showText(TX_SPEAKER_SPOCK, TX_DEM4_026);
+}
+
+void Room::demon4UseMTricorderOnSecurityEquipment() {
+ loadActorAnim2(OBJECT_MCCOY, "mscane", -1, -1, 0);
+ playSoundEffectIndex(4);
+ showText(TX_SPEAKER_SPOCK, TX_DEM4_026); // BUG: Uses spock's voice (speaker says "Spock" too)
}
}
diff --git a/engines/startrek/rooms/function_map.h b/engines/startrek/rooms/function_map.h
index fc5f73a28b..db647df41e 100644
--- a/engines/startrek/rooms/function_map.h
+++ b/engines/startrek/rooms/function_map.h
@@ -314,14 +314,31 @@ RoomAction demon4ActionList[] = {
{ Action(ACTION_FINISHED_ANIMATION, 1, 0, 0), &Room::demon4FinishedAnimation1 },
{ Action(ACTION_FINISHED_ANIMATION, 2, 0, 0), &Room::demon4FinishedAnimation2 },
{ Action(ACTION_FINISHED_ANIMATION, 3, 0, 0), &Room::demon4FinishedAnimation3 },
-
- // TODO: everything
+ { Action(ACTION_TIMER_EXPIRED, 0, 0, 0), &Room::demon4Timer0Expired },
+ { Action(ACTION_TIMER_EXPIRED, 1, 0, 0), &Room::demon4Timer1Expired },
+ { Action(ACTION_FINISHED_WALKING, 4, 0, 0), &Room::demon4CrewmanReachedBeamoutPosition },
+ { Action(ACTION_TIMER_EXPIRED, 2, 0, 0), &Room::demon4Timer2Expired },
+ { Action(ACTION_TIMER_EXPIRED, 3, 0, 0), &Room::demon4Timer3Expired },
+ { Action(ACTION_TIMER_EXPIRED, 4, 0, 0), &Room::demon4Timer4Expired },
+ { Action(ACTION_TIMER_EXPIRED, 5, 0, 0), &Room::demon4Timer5Expired },
+ { Action(ACTION_TIMER_EXPIRED, 6, 0, 0), &Room::demon4Timer6Expired },
+
+ { Action(ACTION_USE, OBJECT_IPHASERK, 8, 0), &Room::demon4UsePhaserOnNauian },
+ { Action(ACTION_USE, OBJECT_IPHASERS, 8, 0), &Room::demon4UsePhaserOnNauian },
+ { Action(ACTION_USE, OBJECT_IMETAL, 0x22, 0), &Room::demon4UseMetalOnSecurityEquipment },
+ { Action(ACTION_FINISHED_WALKING, 5, 0, 0), &Room::demon4KirkReachedSecurityEquipment },
+ { Action(ACTION_FINISHED_ANIMATION, 4, 0, 0), &Room::demon4KirkFinishedUsingSecurityEquipment },
+ { Action(ACTION_USE, OBJECT_IMETAL, 8, 0), &Room::demon4UseMetalOnNauian },
+ { Action(ACTION_FINISHED_WALKING, 1, 0, 0), &Room::demon4KirkReachedNauian },
+ { Action(ACTION_USE, OBJECT_ISKULL, 8, 0), &Room::demon4UseSkullOnNauian },
+ { Action(ACTION_FINISHED_WALKING, 2, 0, 0), &Room::demon4KirkReachedNauianWithSkull },
{ Action(ACTION_USE, OBJECT_IPHASERS, 0x21, 0), &Room::demon4UsePhaserOnPanel },
{ Action(ACTION_USE, OBJECT_IPHASERS, 0x20, 0), &Room::demon4UsePhaserOnPattern },
{ Action(ACTION_USE, OBJECT_IPHASERS, OBJECT_MCCOY, 0), &Room::demon4UsePhaserOnMccoy },
- // TODO
+ { Action(ACTION_FINISHED_ANIMATION, 5, 0, 0), &Room::demon4TalkToNauian },
+ { Action(ACTION_TALK, 8, 0, 0), &Room::demon4TalkToNauian },
{ Action(ACTION_LOOK, 0x20, 0, 0), &Room::demon4LookAtPattern },
{ Action(ACTION_LOOK, 8, 0, 0), &Room::demon4LookAtAlien },
@@ -342,6 +359,23 @@ RoomAction demon4ActionList[] = {
{ Action(ACTION_USE, OBJECT_MCCOY, 0x21, 0), &Room::demon4UseMccoyOnPanel },
{ Action(ACTION_USE, OBJECT_REDSHIRT, 0x21, 0), &Room::demon4UseRedshirtOnPanel },
{ Action(ACTION_FINISHED_WALKING, 3, 0, 0), &Room::demon4CrewmanReachedPanel },
+ { Action(ACTION_TALK, OBJECT_KIRK, 0, 0), &Room::demon4TalkToKirk },
+ { Action(ACTION_TALK, OBJECT_MCCOY, 0, 0), &Room::demon4TalkToMccoy },
+ { Action(ACTION_TALK, OBJECT_SPOCK, 0, 0), &Room::demon4TalkToSpock },
+ { Action(ACTION_TALK, OBJECT_REDSHIRT, 0, 0), &Room::demon4TalkToRedshirt },
+ { Action(ACTION_USE, OBJECT_ISTRICOR, 10, 0), &Room::demon4UseSTricorderOnChamber },
+ { Action(ACTION_USE, OBJECT_ISTRICOR, 0x20, 0), &Room::demon4UseSTricorderOnPattern },
+ { Action(ACTION_USE, OBJECT_IMTRICOR, 0x20, 0), &Room::demon4UseMTricorderOnPattern },
+ { Action(ACTION_USE, OBJECT_ISTRICOR, 0x21, 0), &Room::demon4UseSTricorderOnPanel },
+ { Action(ACTION_USE, OBJECT_IMTRICOR, 0x21, 0), &Room::demon4UseMTricorderOnPanel },
+ { Action(ACTION_USE, OBJECT_ISTRICOR, 0x23, 0), &Room::demon4UseSTricorderOnAnything },
+ { Action(ACTION_USE, OBJECT_ISTRICOR, -1, 0), &Room::demon4UseSTricorderOnAnything },
+ { Action(ACTION_USE, OBJECT_IMTRICOR, 0x23, 0), &Room::demon4UseMTricorderOnAnything },
+ { Action(ACTION_USE, OBJECT_IMTRICOR, -1, 0), &Room::demon4UseMTricorderOnAnything },
+ { Action(ACTION_USE, OBJECT_ISTRICOR, 8, 0), &Room::demon4UseSTricorderOnNauian },
+ { Action(ACTION_USE, OBJECT_IMTRICOR, 8, 0), &Room::demon4UseMTricorderOnNauian },
+ { Action(ACTION_USE, OBJECT_ISTRICOR, 0x22, 0), &Room::demon4UseSTricorderOnSecurityEquipment },
+ { Action(ACTION_USE, OBJECT_IMTRICOR, 0x22, 0), &Room::demon4UseMTricorderOnSecurityEquipment },
};
RoomAction demon5ActionList[] = {
diff --git a/engines/startrek/sprite.cpp b/engines/startrek/sprite.cpp
index 580447501c..f6ba48de9d 100644
--- a/engines/startrek/sprite.cpp
+++ b/engines/startrek/sprite.cpp
@@ -48,6 +48,13 @@ void Sprite::setBitmap(SharedPtr<Bitmap> b) {
bitmapChanged = true;
}
+void Sprite::setXYAndPriority(int16 x, int16 y, int16 priority) {
+ pos.x = x;
+ pos.y = y;
+ drawPriority = priority;
+ bitmapChanged = true;
+}
+
void Sprite::dontDrawNextFrame() {
field16 = true;
bitmapChanged = true;
diff --git a/engines/startrek/sprite.h b/engines/startrek/sprite.h
index ce53372906..e182f927d8 100644
--- a/engines/startrek/sprite.h
+++ b/engines/startrek/sprite.h
@@ -61,6 +61,7 @@ struct Sprite {
Sprite();
void setBitmap(SharedPtr<Bitmap> b);
+ void setXYAndPriority(int16 x, int16 y, int16 priority);
void dontDrawNextFrame();
Common::Rect getRect();
diff --git a/engines/startrek/startrek.h b/engines/startrek/startrek.h
index e37f4427c6..52d23c5677 100644
--- a/engines/startrek/startrek.h
+++ b/engines/startrek/startrek.h
@@ -360,6 +360,7 @@ public:
Common::String _missionToLoad;
int _roomIndexToLoad;
+ int _spawnIndexToLoad;
Common::String _missionName;
int _roomIndex;
diff --git a/engines/startrek/text.h b/engines/startrek/text.h
index 95b49a1cd2..7a8a80f3d9 100644
--- a/engines/startrek/text.h
+++ b/engines/startrek/text.h
@@ -44,6 +44,7 @@ enum GameStringIDs {
TX_SPEAKER_CHUB,
TX_SPEAKER_ROBERTS,
TX_SPEAKER_GRISNASH,
+ TX_SPEAKER_NAUIAN,
TX_DEM0_001,
TX_DEM0_002,
@@ -482,6 +483,7 @@ const char * const g_gameStrings[] = {
"Brother Chub",
"Brother Roberts",
"Brother Grisnash",
+ "Nauian",
"#DEM0\\DEM0_001#Doctor, you need to investigate the possibility of disease, mental or physical, among these people, before we go chasing up the mountains. Prelate Angiven, may we see those who have encountered the demons?",
"#DEM0\\DEM0_002#Aside from seeing demons, has any hard data been collected? Any evidence I could see?",