Permalink
Browse files

STARTREK: Finish implementing first room

Doors now work, and the system of "walking, then performing an action
afterward" is implemented.
  • Loading branch information...
Drenn1 authored and sev- committed May 23, 2018
1 parent bd79e4d commit ca3a9dcc8764909e163a860e4a472404620480e2
@@ -35,8 +35,8 @@ enum Acton {

ACTION_TOUCHED_WARP = 6,
ACTION_TOUCHED_HOTSPOT = 7, // Doors? (Or just hotspots activated by Kirk moving there?)
ACTION_FINISHED_BEAMING_IN = 10,
ACTION_FINISHED_ENTERING_ROOM = 12,
ACTION_FINISHED_ANIMATION = 10,
ACTION_FINISHED_WALKING = 12,
ACTION_OPTIONS = 13 // Not really an action, but selectable from action menu
};

@@ -46,6 +46,7 @@ struct Action {
byte b2;
byte b3;

Action() {}
Action(byte _type, byte _b1, byte _b2, byte _b3)
: type(_type),
b1(_b1),
@@ -60,6 +61,23 @@ struct Action {
bool operator==(const Action &a) const {
return type == a.type && b1 == a.b1 && b2 == a.b2 && b3 == a.b3;
}

uint32 getBitmask() const {
uint32 ret = 0;
if (type != 0xff)
ret |= (0xff << 24);
if (b1 != 0xff)
ret |= (0xff << 16);
if (b2 != 0xff)
ret |= (0xff << 8);
if (b3 != 0xff)
ret |= (0xff << 0);
return ret;
}

uint32 toUint32() const {
return (type << 24) | (b1 << 16) | (b2 << 8) | (b3 << 0);
}
};

#endif
@@ -128,8 +128,8 @@ void StarTrekEngine::initAwayCrewPositions(int warpEntryIndex) {
actorWalkToPosition(i, anim, srcX, srcY, destX, destY);
}

_kirkActor->walkingIntoRoom = 1;
_kirkActor->field66 = 0xff;
_kirkActor->triggerActionWhenAnimFinished = true;
_kirkActor->finishedAnimActionParam = 0xff;
_awayMission.transitioningIntoRoom = 1;
_warpHotspotsActive = false;
break;
@@ -140,8 +140,8 @@ void StarTrekEngine::initAwayCrewPositions(int warpEntryIndex) {
Common::Point warpPos = _room->getBeamInPosition(i);
loadActorAnimWithRoomScaling(i, animFilename, warpPos.x, warpPos.y);
}
_kirkActor->walkingIntoRoom = 1;
_kirkActor->field66 = 0xff;
_kirkActor->triggerActionWhenAnimFinished = true;
_kirkActor->finishedAnimActionParam = 0xff;
_awayMission.transitioningIntoRoom = 1;
playSoundEffectIndex(0x09);
_warpHotspotsActive = false;
@@ -179,26 +179,33 @@ void StarTrekEngine::handleAwayMissionEvents() {
break;

switch (_awayMission.activeAction) {
case ACTION_WALK:
if (_awayMission.field1c == 0) {
_kirkActor->sprite.drawMode = 1; // Hide these objects for function call below?
_spockActor->sprite.drawMode = 1;
_mccoyActor->sprite.drawMode = 1;
_redshirtActor->sprite.drawMode = 1;

// findActorClickedOn();
// ...

_kirkActor->sprite.drawMode = 0;
_spockActor->sprite.drawMode = 0;
_mccoyActor->sprite.drawMode = 0;
_redshirtActor->sprite.drawMode = 0;

Common::String animFilename = getCrewmanAnimFilename(0, "walk");
case ACTION_WALK: {
if (_awayMission.field1c != 0)
break;
_kirkActor->sprite.drawMode = 1; // Hide these objects for function call below?
_spockActor->sprite.drawMode = 1;
_mccoyActor->sprite.drawMode = 1;
_redshirtActor->sprite.drawMode = 1;

int 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(0, animFilename, _kirkActor->pos.x, _kirkActor->pos.y, mousePos.x, mousePos.y);
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.field24 & 8))) {
@@ -246,7 +253,7 @@ void StarTrekEngine::handleAwayMissionEvents() {
|| (activeIsCrewman && passiveIsItem)
|| (activeIsItem && passiveIsItem)) {
if (_awayMission.passiveObject == OBJECT_ICOMM) {
if (sub_2330c())
if (walkActiveObjectToHotspot())
break;
addAction(Action(ACTION_USE, OBJECT_ICOMM, 0, 0));
_sound->playVoc("commun30");
@@ -264,7 +271,7 @@ void StarTrekEngine::handleAwayMissionEvents() {
}

checkAddAction:
if (!sub_2330c())
if (!walkActiveObjectToHotspot())
{
if (clickedObject != -2)
addAction(Action(_awayMission.activeAction, _awayMission.activeObject, _awayMission.passiveObject, 0));
@@ -291,13 +298,13 @@ void StarTrekEngine::handleAwayMissionEvents() {

_awayMission.activeObject = clickedObject;

if (sub_2330c())
if (walkActiveObjectToHotspot())
break;

if (clickedObject != -2)
addAction(Action(_awayMission.activeAction, _awayMission.activeObject, 0, 0));

if (_awayMission.activeAction == ACTION_LOOK && !(_awayMission.field24 & 1))
if (_awayMission.activeAction == ACTION_LOOK && !(_awayMission.field24 & (1 << OBJECT_KIRK)))
showInventoryIcons(false);
}
break;
@@ -316,16 +323,15 @@ void StarTrekEngine::handleAwayMissionEvents() {
playSoundEffectIndex(0x07);
_awayMission.activeAction = showActionMenu();
if (_awayMission.activeAction == ACTION_USE) {
//int16 clickedObject = selectObjectForGetAction(); // TODO
int16 clickedObject = 0;
int16 clickedObject = selectObjectForUseAction();
if (clickedObject == -1)
break;
else
_awayMission.activeObject = clickedObject;
}
if (_awayMission.activeAction == ACTION_USE
&& _awayMission.activeObject == OBJECT_ICOMM && (_awayMission.field24 & 1) == 0) { // TODO
if (!sub_2330c()) {
&& _awayMission.activeObject == OBJECT_ICOMM && (_awayMission.field24 & (1 << OBJECT_KIRK)) == 0) {
if (!walkActiveObjectToHotspot()) {
addAction(Action(_awayMission.activeAction, _awayMission.activeObject, 0, 0));
_sound->playVoc("communic");
_awayMission.activeAction = ACTION_WALK;
@@ -389,24 +395,32 @@ void StarTrekEngine::addAction(const Action &action) {
void StarTrekEngine::handleAwayMissionAction() {
Action action = _actionQueue.pop();

if ((action.type == ACTION_FINISHED_BEAMING_IN || action.type == ACTION_FINISHED_ENTERING_ROOM) && action.b1 == 0xff) {
if ((action.type == ACTION_FINISHED_ANIMATION || action.type == ACTION_FINISHED_WALKING) && action.b1 == 0xff) {
_awayMission.transitioningIntoRoom = 0;
_warpHotspotsActive = true;
return;
}
else if (action.type == ACTION_FINISHED_ENTERING_ROOM && action.b1 >= 0xe0) { // TODO
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) { // TODO: everything
switch (action.type) {

case ACTION_WALK: // TODO
warning("Unhandled walk action: %d %d %d", action.b1, action.b2, action.b3);
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: // TODO
@@ -446,8 +460,7 @@ void StarTrekEngine::handleAwayMissionAction() {
break;

case ACTION_TOUCHED_WARP:
// if (!sub_203e1(action.type)) // Probably calls RDF code
{
if (!_room->handleActionWithBitmask(action)) {
byte warpIndex = action.b1;
int16 roomIndex = _room->readRdfWord(RDF_WARP_ROOM_INDICES + warpIndex * 2);
unloadRoom();
@@ -538,4 +551,15 @@ bool StarTrekEngine::isPositionSolid(int16 x, int16 y) {
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?
}

}
@@ -29,7 +29,7 @@ struct AwayMission {
int16 mouseY;
byte field1c;
byte field1d;
byte transitioningIntoRoom; // Set while beaming in or walking into a room
byte transitioningIntoRoom; // Set while beaming in or walking into a room. Disables control?
bool redshirtDead;
byte activeAction;
byte activeObject; // The item that is going to be used on something
@@ -39,8 +39,11 @@ struct AwayMission {
// any "default" code for the event, if any.
bool rdfStillDoDefaultAction;

// Bits 0-3 correspond to the crewmen? A bit is set if they're not selectable with
// the use action?
byte field24;
int8 field25[4];

int8 field25[4]; // Sets an object's direction after they finish walking somewhere?

// Demon Word: nonzero if a rude response was given to the prelate.
int16 field29;
@@ -56,6 +56,13 @@ const int ITEMS_END = ITEMS_START + NUM_ITEMS; // See items.h
const int NUM_OBJECTS = ITEMS_END;


enum Directions {
DIR_N = 0,
DIR_S = 1,
DIR_E = 2,
DIR_W = 3
};

// Some object indices are reserved (see items.h for item objects)
enum Objects {
OBJECT_KIRK = 0,
@@ -80,8 +87,8 @@ struct Actor {
Common::Point pos;
uint16 field60;
uint16 field62;
uint16 walkingIntoRoom; // Walking or beaming into a room?
uint16 field66;
bool triggerActionWhenAnimFinished;
uint16 finishedAnimActionParam;
char animationString2[8];
uint16 field70;
uint16 field72;
@@ -83,6 +83,23 @@ bool Room::handleAction(const Action &action) {
return false;
}

bool Room::handleActionWithBitmask(const Action &action) {
RoomAction *roomActionPtr = _roomActionList;
int n = _numRoomActions;

while (n-- > 0) {
uint32 bitmask = action.getBitmask();
if ((action.toUint32() & bitmask) == (roomActionPtr->action.toUint32() & bitmask)) {
_vm->_awayMission.rdfStillDoDefaultAction = false;
(this->*(roomActionPtr->funcPtr))();
if (!_vm->_awayMission.rdfStillDoDefaultAction)
return true;
}
roomActionPtr++;
}
return false;
}

Common::Point Room::getBeamInPosition(int crewmanIndex) {
int base = 0xaa + crewmanIndex * 4;
return Common::Point(readRdfWord(base), readRdfWord(base + 2));
@@ -91,7 +108,7 @@ Common::Point Room::getBeamInPosition(int crewmanIndex) {

// Interface for room-specific code

void Room::loadActorAnim(int actorIndex, Common::String anim, int16 x, int16 y, uint16 field66) {
void Room::loadActorAnim(int actorIndex, Common::String anim, int16 x, int16 y, uint16 finishedAnimActionParam) {
Actor *actor = &_vm->_actorList[actorIndex];

if (x == -1 || y == -1) {
@@ -104,9 +121,9 @@ void Room::loadActorAnim(int actorIndex, Common::String anim, int16 x, int16 y,
else
_vm->loadActorAnim(actorIndex, anim, x, y, 256);

if (field66 != 0) {
actor->walkingIntoRoom = 1;
actor->field66 = field66;
if (finishedAnimActionParam != 0) {
actor->triggerActionWhenAnimFinished = true;
actor->finishedAnimActionParam = finishedAnimActionParam;
}
}

@@ -125,8 +142,8 @@ void Room::loadActorStandAnim(int actorIndex) {
/**
* This is exactly the same as "loadActorAnim", but the game calls it at different times?
*/
void Room::loadActorAnim2(int actorIndex, Common::String anim, int16 x, int16 y, uint16 field66) {
loadActorAnim(actorIndex, anim, x, y, field66);
void Room::loadActorAnim2(int actorIndex, Common::String anim, int16 x, int16 y, uint16 finishedAnimActionParam) {
loadActorAnim(actorIndex, anim, x, y, finishedAnimActionParam);
}

// TODO: replace "rdfOffset" with a pointer, so we no longer read from RDF files? (This
@@ -168,27 +185,25 @@ void Room::loadRoomIndex(int roomIndex, int spawnIndex) {
if (_vm->_awayMission.field24 != 0)
return;

_vm->unloadRoom();
_vm->_sound->loadMusicFile("ground");

_vm->loadRoom(_vm->_missionName, roomIndex);
_vm->initAwayCrewPositions(spawnIndex % 6);
_vm->loadRoomIndex(roomIndex, spawnIndex);

// TODO: "retrieveStackVars" call returns program counter directly to beginning of
// away mission loop. How to handle this?
// 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"...
}

void Room::walkCrewman(int actorIndex, int16 destX, int16 destY, uint16 field66) {
void Room::walkCrewman(int actorIndex, int16 destX, int16 destY, uint16 finishedAnimActionParam) {
if (!(actorIndex >= OBJECT_KIRK && actorIndex < OBJECT_REDSHIRT))
error("Tried to walk a non PC");

Actor *actor = &_vm->_actorList[actorIndex];
Common::String anim = _vm->getCrewmanAnimFilename(actorIndex, "walk");
bool success = _vm->actorWalkToPosition(actorIndex, anim, actor->pos.x, actor->pos.y, destX, destY);

if (success && field66 != 0) {
actor->walkingIntoRoom = 1;
actor->field66 = field66;
if (success && finishedAnimActionParam != 0) {
actor->triggerActionWhenAnimFinished = true;
actor->finishedAnimActionParam = finishedAnimActionParam;
}
}

Oops, something went wrong.

0 comments on commit ca3a9dc

Please sign in to comment.