mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-11 12:18:05 +00:00
4fef6d8972
Animations on objects/persons setup by cutaways can still be played after the end of the cutscene. (the only ?) one room in which this is reproducable is the first time you talk to the Oracle (first c44, then c47). As a Cutaway object is created for each cutscene, the _cutAnim member should be moved to an more "persistant" object. Otherwise we're reading data from free'd memory... svn-id: r13488
1375 lines
35 KiB
C++
1375 lines
35 KiB
C++
/* ScummVM - Scumm Interpreter
|
|
* Copyright (C) 2003-2004 The ScummVM project
|
|
*
|
|
* 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 2
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* $Header$
|
|
*
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "queen/cutaway.h"
|
|
|
|
#include "queen/bankman.h"
|
|
#include "queen/display.h"
|
|
#include "queen/graphics.h"
|
|
#include "queen/grid.h"
|
|
#include "queen/input.h"
|
|
#include "queen/logic.h"
|
|
#include "queen/queen.h"
|
|
#include "queen/resource.h"
|
|
#include "queen/sound.h"
|
|
#include "queen/talk.h"
|
|
#include "queen/walk.h"
|
|
|
|
namespace Queen {
|
|
|
|
void Cutaway::run(
|
|
const char *filename,
|
|
char *nextFilename,
|
|
QueenEngine *vm) {
|
|
Cutaway *cutaway = new Cutaway(filename, vm);
|
|
cutaway->run(nextFilename);
|
|
delete cutaway;
|
|
}
|
|
|
|
Cutaway::Cutaway(
|
|
const char *filename,
|
|
QueenEngine *vm)
|
|
: _vm(vm), _personDataCount(0), _personFaceCount(0), _lastSong(0), _songBeforeComic(0) {
|
|
memset(&_bankNames, 0, sizeof(_bankNames));
|
|
_vm->input()->cutawayQuitReset();
|
|
load(filename);
|
|
}
|
|
|
|
Cutaway::~Cutaway() {
|
|
delete[] _fileData;
|
|
}
|
|
|
|
void Cutaway::load(const char *filename) {
|
|
byte *ptr;
|
|
|
|
debug(6, "----- Cutaway::load(\"%s\") -----", filename);
|
|
|
|
ptr = _fileData = _vm->resource()->loadFile(filename, 20);
|
|
|
|
if (0 == scumm_stricmp(filename, "comic.cut"))
|
|
_songBeforeComic = _vm->sound()->lastOverride();
|
|
|
|
strcpy(_basename, filename);
|
|
_basename[strlen(_basename)-4] = '\0';
|
|
|
|
_comPanel = READ_BE_UINT16(ptr);
|
|
ptr += 2;
|
|
debug(6, "_comPanel = %i", _comPanel);
|
|
_cutawayObjectCount = (int16)READ_BE_INT16(ptr);
|
|
ptr += 2;
|
|
|
|
debug(6, "_cutawayObjectCount = %i", _cutawayObjectCount);
|
|
|
|
if (_cutawayObjectCount < 0) {
|
|
_cutawayObjectCount = -_cutawayObjectCount;
|
|
_vm->input()->canQuit(false);
|
|
}
|
|
else
|
|
_vm->input()->canQuit(true);
|
|
|
|
int16 flags1 = (int16)READ_BE_INT16(ptr);
|
|
ptr += 2;
|
|
debug(6, "flags1 = %i", flags1);
|
|
|
|
if (flags1 < 0) {
|
|
_vm->logic()->entryObj(0);
|
|
_finalRoom = -flags1;
|
|
}
|
|
else
|
|
_finalRoom = PREVIOUS_ROOM;
|
|
|
|
_anotherCutaway = (flags1 == 1);
|
|
|
|
debug(6, "[Cutaway::load] _finalRoom = %i", _finalRoom);
|
|
debug(6, "[Cutaway::load] _anotherCutaway = %i", _anotherCutaway);
|
|
|
|
/*
|
|
Pointers to other places in the cutaway data
|
|
*/
|
|
|
|
_gameStatePtr = _fileData + READ_BE_UINT16(ptr);
|
|
ptr += 2;
|
|
|
|
_nextSentence = _fileData + READ_BE_UINT16(ptr);
|
|
ptr += 2;
|
|
|
|
byte *bankNamesPtr = _fileData + READ_BE_UINT16(ptr);
|
|
ptr += 2;
|
|
//debug(6, "Bank name file offset = %08x", 20 + bankNamesPtr - _fileData);
|
|
|
|
_objectData = ptr;
|
|
|
|
loadStrings(bankNamesPtr);
|
|
|
|
if (_bankNames[0][0]) {
|
|
debug(6, "Loading bank '%s'", _bankNames[0]);
|
|
_vm->bankMan()->load(_bankNames[0], CUTAWAY_BANK);
|
|
}
|
|
|
|
char entryString[MAX_STRING_SIZE];
|
|
_nextSentence = Talk::getString(_nextSentence, entryString, MAX_STRING_LENGTH);
|
|
debug(6, "Entry string = '%s'", entryString);
|
|
|
|
_vm->logic()->joeCutFacing(_vm->logic()->joeFacing());
|
|
_vm->logic()->joeFace();
|
|
|
|
if (entryString[0] == '*' &&
|
|
entryString[1] == 'F' &&
|
|
entryString[3] == '\0') {
|
|
switch (entryString[2]) {
|
|
case 'L':
|
|
_vm->logic()->joeCutFacing(DIR_LEFT);
|
|
break;
|
|
case 'R':
|
|
_vm->logic()->joeCutFacing(DIR_RIGHT);
|
|
break;
|
|
case 'F':
|
|
_vm->logic()->joeCutFacing(DIR_FRONT);
|
|
break;
|
|
case 'B':
|
|
_vm->logic()->joeCutFacing(DIR_BACK);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void Cutaway::loadStrings(byte *ptr) {
|
|
int i,j;
|
|
|
|
int bankNameCount = READ_BE_UINT16(ptr);
|
|
ptr += 2;
|
|
|
|
//debug(6, "Bank name count = %i", bankNameCount);
|
|
|
|
/*
|
|
The _bankNames zero-based array is the one-based BANK_NAMEstr array in
|
|
the original source code.
|
|
*/
|
|
|
|
for (i = 0, j = 0; i < bankNameCount; i++) {
|
|
ptr = Talk::getString(ptr, _bankNames[j], MAX_FILENAME_LENGTH);
|
|
|
|
if (_bankNames[j][0]) {
|
|
//debug(6, "Bank name %i = '%s'", j, _bankNames[j]);
|
|
j++;
|
|
}
|
|
}
|
|
|
|
debug(6, "Getting talk file");
|
|
ptr = Talk::getString(ptr, _talkFile, MAX_FILENAME_LENGTH);
|
|
debug(6, "Talk file = '%s'", _talkFile);
|
|
|
|
_talkTo = (int16)READ_BE_INT16(ptr);
|
|
ptr += 2;
|
|
debug(6, "_talkTo = %i", _talkTo);
|
|
}
|
|
|
|
byte *Cutaway::getCutawayObject(byte *ptr, CutawayObject &object)
|
|
{
|
|
byte *oldPtr = ptr;
|
|
|
|
object.objectNumber = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.moveToX = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.moveToY = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.bank = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.animList = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.execute = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.limitBobX1 = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.limitBobY1 = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.limitBobX2 = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.limitBobY2 = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.specialMove = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.animType = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.fromObject = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.bobStartX = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.bobStartY = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.room = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
object.scale = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
|
|
if ((ptr - oldPtr) != 17*sizeof(int16))
|
|
error("Wrong number of values read");
|
|
|
|
// Make ugly reuse of data less ugly
|
|
if (object.limitBobX1 < 0) {
|
|
object.song = -object.limitBobX1;
|
|
object.limitBobX1 = 0;
|
|
}
|
|
else
|
|
object.song = 0;
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void Cutaway::dumpCutawayObject(int index, CutawayObject &object)
|
|
{
|
|
debug(6, "----- CutawayObject[%i] -----", index);
|
|
|
|
const char *objectNumberStr;
|
|
|
|
switch (object.objectNumber) {
|
|
case -1:
|
|
objectNumberStr = "MESSAGE"; break;
|
|
case 0:
|
|
objectNumberStr = "Joe"; break;
|
|
default:
|
|
if (object.objectNumber > 0)
|
|
objectNumberStr = _vm->logic()->objectName(ABS(_vm->logic()->objectData(object.objectNumber)->name));
|
|
else
|
|
objectNumberStr = "Unknown!";
|
|
break;
|
|
}
|
|
|
|
debug(6, "objectNumber = %i (%s)", object.objectNumber, objectNumberStr);
|
|
|
|
if (object.moveToX) debug(6, "moveToX = %i", object.moveToX);
|
|
if (object.moveToY) debug(6, "moveToY = %i", object.moveToY);
|
|
if (object.bank) debug(6, "bank = %i", object.bank);
|
|
if (object.animList) debug(6, "animList = %i", object.animList);
|
|
if (object.execute) debug(6, "execute = %i", object.execute);
|
|
if (object.limitBobX1) debug(6, "limitBobX1 = %i", object.limitBobX1);
|
|
if (object.limitBobY1) debug(6, "limitBobY1 = %i", object.limitBobY1);
|
|
if (object.limitBobX2) debug(6, "limitBobX2 = %i", object.limitBobX2);
|
|
if (object.limitBobY2) debug(6, "limitBobY2 = %i", object.limitBobY2);
|
|
if (object.specialMove) debug(6, "specialMove = %i", object.specialMove);
|
|
if (object.animType) debug(6, "animType = %i", object.animType);
|
|
if (object.fromObject) debug(6, "fromObject = %i", object.fromObject);
|
|
if (object.bobStartX) debug(6, "bobStartX = %i", object.bobStartX);
|
|
if (object.bobStartY) debug(6, "bobStartY = %i", object.bobStartY);
|
|
if (object.room) debug(6, "room = %i", object.room);
|
|
if (object.scale) debug(6, "scale = %i", object.scale);
|
|
|
|
}
|
|
|
|
|
|
byte *Cutaway::turnOnPeople(byte *ptr, CutawayObject &object) {
|
|
// Lines 1248-1259 in cutaway.c
|
|
object.personCount = (int16)READ_BE_INT16(ptr);
|
|
ptr += 2;
|
|
|
|
if (object.personCount > MAX_PERSON_COUNT)
|
|
error("[Cutaway::turnOnPeople] object.personCount > MAX_PERSON_COUNT");
|
|
|
|
for (int i = 0; i < object.personCount; i++) {
|
|
object.person[i] = (int16)READ_BE_INT16(ptr);
|
|
ptr += 2;
|
|
//debug(6, "[%i] Turn on person %i", i, object.person[i]);
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void Cutaway::limitBob(CutawayObject &object) {
|
|
if (object.limitBobX1) {
|
|
|
|
if (object.objectNumber < 0) {
|
|
warning("QueenCutaway::limitBob called with objectNumber = %i", object.objectNumber);
|
|
return;
|
|
}
|
|
|
|
BobSlot *bob =
|
|
_vm->graphics()->bob( _vm->logic()->findBob(object.objectNumber) );
|
|
|
|
if (!bob) {
|
|
warning("Failed to find bob");
|
|
return;
|
|
}
|
|
|
|
bob->box.x1 = object.limitBobX1;
|
|
bob->box.y1 = object.limitBobY1;
|
|
bob->box.x2 = object.limitBobX2;
|
|
bob->box.y2 = object.limitBobY2;
|
|
}
|
|
}
|
|
|
|
void Cutaway::restorePersonData() {
|
|
for (int i = 0; i < _personDataCount; i++) {
|
|
int index = _personData[i].index;
|
|
ObjectData *objectData = _vm->logic()->objectData(index);
|
|
objectData->name = _personData[i].name;
|
|
objectData->image = _personData[i].image;
|
|
}
|
|
}
|
|
|
|
void Cutaway::changeRooms(CutawayObject &object) {
|
|
// Lines 1291-1385 in cutaway.c
|
|
|
|
debug(6, "Changing from room %i to room %i",
|
|
_temporaryRoom,
|
|
object.room);
|
|
|
|
restorePersonData();
|
|
_personDataCount = 0;
|
|
|
|
if (_finalRoom != object.room) {
|
|
int firstObjectInRoom = _vm->logic()->roomData(object.room) + 1;
|
|
int lastObjectInRoom = _vm->logic()->roomData(object.room) + _vm->grid()->objMax(object.room);
|
|
|
|
for (int i = firstObjectInRoom; i <= lastObjectInRoom; i++) {
|
|
ObjectData *objectData = _vm->logic()->objectData(i);
|
|
|
|
if (objectData->image == -3 || objectData->image == -4) {
|
|
|
|
assert(_personDataCount < MAX_PERSON_COUNT);
|
|
// The object is a person! So record the details...
|
|
_personData[_personDataCount].index = i;
|
|
_personData[_personDataCount].name = objectData->name;
|
|
_personData[_personDataCount].image = objectData->image;
|
|
_personDataCount++;
|
|
|
|
// Now, check to see if we need to keep the person on
|
|
bool on = false;
|
|
for (int j = 0; j < object.personCount; j++) {
|
|
if (object.person[j] == i) {
|
|
on = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (on) {
|
|
// It is needed, so ensure it's ON
|
|
objectData->name = ABS(objectData->name);
|
|
}
|
|
else {
|
|
// Not needed, so switch off!
|
|
objectData->name = -ABS(objectData->name);
|
|
}
|
|
|
|
}
|
|
} // for()
|
|
}
|
|
|
|
// set coordinates for Joe if he is on screen
|
|
|
|
_vm->logic()->joePos(0, 0);
|
|
|
|
for (int i = 0; i < object.personCount; i++) {
|
|
if (PERSON_JOE == object.person[i]) {
|
|
_vm->logic()->joePos(object.bobStartX, object.bobStartY);
|
|
}
|
|
}
|
|
|
|
_vm->logic()->oldRoom(_initialRoom);
|
|
|
|
// FIXME - the first cutaway is played at the end of the command 0x178. This
|
|
// command setups some persons and associates bob slots to them. They should be
|
|
// hidden as their y coordinate is > 150, but they aren't ! A (temporary)
|
|
// workaround is to display the room with the panel area enabled. Same problem
|
|
// for cutaway c62c.
|
|
int16 comPanel = _comPanel;
|
|
if ((strcmp(_basename, "c41f") == 0 && _temporaryRoom == 106 && object.room == 41) ||
|
|
(strcmp(_basename, "c62c") == 0 && _temporaryRoom == 105 && object.room == 41)) {
|
|
comPanel = 1;
|
|
}
|
|
|
|
// FIXME - in the original engine, panel is hidden once the 'head room' is displayed, we
|
|
// do it before (ie before palette fading)
|
|
if (object.room == FAYE_HEAD || object.room == AZURA_HEAD || object.room == FRANK_HEAD) {
|
|
comPanel = 2;
|
|
}
|
|
|
|
RoomDisplayMode mode;
|
|
|
|
if (!_vm->logic()->joeX() && !_vm->logic()->joeY()) {
|
|
mode = RDM_FADE_NOJOE;
|
|
}
|
|
else {
|
|
// We need to display Joe on screen
|
|
if (_roomFade)
|
|
mode = RDM_NOFADE_JOE;
|
|
else
|
|
mode = RDM_FADE_JOE_XY;
|
|
}
|
|
|
|
_vm->logic()->displayRoom(_vm->logic()->currentRoom(), mode, object.scale, comPanel, true);
|
|
|
|
_currentImage = _vm->graphics()->numFrames();
|
|
|
|
_temporaryRoom = _vm->logic()->currentRoom();
|
|
|
|
restorePersonData();
|
|
}
|
|
|
|
Cutaway::ObjectType Cutaway::getObjectType(CutawayObject &object) {
|
|
// Lines 1387-1449 in cutaway.c
|
|
|
|
ObjectType objectType = OBJECT_TYPE_ANIMATION;
|
|
|
|
if (object.objectNumber > 0) {
|
|
if (!object.animList) {
|
|
// No anim frames, so treat as a PERSON, ie. allow to speak/walk
|
|
ObjectData *objectData = _vm->logic()->objectData(object.objectNumber);
|
|
if (objectData->image == -3 || objectData->image == -4)
|
|
objectType = OBJECT_TYPE_PERSON;
|
|
}
|
|
}
|
|
else if (object.objectNumber == OBJECT_JOE) {
|
|
// It's Joe. See if he's to be treated as a person.
|
|
if (!object.animList) {
|
|
// There's no animation list, so Joe must be talking.
|
|
objectType = OBJECT_TYPE_PERSON;
|
|
}
|
|
}
|
|
|
|
if (object.fromObject > 0) {
|
|
/* Copy FROM_OBJECT into OBJECT */
|
|
|
|
if(object.objectNumber != object.fromObject) {
|
|
_vm->logic()->objectCopy(object.fromObject, object.objectNumber);
|
|
}
|
|
else {
|
|
// Same object, so just turn it on!
|
|
ObjectData *objectData = _vm->logic()->objectData(object.objectNumber);
|
|
objectData->name = ABS(objectData->name);
|
|
}
|
|
|
|
_vm->graphics()->refreshObject(object.objectNumber);
|
|
|
|
// Skip doing any anim stuff
|
|
objectType = OBJECT_TYPE_NO_ANIMATION;
|
|
}
|
|
|
|
switch(object.objectNumber) {
|
|
case -2:
|
|
// Text to be spoken
|
|
objectType = OBJECT_TYPE_TEXT_SPEAK;
|
|
break;
|
|
case -3:
|
|
// Text to be displayed AND spoken
|
|
objectType = OBJECT_TYPE_TEXT_DISPLAY_AND_SPEAK;
|
|
break;
|
|
case -4:
|
|
// Text to be displayed only (not spoken)
|
|
objectType = OBJECT_TYPE_TEXT_DISPLAY;
|
|
break;
|
|
}
|
|
|
|
if (OBJECT_TYPE_ANIMATION == objectType && !object.execute) {
|
|
// Execute is not on, and it's an object, so ignore any Anims
|
|
objectType = OBJECT_TYPE_NO_ANIMATION;
|
|
}
|
|
|
|
return objectType;
|
|
}
|
|
|
|
byte *Cutaway::getCutawayAnim(byte *ptr, int header, CutawayAnim &anim) {
|
|
// lines 1531-1607 in cutaway.c
|
|
|
|
//debug(6, "[Cutaway::getCutawayAnim] header=%i", header);
|
|
|
|
anim.currentFrame = 0;
|
|
anim.originalFrame = 0;
|
|
|
|
if (-1 == header)
|
|
header = 0;
|
|
|
|
if (0 == header) {
|
|
anim.object = 0;
|
|
anim.originalFrame = 29 + FRAMES_JOE_XTRA;
|
|
}
|
|
else {
|
|
anim.object = _vm->logic()->findBob(header);
|
|
anim.originalFrame = _vm->logic()->findFrame(header);
|
|
}
|
|
|
|
anim.unpackFrame = (int16)READ_BE_INT16(ptr);
|
|
ptr += 2;
|
|
|
|
anim.speed = ((int16)READ_BE_INT16(ptr)) / 3 + 1;
|
|
ptr += 2;
|
|
|
|
anim.bank = (int16)READ_BE_INT16(ptr);
|
|
ptr += 2;
|
|
|
|
if (anim.bank == 0) {
|
|
anim.bank = 15;
|
|
}
|
|
else {
|
|
if (anim.bank != 13) {
|
|
_vm->bankMan()->load(_bankNames[anim.bank-1], CUTAWAY_BANK);
|
|
anim.bank = 8;
|
|
}
|
|
else {
|
|
// Make sure we ref correct JOE bank (7)
|
|
anim.bank = 7;
|
|
}
|
|
}
|
|
|
|
anim.mx = (int16)READ_BE_INT16(ptr);
|
|
ptr += 2;
|
|
|
|
anim.my = (int16)READ_BE_INT16(ptr);
|
|
ptr += 2;
|
|
|
|
anim.cx = (int16)READ_BE_INT16(ptr);
|
|
ptr += 2;
|
|
|
|
anim.cy = (int16)READ_BE_INT16(ptr);
|
|
ptr += 2;
|
|
|
|
anim.scale = (int16)READ_BE_INT16(ptr);
|
|
ptr += 2;
|
|
|
|
if (_vm->resource()->isDemo()) {
|
|
anim.song = 0;
|
|
}
|
|
else {
|
|
anim.song = (int16)READ_BE_INT16(ptr);
|
|
ptr += 2;
|
|
}
|
|
|
|
// Extract information that depend on the signedness of values
|
|
if (anim.unpackFrame < 0) {
|
|
anim.flip = true;
|
|
anim.unpackFrame = -anim.unpackFrame;
|
|
}
|
|
else
|
|
anim.flip = false;
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void Cutaway::dumpCutawayAnim(CutawayAnim &anim) {
|
|
debug(6, "----- CutawayAnim -----");
|
|
if (anim.object) debug(6, "object = %i", anim.object);
|
|
if (anim.unpackFrame) debug(6, "unpackFrame = %i", anim.unpackFrame);
|
|
if (anim.speed) debug(6, "speed = %i", anim.speed);
|
|
if (anim.bank) debug(6, "bank = %i", anim.bank);
|
|
if (anim.mx) debug(6, "mx = %i", anim.mx);
|
|
if (anim.my) debug(6, "my = %i", anim.my);
|
|
if (anim.cx) debug(6, "cx = %i", anim.cx);
|
|
if (anim.cy) debug(6, "cy = %i", anim.cy);
|
|
if (anim.scale) debug(6, "scale = %i", anim.scale);
|
|
if (anim.currentFrame) debug(6, "currentFrame = %i", anim.currentFrame);
|
|
if (anim.originalFrame) debug(6, "originalFrame = %i", anim.originalFrame);
|
|
if (anim.song) debug(6, "song = %i", anim.song);
|
|
}
|
|
|
|
byte *Cutaway::handleAnimation(byte *ptr, CutawayObject &object) {
|
|
// lines 1517-1770 in cutaway.c
|
|
int frameCount = 0;
|
|
int header = 0;
|
|
int i;
|
|
|
|
CutawayAnim objAnim[56];
|
|
|
|
// Read animation frames
|
|
for (;;) {
|
|
|
|
header = (int16)READ_BE_INT16(ptr);
|
|
ptr += 2;
|
|
|
|
if (-2 == header)
|
|
break;
|
|
|
|
//debug(6, "Animation frame %i, header = %i", frameCount, header);
|
|
|
|
if (header > 1000)
|
|
error("Header too large");
|
|
|
|
ptr = getCutawayAnim(ptr, header, objAnim[frameCount]);
|
|
//dumpCutawayAnim(objAnim[frameCount]);
|
|
|
|
frameCount++;
|
|
|
|
if (_vm->input()->cutawayQuit())
|
|
return NULL;
|
|
}
|
|
|
|
if (object.animType == 1) {
|
|
// lines 1615-1636 in cutaway.c
|
|
|
|
debug(6, "----- Complex cutaway animation (animType = %i) -----", object.animType);
|
|
|
|
if ((_vm->logic()->currentRoom() == 47 || _vm->logic()->currentRoom() == 63) &&
|
|
objAnim[0].object == 1) {
|
|
//CR 2 - 3/3/95, Special harcoded section to make Oracle work...
|
|
makeComplexAnimation(_vm->graphics()->personFrames(1) - 1, objAnim, frameCount);
|
|
}
|
|
else {
|
|
_currentImage = makeComplexAnimation(_currentImage, objAnim, frameCount);
|
|
}
|
|
|
|
if (object.bobStartX || object.bobStartY) {
|
|
BobSlot *bob = _vm->graphics()->bob(objAnim[0].object);
|
|
bob->x = object.bobStartX;
|
|
bob->y = object.bobStartY;
|
|
}
|
|
}
|
|
|
|
// Setup the SYNCHRO bob channels
|
|
|
|
for (i = 0; i < frameCount; i++) {
|
|
if (objAnim[i].mx || objAnim[i].my) {
|
|
BobSlot *bob = _vm->graphics()->bob(objAnim[i].object);
|
|
bob->frameNum = objAnim[i].originalFrame;
|
|
bob->move(objAnim[i].mx, objAnim[i].my, (object.specialMove > 0) ? object.specialMove : 4);
|
|
// Boat room hard coded
|
|
if (_vm->logic()->currentRoom() == ROOM_TEMPLE_OUTSIDE) {
|
|
BobSlot *bobJoe = _vm->graphics()->bob(0);
|
|
if (bobJoe->x < 320) {
|
|
bobJoe->move(bobJoe->x + 346, bobJoe->y, 4);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Normal cutaway
|
|
|
|
if (object.animType != 1) {
|
|
// lines 1657-1761 in cutaway.c
|
|
|
|
debug(6, "----- Normal cutaway animation (animType = %i) -----", object.animType);
|
|
|
|
for (i = 0; i < frameCount; i++) {
|
|
//debug(6, "===== Animating frame %i =====", i);
|
|
//dumpCutawayAnim(objAnim[i]);
|
|
|
|
BobSlot *bob = _vm->graphics()->bob(objAnim[i].object);
|
|
bob->active = true;
|
|
if (bob->animating) {
|
|
bob->animating = false;
|
|
bob->frameNum = objAnim[i].originalFrame;
|
|
}
|
|
|
|
if (objAnim[i].object < 4)
|
|
bob->frameNum = 29 + objAnim[i].object + FRAMES_JOE_XTRA;
|
|
|
|
if (objAnim[i].unpackFrame == 0) {
|
|
// Turn off the bob
|
|
bob->active = false;
|
|
}
|
|
else {
|
|
if (object.animType == 2 || object.animType == 0) {
|
|
// Unpack animation, but do not unpack moving people
|
|
|
|
if (!((objAnim[i].mx > 0 || objAnim[i].my > 0) && inRange(objAnim[i].object, 1, 3))) {
|
|
_vm->bankMan()->unpack(
|
|
objAnim[i].unpackFrame,
|
|
objAnim[i].originalFrame,
|
|
objAnim[i].bank);
|
|
}
|
|
|
|
if (0 == objAnim[i].object) {
|
|
// Scale Joe
|
|
bob->scale = scale(object);
|
|
}
|
|
}
|
|
|
|
if (objAnim[i].cx || objAnim[i].cy) {
|
|
bob->x = objAnim[i].cx;
|
|
bob->y = objAnim[i].cy;
|
|
}
|
|
|
|
// Only flip if we are not moving or it is not a person object
|
|
if (!(objAnim[i].object > 0 && objAnim[i].object < 4) ||
|
|
!(objAnim[i].mx || objAnim[i].my) )
|
|
bob->xflip = objAnim[i].flip;
|
|
|
|
// Add frame alteration
|
|
if (!(objAnim[i].object > 0 && objAnim[i].object < 4)) {
|
|
bob->frameNum = objAnim[i].originalFrame;
|
|
}
|
|
|
|
int j;
|
|
for (j = 0; j < objAnim[i].speed; j++)
|
|
_vm->update();
|
|
}
|
|
|
|
if (_vm->input()->cutawayQuit())
|
|
return NULL;
|
|
|
|
if (objAnim[i].song > 0)
|
|
_vm->sound()->playSong(objAnim[i].song);
|
|
|
|
} // for()
|
|
}
|
|
|
|
bool moving = true;
|
|
|
|
while (moving) {
|
|
moving = false;
|
|
_vm->update();
|
|
|
|
for (i = 0; i < frameCount; i++) {
|
|
BobSlot *bob = _vm->graphics()->bob(objAnim[i].object);
|
|
if (bob->moving) {
|
|
moving = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (_vm->input()->cutawayQuit())
|
|
return NULL;
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
static void findCdCut(const char *basename, int index, char *result) {
|
|
// Function find_cd_cut, lines 5-15 in execute.c
|
|
|
|
strcpy(result, basename);
|
|
for (int i = strlen(basename); i < 5; i++)
|
|
result[i] = '_';
|
|
snprintf(result + 5, 3, "%02i", index);
|
|
//debug(6, "findCdCut(\"%s\", %i, \"%s\")", basename, index, result);
|
|
}
|
|
|
|
void Cutaway::handlePersonRecord(
|
|
int index,
|
|
CutawayObject &object,
|
|
const char *sentence) {
|
|
// Lines 1455-1516 in cutaway.c
|
|
|
|
Person p;
|
|
|
|
if (object.objectNumber == OBJECT_JOE) {
|
|
if (object.moveToX || object.moveToY) {
|
|
_vm->walk()->moveJoe(0, object.moveToX, object.moveToY, true);
|
|
}
|
|
}
|
|
else {
|
|
_vm->logic()->initPerson(
|
|
object.objectNumber - _vm->logic()->currentRoomData(),
|
|
"", true, &p);
|
|
|
|
if (object.bobStartX || object.bobStartY) {
|
|
BobSlot *bob = _vm->graphics()->bob(p.actor->bobNum);
|
|
bob->scale = scale(object);
|
|
bob->x = object.bobStartX;
|
|
bob->y = object.bobStartY;
|
|
}
|
|
|
|
if (object.moveToX || object.moveToY)
|
|
_vm->walk()->movePerson(
|
|
&p,
|
|
object.moveToX, object.moveToY,
|
|
_currentImage + 1,
|
|
_vm->logic()->objectData(object.objectNumber)->image
|
|
);
|
|
}
|
|
|
|
if (_vm->input()->cutawayQuit())
|
|
return;
|
|
|
|
if (0 != strcmp(sentence, "*")) {
|
|
if (sentence[0] == '#') {
|
|
debug(4, "Starting credits '%s'", sentence + 1);
|
|
_vm->logic()->startCredits(sentence + 1);
|
|
}
|
|
else {
|
|
if (object.objectNumber > 0) {
|
|
bool foundPerson = false;
|
|
|
|
for (int i = 1; i <= _personFaceCount; i++) {
|
|
if (_personFace[i].index == object.objectNumber) {
|
|
foundPerson = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!foundPerson) {
|
|
_personFaceCount++;
|
|
assert(_personFaceCount < MAX_PERSON_FACE_COUNT);
|
|
_personFace[_personFaceCount].index = object.objectNumber;
|
|
_personFace[_personFaceCount].image = _vm->logic()->objectData(object.objectNumber)->image;
|
|
}
|
|
}
|
|
|
|
char voiceFilePrefix[MAX_STRING_SIZE];
|
|
findCdCut(_basename, index, voiceFilePrefix);
|
|
_vm->logic()->makePersonSpeak(sentence, (object.objectNumber == OBJECT_JOE) ? NULL : &p, voiceFilePrefix);
|
|
}
|
|
|
|
}
|
|
|
|
if (_vm->input()->cutawayQuit())
|
|
return;
|
|
}
|
|
|
|
void Cutaway::run(char *nextFilename) {
|
|
int i;
|
|
nextFilename[0] = '\0';
|
|
|
|
_currentImage = _vm->graphics()->numFrames();
|
|
|
|
BobSlot *joeBob = _vm->graphics()->bob(0);
|
|
int initialJoeX = joeBob->x;
|
|
int initialJoeY = joeBob->y;
|
|
debug(6, "[Cutaway::run] Joe started at (%i, %i)", initialJoeX, initialJoeY);
|
|
|
|
_vm->input()->cutawayRunning(true);
|
|
|
|
_initialRoom = _temporaryRoom = _vm->logic()->currentRoom();
|
|
|
|
_vm->display()->screenMode(_comPanel, true);
|
|
|
|
if (_comPanel == 0 || _comPanel == 2) {
|
|
_vm->logic()->sceneStart();
|
|
}
|
|
|
|
memset(_personFace, 0, sizeof(_personFace));
|
|
_personFaceCount = 0;
|
|
|
|
byte *ptr = _objectData;
|
|
|
|
for (i = 0; i < _cutawayObjectCount; i++) {
|
|
CutawayObject object;
|
|
ptr = getCutawayObject(ptr, object);
|
|
//dumpCutawayObject(i, object);
|
|
|
|
if (!object.moveToX &&
|
|
!object.moveToY &&
|
|
object.specialMove > 0 &&
|
|
object.objectNumber >= 0) {
|
|
_vm->logic()->executeSpecialMove(object.specialMove);
|
|
object.specialMove = 0;
|
|
}
|
|
|
|
if (CURRENT_ROOM == object.room) {
|
|
// Get current room
|
|
object.room = _vm->logic()->currentRoom();
|
|
}
|
|
else {
|
|
// Change current room
|
|
_vm->logic()->currentRoom(object.room);
|
|
}
|
|
|
|
ptr = turnOnPeople(ptr, object);
|
|
|
|
limitBob(object);
|
|
|
|
char sentence[MAX_STRING_SIZE];
|
|
_nextSentence = Talk::getString(_nextSentence, sentence, MAX_STRING_LENGTH);
|
|
//debug(6, "Sentence = '%s'", sentence);
|
|
|
|
if (OBJECT_ROOMFADE == object.objectNumber) {
|
|
_roomFade = true;
|
|
object.objectNumber = OBJECT_JOE;
|
|
}
|
|
else {
|
|
_roomFade = false;
|
|
}
|
|
|
|
if (object.room != _temporaryRoom)
|
|
changeRooms(object);
|
|
|
|
ObjectType objectType = getObjectType(object);
|
|
|
|
if (object.song)
|
|
_vm->sound()->playSong(object.song);
|
|
|
|
switch (objectType) {
|
|
case OBJECT_TYPE_ANIMATION:
|
|
ptr = handleAnimation(ptr, object);
|
|
break;
|
|
|
|
case OBJECT_TYPE_PERSON:
|
|
handlePersonRecord(i + 1, object, sentence);
|
|
break;
|
|
|
|
case OBJECT_TYPE_NO_ANIMATION:
|
|
// Do nothing?
|
|
break;
|
|
|
|
case OBJECT_TYPE_TEXT_SPEAK:
|
|
case OBJECT_TYPE_TEXT_DISPLAY_AND_SPEAK:
|
|
case OBJECT_TYPE_TEXT_DISPLAY:
|
|
handleText(i + 1, objectType, object, sentence);
|
|
break;
|
|
|
|
default:
|
|
warning("Unhandled object type: %i", objectType);
|
|
break;
|
|
}
|
|
|
|
if (_vm->input()->cutawayQuit())
|
|
break;
|
|
|
|
if (_roomFade) {
|
|
_vm->update();
|
|
int end = 223;
|
|
if (Logic::isIntroRoom(_vm->logic()->currentRoom())) {
|
|
end = 255;
|
|
}
|
|
BobSlot *j = _vm->graphics()->bob(0);
|
|
_vm->display()->palFadeIn(0, end, _vm->logic()->currentRoom(), j->active, j->x, j->y);
|
|
_roomFade = false;
|
|
}
|
|
|
|
} // for()
|
|
|
|
_vm->display()->clearTexts(0, 198);
|
|
// XXX lines 1887-1895 in cutaway.c
|
|
|
|
stop();
|
|
|
|
_vm->input()->cutawayQuitReset();
|
|
|
|
updateGameState();
|
|
|
|
_vm->bankMan()->close(CUTAWAY_BANK);
|
|
|
|
talk(nextFilename);
|
|
|
|
if (_comPanel == 0 || (_comPanel == 2 && !_anotherCutaway)) {
|
|
_vm->logic()->sceneStop();
|
|
_comPanel = 0;
|
|
}
|
|
|
|
if (nextFilename[0] == '\0' && !_anotherCutaway) {
|
|
_vm->display()->fullscreen(false);
|
|
|
|
// Lines 2138-2182 in cutaway.c
|
|
if (_finalRoom) {
|
|
_vm->logic()->newRoom(0);
|
|
_vm->logic()->entryObj(0);
|
|
}
|
|
else {
|
|
/// No need to stay in current room, so return to previous room
|
|
// if one exists. Reset Joe's X,Y coords to those when first entered
|
|
|
|
restorePersonData();
|
|
|
|
debug(6, "_vm->logic()->entryObj() = %i", _vm->logic()->entryObj());
|
|
if (_vm->logic()->entryObj() > 0) {
|
|
_initialRoom = _vm->logic()->objectData(_vm->logic()->entryObj())->room;
|
|
}
|
|
else {
|
|
// We're not returning to new room, so return to old Joe X,Y coords
|
|
debug(6, "[Cutaway::run] Moving joe to (%i, %i)", initialJoeX, initialJoeY);
|
|
_vm->logic()->joePos(initialJoeX, initialJoeY);
|
|
}
|
|
|
|
if (_vm->logic()->currentRoom() != _initialRoom) {
|
|
_vm->logic()->currentRoom(_initialRoom);
|
|
_vm->logic()->changeRoom();
|
|
if (_vm->logic()->currentRoom() == _vm->logic()->newRoom()) {
|
|
_vm->logic()->newRoom(0);
|
|
}
|
|
}
|
|
_vm->logic()->joePos(0, 0);
|
|
}
|
|
|
|
_vm->logic()->joeCutFacing(0);
|
|
_comPanel = 0;
|
|
|
|
int k = 0;
|
|
for (i = _vm->logic()->roomData(_vm->logic()->currentRoom());
|
|
i <= _vm->logic()->roomData(_vm->logic()->currentRoom() + 1); i++) {
|
|
|
|
ObjectData *object = _vm->logic()->objectData(i);
|
|
if (object->image == -3 || object->image == -4) {
|
|
k++;
|
|
if (object->name > 0) {
|
|
_vm->graphics()->resetPersonAnim(k);
|
|
}
|
|
}
|
|
}
|
|
|
|
_vm->logic()->removeHotelItemsFromInventory();
|
|
}
|
|
|
|
joeBob->animating = 0;
|
|
joeBob->moving = 0;
|
|
|
|
_vm->input()->cutawayRunning(false);
|
|
_vm->input()->cutawayQuitReset();
|
|
_vm->input()->quickSaveReset();
|
|
_vm->input()->quickLoadReset();
|
|
|
|
if (_songBeforeComic > 0)
|
|
_vm->sound()->playSong(_songBeforeComic);
|
|
else if (_lastSong > 0)
|
|
_vm->sound()->playSong(_lastSong);
|
|
}
|
|
|
|
void Cutaway::stop() {
|
|
// Lines 1901-2032 in cutaway.c
|
|
byte *ptr = _gameStatePtr;
|
|
|
|
// Skipping GAMESTATE data
|
|
int gameStateCount = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
if (gameStateCount > 0)
|
|
ptr += (gameStateCount * 12);
|
|
|
|
// Get the final room and Joe's final position
|
|
|
|
int16 joeRoom = READ_BE_UINT16(ptr); ptr += 2;
|
|
int16 joeX = READ_BE_UINT16(ptr); ptr += 2;
|
|
int16 joeY = READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
debug(6, "[Cutaway::stop] Final position is room %i and coordinates (%i, %i)",
|
|
joeRoom, joeX, joeY);
|
|
|
|
if ((!_vm->input()->cutawayQuit() || (!_anotherCutaway && joeRoom == _finalRoom)) &&
|
|
joeRoom != _temporaryRoom &&
|
|
joeRoom != 0) {
|
|
|
|
debug(6, "[Cutaway::stop] Changing rooms and moving Joe");
|
|
|
|
_vm->logic()->joePos(joeX, joeY);
|
|
_vm->logic()->currentRoom(joeRoom);
|
|
_vm->logic()->oldRoom(_initialRoom);
|
|
_vm->logic()->displayRoom(_vm->logic()->currentRoom(), RDM_FADE_JOE_XY, 0, _comPanel, true);
|
|
}
|
|
|
|
if (_vm->input()->cutawayQuit()) {
|
|
// Lines 1927-2032 in cutaway.c
|
|
int i;
|
|
|
|
// Stop the credits from running
|
|
_vm->logic()->stopCredits();
|
|
|
|
_vm->graphics()->stopBobs();
|
|
|
|
for (i = 1; i <= _personFaceCount; i++) {
|
|
int index = _personFace[i].index;
|
|
if (index > 0) {
|
|
_vm->logic()->objectData(_personFace[i].index)->image = _personFace[i].image;
|
|
|
|
_vm->graphics()->bob(_vm->logic()->findBob(index))->xflip =
|
|
(_personFace[i].image != -4);
|
|
}
|
|
}
|
|
|
|
int quitObjectCount = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
|
|
for (i = 0; i < quitObjectCount; i++) {
|
|
int16 objectIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
int16 fromIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
int16 x = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
int16 y = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
int16 room = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
int16 frame = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
int16 bank = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
|
|
int bobIndex = _vm->logic()->findBob(objectIndex);
|
|
ObjectData *object = _vm->logic()->objectData(objectIndex);
|
|
|
|
if (fromIndex > 0) {
|
|
if (fromIndex == objectIndex) {
|
|
// Enable object
|
|
object->name = ABS(object->name);
|
|
}
|
|
else {
|
|
_vm->logic()->objectCopy(fromIndex, objectIndex);
|
|
|
|
ObjectData *from = _vm->logic()->objectData(fromIndex);
|
|
if (object->image && !from->image && bobIndex && _vm->logic()->currentRoom() == object->room)
|
|
_vm->graphics()->bob(bobIndex)->clear();
|
|
}
|
|
|
|
if (_vm->logic()->currentRoom() == room)
|
|
_vm->graphics()->refreshObject(objectIndex);
|
|
}
|
|
|
|
if (_vm->logic()->currentRoom() == object->room) {
|
|
BobSlot *pbs = _vm->graphics()->bob(bobIndex);
|
|
|
|
if (x || y) {
|
|
pbs->x = x;
|
|
pbs->y = y;
|
|
if (inRange(object->image, -4, -3))
|
|
pbs->scale = _vm->grid()->findScale(x, y);
|
|
}
|
|
|
|
if (frame) {
|
|
if (0 == bank)
|
|
bank = 15;
|
|
else if (bank != 13) {
|
|
_vm->bankMan()->load(_bankNames[bank-1], CUTAWAY_BANK);
|
|
bank = 8;
|
|
}
|
|
|
|
int objectFrame = _vm->logic()->findFrame(objectIndex);
|
|
|
|
if (objectFrame == 1000) {
|
|
_vm->graphics()->bob(bobIndex)->clear();
|
|
}
|
|
else if (objectFrame) {
|
|
_vm->bankMan()->unpack(ABS(frame), objectFrame, bank);
|
|
pbs->frameNum = objectFrame;
|
|
if (frame < 0)
|
|
pbs->xflip = true;
|
|
|
|
}
|
|
}
|
|
}
|
|
} // for()
|
|
|
|
int16 specialMove = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
if (specialMove > 0)
|
|
_vm->logic()->executeSpecialMove(specialMove);
|
|
|
|
_lastSong = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
}
|
|
|
|
if (joeRoom == _temporaryRoom &&
|
|
joeRoom != 37 && joeRoom != 105 && joeRoom != 106 &&
|
|
(joeX || joeY)) {
|
|
BobSlot *joeBob = _vm->graphics()->bob(0);
|
|
|
|
debug(6, "[Cutaway::stop] Moving Joe");
|
|
|
|
joeBob->x = joeX;
|
|
joeBob->y = joeY;
|
|
_vm->logic()->joeScale(_vm->grid()->findScale(joeX, joeY));
|
|
_vm->logic()->joeFace();
|
|
}
|
|
}
|
|
|
|
void Cutaway::updateGameState() {
|
|
// Lines 2047-2115 in cutaway.c
|
|
byte *ptr = _gameStatePtr;
|
|
|
|
int gameStateCount = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
|
|
for (int i = 0; i < gameStateCount; i++) {
|
|
int16 stateIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
int16 stateValue = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
int16 objectIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
int16 areaIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
int16 areaSubIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
int16 fromObject = (int16)READ_BE_INT16(ptr); ptr += 2;
|
|
|
|
bool update = false;
|
|
|
|
if (stateIndex > 0) {
|
|
if(_vm->logic()->gameState(stateIndex) == stateValue)
|
|
update = true;
|
|
}
|
|
else {
|
|
_vm->logic()->gameState(ABS(stateIndex), stateValue);
|
|
update = true;
|
|
}
|
|
|
|
if (update) {
|
|
|
|
if (objectIndex > 0) { // Show the object
|
|
ObjectData *objectData = _vm->logic()->objectData(objectIndex);
|
|
objectData->name = ABS(objectData->name);
|
|
if (fromObject > 0)
|
|
_vm->logic()->objectCopy(fromObject, objectIndex);
|
|
_vm->graphics()->refreshObject(objectIndex);
|
|
}
|
|
else if (objectIndex < 0) { // Hide the object
|
|
objectIndex = -objectIndex;
|
|
ObjectData *objectData = _vm->logic()->objectData(objectIndex);
|
|
objectData->name = -ABS(objectData->name);
|
|
_vm->graphics()->refreshObject(objectIndex);
|
|
}
|
|
|
|
if (areaIndex > 0) {
|
|
|
|
// Turn area on or off
|
|
|
|
if (areaSubIndex > 0) {
|
|
Area *area = _vm->grid()->area(areaIndex, areaSubIndex);
|
|
area->mapNeighbours = ABS(area->mapNeighbours);
|
|
}
|
|
else {
|
|
Area *area = _vm->grid()->area(areaIndex, ABS(areaSubIndex));
|
|
area->mapNeighbours = -ABS(area->mapNeighbours);
|
|
}
|
|
}
|
|
|
|
}
|
|
} // for()
|
|
}
|
|
|
|
static char *right(char *str, int count) {
|
|
// This function does _not_ use static data (the implementation in talk.c does!)
|
|
int length = strlen(str);
|
|
if (count > length)
|
|
return str;
|
|
else
|
|
return str + length - count;
|
|
}
|
|
|
|
void Cutaway::talk(char *nextFilename) {
|
|
// Lines 2119-2131 in cutaway.c
|
|
|
|
if (0 == scumm_stricmp(right(_talkFile, 4), ".dog")) {
|
|
nextFilename[0] = '\0';
|
|
|
|
int personInRoom;
|
|
|
|
if (_talkTo > 0)
|
|
personInRoom = _talkTo - _vm->logic()->roomData(_vm->logic()->currentRoom());
|
|
else {
|
|
warning("_talkTo is 0!");
|
|
personInRoom = 0; // XXX is this correct?
|
|
}
|
|
|
|
_vm->logic()->startDialogue(_talkFile, personInRoom, nextFilename);
|
|
}
|
|
}
|
|
|
|
int Cutaway::makeComplexAnimation(int16 currentImage, Cutaway::CutawayAnim *objAnim, int frameCount) {
|
|
int frameIndex[256];
|
|
int i;
|
|
assert(frameCount < 30);
|
|
AnimFrame cutAnim[30];
|
|
|
|
memset(frameIndex, 0, sizeof(frameIndex));
|
|
debug(6, "[Cutaway::makeComplexAnimation] currentImage = %i", currentImage);
|
|
|
|
for (i = 0; i < frameCount; i++) {
|
|
cutAnim[i].frame = objAnim[i].unpackFrame;
|
|
cutAnim[i].speed = objAnim[i].speed;
|
|
frameIndex[objAnim[i].unpackFrame] = 1;
|
|
}
|
|
|
|
cutAnim[frameCount].frame = 0;
|
|
cutAnim[frameCount].speed = 0;
|
|
|
|
int nextFrameIndex = 1;
|
|
|
|
for (i = 1; i < 256; i++)
|
|
if (frameIndex[i])
|
|
frameIndex[i] = nextFrameIndex++;
|
|
|
|
for (i = 0; i < frameCount; i++) {
|
|
cutAnim[i].frame = currentImage + frameIndex[objAnim[i].unpackFrame];
|
|
}
|
|
|
|
for (i = 1; i < 256; i++) {
|
|
if (frameIndex[i]) {
|
|
currentImage++;
|
|
_vm->bankMan()->unpack(i, currentImage, objAnim[0].bank);
|
|
}
|
|
}
|
|
|
|
_vm->graphics()->setBobCutawayAnim(objAnim[0].object, objAnim[0].flip, cutAnim, frameCount + 1);
|
|
return currentImage;
|
|
}
|
|
|
|
void Cutaway::handleText(
|
|
int index,
|
|
ObjectType type,
|
|
CutawayObject &object,
|
|
const char *sentence) {
|
|
// lines 1776-1863 in cutaway.c
|
|
|
|
//debug(6, "----- Write '%s' ----", sentence);
|
|
|
|
int spaces = countSpaces(type, sentence);
|
|
|
|
int x;
|
|
int flags;
|
|
|
|
if (OBJECT_TYPE_TEXT_DISPLAY == type) {
|
|
x = _vm->display()->textCenterX(sentence);
|
|
flags = 2;
|
|
}
|
|
else {
|
|
x = object.bobStartX;
|
|
flags = 1;
|
|
}
|
|
|
|
BobSlot *bob =
|
|
_vm->graphics()->bob( _vm->logic()->findBob(ABS(object.objectNumber)) );
|
|
|
|
_vm->graphics()->setBobText(bob, sentence, x, object.bobStartY, object.specialMove, flags);
|
|
|
|
if (OBJECT_TYPE_TEXT_SPEAK == type || OBJECT_TYPE_TEXT_DISPLAY_AND_SPEAK == type) {
|
|
if (_vm->sound()->speechOn()) {
|
|
char voiceFileName[MAX_STRING_SIZE];
|
|
findCdCut(_basename, index, voiceFileName);
|
|
strcat(voiceFileName, "1");
|
|
_vm->sound()->playSfx(voiceFileName, true);
|
|
}
|
|
|
|
if (OBJECT_TYPE_TEXT_SPEAK == type && _vm->sound()->speechOn() && !_vm->subtitles())
|
|
_vm->display()->clearTexts(0, 150);
|
|
}
|
|
|
|
int i;
|
|
for (i = 0; i < spaces; i++) {
|
|
_vm->update();
|
|
|
|
if (OBJECT_TYPE_TEXT_SPEAK == type || OBJECT_TYPE_TEXT_DISPLAY_AND_SPEAK == type) {
|
|
// XXX: see if speaking is finished
|
|
}
|
|
|
|
if (_vm->input()->cutawayQuit())
|
|
return;
|
|
|
|
if (_vm->input()->keyVerb() == VERB_SKIP_TEXT) {
|
|
_vm->input()->clearKeyVerb();
|
|
break;
|
|
}
|
|
}
|
|
|
|
_vm->display()->clearTexts(0,198);
|
|
_vm->update();
|
|
}
|
|
|
|
int Cutaway::countSpaces(ObjectType type, const char *segment) {
|
|
int tmp = 0;
|
|
|
|
while (*segment++)
|
|
tmp++;
|
|
|
|
if (tmp < 50)
|
|
tmp = 50;
|
|
|
|
if (OBJECT_TYPE_TEXT_DISPLAY == type)
|
|
tmp *= 3;
|
|
|
|
return (tmp * 2) / (_vm->talkSpeed() / 3);
|
|
|
|
}
|
|
|
|
int Cutaway::scale(CutawayObject &object) {
|
|
int scaling = 100;
|
|
|
|
if (object.scale > 0)
|
|
scaling = object.scale;
|
|
else if (!object.objectNumber) {
|
|
// Only scale Joe
|
|
int x, y;
|
|
|
|
if (object.bobStartX > 0 || object.bobStartY > 0) {
|
|
x = object.bobStartX;
|
|
y = object.bobStartY;
|
|
}
|
|
else {
|
|
BobSlot *bob = _vm->graphics()->bob(0);
|
|
x = bob->x;
|
|
y = bob->y;
|
|
}
|
|
|
|
int zone = _vm->grid()->findAreaForPos(GS_ROOM, x, y);
|
|
if (zone > 0) {
|
|
Area *area = _vm->grid()->area(_vm->logic()->currentRoom(), zone);
|
|
scaling = area->calcScale(y);
|
|
}
|
|
}
|
|
|
|
return scaling;
|
|
}
|
|
|
|
} // End of namespace Queen
|