diff options
Diffstat (limited to 'engines/startrek/rooms')
-rw-r--r-- | engines/startrek/rooms/trial3.cpp | 423 |
1 files changed, 422 insertions, 1 deletions
diff --git a/engines/startrek/rooms/trial3.cpp b/engines/startrek/rooms/trial3.cpp index afbb1eee6e..2e382bccdf 100644 --- a/engines/startrek/rooms/trial3.cpp +++ b/engines/startrek/rooms/trial3.cpp @@ -22,16 +22,437 @@ #include "startrek/room.h" +#define OBJECT_KLINGON_1 8 +#define OBJECT_KLINGON_2 9 // Unused +#define OBJECT_KLINGON_3 10 // Unused +#define OBJECT_EXPLOSION 11 + +#define HOTSPOT_EXIT 0x20 +#define HOTSPOT_WALL 0x21 + namespace StarTrek { extern const RoomAction trial3ActionList[] = { - { {ACTION_TICK, 1, 0, 0}, &Room::trial3Tick1 }, + { {ACTION_TICK, 1, 0, 0}, &Room::trial3Tick1 }, + { {ACTION_TICK, 30, 0, 0}, &Room::trial3Tick30 }, + { {ACTION_DONE_ANIM, 1, 0, 0}, &Room::trial3Klingon1BeamedIn }, + { {ACTION_DONE_ANIM, 2, 0, 0}, &Room::trial3Klingon2BeamedIn }, + { {ACTION_DONE_ANIM, 3, 0, 0}, &Room::trial3Klingon3BeamedIn }, + { {ACTION_DONE_ANIM, 4, 0, 0}, &Room::trial3Klingon1DoneShooting }, + { {ACTION_DONE_ANIM, 5, 0, 0}, &Room::trial3Klingon2DoneShooting }, + { {ACTION_DONE_ANIM, 6, 0, 0}, &Room::trial3Klingon3DoneShooting }, + { {ACTION_DONE_ANIM, 15, 0, 0}, &Room::trial3RedshirtDoneDying }, + { {ACTION_DONE_ANIM, 16, 0, 0}, &Room::trial3KirkDoneDying }, + { {ACTION_DONE_ANIM, 11, 0, 0}, &Room::trial3Klingon1Shot }, + { {ACTION_DONE_ANIM, 12, 0, 0}, &Room::trial3Klingon2Shot }, + { {ACTION_DONE_ANIM, 13, 0, 0}, &Room::trial3Klingon3Shot }, + { {ACTION_DONE_ANIM, 19, 0, 0}, &Room::trial3CrewmanBeamedOut }, + { {ACTION_TICK, 90, 0, 0}, &Room::trial3Tick90 }, + { {ACTION_TOUCHED_HOTSPOT, 3, 0, 0}, &Room::trial3TouchedHotspot3 }, + { {ACTION_DONE_ANIM, 14, 0, 0}, &Room::trial3KirkExploded }, + { {ACTION_LOOK, OBJECT_KIRK, 0, 0}, &Room::trial3LookAtKirk }, + { {ACTION_LOOK, OBJECT_SPOCK, 0, 0}, &Room::trial3LookAtSpock }, + { {ACTION_LOOK, OBJECT_MCCOY, 0, 0}, &Room::trial3LookAtMccoy }, + { {ACTION_LOOK, OBJECT_REDSHIRT, 0, 0}, &Room::trial3LookAtRedshirt }, + { {ACTION_LOOK, HOTSPOT_EXIT, 0, 0}, &Room::trial3LookAtExit }, + { {ACTION_LOOK, HOTSPOT_WALL, 0, 0}, &Room::trial3LookAtWall }, + { {ACTION_TALK, OBJECT_KIRK, 0, 0}, &Room::trial3TalkToKirk }, + { {ACTION_TALK, OBJECT_SPOCK, 0, 0}, &Room::trial3TalkToSpock }, + { {ACTION_TALK, OBJECT_MCCOY, 0, 0}, &Room::trial3TalkToMccoy }, + { {ACTION_TALK, OBJECT_REDSHIRT, 0, 0}, &Room::trial3TalkToRedshirt }, + { {ACTION_USE, OBJECT_IPHASERS, HOTSPOT_WALL, 0}, &Room::trial3UsePhaserOnWall }, + { {ACTION_USE, OBJECT_IPHASERK, HOTSPOT_WALL, 0}, &Room::trial3UsePhaserOnWall }, + + { {ACTION_USE, OBJECT_IPHASERS, OBJECT_KLINGON_1, 0}, &Room::trial3UseStunPhaserOnKlingon1 }, + { {ACTION_DONE_ANIM, 17, 0, 0}, &Room::trial3ReadyToShootKlingon1OnStun }, + { {ACTION_USE, OBJECT_IPHASERK, OBJECT_KLINGON_1, 0}, &Room::trial3UseKillPhaserOnKlingon1 }, + { {ACTION_DONE_ANIM, 18, 0, 0}, &Room::trial3ReadyToShootKlingon1OnKill }, + // OMITTED: Similar code for unused klingons 2 and 3 + + { {ACTION_USE, OBJECT_IPHASERS, 0xff, 0}, &Room::trial3UsePhaserAnywhere }, + { {ACTION_USE, OBJECT_IPHASERK, 0xff, 0}, &Room::trial3UsePhaserAnywhere }, + + { {ACTION_USE, OBJECT_IMTRICOR, OBJECT_KIRK, 0}, &Room::trial3UseMTricorderOnKirk }, + { {ACTION_USE, OBJECT_IMTRICOR, OBJECT_SPOCK, 0}, &Room::trial3UseMTricorderOnSpock }, + { {ACTION_USE, OBJECT_IMTRICOR, OBJECT_MCCOY, 0}, &Room::trial3UseMTricorderOnMccoy }, + { {ACTION_USE, OBJECT_IMTRICOR, OBJECT_REDSHIRT, 0}, &Room::trial3UseMTricorderOnRedshirt }, + { {ACTION_USE, OBJECT_IMTRICOR, HOTSPOT_EXIT, 0}, &Room::trial3UseMTricorderOnExit }, + { {ACTION_USE, OBJECT_ISTRICOR, HOTSPOT_WALL, 0}, &Room::trial3UseSTricorderOnWall }, + { {ACTION_USE, OBJECT_ISTRICOR, HOTSPOT_EXIT, 0}, &Room::trial3UseSTricorderOnExit }, + { {ACTION_USE, OBJECT_IMTRICOR, OBJECT_KLINGON_1, 0}, &Room::trial3UseMTricorderOnKlingon }, + { {ACTION_USE, OBJECT_ICOMM, 0xff, 0}, &Room::trial3UseCommunicator }, + { {ACTION_USE, OBJECT_MCCOY, HOTSPOT_WALL, 0}, &Room::trial3UseMccoyOnWall }, + { {ACTION_USE, OBJECT_MCCOY, HOTSPOT_EXIT, 0}, &Room::trial3UseMccoyOnExit }, + { {ACTION_USE, OBJECT_SPOCK, HOTSPOT_WALL, 0}, &Room::trial3UseSpockOnWall }, + { {ACTION_USE, OBJECT_SPOCK, HOTSPOT_EXIT, 0}, &Room::trial3UseSpockOnExit }, + { {ACTION_USE, OBJECT_REDSHIRT, HOTSPOT_EXIT, 0}, &Room::trial3UseRedshirtOnExit }, + { {ACTION_USE, OBJECT_REDSHIRT, HOTSPOT_WALL, 0}, &Room::trial3UseRedshirtOnWall }, + { {ACTION_WALK, HOTSPOT_EXIT, 0, 0}, &Room::trial3WalkToExit }, + { {ACTION_USE, OBJECT_IMEDKIT, 0xff, 0}, &Room::trial3UseMedkitAnywhere }, }; extern const int trial3NumActions = sizeof(trial3ActionList) / sizeof(RoomAction); void Room::trial3Tick1() { + playVoc("TRI3LOOP"); + + if (!_vm->_awayMission.trial.enteredTrial3FirstTime) { + _vm->_awayMission.disableWalking = true; + _vm->_awayMission.disableInput = 2; + } + playMidiMusicTracks(MIDITRACK_33, -1); +} + +void Room::trial3Tick30() { + if (!_vm->_awayMission.trial.enteredTrial3FirstTime) { + _vm->_awayMission.disableInput = false; + _vm->_awayMission.trial.enteredTrial3FirstTime = true; + + showText(TX_SPEAKER_BENNIE, TX_TRI3_030); + showText(TX_SPEAKER_KIRK, TX_TRI3_005); + showText(TX_SPEAKER_MCCOY, TX_TRI3_019); + showText(TX_SPEAKER_SPOCK, TX_TRI3_025); + showText(TX_SPEAKER_MCCOY, TX_TRI3_020); + showText(TX_SPEAKER_KIRK, TX_TRI3_004); + } +} + +void Room::trial3Klingon1BeamedIn() { + loadActorAnimC(OBJECT_KLINGON_1, "t3kfir", -1, -1, &Room::trial3Klingon1DoneShooting); + trial3KlingonShootsSomeone1(); +} + +void Room::trial3Klingon2BeamedIn() { + loadActorAnimC(OBJECT_KLINGON_2, "t3kfir", -1, -1, &Room::trial3Klingon2DoneShooting); + trial3KlingonShootsSomeone1(); +} + +void Room::trial3Klingon3BeamedIn() { + loadActorAnimC(OBJECT_KLINGON_3, "t3kfir", -1, -1, &Room::trial3Klingon3DoneShooting); + trial3KlingonShootsSomeone1(); +} + +void Room::trial3KlingonShootsSomeone1() { + _vm->_awayMission.trial.klingonShootIndex++; + if (_vm->_awayMission.trial.klingonShootIndex == 1) { + playSoundEffectIndex(SND_PHASSHOT); + showBitmapFor5Ticks("t3phas04", 5); + loadActorAnimC(OBJECT_REDSHIRT, "rkillw", -1, -1, &Room::trial3RedshirtDoneDying); + _vm->_awayMission.redshirtDead = true; + } else if (_vm->_awayMission.trial.klingonShootIndex == 2) { + playSoundEffectIndex(SND_PHASSHOT); + showBitmapFor5Ticks("t3phas05", 5); + playMidiMusicTracks(MIDITRACK_2, -1); + loadActorAnimC(OBJECT_KIRK, "kkillw", -1, -1, &Room::trial3KirkDoneDying); + } +} + +void Room::trial3Klingon1DoneShooting() { + loadActorAnimC(OBJECT_KLINGON_1, "t3kfir", -1, -1, &Room::trial3Klingon1DoneShooting); + trial3KlingonShootsSomeone2(); +} + +void Room::trial3Klingon2DoneShooting() { + loadActorAnimC(OBJECT_KLINGON_2, "t3kfir", -1, -1, &Room::trial3Klingon2DoneShooting); + trial3KlingonShootsSomeone2(); +} + +void Room::trial3Klingon3DoneShooting() { + loadActorAnimC(OBJECT_KLINGON_3, "t3kfir", -1, -1, &Room::trial3Klingon3DoneShooting); + trial3KlingonShootsSomeone2(); +} + +void Room::trial3KlingonShootsSomeone2() { + // This function is almost exactly identical to "trial3KlingonShootsSomeone1(), just + // one line differs... + _vm->_awayMission.trial.klingonShootIndex++; + if (_vm->_awayMission.trial.klingonShootIndex == 1) { + playSoundEffectIndex(SND_PHASSHOT); + showBitmapFor5Ticks("t3phas04", 5); + loadActorAnimC(OBJECT_REDSHIRT, "rkillw", -1, -1, &Room::trial3RedshirtDoneDying); + _vm->_awayMission.redshirtDead = true; + } else if (_vm->_awayMission.trial.klingonShootIndex == 2) { + playSoundEffectIndex(SND_PHASSHOT); + showBitmapFor5Ticks("t3phas05", 5); + // NOTE: Only difference to "trial3KlingonShootsSomeone1" is this doesn't play a midi track? + loadActorAnimC(OBJECT_KIRK, "kkillw", -1, -1, &Room::trial3KirkDoneDying); + } +} + +void Room::trial3RedshirtDoneDying() { + _vm->_awayMission.redshirtDead = true; +} + +void Room::trial3KirkDoneDying() { + showGameOverMenu(); +} + +void Room::trial3Klingon1Shot() { + _vm->_awayMission.trial.shotKlingons |= 1; + trial3CheckShowUhuraText(); +} + +void Room::trial3Klingon2Shot() { + _vm->_awayMission.trial.shotKlingons |= 2; + trial3CheckShowUhuraText(); +} + +void Room::trial3Klingon3Shot() { + _vm->_awayMission.trial.shotKlingons |= 4; + trial3CheckShowUhuraText(); +} + +void Room::trial3CheckShowUhuraText() { + if (_vm->_awayMission.trial.shotKlingons == 1) { + _vm->_awayMission.trial.shotKlingons |= 8; + _vm->_awayMission.disableWalking = false; + loadActorStandAnim(OBJECT_KIRK); + + showText(TX_SPEAKER_UHURA, TX_TRI3U084); + showText(TX_SPEAKER_KIRK, TX_TRI3_007); + showText(TX_SPEAKER_UHURA, TX_TRI3U099); + + _vm->_awayMission.trial.forceFieldDown = true; + + const TextRef choices[] = { + TX_SPEAKER_KIRK, + TX_TRI3_006, TX_TRI3_002, TX_TRI3_003, + TX_BLANK + }; + int choice = showText(choices); + + if (choice == 0) { // Don't beam out + } else if (choice == 1) { // Beam to enterprise + endMission(_vm->_awayMission.trial.missionScore, _vm->_awayMission.trial.field2b, 1); // FIXME: inconsistent + } else if (choice == 2) { // Beam to Vlict + trial3BeamToVlict(); + } + } +} + +void Room::trial3CrewmanBeamedOut() { + if (!_vm->_awayMission.trial.gotPointsForBeamingOut) { + _vm->_awayMission.trial.gotPointsForBeamingOut = true; + _vm->_awayMission.trial.missionScore += 2; // BUG: Doesn't happen when done in other rooms + } + loadRoomIndex(4, 4); +} + +void Room::trial3Tick90() { + if ((!(_vm->_awayMission.trial.shotKlingons & 8) && _vm->_awayMission.trial.shotKlingonState != 20)) { + playSoundEffectIndex(SND_TRANSMAT); + playMidiMusicTracks(MIDITRACK_32, -1); + loadActorAnimC(OBJECT_KLINGON_1, "t3ktel", 0x57, 0xb1, &Room::trial3Klingon1BeamedIn); + _vm->_awayMission.trial.shotKlingonState = 21; + } +} + +void Room::trial3TouchedHotspot3() { // Activated the explosive + playSoundEffectIndex(SND_BLANK_14); + playMidiMusicTracks(MIDITRACK_2, -1); + playVoc("BITOKIRK"); + loadActorAnimC(OBJECT_EXPLOSION, "t3expl", 0, 0xc7, &Room::trial3KirkExploded); +} + +void Room::trial3KirkExploded() { + showGameOverMenu(); +} + +void Room::trial3LookAtKirk() { + showText(TX_TRI3N000); +} + +void Room::trial3LookAtSpock() { + showText(TX_TRI3N004); +} + +void Room::trial3LookAtMccoy() { + showText(TX_TRI3N001); +} + +void Room::trial3LookAtRedshirt() { + showText(TX_TRI3N002); +} + +void Room::trial3LookAtExit() { + showText(TX_TRI3N005); +} + +void Room::trial3LookAtWall() { + showText(TX_TRI3N007); +} + +void Room::trial3TalkToKirk() { + showText(TX_SPEAKER_KIRK, TX_TRI3_001); +} + +void Room::trial3TalkToSpock() { + showText(TX_SPEAKER_SPOCK, TX_TRI3_022); +} + +void Room::trial3TalkToMccoy() { + showText(TX_SPEAKER_MCCOY, TX_TRI3_018); +} + +void Room::trial3TalkToRedshirt() { + showText(TX_SPEAKER_BENNIE, TX_TRI3_029); +} + +void Room::trial3UsePhaserOnWall() { + showText(TX_TRI3N006); +} + +void Room::trial3UseStunPhaserOnKlingon1() { + // BUGFIX: Instead of checking that the klingon isn't unconscious, (22), check that + // he's conscious (21). + // There's also the "dead" state (23) to consider. This prevents a softlock if + // a phaser is used on him just as he's being vaporized. + if (_vm->_awayMission.trial.shotKlingonState == 21) { + _vm->_awayMission.disableInput = true; + loadActorAnimC(OBJECT_KIRK, "kdraww", -1, -1, &Room::trial3ReadyToShootKlingon1OnStun); + } +} + +void Room::trial3ReadyToShootKlingon1OnStun() { + if (_vm->_awayMission.trial.shotKlingonState == 21) { + playSoundEffectIndex(SND_PHASSHOT); + showBitmapFor5Ticks("t3phas00", 5); + loadActorAnimC(OBJECT_KLINGON_1, "t3kstn", -1, -1, &Room::trial3Klingon1Shot); + _vm->_awayMission.disableInput = false; + _vm->_awayMission.trial.shotKlingonState = 22; + } +} + +void Room::trial3UseKillPhaserOnKlingon1() { + // BUGFIX: Prevent softlock by checking that he's conscious (shotKlingonState == 21) + // In addition to preventing the softlock mentioned above, this also prevents + // a softlock where a kill phaser is used on the unconscious klingon. + if (_vm->_awayMission.trial.shotKlingonState == 21) { + _vm->_awayMission.disableInput = true; + loadActorAnimC(OBJECT_KIRK, "kdraww", -1, -1, &Room::trial3ReadyToShootKlingon1OnKill); + } +} + +void Room::trial3ReadyToShootKlingon1OnKill() { + if (_vm->_awayMission.trial.shotKlingonState == 21) { + playSoundEffectIndex(SND_PHASSHOT); + showBitmapFor5Ticks("t3phas02", 5); + loadActorAnimC(OBJECT_KLINGON_1, "t3kdie", -1, -1, &Room::trial3Klingon1Shot); + _vm->_awayMission.disableInput = false; + _vm->_awayMission.trial.shotKlingonState = 23; + _vm->_awayMission.trial.missionScore -= 3; // Penalty for killing klingon + } +} + +void Room::trial3UsePhaserAnywhere() { + showText(TX_TRI3N003); +} + +void Room::trial3UseMTricorderOnKirk() { + // BUGFIX: Original animated Spock instead of Mccoy (same for below mccoy-scan functions) + mccoyScan(DIR_S, TX_TRI3_015, true); +} + +void Room::trial3UseMTricorderOnSpock() { + mccoyScan(DIR_S, TX_TRI3_016, true); +} + +void Room::trial3UseMTricorderOnMccoy() { + mccoyScan(DIR_S, TX_TRI3_013, true); +} + +void Room::trial3UseMTricorderOnRedshirt() { + mccoyScan(DIR_S, TX_TRI3_014, true); +} + +void Room::trial3UseMTricorderOnExit() { + mccoyScan(DIR_S, TX_TRI3_009, true); +} + +void Room::trial3UseSTricorderOnWall() { + spockScan(DIR_S, TX_TRI3_024, true); +} + +void Room::trial3UseSTricorderOnExit() { + spockScan(DIR_S, TX_TRI3_023, true); +} + +void Room::trial3UseMTricorderOnKlingon() { + if (_vm->_awayMission.trial.shotKlingonState == 22) { // Unconscious + mccoyScan(DIR_S, TX_TRI3_011); + showText(TX_SPEAKER_BENNIE, TX_TRI3_028); + } +} + +void Room::trial3UseCommunicator() { + if (_vm->_awayMission.trial.forceFieldDown) { + showText(TX_SPEAKER_UHURA, TX_TRI3U089); + + const TextRef choices[] = { + TX_SPEAKER_KIRK, + TX_TRI3_103, TX_TRI3_104, TX_TRI3_107, + TX_BLANK + }; + int choice = showText(choices); + + if (choice == 0) { // "Beam us back to the enterprise" + _vm->_awayMission.trial.field5f = 1; + endMission(_vm->_awayMission.trial.missionScore, _vm->_awayMission.trial.field2b, 1); // FIXME: inconsistent + } else if (choice == 1) { // "Beam us to Vlict's position" + trial3BeamToVlict(); + } // Else don't transport anywhere + } else { // Force field still up + showText(TX_SPEAKER_UHURA, TX_TRI3U067); + } +} + +void Room::trial3BeamToVlict() { + // ENHANCEMENT: The audio that should play here (TX_TRI3U080) doesn't seem to have the + // normal "filter" applied over it, making it sound jarring. So, use the equivalent + // text from TRIAL1 instead. + showText(TX_SPEAKER_UHURA, TX_TRI1U080); + + _vm->_awayMission.disableInput = true; + playSoundEffectIndex(SND_TRANSDEM); + + loadActorAnimC(OBJECT_KIRK, "kteled", -1, -1, &Room::trial3CrewmanBeamedOut); + loadActorAnimC(OBJECT_SPOCK, "steled", -1, -1, &Room::trial3CrewmanBeamedOut); + loadActorAnimC(OBJECT_MCCOY, "mteled", -1, -1, &Room::trial3CrewmanBeamedOut); + if (!_vm->_awayMission.redshirtDead) + loadActorAnimC(OBJECT_REDSHIRT, "rteled", -1, -1, &Room::trial3CrewmanBeamedOut); +} + +void Room::trial3UseMccoyOnWall() { + showText(TX_SPEAKER_MCCOY, TX_TRI3_010); +} + +void Room::trial3UseMccoyOnExit() { + showText(TX_SPEAKER_MCCOY, TX_TRI3_012); +} + +void Room::trial3UseSpockOnWall() { + showText(TX_SPEAKER_SPOCK, TX_TRI3_021); +} + +void Room::trial3UseSpockOnExit() { + showText(TX_SPEAKER_SPOCK, TX_TRI3_008); +} + +void Room::trial3UseRedshirtOnExit() { + showText(TX_SPEAKER_BENNIE, TX_TRI3_027); +} + +void Room::trial3UseRedshirtOnWall() { + showText(TX_SPEAKER_BENNIE, TX_TRI3_026); +} + +void Room::trial3WalkToExit() { + walkCrewman(OBJECT_KIRK, 0x26, 0x9d); +} + +void Room::trial3UseMedkitAnywhere() { + showText(TX_SPEAKER_MCCOY, TX_TRI3_017); } } |