STARTREK: Warps between rooms

This commit is contained in:
Matthew Stewart 2018-05-15 17:36:11 -04:00 committed by Eugene Sandulenko
parent 2a588200ed
commit be8e807a4b
8 changed files with 184 additions and 66 deletions

View File

@ -51,7 +51,7 @@ void StarTrekEngine::runAwayMission() {
if (!_commandQueue.empty()) {
// sub_200e7();
// sub_20118();
runAwayMissionCycle();
handleAwayMissionCommand();
}
}
}
@ -61,16 +61,13 @@ void StarTrekEngine::cleanupAwayMission() {
}
void StarTrekEngine::loadRoom(const Common::String &missionName, int roomIndex) {
if (_room != nullptr)
delete _room;
_keyboardControlsMouse = true;
_missionName = _missionToLoad;
_roomIndex = _roomIndexToLoad;
_roomIndex = roomIndex;
_roomFrameCounter = 0;
_awayMission.field1d = 0;
_awayMission.transitioningIntoRoom = 0;
_gfx->fadeoutScreen();
_sound->stopAllVocSounds();
@ -82,7 +79,7 @@ void StarTrekEngine::loadRoom(const Common::String &missionName, int roomIndex)
_gfx->loadPalette("palette");
_gfx->copyBackgroundScreen();
_room = new Room(this, _screenName);
_room = SharedPtr<Room>(new Room(this, _screenName));
// Original sets up bytes 0-3 of rdf file as "remote function caller"
@ -110,13 +107,27 @@ void StarTrekEngine::initAwayCrewPositions(int warpEntryIndex) {
memset(_awayMission.field25, 0xff, 4);
switch (warpEntryIndex) {
case 0:
break;
case 0: // 0-3: Read warp positions from RDF file
case 1:
break;
case 2:
break;
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);
objectWalkToPosition(i, anim, srcX, srcY, destX, destY);
}
_kirkObject->walkingIntoRoom = 1;
_kirkObject->field66 = 0xff;
_awayMission.transitioningIntoRoom = 1;
_warpHotspotsActive = false;
break;
case 4: // Crew is beaming in.
warpEntryIndex -= 4;
@ -125,11 +136,11 @@ void StarTrekEngine::initAwayCrewPositions(int warpEntryIndex) {
Common::Point warpPos = _room->getBeamInPosition(i);
loadObjectAnimWithRoomScaling(i, animFilename, warpPos.x, warpPos.y);
}
_kirkObject->field64 = 1;
_kirkObject->walkingIntoRoom = 1;
_kirkObject->field66 = 0xff;
_awayMission.field1d = 1;
_awayMission.transitioningIntoRoom = 1;
playSoundEffectIndex(0x09);
// word_466f2 = 0;
_warpHotspotsActive = false;
break;
case 5:
break;
@ -154,13 +165,13 @@ void StarTrekEngine::handleAwayMissionEvents() {
// sub_22de0();
_frameIndex++;
_roomFrameCounter++;
// sub_20099(0, _roomFrameCounter & 0xff, (_roomFrameCounter >> 8) & 0xff, 0);
addCommand(Command(COMMAND_TICK, _roomFrameCounter & 0xff, (_roomFrameCounter >> 8) & 0xff, 0));
if (_roomFrameCounter >= 2)
_gfx->incPaletteFadeLevel();
break;
case TREKEVENT_LBUTTONDOWN:
//if (_awayMission.field1d != 0) // FIXME: uncomment
// break;
if (_awayMission.transitioningIntoRoom != 0)
break;
switch (_awayMission.mapFileLoaded) {
case 1:
if (_awayMission.field1c == 0) {
@ -204,6 +215,14 @@ void StarTrekEngine::handleAwayMissionEvents() {
}
}
void StarTrekEngine::unloadRoom() {
_gfx->fadeoutScreen();
// sub_2394b(); // TODO
objectFunc1();
_room.reset();
_mapFile.reset();
}
/**
* Similar to loadObjectAnim, but scale is determined by the y-position in the room. The
* further up (away) the object is, the smaller it is.
@ -226,12 +245,108 @@ uint16 StarTrekEngine::getObjectScaleAtPosition(int16 y) {
return ((_playerObjectScale * (y - var08)) >> 8) + var0a;
}
Room *StarTrekEngine::getRoom() {
SharedPtr<Room> StarTrekEngine::getRoom() {
return _room;
}
void StarTrekEngine::runAwayMissionCycle() {
// TODO
void StarTrekEngine::addCommand(const Command &command) {
if (command.type != COMMAND_TICK)
debug("Command %d: %x, %x, %x", command.type, command.b1, command.b2, command.b3);
_commandQueue.push(command);
}
void StarTrekEngine::handleAwayMissionCommand() {
Command command = _commandQueue.pop();
if ((command.type == COMMAND_FINISHED_BEAMING_IN || command.type == FINISHED_ENTERING_ROOM) && command.b1 == 0xff) {
_awayMission.transitioningIntoRoom = 0;
_warpHotspotsActive = true;
return;
}
else if (command.type == FINISHED_ENTERING_ROOM && command.b1 >= 0xe0) { // TODO
return;
}
switch (command.type) { // TODO: everything
case COMMAND_TOUCHED_WARP:
// if (!sub_203e1(command.type)) // Probably calls RDF code
{
byte warpIndex = command.b1;
int16 roomIndex = _room->readRdfWord(RDF_WARP_ROOM_INDICES + warpIndex * 2);
unloadRoom();
_sound->loadMusicFile("ground");
loadRoom(_missionName, roomIndex);
initAwayCrewPositions(warpIndex ^ 1);
}
break;
}
}
/**
* Returns true if the given position is contained in a polygon?
*
* The data passed contains the following words in this order:
* * Index of polygon (unused here)
* * Number of vertices in polygon
* * For each vertex: x and y coordinates.
*/
bool StarTrekEngine::isPointInPolygon(int16 *data, int16 x, int16 y) {
int16 numVertices = data[1];
int16 *vertData = &data[2];
for (int i = 0; i < numVertices; i++) {
Common::Point p1(vertData[0], vertData[1]);
Common::Point p2;
if (i == numVertices - 1) // Loop to 1st vertex
p2 = Common::Point(data[2], data[3]);
else
p2 = Common::Point(vertData[2], vertData[3]);
if ((p2.x - p1.x) * (y - p1.y) - (p2.y - p1.y) * (x - p1.x) < 0)
return false;
vertData += 2;
}
return true;
}
void StarTrekEngine::checkTouchedLoadingZone(int16 x, int16 y) {
int16 offset = _room->getFirstDoorPolygonOffset();
while (offset != _room->getDoorPolygonEndOffset()) {
if (isPointInPolygon((int16*)(_room->_rdfData + offset), x, y)) {
uint16 var = _room->readRdfWord(offset);
if (_activeDoorWarpHotspot != var) {
_activeDoorWarpHotspot = var;
addCommand(Command(COMMAND_7, var & 0xff, 0, 0));
}
return;
}
int16 numVertices = _room->readRdfWord(offset + 2);
offset += numVertices * 4 + 4;
}
_activeDoorWarpHotspot = -1;
if (_awayMission.field24 == 0 && _warpHotspotsActive) {
offset = _room->getFirstWarpPolygonOffset();
while (offset != _room->getWarpPolygonEndOffset()) {
if (isPointInPolygon((int16*)(_room->_rdfData + offset), x, y)) {
uint16 var = _room->readRdfWord(offset);
if (_activeWarpHotspot != var) {
_activeWarpHotspot = var;
addCommand(Command(COMMAND_TOUCHED_WARP, var & 0xff, 0, 0));
}
return;
}
int16 numVertices = _room->readRdfWord(offset + 2);
offset += numVertices * 4 + 4;
}
}
_activeWarpHotspot = -1;
}
/**

View File

@ -28,9 +28,10 @@ struct AwayMission {
int16 mouseX;
int16 mouseY;
byte field1c;
byte field1d; // Set while beaming in?
byte transitioningIntoRoom; // Set while beaming in or walking into a room
bool redshirtDead;
byte mapFileLoaded;
byte field24;
int8 field25[4];
bool rdfRunNextCommand;

View File

@ -41,6 +41,8 @@ void StarTrekEngine::pollSystemEvents() {
addEventToQueue(trekEvent);
break;
case Common::EVENT_LBUTTONDOWN:
// TODO: what happens when mouse click is outside normal screen bounds?
// (apparently this can happen)
trekEvent.type = TREKEVENT_LBUTTONDOWN;
addEventToQueue(trekEvent);
break;

View File

@ -48,7 +48,7 @@ struct Object {
Common::Point pos;
uint16 field60;
uint16 field62;
uint16 field64;
uint16 walkingIntoRoom; // Walking or beaming into a room?
uint16 field66;
char animationString2[8];
uint16 field70;

View File

@ -34,6 +34,12 @@ namespace StarTrek {
class StarTrekEngine;
// Offsets of data in RDF files
const int RDF_WARP_ROOM_INDICES = 0x22;
const int RDF_ROOM_ENTRY_POSITIONS = 0x2a;
const int RDF_BEAM_IN_POSITIONS = 0xaa;
class Room {
public:
@ -49,6 +55,12 @@ public:
int16 getVar0a() { return readRdfWord(0x0a); }
int16 getVar0c() { return readRdfWord(0x0c); }
// Warp-related stuff
int16 getFirstWarpPolygonOffset() { return readRdfWord(0x16); }
int16 getWarpPolygonEndOffset() { return readRdfWord(0x18); }
int16 getFirstDoorPolygonOffset() { return readRdfWord(0x1a); }
int16 getDoorPolygonEndOffset() { return readRdfWord(0x1c); }
Common::Point getBeamInPosition(int crewmanIndex);
byte *_rdfData;

View File

@ -54,7 +54,6 @@ StarTrekEngine::StarTrekEngine(OSystem *syst, const StarTrekGameDescription *gam
_gfx = nullptr;
_sound = nullptr;
_macResFork = nullptr;
_room = nullptr;
_clockTicks = 0;
@ -78,8 +77,6 @@ StarTrekEngine::~StarTrekEngine() {
delete _gfx;
delete _sound;
delete _macResFork;
delete _room;
}
Common::Error StarTrekEngine::run() {
@ -103,26 +100,6 @@ Common::Error StarTrekEngine::run() {
runGameMode(GAMEMODE_AWAYMISSION);
return Common::kNoError;
#if 1
_room = new Room(this, "DEMON0");
_gfx->loadPalette("PALETTE");
_gfx->loadPri("DEMON0.PRI");
_sound->loadMusicFile("GROUND");
while (true) {
_gfx->showOptionsMenu(0, 0);
}
while (!shouldQuit()) {
pollSystemEvents();
}
return Common::kNoError;
#endif
}
Common::Error StarTrekEngine::runGameMode(int mode) {
@ -298,10 +275,10 @@ void StarTrekEngine::playSoundEffectIndex(int index) {
case 0x08:
_sound->playVoc("TRANSDEM");
break;
case 0x09:
case 0x09: // Beaming in?
_sound->playVoc("TRANSMAT");
break;
case 0x0a:
case 0x0a: // Beaming out?
_sound->playVoc("TRANSENE");
break;
case 0x10: // Menu selection sound
@ -376,7 +353,7 @@ int StarTrekEngine::loadObjectAnim(int objectIndex, const Common::String &animNa
drawObjectToScreen(object, animName, x, y, scale, true);
}
object->field64 = 0;
object->walkingIntoRoom = 0;
object->field66 = 0;
return objectIndex;
@ -391,7 +368,7 @@ bool StarTrekEngine::objectWalkToPosition(int objectIndex, const Common::String
Object *object = &_objectList[objectIndex];
object->field64 = 0;
object->walkingIntoRoom = 0;
if (isPositionSolid(destX, destY))
return false;
@ -408,7 +385,7 @@ bool StarTrekEngine::objectWalkToPosition(int objectIndex, const Common::String
object->dest.x = destX;
object->dest.y = destY;
object->field92 = 0;
object->field64 = 0;
object->walkingIntoRoom = 0;
object->iwDestPosition = -1;
object->iwSrcPosition = -1;
@ -458,8 +435,8 @@ void StarTrekEngine::updateObjectAnimations() {
if (object->animFrame != nextAnimFrame) {
if (nextAnimFrame == object->numAnimFrames - 1) {
object->field62++;
if (object->field64 != 0) {
// sub_20099(10, object->field66, 0, 0);
if (object->walkingIntoRoom != 0) {
addCommand(Command(COMMAND_FINISHED_BEAMING_IN, object->field66, 0, 0));
}
}
}
@ -500,10 +477,8 @@ void StarTrekEngine::updateObjectAnimations() {
case 1: // Walking
if (_frameIndex < object->frameToStartNextAnim)
break;
/*
if (i == 0) // TODO: Kirk only
sub_22c2d(object->pos.x, object->pos.y);
*/
if (i == 0) // Kirk only
checkTouchedLoadingZone(object->pos.x, object->pos.y);
if (object->field90 != 0) {
Sprite *sprite = &object->sprite;
int loops;
@ -530,9 +505,9 @@ void StarTrekEngine::updateObjectAnimations() {
}
else { // object->field90 == 0
if (object->iwSrcPosition == -1) {
if (object->field64 != 0) {
object->field64 = 0;
//addCommand(COMMAND_12, object->field66 & 0xff, 0, 0); // TODO
if (object->walkingIntoRoom != 0) {
object->walkingIntoRoom = 0;
addCommand(Command(FINISHED_ENTERING_ROOM, object->field66 & 0xff, 0, 0));
}
object->sprite.bitmap.reset();
@ -1287,7 +1262,7 @@ void StarTrekEngine::playMovieMac(Common::String filename) {
delete qtDecoder;
// Swap back to 8bpp mode
initGraphics(320, 200);
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT);
}
} // End of namespace StarTrek

View File

@ -100,14 +100,20 @@ struct TrekEvent {
enum Commands {
COMMAND_TICK = 0,
COMMAND_CLICKED_ON_OBJECT = 1,
COMMAND_12 = 12
COMMAND_TOUCHED_WARP = 6,
COMMAND_7 = 7, // Doors? (Or just hotspots activated by Kirk moving there?)
COMMAND_FINISHED_BEAMING_IN = 10,
FINISHED_ENTERING_ROOM = 12
};
struct Command {
byte type;
byte b1; // These depend on command type?
byte b1;
byte b2;
byte b3;
Command(byte _type, byte _b1, byte _b2, byte _b3)
: type(_type), b1(_b1), b2(_b2), b3(_b3) {}
};
const int MAX_OBJECTS = 0x20;
@ -132,14 +138,18 @@ private:
void loadRoom(const Common::String &missionName, int roomIndex);
void initAwayCrewPositions(int warpEntryIndex);
void handleAwayMissionEvents();
void unloadRoom();
int loadObjectAnimWithRoomScaling(int objectIndex, const Common::String &animName, int16 x, int16 y);
uint16 getObjectScaleAtPosition(int16 y);
void runAwayMissionCycle();
void addCommand(const Command &command);
void handleAwayMissionCommand();
bool isPointInPolygon(int16 *data, int16 x, int16 y);
void checkTouchedLoadingZone(int16 x, int16 y);
bool isPositionSolid(int16 x, int16 y);
public:
Room *getRoom();
SharedPtr<Room> getRoom();
private:
// Transporter room
@ -232,6 +242,9 @@ public:
Common::Queue<Command> _commandQueue;
AwayMission _awayMission;
bool _warpHotspotsActive;
int16 _activeWarpHotspot;
int16 _activeDoorWarpHotspot;
Object _objectList[MAX_OBJECTS];
Object * const _kirkObject;
@ -271,7 +284,7 @@ public:
private:
Common::MacResManager *_macResFork;
Room *_room;
SharedPtr<Room> _room;
SharedPtr<IWFile> _iwFile;
};

View File

@ -387,7 +387,7 @@ int Graphics::handleMenuEvents(uint32 ticksUntilClickingEnabled, bool arg4) {
* Text getter for showText which reads from an rdf file.
*/
String Graphics::readTextFromRdf(int choiceIndex, uintptr data, String *headerTextOutput) {
Room *room = _vm->getRoom();
SharedPtr<Room> room = _vm->getRoom();
int rdfVar = (size_t)data;