mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 13:50:13 +00:00
783 lines
24 KiB
C++
783 lines
24 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "startrek/iwfile.h"
|
|
#include "startrek/resource.h"
|
|
#include "startrek/room.h"
|
|
#include "startrek/startrek.h"
|
|
|
|
namespace StarTrek {
|
|
|
|
void StarTrekEngine::initAwayMission() {
|
|
_awayMission = AwayMission(); // Initialize members to 0
|
|
|
|
// memset(bitmapBuffer->pixels, 0, 0xfa00);
|
|
|
|
_resource->setTxtFileName("ground");
|
|
|
|
// sub_23a60(); // TODO
|
|
_sound->loadMusicFile("ground");
|
|
|
|
loadRoom(_missionToLoad, _roomIndexToLoad);
|
|
_roomIndexToLoad = -1;
|
|
|
|
// Load crew positions for beaming in
|
|
initAwayCrewPositions(4);
|
|
}
|
|
|
|
void StarTrekEngine::runAwayMission() {
|
|
while (_gameMode == GAMEMODE_AWAYMISSION && !_resetGameMode) {
|
|
// 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();
|
|
_awayMission.mouseX = mousePos.x;
|
|
_awayMission.mouseY = mousePos.y;
|
|
|
|
assert(_actionQueue.size() <= 16);
|
|
while (!_actionQueue.empty()) {
|
|
// sub_200e7(); // TODO
|
|
// sub_20118();
|
|
handleAwayMissionAction();
|
|
}
|
|
}
|
|
}
|
|
|
|
void StarTrekEngine::cleanupAwayMission() {
|
|
// TODO
|
|
}
|
|
|
|
void StarTrekEngine::loadRoom(const Common::String &missionName, int roomIndex) {
|
|
_keyboardControlsMouse = true;
|
|
|
|
_missionName = _missionToLoad;
|
|
_roomIndex = roomIndex;
|
|
|
|
_roomFrameCounter = 0;
|
|
_awayMission.disableInput = false;
|
|
|
|
_gfx->fadeoutScreen();
|
|
_sound->stopAllVocSounds();
|
|
|
|
_gfx->setBackgroundImage(getScreenName());
|
|
_gfx->loadPri(getScreenName());
|
|
_gfx->loadPalette("palette");
|
|
_gfx->copyBackgroundScreen();
|
|
|
|
_room = new Room(this, getScreenName());
|
|
|
|
// Original sets up bytes 0-3 of rdf file as "remote function caller"
|
|
|
|
bool isDemo = getFeatures() & GF_DEMO;
|
|
if (!isDemo)
|
|
_room->loadMapFile(getScreenName());
|
|
|
|
_awayMission.activeAction = ACTION_WALK;
|
|
|
|
removeDrawnActorsFromScreen();
|
|
initActors();
|
|
|
|
Fixed8 num = _room->getMaxScale() - _room->getMinScale();
|
|
int16 den = _room->getMaxY() - _room->getMinY() + 1;
|
|
_playerActorScale = Fixed16(num) / den;
|
|
|
|
_actionQueue.clear();
|
|
|
|
if (!isDemo) {
|
|
int16 addr = _room->getBanDataStart();
|
|
while (addr != _room->getBanDataEnd()) {
|
|
Common::String name((char *)&_room->_rdfData[addr]);
|
|
loadBanFile(name);
|
|
addr += strlen((char *)&_room->_rdfData[addr]) + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void StarTrekEngine::initAwayCrewPositions(int warpEntryIndex) {
|
|
_sound->stopAllVocSounds();
|
|
|
|
memset(_awayMission.crewDirectionsAfterWalk, 0xff, 4);
|
|
|
|
switch (warpEntryIndex) {
|
|
case 0: // 0-3: Crew spawns in a spot and walks to a spot.
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
for (int i = 0; i < (_awayMission.redshirtDead ? 3 : 4); i++) {
|
|
Common::String anim = getCrewmanAnimFilename(i, "walk");
|
|
|
|
int16 rdfOffset = RDF_ROOM_ENTRY_POSITIONS + warpEntryIndex * 32 + i * 8;
|
|
|
|
int16 srcX = _room->readRdfWord(rdfOffset + 0); // Position to spawn at
|
|
int16 srcY = _room->readRdfWord(rdfOffset + 2);
|
|
int16 destX = _room->readRdfWord(rdfOffset + 4); // Position to walk to
|
|
int16 destY = _room->readRdfWord(rdfOffset + 6);
|
|
|
|
actorWalkToPosition(i, anim, srcX, srcY, destX, destY);
|
|
}
|
|
|
|
_kirkActor->triggerActionWhenAnimFinished = true;
|
|
_kirkActor->finishedAnimActionParam = 0xff;
|
|
_awayMission.disableInput = true;
|
|
_warpHotspotsActive = false;
|
|
break;
|
|
case 4: // Crew is beaming in.
|
|
warpEntryIndex -= 4;
|
|
for (int i = 0; i < (_awayMission.redshirtDead ? 3 : 4); i++) {
|
|
Common::String animFilename = getCrewmanAnimFilename(i, "tele");
|
|
Common::Point warpPos = _room->getBeamInPosition(i);
|
|
loadActorAnimWithRoomScaling(i, animFilename, warpPos.x, warpPos.y);
|
|
}
|
|
_kirkActor->triggerActionWhenAnimFinished = true;
|
|
_kirkActor->finishedAnimActionParam = 0xff;
|
|
_awayMission.disableInput = true;
|
|
_sound->playSoundEffectIndex(kSfxTransporterMaterialize);
|
|
_warpHotspotsActive = false;
|
|
break;
|
|
case 5: // Crew spawns in directly at a position.
|
|
for (int i = 0; i < (_awayMission.redshirtDead ? 3 : 4); i++) {
|
|
Common::String animFilename = getCrewmanAnimFilename(i, "stnds");
|
|
Common::Point warpPos = _room->getSpawnPosition(i);
|
|
loadActorAnimWithRoomScaling(i, animFilename, warpPos.x, warpPos.y);
|
|
}
|
|
_warpHotspotsActive = true;
|
|
break;
|
|
case 6:
|
|
loadBridgeActors();
|
|
break;
|
|
default:
|
|
warning("Invalid parameter (%d) to initAwayCrewPositions", warpEntryIndex);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void StarTrekEngine::handleAwayMissionEvents() {
|
|
TrekEvent event;
|
|
|
|
if (popNextEvent(&event)) {
|
|
switch (event.type) {
|
|
case TREKEVENT_TICK:
|
|
updateActorAnimations();
|
|
updateCrewmanGetupTimers();
|
|
|
|
updateMouseBitmap();
|
|
renderBanBelowSprites();
|
|
_gfx->drawAllSprites(false);
|
|
renderBanAboveSprites();
|
|
_gfx->updateScreen();
|
|
|
|
_sound->checkLoopMusic();
|
|
updateAwayMissionTimers();
|
|
_frameIndex++;
|
|
_roomFrameCounter++;
|
|
addAction(ACTION_TICK, _roomFrameCounter & 0xff, (_roomFrameCounter >> 8) & 0xff, 0);
|
|
if (_roomFrameCounter >= 2)
|
|
_gfx->incPaletteFadeLevel();
|
|
break;
|
|
|
|
case TREKEVENT_LBUTTONDOWN:
|
|
awayMissionLeftClick();
|
|
break; // End of TREKEVENT_LBUTTONDOWN
|
|
|
|
case TREKEVENT_MOUSEMOVE:
|
|
break;
|
|
|
|
case TREKEVENT_RBUTTONDOWN:
|
|
awayMissionSelectAction(true);
|
|
break;
|
|
|
|
case TREKEVENT_KEYDOWN:
|
|
if (_awayMission.disableInput)
|
|
break;
|
|
|
|
switch (event.kbd.keycode) {
|
|
case Common::KEYCODE_ESCAPE:
|
|
case Common::KEYCODE_SPACE:
|
|
case Common::KEYCODE_F2:
|
|
awayMissionSelectAction(true);
|
|
break;
|
|
|
|
case Common::KEYCODE_t:
|
|
hideInventoryIcons();
|
|
_awayMission.activeAction = ACTION_TALK;
|
|
awayMissionSelectAction(false);
|
|
break;
|
|
|
|
case Common::KEYCODE_l:
|
|
hideInventoryIcons();
|
|
_awayMission.activeAction = ACTION_LOOK;
|
|
awayMissionSelectAction(false);
|
|
break;
|
|
|
|
case Common::KEYCODE_g:
|
|
hideInventoryIcons();
|
|
_awayMission.activeAction = ACTION_GET;
|
|
awayMissionSelectAction(false);
|
|
break;
|
|
|
|
case Common::KEYCODE_u:
|
|
hideInventoryIcons();
|
|
_awayMission.activeAction = ACTION_USE;
|
|
awayMissionSelectAction(false);
|
|
break;
|
|
|
|
case Common::KEYCODE_w:
|
|
hideInventoryIcons();
|
|
_awayMission.activeAction = ACTION_WALK;
|
|
break;
|
|
|
|
case Common::KEYCODE_i:
|
|
if (_awayMission.activeAction == ACTION_USE) {
|
|
hideInventoryIcons();
|
|
int clickedObject = showInventoryMenu(50, 50, true);
|
|
if (clickedObject == -1)
|
|
clickedObject = -2;
|
|
awayMissionUseObject(clickedObject);
|
|
} else if (_awayMission.activeAction == ACTION_LOOK) {
|
|
hideInventoryIcons();
|
|
int clickedObject = showInventoryMenu(50, 50, true);
|
|
if (clickedObject == -1)
|
|
clickedObject = -2;
|
|
awayMissionGetLookOrTalk(clickedObject);
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_RETURN:
|
|
case Common::KEYCODE_KP_ENTER:
|
|
case Common::KEYCODE_F1:
|
|
awayMissionLeftClick();
|
|
break;
|
|
|
|
case Common::KEYCODE_c:
|
|
// Bridge computer, where the player can ask about various topics.
|
|
// ENHANCEMENT: Normally, this is only available when in the bridge.
|
|
// We also show it in missions.
|
|
if (!(getFeatures() & GF_DEMO))
|
|
handleBridgeComputer();
|
|
break;
|
|
|
|
case Common::KEYCODE_p:
|
|
// Pause game
|
|
// TODO
|
|
break;
|
|
|
|
case Common::KEYCODE_e:
|
|
if (event.kbd.flags & Common::KBD_CTRL) {
|
|
_sound->toggleSfx();
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_m:
|
|
if (event.kbd.flags & Common::KBD_CTRL) {
|
|
_sound->toggleMusic();
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_q:
|
|
if (event.kbd.flags & Common::KBD_CTRL) {
|
|
showQuitGamePrompt(20, 20);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void StarTrekEngine::awayMissionLeftClick() {
|
|
if (_awayMission.disableInput)
|
|
return;
|
|
|
|
switch (_awayMission.activeAction) {
|
|
case ACTION_WALK: {
|
|
if (_awayMission.disableWalking)
|
|
break;
|
|
_kirkActor->sprite.drawMode = 1; // Hide these objects for function call below?
|
|
_spockActor->sprite.drawMode = 1;
|
|
_mccoyActor->sprite.drawMode = 1;
|
|
_redshirtActor->sprite.drawMode = 1;
|
|
|
|
int16 clickedObject = findObjectAt(_gfx->getMousePos());
|
|
|
|
_kirkActor->sprite.drawMode = 0;
|
|
_spockActor->sprite.drawMode = 0;
|
|
_mccoyActor->sprite.drawMode = 0;
|
|
_redshirtActor->sprite.drawMode = 0;
|
|
|
|
if (walkActiveObjectToHotspot())
|
|
break;
|
|
|
|
if (clickedObject > OBJECT_KIRK && clickedObject < ITEMS_START)
|
|
addAction(ACTION_WALK, clickedObject, 0, 0);
|
|
else {
|
|
Common::String animFilename = getCrewmanAnimFilename(OBJECT_KIRK, "walk");
|
|
Common::Point mousePos = _gfx->getMousePos();
|
|
actorWalkToPosition(OBJECT_KIRK, animFilename, _kirkActor->pos.x, _kirkActor->pos.y, mousePos.x, mousePos.y);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ACTION_USE: {
|
|
if (_awayMission.activeObject == OBJECT_REDSHIRT && (_awayMission.redshirtDead || (_awayMission.crewDownBitset & (1 << OBJECT_REDSHIRT)))) {
|
|
hideInventoryIcons();
|
|
_awayMission.activeAction = ACTION_WALK;
|
|
break;
|
|
}
|
|
|
|
int16 clickedObject = findObjectAt(_gfx->getMousePos());
|
|
hideInventoryIcons();
|
|
|
|
if (clickedObject == OBJECT_INVENTORY_ICON) {
|
|
clickedObject = showInventoryMenu(50, 50, false);
|
|
|
|
// -1 means "clicked on something unknown"; -2 means "clicked on
|
|
// nothing". In the case of the inventory, either one clicks on an
|
|
// inventory item, or no action is performed.
|
|
if (clickedObject == -1)
|
|
clickedObject = -2;
|
|
}
|
|
|
|
awayMissionUseObject(clickedObject);
|
|
break;
|
|
}
|
|
|
|
case ACTION_GET:
|
|
case ACTION_LOOK:
|
|
case ACTION_TALK: {
|
|
int16 clickedObject = findObjectAt(_gfx->getMousePos());
|
|
if (!isObjectUnusable(clickedObject, _awayMission.activeAction)) {
|
|
hideInventoryIcons();
|
|
|
|
if (clickedObject == OBJECT_INVENTORY_ICON) {
|
|
clickedObject = showInventoryMenu(50, 50, false);
|
|
if (clickedObject == -1)
|
|
clickedObject = -2;
|
|
}
|
|
|
|
awayMissionGetLookOrTalk(clickedObject);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void StarTrekEngine::awayMissionSelectAction(bool openActionMenu) {
|
|
if (openActionMenu) {
|
|
if (_awayMission.disableInput)
|
|
return;
|
|
hideInventoryIcons();
|
|
_sound->playSoundEffectIndex(kSfxButton);
|
|
_awayMission.activeAction = showActionMenu();
|
|
}
|
|
|
|
if (_awayMission.activeAction == ACTION_USE) {
|
|
int16 clickedObject = selectObjectForUseAction();
|
|
if (clickedObject == -1)
|
|
return;
|
|
else
|
|
_awayMission.activeObject = clickedObject;
|
|
}
|
|
if (_awayMission.activeAction == ACTION_USE
|
|
&& _awayMission.activeObject == OBJECT_ICOMM && (_awayMission.crewDownBitset & (1 << OBJECT_KIRK)) == 0) {
|
|
if (!walkActiveObjectToHotspot()) {
|
|
addAction(_awayMission.activeAction, _awayMission.activeObject, 0, 0);
|
|
_sound->playVoc("communic");
|
|
_awayMission.activeAction = ACTION_WALK;
|
|
}
|
|
} else if (_awayMission.activeAction == ACTION_LOOK)
|
|
showInventoryIcons(false);
|
|
else if (_awayMission.activeAction == ACTION_USE && (_awayMission.crewDownBitset & (1 << OBJECT_KIRK)) == 0)
|
|
showInventoryIcons(true);
|
|
}
|
|
|
|
void StarTrekEngine::awayMissionUseObject(int16 clickedObject) {
|
|
_awayMission.passiveObject = clickedObject;
|
|
|
|
bool activeIsCrewman = _awayMission.activeObject <= OBJECT_REDSHIRT;
|
|
bool activeIsItem = _awayMission.activeObject >= ITEMS_START && _awayMission.activeObject < ITEMS_END;
|
|
bool passiveIsCrewman = _awayMission.passiveObject <= OBJECT_REDSHIRT;
|
|
bool passiveIsItem = _awayMission.passiveObject >= ITEMS_START && _awayMission.passiveObject <= ITEMS_END; // FIXME: "<= ITEMS_END" doesn't make sense?
|
|
|
|
bool tryWalkToHotspot = false;
|
|
bool showInventory = false;
|
|
|
|
if (clickedObject == -2)
|
|
tryWalkToHotspot = true;
|
|
else if (_room->actionHasCode(ACTION_USE, _awayMission.activeObject, _awayMission.passiveObject, 0))
|
|
tryWalkToHotspot = true;
|
|
else if (_awayMission.activeObject == OBJECT_MCCOY && _room->actionHasCode(ACTION_USE, OBJECT_IMEDKIT, _awayMission.passiveObject, 0))
|
|
tryWalkToHotspot = true;
|
|
// CHECKME: Identical to the previous check, thus never used
|
|
//else if (_awayMission.activeObject == OBJECT_MCCOY && _room->actionHasCode(ACTION_USE, OBJECT_IMEDKIT, _awayMission.passiveObject, 0))
|
|
// tryWalkToHotspot = true;
|
|
else if (_awayMission.activeObject == OBJECT_SPOCK && _room->actionHasCode(ACTION_USE, OBJECT_ISTRICOR, _awayMission.passiveObject, 0))
|
|
tryWalkToHotspot = true;
|
|
|
|
if (!tryWalkToHotspot) {
|
|
if ((activeIsCrewman && passiveIsCrewman)
|
|
|| (activeIsCrewman && passiveIsItem)
|
|
|| (activeIsItem && passiveIsItem)) {
|
|
if (_awayMission.passiveObject == OBJECT_ICOMM) {
|
|
if (walkActiveObjectToHotspot())
|
|
return;
|
|
addAction(ACTION_USE, OBJECT_ICOMM, 0, 0);
|
|
_sound->playVoc("commun30");
|
|
if (_awayMission.activeObject <= OBJECT_REDSHIRT) {
|
|
showInventory = true;
|
|
} else {
|
|
_awayMission.activeAction = ACTION_WALK;
|
|
return;
|
|
}
|
|
}
|
|
|
|
_awayMission.activeObject = _awayMission.passiveObject;
|
|
showInventory = true;
|
|
} else
|
|
tryWalkToHotspot = true;
|
|
}
|
|
|
|
if (tryWalkToHotspot) {
|
|
if (!walkActiveObjectToHotspot()) {
|
|
if (clickedObject != -2)
|
|
addAction(_awayMission.activeAction, _awayMission.activeObject, _awayMission.passiveObject, 0);
|
|
showInventory = true;
|
|
}
|
|
}
|
|
|
|
if (showInventory && !(_awayMission.crewDownBitset & (1 << OBJECT_KIRK)))
|
|
showInventoryIcons(true);
|
|
}
|
|
|
|
void StarTrekEngine::awayMissionGetLookOrTalk(int16 clickedObject) {
|
|
_awayMission.activeObject = clickedObject;
|
|
|
|
if (walkActiveObjectToHotspot())
|
|
return;
|
|
|
|
if (clickedObject != -2)
|
|
addAction(_awayMission.activeAction, _awayMission.activeObject, 0, 0);
|
|
|
|
if (_awayMission.activeAction == ACTION_LOOK && !(_awayMission.crewDownBitset & (1 << OBJECT_KIRK)))
|
|
showInventoryIcons(false);
|
|
}
|
|
|
|
void StarTrekEngine::unloadRoom() {
|
|
_gfx->fadeoutScreen();
|
|
// sub_2394b(); // TODO
|
|
removeDrawnActorsFromScreen();
|
|
delete _room;
|
|
_room = nullptr;
|
|
delete _mapFile;
|
|
_mapFile = nullptr;
|
|
delete _iwFile;
|
|
_iwFile = nullptr;
|
|
}
|
|
|
|
int StarTrekEngine::loadActorAnimWithRoomScaling(int actorIndex, const Common::String &animName, int16 x, int16 y) {
|
|
Fixed8 scale = getActorScaleAtPosition(y);
|
|
return loadActorAnim(actorIndex, animName, x, y, scale);
|
|
}
|
|
|
|
Fixed8 StarTrekEngine::getActorScaleAtPosition(int16 y) {
|
|
int16 maxY = _room->getMaxY();
|
|
int16 minY = _room->getMinY();
|
|
Fixed8 minScale = _room->getMinScale();
|
|
|
|
if (y > maxY)
|
|
y = maxY;
|
|
if (y < minY)
|
|
y = minY;
|
|
|
|
return Fixed8(_playerActorScale * (y - minY)) + minScale;
|
|
}
|
|
|
|
Room *StarTrekEngine::getRoom() {
|
|
return _room;
|
|
}
|
|
|
|
void StarTrekEngine::addAction(const Action &action) {
|
|
if (action.type != ACTION_TICK)
|
|
debugC(kDebugGeneral, 4, "Action %d: %x, %x, %x", action.type, action.b1, action.b2, action.b3);
|
|
_actionQueue.push(action);
|
|
}
|
|
|
|
void StarTrekEngine::addAction(int8 type, byte b1, byte b2, byte b3) {
|
|
const Action a = {type, b1, b2, b3};
|
|
addAction(a);
|
|
}
|
|
|
|
void StarTrekEngine::handleAwayMissionAction() {
|
|
Action action = _actionQueue.pop();
|
|
|
|
if ((action.type == ACTION_FINISHED_ANIMATION || action.type == ACTION_FINISHED_WALKING) && action.b1 == 0xff) {
|
|
// Just finished walking or beaming into a room
|
|
if (_awayMission.disableInput == 1)
|
|
_awayMission.disableInput = false;
|
|
_warpHotspotsActive = true;
|
|
return;
|
|
} else if (action.type == ACTION_FINISHED_WALKING && action.b1 >= 0xe0) {
|
|
// Finished walking to a position; perform the action that was input back when
|
|
// they started walking over there.
|
|
int index = action.b1 - 0xe0;
|
|
addAction(_actionOnWalkCompletion[index]);
|
|
_actionOnWalkCompletionInUse[index] = false;
|
|
}
|
|
|
|
if (_room->handleAction(action))
|
|
return;
|
|
|
|
// Action not defined for the room, check for default behaviour
|
|
|
|
switch (action.type) {
|
|
|
|
case ACTION_WALK:
|
|
if (!_room->handleActionWithBitmask(action)) {
|
|
Common::String animFilename = getCrewmanAnimFilename(OBJECT_KIRK, "walk");
|
|
Common::Point mousePos = _gfx->getMousePos();
|
|
actorWalkToPosition(OBJECT_KIRK, animFilename, _kirkActor->pos.x, _kirkActor->pos.y, mousePos.x, mousePos.y);
|
|
}
|
|
break;
|
|
|
|
case ACTION_USE:
|
|
if (action.activeObject() != action.passiveObject()) {
|
|
switch (action.activeObject()) {
|
|
case OBJECT_KIRK:
|
|
// BUGFIX: Don't allow the "use" action to bypass the "disableWalking" variable
|
|
if (!(!_awayMission.disableWalking && _room->handleAction(ACTION_WALK, action.passiveObject(), 0, 0))
|
|
&& !_room->handleAction(ACTION_GET, action.passiveObject(), 0, 0)) {
|
|
showTextbox("Capt. Kirk", _resource->getLoadedText(GROUNDTX_KIRK_USE), 20, 20, TEXTCOLOR_YELLOW, 0);
|
|
}
|
|
break;
|
|
|
|
case OBJECT_SPOCK:
|
|
if (!_room->handleAction(ACTION_USE, OBJECT_ISTRICOR, action.passiveObject(), 0)) {
|
|
// BUGFIX: Original game has just "Spock" instead of "Mr. Spock" as the
|
|
// speaker. That's inconsistent.
|
|
// Same applies to other parts of this function.
|
|
showTextbox("Mr. Spock", _resource->getLoadedText(GROUNDTX_SPOCK_USE), 20, 20, TEXTCOLOR_BLUE, 0);
|
|
}
|
|
break;
|
|
|
|
case OBJECT_MCCOY:
|
|
if (!_room->handleAction(ACTION_USE, OBJECT_IMEDKIT, action.passiveObject(), 0)
|
|
&& !_room->handleAction(ACTION_USE, OBJECT_IMTRICOR, action.passiveObject(), 0)) {
|
|
// BUGFIX: Original game has just "McCoy" instead of "Dr. McCoy".
|
|
showTextbox("Dr. McCoy", _resource->getLoadedText(GROUNDTX_MCCOY_USE), 20, 20, TEXTCOLOR_BLUE, 0);
|
|
}
|
|
break;
|
|
|
|
case OBJECT_REDSHIRT:
|
|
showTextbox(NULL, _resource->getLoadedText(GROUNDTX_REDSHIRT_USE), 20, 20, TEXTCOLOR_YELLOW, 0);
|
|
break;
|
|
|
|
case OBJECT_IPHASERS:
|
|
case OBJECT_IPHASERK:
|
|
if (action.passiveObject() == OBJECT_SPOCK) {
|
|
int text = GROUNDTX_PHASER_ON_SPOCK + getRandomWord() % 8;
|
|
showTextbox("Mr. Spock", _resource->getLoadedText(text), 20, 20, TEXTCOLOR_BLUE, 0);
|
|
} else if (action.passiveObject() == OBJECT_MCCOY) {
|
|
int text = GROUNDTX_PHASER_ON_MCCOY + getRandomWord() % 8;
|
|
showTextbox("Dr. McCoy", _resource->getLoadedText(text), 20, 20, TEXTCOLOR_BLUE, 0);
|
|
} else if (action.passiveObject() == OBJECT_REDSHIRT) {
|
|
Common::String text = _resource->getLoadedText(GROUNDTX_PHASER_ON_REDSHIRT + getRandomWord() % 8);
|
|
// Replace audio filename with start of mission name (to load the
|
|
// audio for the crewman specific to the mission))
|
|
text.setChar(_missionName[0], 6);
|
|
text.setChar(_missionName[1], 7);
|
|
text.setChar(_missionName[2], 8);
|
|
showTextbox("Security Officer", text, 20, 20, TEXTCOLOR_RED, 0);
|
|
// TODO: replace "Security Officer" string with their actual name as
|
|
// an enhancement?
|
|
} else if (!_room->handleActionWithBitmask(action)) {
|
|
int index = getRandomWord() % 7;
|
|
if (index & 1)
|
|
showTextbox("Dr. McCoy", _resource->getLoadedText(GROUNDTX_PHASER_ANYWHERE + index), 20, 20, TEXTCOLOR_BLUE, 0);
|
|
else
|
|
showTextbox("Mr. Spock", _resource->getLoadedText(GROUNDTX_PHASER_ANYWHERE + index), 20, 20, TEXTCOLOR_BLUE, 0);
|
|
}
|
|
break;
|
|
|
|
case OBJECT_ISTRICOR:
|
|
showTextbox("Mr. Spock", _resource->getLoadedText(GROUNDTX_SPOCK_SCAN), 20, 20, TEXTCOLOR_BLUE, 0);
|
|
break;
|
|
|
|
case OBJECT_IMTRICOR:
|
|
showTextbox("Dr. McCoy", _resource->getLoadedText(GROUNDTX_MCCOY_SCAN), 20, 20, TEXTCOLOR_BLUE, 0);
|
|
break;
|
|
|
|
case OBJECT_ICOMM:
|
|
if (!_room->handleAction(ACTION_USE, OBJECT_ICOMM, 0xff, 0))
|
|
showTextbox("Lt. Uhura", _resource->getLoadedText(GROUNDTX_USE_COMMUNICATOR), 20, 20, TEXTCOLOR_RED, 0);
|
|
break;
|
|
|
|
case OBJECT_IMEDKIT:
|
|
showTextbox("Dr. McCoy", _resource->getLoadedText(GROUNDTX_USE_MEDKIT), 20, 20, TEXTCOLOR_BLUE, 0);
|
|
break;
|
|
|
|
default:
|
|
if (!_room->handleActionWithBitmask(action.type, action.b1, action.b2, action.b3))
|
|
showTextbox("", _resource->getLoadedText(GROUNDTX_NOTHING_HAPPENS), 20, 20, TEXTCOLOR_YELLOW, 0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ACTION_GET:
|
|
if (!_room->handleActionWithBitmask(action.type, action.b1, action.b2, action.b3))
|
|
showTextbox("", _resource->getLoadedText(GROUNDTX_FAIL_TO_OBTAIN_ANYTHING), 20, 20, TEXTCOLOR_YELLOW, 0);
|
|
break;
|
|
|
|
case ACTION_LOOK:
|
|
if (action.activeObject() >= ITEMS_START && action.activeObject() < ITEMS_END) {
|
|
int i = action.activeObject() - ITEMS_START;
|
|
Common::String text = _resource->getLoadedText(_itemList[i].textIndex);
|
|
showTextbox("", text, 20, 20, TEXTCOLOR_YELLOW, 0);
|
|
} else if (action.activeObject() == OBJECT_KIRK)
|
|
showTextbox("", _resource->getLoadedText(GROUNDTX_LOOK_KIRK), 20, 20, TEXTCOLOR_YELLOW, 0);
|
|
else if (action.activeObject() == OBJECT_SPOCK)
|
|
showTextbox("", _resource->getLoadedText(GROUNDTX_LOOK_SPOCK), 20, 20, TEXTCOLOR_YELLOW, 0);
|
|
else if (action.activeObject() == OBJECT_MCCOY)
|
|
showTextbox("", _resource->getLoadedText(GROUNDTX_LOOK_MCCOY), 20, 20, TEXTCOLOR_YELLOW, 0);
|
|
else if (action.activeObject() == OBJECT_REDSHIRT)
|
|
showTextbox("", _resource->getLoadedText(GROUNDTX_LOOK_REDSHIRT), 20, 20, TEXTCOLOR_YELLOW, 0);
|
|
else
|
|
// Show generic "nothing of note" text.
|
|
// BUGFIX: originally this was shown after the redshirt's text as well.
|
|
// Though, the original game may not have used this default implementation
|
|
// anywhere...
|
|
showTextbox("", _resource->getLoadedText(GROUNDTX_LOOK_ANYWHERE), 20, 20, TEXTCOLOR_YELLOW, 0);
|
|
break;
|
|
|
|
case ACTION_TALK:
|
|
switch (action.activeObject()) {
|
|
case OBJECT_KIRK:
|
|
case OBJECT_SPOCK:
|
|
case OBJECT_MCCOY:
|
|
case OBJECT_REDSHIRT:
|
|
showTextbox("", _resource->getLoadedText(GROUNDTX_TALK_TO_CREWMAN), 20, 20, TEXTCOLOR_YELLOW, 0);
|
|
break;
|
|
|
|
default:
|
|
showTextbox("", _resource->getLoadedText(GROUNDTX_NO_RESPONSE), 20, 20, TEXTCOLOR_YELLOW, 0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case ACTION_TOUCHED_WARP:
|
|
if (!_room->handleActionWithBitmask(action)) {
|
|
byte warpIndex = action.b1;
|
|
int16 roomIndex = _room->readRdfWord(RDF_WARP_ROOM_INDICES + warpIndex * 2);
|
|
unloadRoom();
|
|
_sound->loadMusicFile("ground");
|
|
loadRoom(_missionName, roomIndex);
|
|
initAwayCrewPositions(warpIndex ^ 1);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
_room->handleActionWithBitmask(action);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void StarTrekEngine::checkTouchedLoadingZone(int16 x, int16 y) {
|
|
int16 offset = _room->getFirstDoorPolygonOffset();
|
|
|
|
while (offset != _room->getDoorPolygonEndOffset()) {
|
|
if (_room->isPointInPolygon(offset, x, y)) {
|
|
uint16 var = _room->readRdfWord(offset);
|
|
if (_activeDoorWarpHotspot != var) {
|
|
_activeDoorWarpHotspot = var;
|
|
addAction(ACTION_TOUCHED_HOTSPOT, var & 0xff, 0, 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
int16 numVertices = _room->readRdfWord(offset + 2);
|
|
offset += numVertices * 4 + 4;
|
|
}
|
|
_activeDoorWarpHotspot = -1;
|
|
|
|
if (_awayMission.crewDownBitset == 0 && _warpHotspotsActive) {
|
|
offset = _room->getFirstWarpPolygonOffset();
|
|
|
|
while (offset != _room->getWarpPolygonEndOffset()) {
|
|
if (_room->isPointInPolygon(offset, x, y)) {
|
|
uint16 var = _room->readRdfWord(offset);
|
|
if (_activeWarpHotspot != var) {
|
|
_activeWarpHotspot = var;
|
|
addAction(ACTION_TOUCHED_WARP, var & 0xff, 0, 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
int16 numVertices = _room->readRdfWord(offset + 2);
|
|
offset += numVertices * 4 + 4;
|
|
}
|
|
}
|
|
_activeWarpHotspot = -1;
|
|
}
|
|
|
|
void StarTrekEngine::updateAwayMissionTimers() {
|
|
for (int i = 0; i < 8; i++) {
|
|
if (_awayMission.timers[i] == 0)
|
|
continue;
|
|
_awayMission.timers[i]--;
|
|
if (_awayMission.timers[i] == 0)
|
|
addAction(ACTION_TIMER_EXPIRED, i, 0, 0);
|
|
}
|
|
}
|
|
|
|
bool StarTrekEngine::isPositionSolid(int16 x, int16 y) {
|
|
assert(x >= 0 && x < SCREEN_WIDTH && y >= 0 && y < SCREEN_HEIGHT);
|
|
|
|
_mapFile->seek((y * SCREEN_WIDTH + x) / 8, SEEK_SET);
|
|
return _mapFile->readByte() & (0x80 >> (x % 8));
|
|
}
|
|
|
|
void StarTrekEngine::loadRoomIndex(int roomIndex, int spawnIndex) {
|
|
unloadRoom();
|
|
_sound->loadMusicFile("ground");
|
|
|
|
loadRoom(_missionName, roomIndex);
|
|
initAwayCrewPositions(spawnIndex % 6);
|
|
|
|
// WORKAROUND: original game calls "retrieveStackVars" to return execution directly to
|
|
// the top of "runAwayMission". That can't really be done here. But does it matter?
|
|
}
|
|
|
|
} // End of namespace StarTrek
|