Initial commit
This commit is contained in:
1
engines/queen/POTFILES
Normal file
1
engines/queen/POTFILES
Normal file
@@ -0,0 +1 @@
|
||||
engines/queen/metaengine.cpp
|
||||
243
engines/queen/bankman.cpp
Normal file
243
engines/queen/bankman.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
/* 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 "queen/bankman.h"
|
||||
#include "queen/resource.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
BankManager::BankManager(Resource *res)
|
||||
: _res(res) {
|
||||
memset(_frames, 0, sizeof(_frames));
|
||||
memset(_banks, 0, sizeof(_banks));
|
||||
}
|
||||
|
||||
BankManager::~BankManager() {
|
||||
for (uint32 i = 0; i < MAX_BANKS_NUMBER; ++i) {
|
||||
close(i);
|
||||
}
|
||||
eraseFrames(true);
|
||||
}
|
||||
|
||||
void BankManager::load(const char *bankname, uint32 bankslot) {
|
||||
debug(9, "BankManager::load(%s, %d)", bankname, bankslot);
|
||||
|
||||
assert(bankslot < MAX_BANKS_NUMBER);
|
||||
PackedBank *bank = &_banks[bankslot];
|
||||
|
||||
if (!scumm_stricmp(bankname, bank->name)) {
|
||||
debug(9, "BankManager::load() bank '%s' already loaded", bankname);
|
||||
return;
|
||||
}
|
||||
|
||||
close(bankslot);
|
||||
|
||||
if (_res->getPlatform() == Common::kPlatformAmiga && !_res->fileExists(bankname)) {
|
||||
debug(9, "BankManager::load() bank '%s' doesn't exist", bankname);
|
||||
return;
|
||||
}
|
||||
|
||||
bank->data = _res->loadFile(bankname);
|
||||
|
||||
if (_res->getPlatform() == Common::kPlatformAmiga) {
|
||||
uint16 entries = READ_BE_UINT16(bank->data + 4);
|
||||
debug(9, "BankManager::load() entries = %d", entries);
|
||||
assert(entries < MAX_BANK_SIZE);
|
||||
uint32 offset = 6;
|
||||
_banks[bankslot].indexes[0] = offset;
|
||||
for (uint16 i = 1; i <= entries; ++i) {
|
||||
_banks[bankslot].indexes[i] = offset;
|
||||
uint16 dataSize = READ_BE_UINT16(bank->data + offset + 10);
|
||||
offset += dataSize + 12;
|
||||
}
|
||||
} else {
|
||||
uint16 entries = READ_LE_UINT16(bank->data);
|
||||
debug(9, "BankManager::load() entries = %d", entries);
|
||||
assert(entries < MAX_BANK_SIZE);
|
||||
uint32 offset = 2;
|
||||
_banks[bankslot].indexes[0] = offset;
|
||||
for (uint16 i = 1; i <= entries; ++i) {
|
||||
_banks[bankslot].indexes[i] = offset;
|
||||
uint16 w = READ_LE_UINT16(bank->data + offset + 0);
|
||||
uint16 h = READ_LE_UINT16(bank->data + offset + 2);
|
||||
offset += w * h + 8;
|
||||
}
|
||||
}
|
||||
|
||||
// mark this bank as loaded
|
||||
Common::strcpy_s(bank->name, bankname);
|
||||
}
|
||||
|
||||
static void convertPlanarBitmap(uint8 *dst, int dstPitch, const uint8 *src, int w, int h, int plane) {
|
||||
assert(w != 0 && h != 0);
|
||||
int planarSize = plane * h * w * 2;
|
||||
uint8 *planarBuf = new uint8[ planarSize ];
|
||||
uint8 *dstPlanar = planarBuf;
|
||||
while (planarSize > 0) {
|
||||
if (src[0] == 0) {
|
||||
int count = src[1];
|
||||
memset(dstPlanar, 0, count);
|
||||
dstPlanar += count;
|
||||
src += 2;
|
||||
planarSize -= count;
|
||||
} else {
|
||||
*dstPlanar++ = *src++;
|
||||
--planarSize;
|
||||
}
|
||||
}
|
||||
|
||||
src = planarBuf;
|
||||
int i = 0;
|
||||
int planeSize = h * w * 2;
|
||||
while (h--) {
|
||||
for (int x = 0; x < w * 2; ++x) {
|
||||
for (int b = 0; b < 8; ++b) {
|
||||
const uint8 mask = (1 << (7 - b));
|
||||
uint8 color = 0;
|
||||
for (int p = 0; p < plane; ++p) {
|
||||
if (src[planeSize * p + i] & mask) {
|
||||
color |= (1 << p);
|
||||
}
|
||||
}
|
||||
dst[8 * x + b] = color;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
dst += dstPitch;
|
||||
}
|
||||
|
||||
delete[] planarBuf;
|
||||
}
|
||||
|
||||
void BankManager::unpack(uint32 srcframe, uint32 dstframe, uint32 bankslot) {
|
||||
debug(9, "BankManager::unpack(%d, %d, %d)", srcframe, dstframe, bankslot);
|
||||
|
||||
assert(bankslot < MAX_BANKS_NUMBER);
|
||||
PackedBank *bank = &_banks[bankslot];
|
||||
assert(bank->data != nullptr);
|
||||
|
||||
assert(dstframe < MAX_FRAMES_NUMBER);
|
||||
BobFrame *bf = &_frames[dstframe];
|
||||
delete[] bf->data;
|
||||
bf->data = nullptr;
|
||||
|
||||
const uint8 *p = bank->data + bank->indexes[srcframe];
|
||||
|
||||
if (_res->getPlatform() == Common::kPlatformAmiga) {
|
||||
uint16 w = READ_BE_UINT16(p + 0);
|
||||
uint16 h = READ_BE_UINT16(p + 2);
|
||||
uint16 plane = READ_BE_UINT16(p + 4);
|
||||
bf->xhotspot = READ_BE_UINT16(p + 6);
|
||||
bf->yhotspot = READ_BE_UINT16(p + 8);
|
||||
bf->width = w * 16;
|
||||
bf->height = h;
|
||||
|
||||
uint32 size = bf->width * bf->height;
|
||||
if (size != 0) {
|
||||
bf->data = new uint8[ size ];
|
||||
convertPlanarBitmap(bf->data, bf->width, p + 12, w, h, plane);
|
||||
}
|
||||
} else {
|
||||
bf->width = READ_LE_UINT16(p + 0);
|
||||
bf->height = READ_LE_UINT16(p + 2);
|
||||
bf->xhotspot = READ_LE_UINT16(p + 4);
|
||||
bf->yhotspot = READ_LE_UINT16(p + 6);
|
||||
|
||||
uint32 size = bf->width * bf->height;
|
||||
if (size != 0) {
|
||||
bf->data = new uint8[ size ];
|
||||
memcpy(bf->data, p + 8, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BankManager::overpack(uint32 srcframe, uint32 dstframe, uint32 bankslot) {
|
||||
debug(9, "BankManager::overpack(%d, %d, %d)", srcframe, dstframe, bankslot);
|
||||
|
||||
assert(bankslot < MAX_BANKS_NUMBER);
|
||||
PackedBank *bank = &_banks[bankslot];
|
||||
assert(bank->data != nullptr);
|
||||
|
||||
assert(dstframe < MAX_FRAMES_NUMBER);
|
||||
BobFrame *bf = &_frames[dstframe];
|
||||
|
||||
const uint8 *p = bank->data + bank->indexes[srcframe];
|
||||
|
||||
if (_res->getPlatform() == Common::kPlatformAmiga) {
|
||||
uint16 w = READ_BE_UINT16(p + 0);
|
||||
uint16 h = READ_BE_UINT16(p + 2);
|
||||
uint16 plane = READ_BE_UINT16(p + 4);
|
||||
uint16 src_w = w * 16;
|
||||
uint16 src_h = h;
|
||||
|
||||
if (bf->width < src_w || bf->height < src_h) {
|
||||
unpack(srcframe, dstframe, bankslot);
|
||||
} else {
|
||||
convertPlanarBitmap(bf->data, bf->width, p + 12, w, h, plane);
|
||||
}
|
||||
} else {
|
||||
uint16 src_w = READ_LE_UINT16(p + 0);
|
||||
uint16 src_h = READ_LE_UINT16(p + 2);
|
||||
|
||||
// unpack if destination frame is smaller than source
|
||||
if (bf->width < src_w || bf->height < src_h) {
|
||||
unpack(srcframe, dstframe, bankslot);
|
||||
} else {
|
||||
// copy data 'over' destination frame (without updating frame header)
|
||||
memcpy(bf->data, p + 8, src_w * src_h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BankManager::close(uint32 bankslot) {
|
||||
debug(9, "BankManager::close(%d)", bankslot);
|
||||
assert(bankslot < MAX_BANKS_NUMBER);
|
||||
PackedBank *bank = &_banks[bankslot];
|
||||
delete[] bank->data;
|
||||
memset(bank, 0, sizeof(PackedBank));
|
||||
}
|
||||
|
||||
BobFrame *BankManager::fetchFrame(uint32 index) {
|
||||
debug(9, "BankManager::fetchFrame(%d)", index);
|
||||
assert(index < MAX_FRAMES_NUMBER);
|
||||
BobFrame *bf = &_frames[index];
|
||||
assert((bf->width == 0 && bf->height == 0) || bf->data != nullptr);
|
||||
return bf;
|
||||
}
|
||||
|
||||
void BankManager::eraseFrame(uint32 index) {
|
||||
debug(9, "BankManager::eraseFrame(%d)", index);
|
||||
assert(index < MAX_FRAMES_NUMBER);
|
||||
BobFrame *bf = &_frames[index];
|
||||
delete[] bf->data;
|
||||
memset(bf, 0, sizeof(BobFrame));
|
||||
}
|
||||
|
||||
void BankManager::eraseFrames(bool joe) {
|
||||
for (uint32 i = joe ? 0 : FRAMES_JOE; i < MAX_FRAMES_NUMBER; ++i) {
|
||||
eraseFrame(i);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Queen
|
||||
84
engines/queen/bankman.h
Normal file
84
engines/queen/bankman.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_BANKMAN_H
|
||||
#define QUEEN_BANKMAN_H
|
||||
|
||||
#include "common/util.h"
|
||||
#include "queen/structs.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
class Resource;
|
||||
|
||||
class BankManager {
|
||||
public:
|
||||
|
||||
BankManager(Resource *res);
|
||||
~BankManager();
|
||||
|
||||
//! load a bank into the specified slot
|
||||
void load(const char *bankname, uint32 bankslot);
|
||||
|
||||
//! unpack a frame from a loaded bank
|
||||
void unpack(uint32 srcframe, uint32 dstframe, uint32 bankslot);
|
||||
|
||||
//! unpack a frame over an existing one from a loaded bank
|
||||
void overpack(uint32 srcframe, uint32 dstframe, uint32 bankslot);
|
||||
|
||||
//! close a bank
|
||||
void close(uint32 bankslot);
|
||||
|
||||
//! get a reference to unpacked frame
|
||||
BobFrame *fetchFrame(uint32 index);
|
||||
|
||||
//! erase a frame
|
||||
void eraseFrame(uint32 index);
|
||||
|
||||
//! erase all unpacked frames
|
||||
void eraseFrames(bool joe);
|
||||
|
||||
enum {
|
||||
MAX_BANK_SIZE = 110,
|
||||
MAX_FRAMES_NUMBER = 256,
|
||||
MAX_BANKS_NUMBER = 18
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
struct PackedBank {
|
||||
uint32 indexes[MAX_BANK_SIZE];
|
||||
uint8 *data;
|
||||
char name[20];
|
||||
};
|
||||
|
||||
//! unpacked bob frames
|
||||
BobFrame _frames[MAX_FRAMES_NUMBER];
|
||||
|
||||
//! banked bob frames
|
||||
PackedBank _banks[MAX_BANKS_NUMBER];
|
||||
|
||||
Resource *_res;
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
1326
engines/queen/command.cpp
Normal file
1326
engines/queen/command.cpp
Normal file
File diff suppressed because it is too large
Load Diff
235
engines/queen/command.h
Normal file
235
engines/queen/command.h
Normal file
@@ -0,0 +1,235 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_COMMAND_H
|
||||
#define QUEEN_COMMAND_H
|
||||
|
||||
#include "common/util.h"
|
||||
#include "queen/structs.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
class QueenEngine;
|
||||
|
||||
class CmdText {
|
||||
public:
|
||||
|
||||
static CmdText *makeCmdTextInstance(uint8 y, QueenEngine *vm);
|
||||
|
||||
CmdText(uint8 y, QueenEngine *vm);
|
||||
virtual ~CmdText() {}
|
||||
|
||||
//! reset the command sentence
|
||||
void clear();
|
||||
|
||||
//! display the command sentence using the specified color
|
||||
void display(InkColor color, const char *command = 0, bool outlined = false);
|
||||
|
||||
//! display a temporary command sentence using the specified parameters
|
||||
void displayTemp(InkColor color, Verb v);
|
||||
|
||||
//! display a temporary command sentence using the specified parameters
|
||||
virtual void displayTemp(InkColor color, const char *name, bool outlined);
|
||||
|
||||
//! set the verb for the command sentence
|
||||
void setVerb(Verb v);
|
||||
|
||||
//! set the link word (between verb and object) for the command sentence
|
||||
virtual void addLinkWord(Verb v);
|
||||
|
||||
//! add an object name to the command sentence
|
||||
virtual void addObject(const char *objName);
|
||||
|
||||
//! returns true if the command sentence is empty
|
||||
bool isEmpty() const { return _command[0] == 0; }
|
||||
|
||||
enum {
|
||||
MAX_COMMAND_LEN = 256,
|
||||
COMMAND_Y_POS = 151
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
//! buffer containing the current command sentence
|
||||
char _command[MAX_COMMAND_LEN];
|
||||
|
||||
uint8 _y;
|
||||
|
||||
QueenEngine *_vm;
|
||||
};
|
||||
|
||||
struct CmdState {
|
||||
|
||||
void init();
|
||||
|
||||
Verb oldVerb, verb;
|
||||
Verb action;
|
||||
int16 oldNoun, noun;
|
||||
int commandLevel;
|
||||
int16 subject[2];
|
||||
|
||||
Verb selAction;
|
||||
int16 selNoun;
|
||||
};
|
||||
|
||||
class Command {
|
||||
public:
|
||||
|
||||
Command(QueenEngine *vm);
|
||||
~Command();
|
||||
|
||||
//! initialize command construction
|
||||
void clear(bool clearTexts);
|
||||
|
||||
//! execute last constructed command
|
||||
void executeCurrentAction();
|
||||
|
||||
//! get player input and construct command from it
|
||||
void updatePlayer();
|
||||
|
||||
//! read all command arrays from stream
|
||||
void readCommandsFrom(byte *&ptr);
|
||||
|
||||
enum {
|
||||
MAX_MATCHING_CMDS = 50
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
//! get a reference to the ObjectData for the specified room object
|
||||
ObjectData *findObjectData(uint16 objRoomNum) const;
|
||||
|
||||
//! get a reference to the ItemData for the specified inventory object
|
||||
ItemData *findItemData(Verb invNum) const;
|
||||
|
||||
//! execute the current command
|
||||
int16 executeCommand(uint16 comId, int16 condResult);
|
||||
|
||||
//! move Joe to the specified position, handling new room switching
|
||||
int16 makeJoeWalkTo(int16 x, int16 y, int16 objNum, Verb v, bool mustWalk);
|
||||
|
||||
//! update command state with current selected action
|
||||
void grabCurrentSelection();
|
||||
|
||||
//! update command state with current selected object
|
||||
void grabSelectedObject(int16 objNum, uint16 objState, uint16 objName);
|
||||
|
||||
//! update command state with current selected inventory object
|
||||
void grabSelectedItem();
|
||||
|
||||
//! update command state with current selected room object
|
||||
void grabSelectedNoun();
|
||||
|
||||
//! update command state with current selected verb
|
||||
void grabSelectedVerb();
|
||||
|
||||
//! if the description is a cutaway file, execute it
|
||||
bool executeIfCutaway(const char *description);
|
||||
|
||||
//! if the description is a dialog file, execute it
|
||||
bool executeIfDialog(const char *description);
|
||||
|
||||
//! handle a wrong/invalid user action
|
||||
bool handleWrongAction();
|
||||
|
||||
//! make Joe speak something for a wrong/invalid action
|
||||
void sayInvalidAction(Verb action, int16 subj1, int16 subj2);
|
||||
|
||||
//! update an object state
|
||||
void changeObjectState(Verb action, int16 obj, int16 song, bool cutDone);
|
||||
|
||||
//! reset current action
|
||||
void cleanupCurrentAction();
|
||||
|
||||
//! OPEN_CLOSE_OTHER(OBJECT_DATA[S][4])
|
||||
void openOrCloseAssociatedObject(Verb action, int16 obj);
|
||||
|
||||
//! update gamestates - P1_SET_CONDITIONS
|
||||
int16 setConditions(uint16 command, bool lastCmd);
|
||||
|
||||
//! turn on/off areas - P2_SET_AREAS
|
||||
void setAreas(uint16 command);
|
||||
|
||||
//! hide/show objects, redisplay if in the same room as Joe - P3_SET_OBJECTS
|
||||
void setObjects(uint16 command);
|
||||
|
||||
//! inserts/deletes items (inventory) - P4_SET_ITEMS
|
||||
void setItems(uint16 command);
|
||||
|
||||
//! update description for object and returns description number to use
|
||||
uint16 nextObjectDescription(ObjectDescription *objDesc, uint16 firstDesc);
|
||||
|
||||
//! speak description of selected object
|
||||
void lookAtSelectedObject();
|
||||
|
||||
//! get the current object under the cursor
|
||||
void lookForCurrentObject(int16 cx, int16 cy);
|
||||
|
||||
//! get the current icon panel under the cursor (inventory item or verb)
|
||||
void lookForCurrentIcon(int16 cx, int16 cy);
|
||||
|
||||
//! returns true if the verb is an action verb
|
||||
bool isVerbAction(Verb v) const { return (v >= VERB_PANEL_COMMAND_FIRST && v <= VERB_PANEL_COMMAND_LAST) || (v == VERB_WALK_TO); }
|
||||
|
||||
//! return true if the verb is an inventory item
|
||||
bool isVerbInv(Verb v) const { return v >= VERB_INV_FIRST && v <= VERB_INV_LAST; }
|
||||
|
||||
//! returns true if the specified verb is an inventory scroll
|
||||
bool isVerbInvScroll(Verb v) const { return v == VERB_SCROLL_UP || v == VERB_SCROLL_DOWN; }
|
||||
|
||||
//! commands list for each possible action
|
||||
CmdListData *_cmdList;
|
||||
uint16 _numCmdList;
|
||||
|
||||
//! commands list for areas
|
||||
CmdArea *_cmdArea;
|
||||
uint16 _numCmdArea;
|
||||
|
||||
//! commands list for objects
|
||||
CmdObject *_cmdObject;
|
||||
uint16 _numCmdObject;
|
||||
|
||||
//! commands list for inventory
|
||||
CmdInventory *_cmdInventory;
|
||||
uint16 _numCmdInventory;
|
||||
|
||||
//! commands list for gamestate
|
||||
CmdGameState *_cmdGameState;
|
||||
uint16 _numCmdGameState;
|
||||
|
||||
//! textual form of the command (displayed between room and panel areas)
|
||||
CmdText *_cmdText;
|
||||
|
||||
//! flag indicating that the current command is fully constructed
|
||||
bool _parse;
|
||||
|
||||
//! state of current constructed command
|
||||
CmdState _state;
|
||||
|
||||
//! last user selection
|
||||
int _mouseKey, _selPosX, _selPosY;
|
||||
|
||||
QueenEngine *_vm;
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
3
engines/queen/configure.engine
Normal file
3
engines/queen/configure.engine
Normal file
@@ -0,0 +1,3 @@
|
||||
# This file is included from the main "configure" script
|
||||
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
|
||||
add_engine queen "Flight of the Amazon Queen" yes "" "" "" "midi"
|
||||
146
engines/queen/credits.cpp
Normal file
146
engines/queen/credits.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
/* 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 "queen/credits.h"
|
||||
|
||||
#include "queen/display.h"
|
||||
#include "queen/queen.h"
|
||||
#include "queen/resource.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
Credits::Credits(QueenEngine *vm, const char* filename) :
|
||||
_vm(vm), _running(true), _count(0), _pause(0), _justify(0), _fontSize(0), _color(0), _zone(0), _lineNum(0) {
|
||||
_vm->resource()->loadTextFile(filename, _credits);
|
||||
}
|
||||
|
||||
void Credits::nextRoom() {
|
||||
if (-1 == _pause) {
|
||||
_pause = 0;
|
||||
_vm->display()->clearTexts(0, 199);
|
||||
}
|
||||
}
|
||||
|
||||
void Credits::update() {
|
||||
if (!_running)
|
||||
return;
|
||||
|
||||
if (_pause > 0) {
|
||||
_pause--;
|
||||
if (!_pause)
|
||||
_vm->display()->clearTexts(0, 199);
|
||||
return;
|
||||
}
|
||||
|
||||
/* wait until next room */
|
||||
if (-1 == _pause)
|
||||
return;
|
||||
|
||||
while (_lineNum < _credits.size()) {
|
||||
const char *line = _credits[_lineNum].c_str();
|
||||
++_lineNum;
|
||||
|
||||
if (0 == memcmp(line, "EN", 2)) {
|
||||
_running = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if ('.' == line[0]) {
|
||||
int i;
|
||||
|
||||
switch (tolower(line[1])) {
|
||||
case 'l' :
|
||||
_justify = 0;
|
||||
break;
|
||||
case 'c' :
|
||||
_justify = 1;
|
||||
break;
|
||||
case 'r' :
|
||||
_justify = 2;
|
||||
break;
|
||||
case 's' :
|
||||
_fontSize = 0;
|
||||
break;
|
||||
case 'b' :
|
||||
_fontSize = 1;
|
||||
break;
|
||||
case 'p' :
|
||||
_pause = atoi(&line[3]);
|
||||
_pause *= 10;
|
||||
/* wait until next room */
|
||||
if (0 == _pause)
|
||||
_pause = -1;
|
||||
for (i = 0; i < _count; i++) {
|
||||
_vm->display()->textCurrentColor(_list[i].color);
|
||||
_vm->display()->setText(_list[i].x, _list[i].y, _list[i].text);
|
||||
}
|
||||
_count = 0;
|
||||
return;
|
||||
case 'i' :
|
||||
_color = atoi(&line[3]);
|
||||
if (_vm->resource()->getPlatform() == Common::kPlatformAmiga) {
|
||||
_color &= 31;
|
||||
}
|
||||
break;
|
||||
case '1' :
|
||||
case '2' :
|
||||
case '3' :
|
||||
case '4' :
|
||||
case '5' :
|
||||
case '6' :
|
||||
case '7' :
|
||||
case '8' :
|
||||
case '9' :
|
||||
_zone = line[1] - '1';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
assert(_count < ARRAYSIZE(_list));
|
||||
_list[_count].text = line;
|
||||
_list[_count].color = _color;
|
||||
_list[_count].fontSize = _fontSize;
|
||||
switch (_justify) {
|
||||
case 0:
|
||||
_list[_count].x = (_zone % 3) * (320 / 3) + 8;
|
||||
break;
|
||||
case 1:
|
||||
_list[_count].x = (_zone % 3) * (320 / 3) + 54 - _vm->display()->textWidth(line) / 2;
|
||||
if (_list[_count].x < 8)
|
||||
_list[_count].x = 8;
|
||||
break;
|
||||
case 2:
|
||||
_list[_count].x = (_zone % 3) * (320 / 3) + 100 - _vm->display()->textWidth(line);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_list[_count].y = (_zone / 3) * (200 / 3) + (_count * 10);
|
||||
_count++;
|
||||
}
|
||||
}
|
||||
_running = false;
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace Queen
|
||||
88
engines/queen/credits.h
Normal file
88
engines/queen/credits.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_CREDITS_H
|
||||
#define QUEEN_CREDITS_H
|
||||
|
||||
#include "common/str-array.h"
|
||||
#include "queen/defs.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
class QueenEngine;
|
||||
class LineReader;
|
||||
|
||||
class Credits {
|
||||
public:
|
||||
|
||||
Credits(QueenEngine *vm, const char* filename);
|
||||
|
||||
//! update/display credits for current room
|
||||
void update();
|
||||
|
||||
//! handles room switching
|
||||
void nextRoom();
|
||||
|
||||
//! returns true if the credits are running
|
||||
bool running() const { return _running; }
|
||||
|
||||
private:
|
||||
|
||||
struct Line {
|
||||
short x, y, color, fontSize;
|
||||
const char *text;
|
||||
};
|
||||
|
||||
//! contains the formatted lines of texts to display
|
||||
Line _list[19];
|
||||
|
||||
//! true if end of credits description hasn't been reached
|
||||
bool _running;
|
||||
|
||||
//! number of elements in _list array
|
||||
int _count;
|
||||
|
||||
//! pause counts for next room
|
||||
int _pause;
|
||||
|
||||
//! current text justification mode
|
||||
int _justify;
|
||||
|
||||
//! current font size (unused ?)
|
||||
int _fontSize;
|
||||
|
||||
//! current text color
|
||||
int _color;
|
||||
|
||||
//! current text position
|
||||
int _zone;
|
||||
|
||||
uint _lineNum;
|
||||
|
||||
//! contains the credits description
|
||||
Common::StringArray _credits;
|
||||
|
||||
QueenEngine *_vm;
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
5
engines/queen/credits.pl
Normal file
5
engines/queen/credits.pl
Normal file
@@ -0,0 +1,5 @@
|
||||
begin_section("Queen");
|
||||
add_person("David Eriksson", "twogood", "(retired)");
|
||||
add_person("Gregory Montoir", "cyx", "(retired)");
|
||||
add_person("Joost Peters", "joostp", "");
|
||||
end_section();
|
||||
1325
engines/queen/cutaway.cpp
Normal file
1325
engines/queen/cutaway.cpp
Normal file
File diff suppressed because it is too large
Load Diff
264
engines/queen/cutaway.h
Normal file
264
engines/queen/cutaway.h
Normal file
@@ -0,0 +1,264 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_CUTAWAY_H
|
||||
#define QUEEN_CUTAWAY_H
|
||||
|
||||
#include "common/util.h"
|
||||
#include "queen/structs.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
class QueenEngine;
|
||||
|
||||
class Cutaway {
|
||||
public:
|
||||
|
||||
//! Public interface to run a cutaway from a file
|
||||
static void run(const char *filename, char *nextFilename, QueenEngine *vm);
|
||||
|
||||
//! Collection of constants used by QueenCutaway
|
||||
enum {
|
||||
PREVIOUS_ROOM = 0,
|
||||
CURRENT_ROOM = 0,
|
||||
OBJECT_ROOMFADE = -1,
|
||||
PERSON_JOE = -1,
|
||||
OBJECT_JOE = 0,
|
||||
MAX_PERSON_COUNT = 6,
|
||||
CUTAWAY_BANK = 8,
|
||||
MAX_BANK_NAME_COUNT = 5,
|
||||
MAX_FILENAME_LENGTH = 12,
|
||||
MAX_FILENAME_SIZE = (MAX_FILENAME_LENGTH + 1),
|
||||
MAX_PERSON_FACE_COUNT = 13,
|
||||
MAX_STRING_LENGTH = 255,
|
||||
MAX_STRING_SIZE = (MAX_STRING_LENGTH + 1),
|
||||
LEFT = 1,
|
||||
RIGHT = 2,
|
||||
FRONT = 3,
|
||||
BACK = 4
|
||||
};
|
||||
|
||||
//! Different kinds of cutaway objects
|
||||
enum ObjectType {
|
||||
OBJECT_TYPE_ANIMATION = 0,
|
||||
OBJECT_TYPE_PERSON = 1,
|
||||
OBJECT_TYPE_NO_ANIMATION = 2,
|
||||
OBJECT_TYPE_TEXT_SPEAK = 3,
|
||||
OBJECT_TYPE_TEXT_DISPLAY_AND_SPEAK = 4,
|
||||
OBJECT_TYPE_TEXT_DISPLAY = 5
|
||||
};
|
||||
|
||||
private:
|
||||
//! Data for a cutaway object
|
||||
struct CutawayObject {
|
||||
int16 objectNumber; // 0 = JOE, -1 = MESSAGE
|
||||
int16 moveToX;
|
||||
int16 moveToY;
|
||||
int16 bank; // 0 = PBOB, 13 = Joe Bank, else BANK NAMEstr()
|
||||
int16 animList;
|
||||
int16 execute; // 1 Yes, 0 No
|
||||
int16 limitBobX1;
|
||||
int16 limitBobY1;
|
||||
int16 limitBobX2;
|
||||
int16 limitBobY2;
|
||||
int16 specialMove;
|
||||
int16 animType; // 0 - Packet, 1 - Amal, 2 - Unpack
|
||||
int16 fromObject;
|
||||
int16 bobStartX;
|
||||
int16 bobStartY;
|
||||
int16 room;
|
||||
int16 scale;
|
||||
// Variables derived from the variables above
|
||||
int song;
|
||||
|
||||
//! People to turn on
|
||||
int person[MAX_PERSON_COUNT];
|
||||
|
||||
//! Number of elements used in _person array
|
||||
int personCount;
|
||||
};
|
||||
|
||||
struct CutawayAnim {
|
||||
int16 object;
|
||||
int16 unpackFrame; // Frame to unpack
|
||||
int16 speed;
|
||||
int16 bank;
|
||||
int16 mx;
|
||||
int16 my;
|
||||
int16 cx;
|
||||
int16 cy;
|
||||
int16 scale;
|
||||
int16 currentFrame; // Index to Current Frame
|
||||
int16 originalFrame; // Index to Original Object Frame
|
||||
int16 song;
|
||||
bool flip; // set this if unpackFrame is negative
|
||||
};
|
||||
|
||||
struct ObjectDataBackup {
|
||||
int index;
|
||||
int16 name;
|
||||
int16 image;
|
||||
};
|
||||
|
||||
struct PersonFace {
|
||||
int16 index;
|
||||
int16 image;
|
||||
};
|
||||
|
||||
QueenEngine *_vm;
|
||||
|
||||
//! Raw .cut file data (without 20 byte header)
|
||||
byte *_fileData;
|
||||
|
||||
//! COMPANEL
|
||||
int16 _comPanel;
|
||||
|
||||
//! Game state data inside of _fileDat
|
||||
byte *_gameStatePtr;
|
||||
|
||||
//! Actual cutaway data inside of _fileData
|
||||
byte *_objectData;
|
||||
|
||||
//! Pointer to next sentence string in _fileData
|
||||
uint16 _nextSentenceOff;
|
||||
|
||||
//! ???
|
||||
bool _roomFade;
|
||||
|
||||
//! Number of cutaway objects at _cutawayData
|
||||
int16 _cutawayObjectCount;
|
||||
|
||||
//! This cutaway is followed by another
|
||||
bool _anotherCutaway;
|
||||
|
||||
//! Room before cutaway
|
||||
int _initialRoom;
|
||||
|
||||
//! Temporary room for cutaway
|
||||
int _temporaryRoom;
|
||||
|
||||
//! Room to stay in
|
||||
int _finalRoom;
|
||||
|
||||
//! Bank names
|
||||
char _bankNames[MAX_BANK_NAME_COUNT][MAX_FILENAME_SIZE];
|
||||
|
||||
//! Filename without ".cut"
|
||||
char _basename[MAX_FILENAME_SIZE];
|
||||
|
||||
//! Name of .dog file
|
||||
char _talkFile[MAX_FILENAME_SIZE];
|
||||
|
||||
//! Person to talk to
|
||||
int16 _talkTo;
|
||||
|
||||
//! Used by changeRooms
|
||||
ObjectDataBackup _personData[MAX_PERSON_COUNT];
|
||||
|
||||
//! Number of elements used in _personData array
|
||||
int _personDataCount;
|
||||
|
||||
//! Used by handlePersonRecord()
|
||||
PersonFace _personFace[MAX_PERSON_FACE_COUNT];
|
||||
|
||||
//! Number of entries in _personFace array
|
||||
int _personFaceCount;
|
||||
|
||||
//! Play this song when leaving cutaway
|
||||
int16 _lastSong;
|
||||
|
||||
//! Song played before running comic.cut
|
||||
int16 _songBeforeComic;
|
||||
|
||||
int16 _currentImage;
|
||||
|
||||
Cutaway(const char *filename, QueenEngine *vm);
|
||||
~Cutaway();
|
||||
|
||||
//! Run this cutaway object
|
||||
void run(char *nextFilename);
|
||||
|
||||
//! Load cutaway data from file
|
||||
void load(const char *filename);
|
||||
|
||||
//! Used by load to read string data
|
||||
void loadStrings(uint16 offset);
|
||||
|
||||
//! Get persons
|
||||
const byte *turnOnPeople(const byte *ptr, CutawayObject &object);
|
||||
|
||||
//! Limit the BOB
|
||||
void limitBob(CutawayObject &object);
|
||||
|
||||
//! This cutaway object occurs in another room
|
||||
void changeRooms(CutawayObject &object);
|
||||
|
||||
//! Get the object type for this CutawayObject
|
||||
ObjectType getObjectType(CutawayObject &object);
|
||||
|
||||
//! Perform actions for an animation
|
||||
const byte *handleAnimation(const byte *ptr, CutawayObject &object);
|
||||
|
||||
//! Perform actions for a person record
|
||||
void handlePersonRecord(int index, CutawayObject &object, const char *sentence);
|
||||
|
||||
//! Perform text actions
|
||||
void handleText(int index, ObjectType type, CutawayObject &object, const char *sentence);
|
||||
|
||||
//! Restore Logic::_objectData from _personData
|
||||
void restorePersonData();
|
||||
|
||||
//! Stop the cutaway
|
||||
void stop();
|
||||
|
||||
//! Update game state after cutaway
|
||||
void updateGameState();
|
||||
|
||||
//! Prepare for talk after cutaway
|
||||
void talk(char *nextFilename);
|
||||
|
||||
//! Get CutawayAnim data from ptr and return new ptr
|
||||
const byte *getCutawayAnim(const byte *ptr, int header, CutawayAnim &anim);
|
||||
|
||||
//! Special animation
|
||||
int makeComplexAnimation(int16 currentImage, CutawayAnim *objAnim, int frameCount);
|
||||
|
||||
//! Read a CutawayObject from ptr and return new ptr
|
||||
static const byte *getCutawayObject(const byte *ptr, CutawayObject &object);
|
||||
|
||||
//! Dump a CutawayObject with debug()
|
||||
void dumpCutawayObject(int index, CutawayObject &object);
|
||||
|
||||
//! Used by handleText()
|
||||
int countSpaces(ObjectType type, const char *segment);
|
||||
|
||||
//! Scale Joe
|
||||
int scale(CutawayObject &object);
|
||||
|
||||
//! Dump CutawayAnum data with debug()
|
||||
static void dumpCutawayAnim(CutawayAnim &anim);
|
||||
|
||||
bool inRange(int16 x, int16 l, int16 h) const { return (x <= h && x >= l); }
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
204
engines/queen/debug.cpp
Normal file
204
engines/queen/debug.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/* 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 "common/scummsys.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "queen/debug.h"
|
||||
|
||||
#include "queen/graphics.h"
|
||||
#include "queen/logic.h"
|
||||
#include "queen/queen.h"
|
||||
#include "queen/resource.h"
|
||||
#include "queen/sound.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
Debugger::Debugger(QueenEngine *vm)
|
||||
: _vm(vm), _flags(0) {
|
||||
|
||||
registerCmd("areas", WRAP_METHOD(Debugger, Cmd_Areas));
|
||||
registerCmd("asm", WRAP_METHOD(Debugger, Cmd_Asm));
|
||||
registerCmd("bob", WRAP_METHOD(Debugger, Cmd_Bob));
|
||||
registerCmd("bobs", WRAP_METHOD(Debugger, Cmd_PrintBobs));
|
||||
registerCmd("gs", WRAP_METHOD(Debugger, Cmd_GameState));
|
||||
registerCmd("info", WRAP_METHOD(Debugger, Cmd_Info));
|
||||
registerCmd("items", WRAP_METHOD(Debugger, Cmd_Items));
|
||||
registerCmd("room", WRAP_METHOD(Debugger, Cmd_Room));
|
||||
registerCmd("song", WRAP_METHOD(Debugger, Cmd_Song));
|
||||
}
|
||||
|
||||
void Debugger::preEnter() {
|
||||
GUI::Debugger::preEnter();
|
||||
}
|
||||
|
||||
void Debugger::postEnter() {
|
||||
GUI::Debugger::postEnter();
|
||||
_vm->graphics()->setupMouseCursor();
|
||||
}
|
||||
|
||||
static bool isNumeric(const char *arg) {
|
||||
const char *str = arg;
|
||||
bool retVal = true;
|
||||
while (retVal && (*str != '\0')) {
|
||||
retVal = Common::isDigit(*str++);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_Asm(int argc, const char **argv) {
|
||||
if (argc == 2 && isNumeric(argv[1])) {
|
||||
uint16 sm = atoi(argv[1]);
|
||||
_vm->logic()->executeSpecialMove(sm);
|
||||
return false;
|
||||
} else {
|
||||
debugPrintf("Usage: %s smnum\n", argv[0]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_Areas(int argc, const char **argv) {
|
||||
_flags ^= DF_DRAW_AREAS;
|
||||
debugPrintf("Room areas display %s\n", (_flags & DF_DRAW_AREAS) != 0 ? "on" : "off");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_Bob(int argc, const char **argv) {
|
||||
if (argc >= 3 && isNumeric(argv[1])) {
|
||||
int bobNum = atoi(argv[1]);
|
||||
if (bobNum >= Graphics::MAX_BOBS_NUMBER) {
|
||||
debugPrintf("Bob %d is out of range (range: 0 - %d)\n", bobNum, Graphics::MAX_BOBS_NUMBER);
|
||||
} else {
|
||||
int param = 0;
|
||||
if (argc > 3 && isNumeric(argv[3])) {
|
||||
param = atoi(argv[3]);
|
||||
} else {
|
||||
debugPrintf("Invalid parameter for bob command '%s'\n", argv[2]);
|
||||
}
|
||||
BobSlot *bob = _vm->graphics()->bob(bobNum);
|
||||
if (!strcmp(argv[2], "toggle")) {
|
||||
bob->active = !bob->active;
|
||||
debugPrintf("bob[%d].active = %d\n", bobNum, bob->active);
|
||||
} else if (!strcmp(argv[2], "x")) {
|
||||
bob->x = param;
|
||||
debugPrintf("bob[%d].x = %d\n", bobNum, bob->x);
|
||||
} else if (!strcmp(argv[2], "y")) {
|
||||
bob->y = param;
|
||||
debugPrintf("bob[%d].y = %d\n", bobNum, bob->y);
|
||||
} else if (!strcmp(argv[2], "frame")) {
|
||||
bob->frameNum = param;
|
||||
debugPrintf("bob[%d].frameNum = %d\n", bobNum, bob->frameNum);
|
||||
} else if (!strcmp(argv[2], "speed")) {
|
||||
bob->speed = param;
|
||||
debugPrintf("bob[%d].speed = %d\n", bobNum, bob->speed);
|
||||
} else {
|
||||
debugPrintf("Unknown bob command '%s'\n", argv[2]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debugPrintf("Usage: %s bobnum command parameter\n", argv[0]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_GameState(int argc, const char **argv) {
|
||||
uint16 slot;
|
||||
if ((argc == 2 || argc == 3) && isNumeric(argv[1])) {
|
||||
slot = atoi(argv[1]);
|
||||
debugPrintf("GAMESTATE[%d] ", slot);
|
||||
debugPrintf("%s %d\n", (argc == 2) ? "is" : "was", _vm->logic()->gameState(slot));
|
||||
|
||||
if (argc == 3) {
|
||||
if (isNumeric(argv[1])) {
|
||||
_vm->logic()->gameState(slot, atoi(argv[2]));
|
||||
debugPrintf("now %d\n", _vm->logic()->gameState(slot));
|
||||
} else {
|
||||
debugPrintf("Usage: %s slotnum <value>\n", argv[0]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debugPrintf("Usage: %s slotnum <value>\n", argv[0]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_Info(int argc, const char **argv) {
|
||||
debugPrintf("Version: %s\n", _vm->resource()->getJASVersion());
|
||||
debugPrintf("Audio compression: %d\n", _vm->resource()->getCompression());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_Items(int argc, const char **argv) {
|
||||
int n = _vm->logic()->itemDataCount();
|
||||
ItemData *item = _vm->logic()->itemData(1);
|
||||
while (n--) {
|
||||
item->name = ABS(item->name);
|
||||
++item;
|
||||
}
|
||||
debugPrintf("Enabled all inventory items\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_PrintBobs(int argc, const char**argv) {
|
||||
int i;
|
||||
BobSlot *bob = _vm->graphics()->bob(0);
|
||||
debugPrintf("+------------------------------------+\n");
|
||||
debugPrintf("|# | x| y|f|scl|frm|a|m|spd| ex| ey|\n");
|
||||
debugPrintf("+--+---+---+-+---+---+-+-+---+---+---+\n");
|
||||
for (i = 0; i < Graphics::MAX_BOBS_NUMBER; ++i, ++bob) {
|
||||
if (bob->active) {
|
||||
debugPrintf("|%2d|%3d|%3d|%1d|%3d|%3d|%1d|%1d|%3d|%3d|%3d|\n",
|
||||
i, bob->x, bob->y, bob->xflip, bob->scale, bob->frameNum,
|
||||
bob->animating, bob->moving, bob->speed, bob->endx, bob->endy);
|
||||
}
|
||||
}
|
||||
debugPrintf("+--------------------------------+\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_Room(int argc, const char **argv) {
|
||||
if (argc == 2 && isNumeric(argv[1])) {
|
||||
uint16 roomNum = atoi(argv[1]);
|
||||
_vm->logic()->joePos(0, 0);
|
||||
_vm->logic()->newRoom(roomNum);
|
||||
_vm->logic()->entryObj(_vm->logic()->roomData(roomNum) + 1);
|
||||
return false;
|
||||
} else {
|
||||
debugPrintf("Current room: %d (%s), use '%s <roomnum>' to switch\n",
|
||||
_vm->logic()->currentRoom(),
|
||||
_vm->logic()->roomName(_vm->logic()->currentRoom()),
|
||||
argv[0]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_Song(int argc, const char **argv) {
|
||||
if (argc == 2 && isNumeric(argv[1])) {
|
||||
int16 songNum = atoi(argv[1]);
|
||||
_vm->sound()->playSong(songNum);
|
||||
debugPrintf("Playing song %d\n", songNum);
|
||||
} else {
|
||||
debugPrintf("Usage: %s songnum\n", argv[0]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Queen
|
||||
63
engines/queen/debug.h
Normal file
63
engines/queen/debug.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_DEBUG_H
|
||||
#define QUEEN_DEBUG_H
|
||||
|
||||
#include "gui/debugger.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
class QueenEngine;
|
||||
|
||||
class Debugger : public GUI::Debugger {
|
||||
public:
|
||||
Debugger(QueenEngine *vm);
|
||||
|
||||
int flags() const { return _flags; }
|
||||
|
||||
enum {
|
||||
DF_DRAW_AREAS = 1 << 0
|
||||
};
|
||||
|
||||
private:
|
||||
void preEnter() override;
|
||||
void postEnter() override;
|
||||
|
||||
private:
|
||||
bool Cmd_Areas(int argc, const char **argv);
|
||||
bool Cmd_Asm(int argc, const char **argv);
|
||||
bool Cmd_Bob(int argc, const char **argv);
|
||||
bool Cmd_GameState(int argc, const char **argv);
|
||||
bool Cmd_Info(int argc, const char **argv);
|
||||
bool Cmd_Items(int argc, const char **argv);
|
||||
bool Cmd_PrintBobs(int argc, const char **argv);
|
||||
bool Cmd_Room(int argc, const char **argv);
|
||||
bool Cmd_Song(int argc, const char **argv);
|
||||
|
||||
private:
|
||||
QueenEngine *_vm;
|
||||
int _flags;
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
335
engines/queen/defs.h
Normal file
335
engines/queen/defs.h
Normal file
@@ -0,0 +1,335 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_DEFS_H
|
||||
#define QUEEN_DEFS_H
|
||||
|
||||
namespace Queen {
|
||||
|
||||
#define SAVEGAME_SIZE 24622
|
||||
|
||||
enum GameFeatures {
|
||||
GF_DEMO = 1 << 0, // demo
|
||||
GF_TALKIE = 1 << 1, // equivalent to cdrom version check
|
||||
GF_FLOPPY = 1 << 2, // floppy, ie. non-talkie version
|
||||
GF_INTERVIEW = 1 << 3, // interview demo
|
||||
GF_REBUILT = 1 << 4 // version rebuilt with the 'compression_queen' tool
|
||||
};
|
||||
|
||||
enum {
|
||||
COMPRESSION_NONE = 0,
|
||||
COMPRESSION_MP3 = 1,
|
||||
COMPRESSION_OGG = 2,
|
||||
COMPRESSION_FLAC = 3
|
||||
};
|
||||
|
||||
enum Version {
|
||||
VER_ENG_FLOPPY = 0,
|
||||
VER_ENG_TALKIE = 1,
|
||||
VER_FRE_FLOPPY = 2,
|
||||
VER_FRE_TALKIE = 3,
|
||||
VER_GER_FLOPPY = 4,
|
||||
VER_GER_TALKIE = 5,
|
||||
VER_ITA_FLOPPY = 6,
|
||||
VER_ITA_TALKIE = 7,
|
||||
VER_SPA_TALKIE = 8,
|
||||
VER_HEB_TALKIE = 9,
|
||||
VER_DEMO_PCGAMES = 10,
|
||||
VER_DEMO = 11,
|
||||
VER_INTERVIEW = 12,
|
||||
VER_AMI_ENG_FLOPPY = 13,
|
||||
VER_AMI_DEMO = 14,
|
||||
VER_AMI_INTERVIEW = 15,
|
||||
VER_AMI_GER_FLOPPY = 16,
|
||||
|
||||
VER_COUNT = 17
|
||||
};
|
||||
|
||||
enum {
|
||||
GAME_SCREEN_WIDTH = 320,
|
||||
GAME_SCREEN_HEIGHT = 200,
|
||||
ROOM_ZONE_HEIGHT = 150,
|
||||
PANEL_ZONE_HEIGHT = 50
|
||||
};
|
||||
|
||||
enum {
|
||||
FRAMES_JOE = 38,
|
||||
FRAMES_JOURNAL = 40
|
||||
};
|
||||
|
||||
enum Direction {
|
||||
DIR_LEFT = 1,
|
||||
DIR_RIGHT = 2,
|
||||
DIR_FRONT = 3,
|
||||
DIR_BACK = 4
|
||||
};
|
||||
|
||||
enum InkColor {
|
||||
INK_BG_PANEL = 0,
|
||||
INK_JOURNAL,
|
||||
INK_PINNACLE_ROOM,
|
||||
INK_CMD_SELECT,
|
||||
INK_CMD_NORMAL,
|
||||
INK_TALK_NORMAL,
|
||||
INK_JOE,
|
||||
INK_OUTLINED_TEXT,
|
||||
|
||||
INK_COUNT
|
||||
};
|
||||
|
||||
enum {
|
||||
ITEM_NONE = 0,
|
||||
ITEM_BAT,
|
||||
ITEM_JOURNAL,
|
||||
ITEM_KNIFE,
|
||||
ITEM_COCONUT_HALVES,
|
||||
ITEM_BEEF_JERKY,
|
||||
ITEM_PROPELLER,
|
||||
ITEM_BANANA,
|
||||
ITEM_VINE,
|
||||
ITEM_SLOTH_HAIR,
|
||||
ITEM_COMIC_BOOK,
|
||||
ITEM_FLOWER,
|
||||
ITEM_BEETLE,
|
||||
ITEM_ORCHID,
|
||||
ITEM_DICTIONARY,
|
||||
ITEM_DEATH_MASH,
|
||||
ITEM_PERFUME,
|
||||
ITEM_TYRANNO_HORN,
|
||||
ITEM_LOTION,
|
||||
ITEM_RECORD,
|
||||
ITEM_VACUUM_CLEANER,
|
||||
ITEM_NET,
|
||||
ITEM_ALCOHOL,
|
||||
ITEM_ROCKET_PACK,
|
||||
ITEM_SOME_MONEY,
|
||||
ITEM_CHEESE_BITZ,
|
||||
ITEM_DOG_FOOD,
|
||||
ITEM_CAN_OPENER,
|
||||
ITEM_LETTER,
|
||||
ITEM_SQUEAKY_TOY,
|
||||
ITEM_KEY,
|
||||
ITEM_BOOK,
|
||||
ITEM_PIECE_OF_PAPER,
|
||||
ITEM_ROCKET_PLAN,
|
||||
ITEM_PADLOCK_KEY,
|
||||
ITEM_RIB_CAGE,
|
||||
ITEM_SKULL,
|
||||
ITEM_LEG_BONE,
|
||||
ITEM_BAT2,
|
||||
ITEM_MAKESHIFT_TOCH,
|
||||
ITEM_LIGHTER,
|
||||
ITEM_GREEN_JEWEL,
|
||||
ITEM_PICK,
|
||||
ITEM_STONE_KEY,
|
||||
ITEM_BLUE_JEWEL,
|
||||
ITEM_CRYSTAL_SKULL,
|
||||
ITEM_TREE_SAP,
|
||||
ITEM_DINO_RAY_GUN,
|
||||
ITEM_BRANCHES,
|
||||
ITEM_WIG,
|
||||
ITEM_TOWEL,
|
||||
ITEM_OTHER_SHEET,
|
||||
ITEM_SHEET,
|
||||
ITEM_SHEET_ROPE,
|
||||
ITEM_CROWBAR,
|
||||
ITEM_COMEDY_BREASTS,
|
||||
ITEM_DRESS,
|
||||
ITEM_KEY2,
|
||||
ITEM_CLOTHES,
|
||||
ITEM_HAY,
|
||||
ITEM_OIL,
|
||||
ITEM_CHICKEN,
|
||||
ITEM_LIT_TORCH,
|
||||
ITEM_OPENED_DOG_FOOD,
|
||||
ITEM_SOME_MONEY2,
|
||||
ITEM_SOME_MORE_MONEY,
|
||||
ITEM_PEELED_BANANA,
|
||||
ITEM_STONE_DISC,
|
||||
ITEM_GNARLED_VINE,
|
||||
ITEM_FLINT,
|
||||
ITEM_LIGHTER2,
|
||||
ITEM_REST_OF_BEEF_JERKY,
|
||||
ITEM_LOTS_OF_MONEY,
|
||||
ITEM_HEAPS_OF_MONEY,
|
||||
ITEM_OPEN_BOOK,
|
||||
ITEM_REST_OF_THE_CHEESE_BITZ,
|
||||
ITEM_SCISSORS,
|
||||
ITEM_PENCIL,
|
||||
ITEM_SUPER_WEENIE_SERUM,
|
||||
ITEM_MUMMY_WRAPPINGS,
|
||||
ITEM_COCONUT,
|
||||
ITEM_ID_CARD,
|
||||
ITEM_BIT_OF_STONE,
|
||||
ITEM_CHUNK_OF_ROCK,
|
||||
ITEM_BIG_STICK,
|
||||
ITEM_STICKY_BIT_OF_STONE,
|
||||
ITEM_STICKY_CHUNK_OF_ROCK,
|
||||
ITEM_DEATH_MASK2,
|
||||
ITEM_CHEFS_SURPRISE,
|
||||
ITEM_STICKY_BAT,
|
||||
ITEM_REST_OF_WRAPPINGS,
|
||||
ITEM_BANANA2,
|
||||
ITEM_MUG,
|
||||
ITEM_FILE,
|
||||
ITEM_POCKET_ROCKET_BLUEPRINTS,
|
||||
ITEM_HAND_PUPPET,
|
||||
ITEM_ARM_BONE,
|
||||
ITEM_CROWN,
|
||||
ITEM_COMIC_COUPON,
|
||||
ITEM_TORN_PAGE
|
||||
};
|
||||
|
||||
enum {
|
||||
ROOM_JUNGLE_INSIDE_PLANE = 1,
|
||||
ROOM_JUNGLE_OUTSIDE_PLANE = 2,
|
||||
ROOM_JUNGLE_BRIDGE = 4,
|
||||
ROOM_JUNGLE_GORILLA_1 = 6,
|
||||
ROOM_JUNGLE_PINNACLE = 7,
|
||||
ROOM_JUNGLE_SLOTH = 8,
|
||||
ROOM_JUNGLE_BUD_SKIP = 9,
|
||||
ROOM_JUNGLE_BEETLE = 11,
|
||||
ROOM_JUNGLE_MISSIONARY = 13,
|
||||
ROOM_JUNGLE_GORILLA_2 = 14,
|
||||
|
||||
ROOM_AMAZON_ENTRANCE = 16,
|
||||
ROOM_AMAZON_HIDEOUT = 17,
|
||||
ROOM_AMAZON_THRONE = 18,
|
||||
ROOM_AMAZON_JAIL = 19,
|
||||
|
||||
ROOM_VILLAGE = 20,
|
||||
ROOM_TRADER_BOBS = 21,
|
||||
|
||||
ROOM_FLODA_OUTSIDE = 22,
|
||||
ROOM_FLODA_KITCHEN = 26,
|
||||
ROOM_FLODA_LOCKERROOM = 27,
|
||||
ROOM_FLODA_KLUNK = 30,
|
||||
ROOM_FLODA_HENRY = 32,
|
||||
ROOM_FLODA_OFFICE = 35,
|
||||
ROOM_FLODA_JAIL = 41,
|
||||
ROOM_FLODA_FRONTDESK = 103,
|
||||
|
||||
ROOM_TEMPLE_OUTSIDE = 43,
|
||||
ROOM_TEMPLE_MUMMIES = 46,
|
||||
ROOM_TEMPLE_ZOMBIES = 50,
|
||||
ROOM_TEMPLE_TREE = 51,
|
||||
ROOM_TEMPLE_SNAKE = 53,
|
||||
ROOM_TEMPLE_LIZARD_LASER = 55,
|
||||
ROOM_TEMPLE_MAZE = 58,
|
||||
ROOM_TEMPLE_MAZE_2 = 59,
|
||||
ROOM_TEMPLE_MAZE_3 = 60,
|
||||
ROOM_TEMPLE_MAZE_4 = 61,
|
||||
ROOM_TEMPLE_MAZE_5 = 100,
|
||||
ROOM_TEMPLE_MAZE_6 = 101,
|
||||
|
||||
ROOM_VALLEY_CARCASS = 67,
|
||||
|
||||
ROOM_HOTEL_UPSTAIRS = 70,
|
||||
ROOM_HOTEL_DOWNSTAIRS = 71,
|
||||
ROOM_HOTEL_LOLA = 72,
|
||||
ROOM_HOTEL_LOBBY = 73,
|
||||
|
||||
ROOM_CAR_CHASE = 74,
|
||||
|
||||
ROOM_FINAL_FIGHT = 69,
|
||||
|
||||
ROOM_INTRO_RITA_JOE_HEADS = 116,
|
||||
ROOM_INTRO_EXPLOSION = 123,
|
||||
|
||||
//special
|
||||
SPARKY_OUTSIDE_HOTEL = 77,
|
||||
DEATH_MASK = 79,
|
||||
IBI_LOGO = 82,
|
||||
COMIC_1 = 87,
|
||||
COMIC_2 = 88,
|
||||
COMIC_3 = 89,
|
||||
ROOM_UNUSED_INTRO_1 = 90,
|
||||
ROOM_UNUSED_INTRO_2 = 91,
|
||||
ROOM_UNUSED_INTRO_3 = 92,
|
||||
ROOM_UNUSED_INTRO_4 = 93,
|
||||
ROOM_UNUSED_INTRO_5 = 94,
|
||||
FOTAQ_LOGO = 95,
|
||||
WARNER_LOGO = 126,
|
||||
|
||||
FAYE_HEAD = 37,
|
||||
AZURA_HEAD = 106,
|
||||
FRANK_HEAD = 107,
|
||||
|
||||
ROOM_ENDING_CREDITS = 110,
|
||||
|
||||
ROOM_JOURNAL = 200 // dummy value to keep Display methods happy
|
||||
};
|
||||
|
||||
//! GameState vars
|
||||
enum {
|
||||
VAR_HOTEL_ITEMS_REMOVED = 3,
|
||||
VAR_JOE_DRESSING_MODE = 19,
|
||||
VAR_BYPASS_ZOMBIES = 21,
|
||||
VAR_BYPASS_FLODA_RECEPTIONIST = 35,
|
||||
VAR_GUARDS_TURNED_ON = 85,
|
||||
VAR_HOTEL_ESCAPE_STATE = 93,
|
||||
VAR_INTRO_PLAYED = 117,
|
||||
VAR_AZURA_IN_LOVE = 167
|
||||
};
|
||||
|
||||
enum Verb {
|
||||
VERB_NONE = 0,
|
||||
|
||||
VERB_PANEL_COMMAND_FIRST = 1,
|
||||
VERB_OPEN = 1,
|
||||
VERB_CLOSE = 2,
|
||||
VERB_MOVE = 3,
|
||||
// no verb 4
|
||||
VERB_GIVE = 5,
|
||||
VERB_USE = 6,
|
||||
VERB_PICK_UP = 7,
|
||||
VERB_LOOK_AT = 9,
|
||||
VERB_TALK_TO = 8,
|
||||
VERB_PANEL_COMMAND_LAST = 9,
|
||||
|
||||
VERB_WALK_TO = 10,
|
||||
VERB_SCROLL_UP = 11,
|
||||
VERB_SCROLL_DOWN = 12,
|
||||
|
||||
VERB_DIGIT_FIRST = 13,
|
||||
VERB_DIGIT_1 = 13,
|
||||
VERB_DIGIT_2 = 14,
|
||||
VERB_DIGIT_3 = 15,
|
||||
VERB_DIGIT_4 = 16,
|
||||
VERB_DIGIT_LAST = 16,
|
||||
|
||||
VERB_INV_FIRST = VERB_DIGIT_FIRST,
|
||||
VERB_INV_1 = VERB_DIGIT_1,
|
||||
VERB_INV_2 = VERB_DIGIT_2,
|
||||
VERB_INV_3 = VERB_DIGIT_3,
|
||||
VERB_INV_4 = VERB_DIGIT_4,
|
||||
VERB_INV_LAST = VERB_DIGIT_LAST,
|
||||
|
||||
VERB_USE_JOURNAL = 20,
|
||||
VERB_SKIP_TEXT = 101,
|
||||
|
||||
VERB_PREP_WITH = 11,
|
||||
VERB_PREP_TO = 12
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
543
engines/queen/detection.cpp
Normal file
543
engines/queen/detection.cpp
Normal file
@@ -0,0 +1,543 @@
|
||||
/* 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 "base/plugins.h"
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
#include "queen/defs.h"
|
||||
#include "queen/detection.h"
|
||||
#include "queen/version.h"
|
||||
|
||||
static const PlainGameDescriptor queenGames[] = {
|
||||
{"queen", "Flight of the Amazon Queen"},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
namespace Queen {
|
||||
|
||||
static const QueenGameDescription gameDescriptions[] = {
|
||||
// Amiga Demo - English
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"Demo",
|
||||
AD_ENTRY1s("queen.1", "f7a1a37ac93bf763b1569231237cb4d8", 563335),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOSPEECH)
|
||||
},
|
||||
},
|
||||
|
||||
// Amiga Interview Demo - English
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"Interview",
|
||||
AD_ENTRY1s("queen.1", "f5d42a18d8f5689480413871410663d7", 597032),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOSPEECH)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS Demo - English
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"Demo",
|
||||
AD_ENTRY1s("queen.1", "f39334d8133840aa3bcbd733c12937cf", 3732177),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOSPEECH)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS Demo - English (from Bugreport #6946)
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"Demo Alt",
|
||||
AD_ENTRY1s("queen.1", "2871fc6f8090f37fa1a0c556a1c97460", 3735447),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOSPEECH)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS Interview Demo - English
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"Interview",
|
||||
AD_ENTRY1s("queen.1", "30b3291f37665bf24d9482b183cb2f67", 1915913),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOSPEECH)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS Interview Demo - Russian
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"Interview",
|
||||
AD_ENTRY1s("queen.1c", "246dd55f475c9ea6524c556227fd0383", 1889658),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOSPEECH)
|
||||
},
|
||||
},
|
||||
|
||||
// PCGAMES DOS Demo - English
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"Demo",
|
||||
AD_ENTRY1s("queen.1", "f39334d8133840aa3bcbd733c12937cf", 3724538),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOSPEECH)
|
||||
},
|
||||
},
|
||||
|
||||
// Amiga Floppy - English
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"Floppy",
|
||||
AD_ENTRY1s("queen.1", "9c209c2cbc1730e3138663c4fd29c2e8", 351775),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOSPEECH)
|
||||
},
|
||||
},
|
||||
|
||||
// Amiga Floppy - German. Bugreport #12313
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"Floppy",
|
||||
AD_ENTRY1s("queen.1", "b545c73010236dc022bad51c59120a75", 344575),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformAmiga,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOSPEECH)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS Floppy - English
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"Floppy",
|
||||
AD_ENTRY1s("queen.1", "979a33954634fae674b59711ef423f40", 22677657),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_TAILMD5,
|
||||
GUIO1(GUIO_NOSPEECH)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - English
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1", "b6302bccf70463de3d5faf0f0628f742", 190787021),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS Floppy - French
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"Floppy",
|
||||
AD_ENTRY1s("queen.1", "f5e827645d3c887be3bdf4729d847756", 22157304),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOSPEECH)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS Floppy - Russian (From Bugreport #6946) - Saveliev Translation
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"Floppy",
|
||||
AD_ENTRY1s("queen.1", "6e30974bfab8e5f5180363831d204ba0", 22677657),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_TAILMD5,
|
||||
GUIO1(GUIO_NOSPEECH)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - French
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1", "6fd5486a0db75bae2e023b575c3d6a5d", 186689095),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS Floppy - German
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"Floppy",
|
||||
AD_ENTRY1s("queen.1", "f5e827645d3c887be3bdf4729d847756", 22240013),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOSPEECH)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - German
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1", "551d595be8af890fc4cb8533c9c5f5f1", 217648975),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - Hebrew
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1", "b6302bccf70463de3d5faf0f0628f742", 190705558),
|
||||
Common::HE_ISR,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_ALT_INTRO, GAMEOPTION_ALT_FONT)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS Floppy - Italian
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"Floppy",
|
||||
AD_ENTRY1s("queen.1", "f5e827645d3c887be3bdf4729d847756", 22461366),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOSPEECH)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - Italian
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1", "b6302bccf70463de3d5faf0f0628f742", 190795582),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - Spanish
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1", "b6302bccf70463de3d5faf0f0628f742", 190730602),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - English (Compressed Freeware Release v1.0)
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1c", "a0749bb8b72e537ead1a63a3dde1443d", 54108887),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - English (Compressed Freeware Release v1.1)
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1c", "21fd690b372f8a6289f6f33bc986276c", 51222412),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - French (Compressed Freeware Release v1.0)
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1c", "67e3020f8a35e1df7b1c753b5aaa71e1", 97382620),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - German (Compressed Freeware Release v1.0)
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1c", "28f78dbec7e20f603a10c2f8ea889a5c", 108738717),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - Hebrew (Compressed Freeware Release v1.0)
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1c", "4d52d8780613ef27a2b779caecb20a21", 99391805),
|
||||
Common::HE_ISR,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_ALT_INTRO, GAMEOPTION_ALT_FONT)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - Hebrew
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1c", "a88effce52227a1842636ce753c2e646", 100455438),
|
||||
Common::HE_ISR,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_ALT_INTRO, GAMEOPTION_ALT_FONT)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - Italian (Compressed Freeware Release v1.0)
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1c", "2f72b715ed753cf905a37cdcc7ea611e", 98327801),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - Hungarian (Compressed Freeware Release v1.02)
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1c", "21fd690b372f8a6289f6f33bc986276c", 51329031),
|
||||
Common::HU_HUN,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
// DOS CD - Russian (Compressed Freeware Release v1.0)
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1c", "908d04940d40537d32c50a8429cd8631", 51222412),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
// TODO: Freeware Release for Spanish DOS CD is missing.
|
||||
#if 0
|
||||
// DOS CD - Spanish (Compressed Freeware Release v1.0)
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"CD",
|
||||
AD_ENTRY1s("queen.1c", NULL, ?),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
#endif
|
||||
|
||||
// GoG.com Release - German
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"GOG.com",
|
||||
AD_ENTRY1s("queen.1", "28f78dbec7e20f603a10c2f8ea889a5c", 108738717),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
// GoG.com Release - French
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"GOG.com",
|
||||
AD_ENTRY1s("queen.1", "67e3020f8a35e1df7b1c753b5aaa71e1", 97382620),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
// GoG.com Release - Italian
|
||||
{
|
||||
{
|
||||
"queen",
|
||||
"GOG.com",
|
||||
AD_ENTRY1s("queen.1", "2f72b715ed753cf905a37cdcc7ea611e", 98327801),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_ALT_INTRO)
|
||||
},
|
||||
},
|
||||
|
||||
{ AD_TABLE_END_MARKER }
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
class QueenMetaEngineDetection : public AdvancedMetaEngineDetection<Queen::QueenGameDescription> {
|
||||
public:
|
||||
QueenMetaEngineDetection() : AdvancedMetaEngineDetection(Queen::gameDescriptions, queenGames) {
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "queen";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Flight of the Amazon Queen";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "Flight of the Amazon Queen (C) John Passfield and Steve Stamatiadis";
|
||||
}
|
||||
|
||||
ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra) const override;
|
||||
};
|
||||
|
||||
ADDetectedGame QueenMetaEngineDetection::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra) const {
|
||||
static ADGameDescription desc;
|
||||
|
||||
// Iterate over all files in the given directory
|
||||
for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
|
||||
if (file->isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
if (file->getName().equalsIgnoreCase("queen.1") || file->getName().equalsIgnoreCase("queen.1c")) {
|
||||
Common::File dataFile;
|
||||
if (!dataFile.open(*file)) {
|
||||
continue;
|
||||
}
|
||||
Queen::DetectedGameVersion version;
|
||||
if (Queen::detectVersion(&version, &dataFile)) {
|
||||
desc.gameId = "queen";
|
||||
desc.language = version.language;
|
||||
desc.platform = version.platform;
|
||||
desc.flags = ADGF_NO_FLAGS;
|
||||
desc.guiOptions = GUIO0();
|
||||
if (version.features & Queen::GF_DEMO) {
|
||||
desc.extra = "Demo";
|
||||
desc.flags = ADGF_DEMO;
|
||||
desc.guiOptions = GUIO_NOSPEECH;
|
||||
} else if (version.features & Queen::GF_INTERVIEW) {
|
||||
desc.extra = "Interview";
|
||||
desc.flags = ADGF_DEMO;
|
||||
desc.guiOptions = GUIO_NOSPEECH;
|
||||
} else if (version.features & Queen::GF_FLOPPY) {
|
||||
desc.extra = "Floppy";
|
||||
desc.guiOptions = GUIO_NOSPEECH;
|
||||
} else if (version.features & Queen::GF_TALKIE) {
|
||||
desc.extra = "CD";
|
||||
desc.guiOptions = GAMEOPTION_ALT_INTRO;
|
||||
if (desc.language == Common::HE_ISR)
|
||||
desc.guiOptions = GUIO2(GAMEOPTION_ALT_INTRO, GAMEOPTION_ALT_FONT);
|
||||
}
|
||||
|
||||
return ADDetectedGame(&desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ADDetectedGame();
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_STATIC(QUEEN_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, QueenMetaEngineDetection);
|
||||
38
engines/queen/detection.h
Normal file
38
engines/queen/detection.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_DETECTION_H
|
||||
#define QUEEN_DETECTION_H
|
||||
|
||||
namespace Queen {
|
||||
|
||||
struct QueenGameDescription {
|
||||
AD_GAME_DESCRIPTION_HELPERS(desc);
|
||||
|
||||
ADGameDescription desc;
|
||||
};
|
||||
|
||||
#define GAMEOPTION_ALT_INTRO GUIO_GAMEOPTIONS1
|
||||
#define GAMEOPTION_ALT_FONT GUIO_GAMEOPTIONS2
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif // QUEEN_DETECTION_H
|
||||
1839
engines/queen/display.cpp
Normal file
1839
engines/queen/display.cpp
Normal file
File diff suppressed because it is too large
Load Diff
284
engines/queen/display.h
Normal file
284
engines/queen/display.h
Normal file
@@ -0,0 +1,284 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_DISPLAY_H
|
||||
#define QUEEN_DISPLAY_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/util.h"
|
||||
#include "common/random.h"
|
||||
#include "queen/defs.h"
|
||||
|
||||
class OSystem;
|
||||
|
||||
namespace Common {
|
||||
struct Rect;
|
||||
}
|
||||
|
||||
namespace Queen {
|
||||
|
||||
class QueenEngine;
|
||||
|
||||
class Display {
|
||||
public:
|
||||
|
||||
Display(QueenEngine *vm, OSystem *system);
|
||||
~Display();
|
||||
|
||||
//! initialize dynalum for the specified room
|
||||
void dynalumInit(const char *roomName, uint16 roomNum);
|
||||
|
||||
//! update dynalum for the current room
|
||||
void dynalumUpdate(int16 x, int16 y);
|
||||
|
||||
//! update the palette
|
||||
void palSet(const uint8 *pal, int start, int end, bool updateScreen = false);
|
||||
|
||||
//! setup palette for Joe's dress
|
||||
void palSetJoeDress();
|
||||
|
||||
//! setup palette for Joe's normal clothes
|
||||
void palSetJoeNormal();
|
||||
|
||||
//! setup palette for panel and inventory objects
|
||||
void palSetPanel();
|
||||
|
||||
//! fade the current palette in
|
||||
void palFadeIn(uint16 roomNum, bool dynalum = false, int16 dynaX = 0, int16 dynaY = 0);
|
||||
|
||||
//! fade the current palette out
|
||||
void palFadeOut(uint16 roomNum);
|
||||
|
||||
//! grey the panel area (used when panel is disabled)
|
||||
void palGreyPanel();
|
||||
|
||||
//! scroll some palette colors
|
||||
void palScroll(int start, int end);
|
||||
|
||||
void palSetAmigaColor(uint8 color, uint16 rgb);
|
||||
|
||||
//! custom palette effect for the specified room
|
||||
void palCustomColors(uint16 roomNum);
|
||||
|
||||
//! custom palette scroll for the specified room
|
||||
void palCustomScroll(uint16 roomNum);
|
||||
|
||||
//! process a 'palette flash' effect
|
||||
void palCustomFlash();
|
||||
|
||||
void palCustomLightsOff(uint16 roomNum);
|
||||
void palCustomLightsOn(uint16 roomNum);
|
||||
|
||||
//! mark all palette entries as dirty
|
||||
void palSetAllDirty() { _pal.dirtyMin = 0; _pal.dirtyMax = 255; }
|
||||
|
||||
//! returns the number of colors used by the room
|
||||
int getNumColorsForRoom(uint16 room) const;
|
||||
|
||||
//! returns true if we shouldn't fade the palette in the specified room
|
||||
bool isPalFadingDisabled(uint16 room) const;
|
||||
|
||||
//! change fullscreen/panel mode
|
||||
void screenMode(int comPanel, bool inCutaway);
|
||||
|
||||
void prepareUpdate();
|
||||
void update(bool dynalum = false, int16 dynaX = 0, int16 dynaY = 0);
|
||||
|
||||
void setupPanel();
|
||||
void setupNewRoom(const char *name, uint16 room);
|
||||
|
||||
void drawBobSprite(const uint8 *data, uint16 x, uint16 y, uint16 w, uint16 h, uint16 pitch, bool xflip);
|
||||
void drawBobPasteDown(const uint8 *data, uint16 x, uint16 y, uint16 w, uint16 h);
|
||||
void drawInventoryItem(const uint8 *data, uint16 x, uint16 y, uint16 w, uint16 h);
|
||||
|
||||
void blit(uint8 *dstBuf, uint16 dstPitch, uint16 x, uint16 y, const uint8 *srcBuf, uint16 srcPitch, uint16 w, uint16 h, bool xflip, bool masked);
|
||||
void fill(uint8 *dstBuf, uint16 dstPitch, uint16 x, uint16 y, uint16 w, uint16 h, uint8 color);
|
||||
|
||||
//! decode PCX picture data
|
||||
void decodePCX(const uint8 *src, uint32 srcSize, uint8 *dst, uint16 dstPitch, uint16 *w, uint16 *h, uint8 *pal, uint16 palStart, uint16 palEnd);
|
||||
|
||||
//! decode IFF picture data
|
||||
void decodeIFF(const uint8 *src, uint32 srcSize, uint8 *dst, uint16 dstPitch, uint16 *w, uint16 *h, uint8 *pal, uint16 palStart, uint16 palEnd, uint8 colorBase = 0);
|
||||
|
||||
void horizontalScrollUpdate(int16 xCamera);
|
||||
void horizontalScroll(int16 scroll);
|
||||
int16 horizontalScroll() const { return _horizontalScroll; }
|
||||
|
||||
void fullscreen(bool fs) { _fullRefresh = 2; _fullscreen = fs; }
|
||||
bool fullscreen() const { return _fullscreen; }
|
||||
|
||||
//! mark the specified block as dirty
|
||||
void setDirtyBlock(uint16 x, uint16 y, uint16 w, uint16 h);
|
||||
|
||||
//! force a full refresh (bypassing the dirtyblocks rendering), on next screen update
|
||||
void forceFullRefresh() { _fullRefresh = 2; }
|
||||
|
||||
//! change mouse cursor bitmap
|
||||
void setMouseCursor(uint8 *buf, uint16 w, uint16 h);
|
||||
|
||||
//! show/hide mouse cursor
|
||||
void showMouseCursor(bool show);
|
||||
|
||||
//! initialize font, compute justification sizes
|
||||
void initFont();
|
||||
|
||||
//! add the specified text to the texts list
|
||||
void setText(uint16 x, uint16 y, const char *text, bool outlined = true);
|
||||
|
||||
//! add the specified text to the texts list
|
||||
void setTextCentered(uint16 y, const char *text, bool outlined = true);
|
||||
|
||||
//! draw the text lists
|
||||
void drawTexts();
|
||||
|
||||
//! remove entries from the texts list
|
||||
void clearTexts(uint16 y1, uint16 y2);
|
||||
|
||||
void setupInkColors();
|
||||
|
||||
uint8 getInkColor(InkColor color) const { return _inkColors[color]; }
|
||||
|
||||
//! change the current text color
|
||||
void textCurrentColor(uint8 color) { _curTextColor = color; }
|
||||
|
||||
//! change the text color for the specified texts list entry
|
||||
void textColor(uint16 y, uint8 color) { _texts[y].color = color; }
|
||||
|
||||
//! Set the focus rectangle to the speaking character
|
||||
void setFocusRect(const Common::Rect& rect);
|
||||
|
||||
int textCenterX(const char *text) const;
|
||||
uint16 textWidth(const char *text) const;
|
||||
uint16 textWidth(const char *text, uint16 len) const;
|
||||
void drawChar(uint16 x, uint16 y, uint8 color, const uint8 *chr);
|
||||
void drawText(uint16 x, uint16 y, uint8 color, const char *text, bool outlined = true);
|
||||
void drawBox(int16 x1, int16 y1, int16 x2, int16 y2, uint8 col);
|
||||
|
||||
void shake(bool reset);
|
||||
|
||||
void blankScreen();
|
||||
void blankScreenEffect1();
|
||||
void blankScreenEffect2();
|
||||
void blankScreenEffect3();
|
||||
|
||||
private:
|
||||
|
||||
enum {
|
||||
FADE_SPEED = 16,
|
||||
D_BLOCK_W = 8,
|
||||
D_BLOCK_H = 8
|
||||
};
|
||||
|
||||
enum BufferDimension {
|
||||
BACKDROP_W = 640,
|
||||
BACKDROP_H = 200,
|
||||
SCREEN_W = 320,
|
||||
SCREEN_H = 200,
|
||||
PANEL_W = 320,
|
||||
PANEL_H = 50
|
||||
};
|
||||
|
||||
struct {
|
||||
uint8 *room;
|
||||
uint8 *screen;
|
||||
uint8 *panel;
|
||||
int dirtyMin, dirtyMax;
|
||||
bool scrollable;
|
||||
} _pal;
|
||||
|
||||
struct Dynalum {
|
||||
bool valid;
|
||||
uint8 *mskBuf;
|
||||
uint32 mskSize;
|
||||
int8 *lumBuf;
|
||||
uint32 lumSize;
|
||||
uint8 prevColMask;
|
||||
|
||||
void clear() {
|
||||
valid = false;
|
||||
mskBuf = nullptr;
|
||||
mskSize = 0;
|
||||
lumBuf = nullptr;
|
||||
lumSize = 0;
|
||||
prevColMask = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct TextSlot {
|
||||
uint16 x;
|
||||
uint8 color;
|
||||
Common::String text;
|
||||
bool outlined;
|
||||
|
||||
void clear() {
|
||||
x = 0;
|
||||
color = 0;
|
||||
text = "";
|
||||
outlined = false;
|
||||
}
|
||||
};
|
||||
|
||||
uint8 *_screenBuf;
|
||||
uint8 *_panelBuf;
|
||||
uint8 *_backdropBuf;
|
||||
|
||||
uint8 _fullRefresh;
|
||||
uint8 *_dirtyBlocks;
|
||||
uint16 _dirtyBlocksWidth, _dirtyBlocksHeight;
|
||||
|
||||
bool _fullscreen;
|
||||
|
||||
uint16 _horizontalScroll;
|
||||
uint16 _bdWidth, _bdHeight;
|
||||
|
||||
const char *_imageExt;
|
||||
|
||||
//! texts list
|
||||
TextSlot _texts[GAME_SCREEN_HEIGHT];
|
||||
|
||||
//! current text color to use for display
|
||||
uint8 _curTextColor;
|
||||
|
||||
//! font justification sizes
|
||||
uint8 _charWidth[256];
|
||||
|
||||
uint8 _inkColors[INK_COUNT];
|
||||
|
||||
Common::RandomSource _rnd;
|
||||
Dynalum _dynalum;
|
||||
OSystem *_system;
|
||||
QueenEngine *_vm;
|
||||
|
||||
const uint8 *_font;
|
||||
|
||||
static const uint8 _fontRegular[];
|
||||
static const uint8 _fontHebrew[];
|
||||
static const uint8 _fontHebrewAdvBrew[];
|
||||
static const uint8 _fontRussian[];
|
||||
static const uint8 _fontGreek[];
|
||||
static const uint8 _palJoeClothes[];
|
||||
static const uint8 _palJoeDress[];
|
||||
};
|
||||
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
1629
engines/queen/graphics.cpp
Normal file
1629
engines/queen/graphics.cpp
Normal file
File diff suppressed because it is too large
Load Diff
283
engines/queen/graphics.h
Normal file
283
engines/queen/graphics.h
Normal file
@@ -0,0 +1,283 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_GRAPHICS_H
|
||||
#define QUEEN_GRAPHICS_H
|
||||
|
||||
#include "common/util.h"
|
||||
#include "queen/structs.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
struct BobSlot {
|
||||
bool active;
|
||||
//! current position
|
||||
int16 x, y;
|
||||
//! bounding box
|
||||
Box box;
|
||||
bool xflip;
|
||||
//! shrinking percentage
|
||||
uint16 scale;
|
||||
//! associated BobFrame
|
||||
uint16 frameNum;
|
||||
//! 'direction' for the next frame (-1, 1)
|
||||
int frameDir;
|
||||
|
||||
//! animation stuff
|
||||
bool animating;
|
||||
struct {
|
||||
int16 speed, speedBak;
|
||||
|
||||
//! string based animation
|
||||
struct {
|
||||
const AnimFrame *buffer;
|
||||
const AnimFrame *curPos;
|
||||
} string;
|
||||
|
||||
//! normal moving animation
|
||||
struct {
|
||||
bool rebound;
|
||||
uint16 firstFrame, lastFrame;
|
||||
} normal;
|
||||
|
||||
} anim;
|
||||
|
||||
bool moving;
|
||||
//! moving speed
|
||||
int16 speed;
|
||||
//! move along x axis instead of y
|
||||
bool xmajor;
|
||||
//! moving direction
|
||||
int8 xdir, ydir;
|
||||
//! destination point
|
||||
int16 endx, endy;
|
||||
uint16 dx, dy;
|
||||
uint16 total;
|
||||
|
||||
void curPos(int16 xx, int16 yy);
|
||||
void move(int16 dstx, int16 dsty, int16 spd);
|
||||
void moveOneStep();
|
||||
void animOneStep();
|
||||
|
||||
void animString(const AnimFrame *animBuf);
|
||||
void animNormal(uint16 firstFrame, uint16 lastFrame, uint16 speed, bool rebound, bool xflip);
|
||||
|
||||
void scaleWalkSpeed(uint16 ms);
|
||||
|
||||
void clear();
|
||||
void clear(const Box *defaultBox);
|
||||
};
|
||||
|
||||
class QueenEngine;
|
||||
|
||||
class Graphics {
|
||||
public:
|
||||
|
||||
Graphics(QueenEngine *vm);
|
||||
~Graphics();
|
||||
|
||||
//! unpacks control frames (ie. arrows)
|
||||
void unpackControlBank();
|
||||
|
||||
//! setup dialog arrows
|
||||
void setupArrows();
|
||||
|
||||
//! setup mouse cursor
|
||||
void setupMouseCursor();
|
||||
|
||||
//! draw a bob
|
||||
void drawBob(const BobSlot *bs, const BobFrame *bf, const Box *box, int16 x, int16 y);
|
||||
|
||||
//! draw an inventory item
|
||||
void drawInventoryItem(uint32 frameNum, uint16 x, uint16 y);
|
||||
|
||||
//! draw a bob directly on the backdrop bitmap
|
||||
void pasteBob(uint16 objNum, uint16 image);
|
||||
|
||||
//! resize a bobframe
|
||||
void shrinkFrame(const BobFrame *bf, uint16 percentage);
|
||||
|
||||
//! animate/move bobs and sort them
|
||||
void sortBobs();
|
||||
|
||||
//! draw all the sorted bobs
|
||||
void drawBobs();
|
||||
|
||||
//! clear all setup bobs
|
||||
void clearBobs();
|
||||
|
||||
//! stop all animating/movings bobs
|
||||
void stopBobs();
|
||||
|
||||
//! returns a reference to the specified bob
|
||||
BobSlot *bob(int index);
|
||||
|
||||
void clearBob(int index) { bob(index)->clear(&_defaultBox); }
|
||||
|
||||
//! display a text 'near' the specified bob
|
||||
void setBobText(const BobSlot *bob, const char *text, int textX, int textY, int color, int flags);
|
||||
|
||||
//! handles parallax scrolling for the specified room
|
||||
void handleParallax(uint16 roomNum);
|
||||
|
||||
void setupNewRoom(const char *room, uint16 roomNum, int16 *furniture, uint16 furnitureCount);
|
||||
|
||||
void setBobCutawayAnim(uint16 bobNum, bool xflip, const AnimFrame *af, uint8 frameCount);
|
||||
void fillAnimBuffer(const char *anim, AnimFrame *af);
|
||||
uint16 countAnimFrames(const char *anim);
|
||||
void setupObjectAnim(const GraphicData *gd, uint16 firstImage, uint16 bobNum, bool visible);
|
||||
uint16 setupPersonAnim(const ActorData *ad, const char *anim, uint16 curImage);
|
||||
void resetPersonAnim(uint16 bobNum);
|
||||
void erasePersonAnim(uint16 bobNum);
|
||||
void eraseAllAnims();
|
||||
|
||||
uint16 refreshObject(uint16 obj);
|
||||
|
||||
void setupRoomFurniture(int16 *furniture, uint16 furnitureCount);
|
||||
void setupRoomObjects();
|
||||
|
||||
uint16 setupPerson(uint16 noun, uint16 curImage);
|
||||
uint16 allocPerson(uint16 noun, uint16 curImage);
|
||||
|
||||
uint16 personFrames(uint16 bobNum) const { return _personFrames[bobNum]; }
|
||||
void clearPersonFrames() { memset(_personFrames, 0, sizeof(_personFrames)); }
|
||||
uint16 numFrames() const { return _numFrames; }
|
||||
uint16 numStaticFurniture() const { return _numFurnitureStatic; }
|
||||
uint16 numAnimatedFurniture() const { return _numFurnitureAnimated; }
|
||||
uint16 numFurnitureFrames() const { return _numFurnitureStatic + _numFurnitureAnimatedLen; }
|
||||
|
||||
void putCameraOnBob(int bobNum) { _cameraBob = bobNum; }
|
||||
|
||||
void update(uint16 room);
|
||||
|
||||
enum {
|
||||
ARROW_BOB_UP = 62,
|
||||
ARROW_BOB_DOWN = 63,
|
||||
MAX_BOBS_NUMBER = 64,
|
||||
MAX_STRING_LENGTH = 255,
|
||||
MAX_STRING_SIZE = (MAX_STRING_LENGTH + 1),
|
||||
BOB_SHRINK_BUF_SIZE = 60000
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
|
||||
BobSlot _bobs[MAX_BOBS_NUMBER];
|
||||
|
||||
//! bobs to display
|
||||
BobSlot *_sortedBobs[MAX_BOBS_NUMBER];
|
||||
|
||||
//! number of bobs to display
|
||||
uint16 _sortedBobsCount;
|
||||
|
||||
//! used to scale a BobFrame
|
||||
BobFrame _shrinkBuffer;
|
||||
|
||||
//! in-game objects/persons animations
|
||||
AnimFrame _newAnim[17][30];
|
||||
|
||||
//! cutaway objects/persons animations
|
||||
AnimFrame _cutAnim[21][30];
|
||||
|
||||
uint16 _personFrames[4];
|
||||
|
||||
//! number of animated furniture in current room
|
||||
uint16 _numFurnitureAnimated;
|
||||
|
||||
//! number of static furniture in current room
|
||||
uint16 _numFurnitureStatic;
|
||||
|
||||
//! total number of frames for the animated furniture
|
||||
uint16 _numFurnitureAnimatedLen;
|
||||
|
||||
//! current number of frames unpacked
|
||||
uint16 _numFrames;
|
||||
|
||||
//! bob number followed by camera
|
||||
int _cameraBob;
|
||||
|
||||
QueenEngine *_vm;
|
||||
|
||||
const Box _defaultBox;
|
||||
const Box _gameScreenBox;
|
||||
const Box _fullScreenBox;
|
||||
};
|
||||
|
||||
class BamScene {
|
||||
public:
|
||||
|
||||
BamScene(QueenEngine *vm);
|
||||
|
||||
void playSfx();
|
||||
void prepareAnimation();
|
||||
void updateCarAnimation();
|
||||
void updateFightAnimation();
|
||||
|
||||
void saveState(byte *&ptr);
|
||||
void loadState(uint32 ver, byte *&ptr);
|
||||
|
||||
enum {
|
||||
BOB_OBJ1 = 5,
|
||||
BOB_OBJ2 = 6,
|
||||
BOB_FX = 7
|
||||
};
|
||||
|
||||
enum {
|
||||
F_STOP = 0,
|
||||
F_PLAY = 1,
|
||||
F_REQ_STOP = 2
|
||||
};
|
||||
|
||||
uint16 _flag, _index;
|
||||
|
||||
private:
|
||||
|
||||
struct BamDataObj {
|
||||
int16 x, y;
|
||||
int16 frame;
|
||||
};
|
||||
|
||||
struct BamDataBlock {
|
||||
BamDataObj obj1; // truck / Frank
|
||||
BamDataObj obj2; // Rico / robot
|
||||
BamDataObj fx;
|
||||
int16 sfx;
|
||||
};
|
||||
|
||||
BobSlot *_obj1;
|
||||
BobSlot *_obj2;
|
||||
BobSlot *_objfx;
|
||||
bool _screenShaked;
|
||||
const BamDataBlock *_fightData;
|
||||
uint16 _lastSoundIndex;
|
||||
|
||||
QueenEngine *_vm;
|
||||
|
||||
static const BamDataBlock _carData[];
|
||||
static const BamDataBlock _fight1Data[];
|
||||
static const BamDataBlock _fight2Data[];
|
||||
static const BamDataBlock _fight3Data[];
|
||||
static const BamDataBlock _fight4Data[];
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
271
engines/queen/grid.cpp
Normal file
271
engines/queen/grid.cpp
Normal file
@@ -0,0 +1,271 @@
|
||||
/* 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 "queen/grid.h"
|
||||
|
||||
#include "queen/display.h"
|
||||
#include "queen/logic.h"
|
||||
#include "queen/queen.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
Grid::Grid(QueenEngine *vm)
|
||||
: _vm(vm) {
|
||||
memset(_zones, 0, sizeof(_zones));
|
||||
}
|
||||
|
||||
Grid::~Grid() {
|
||||
delete[] _objMax;
|
||||
delete[] _areaMax;
|
||||
delete[] _area;
|
||||
delete[] _objectBox;
|
||||
}
|
||||
|
||||
void Grid::readDataFrom(uint16 numObjects, uint16 numRooms, byte *&ptr) {
|
||||
uint16 i, j;
|
||||
|
||||
_numRoomAreas = numRooms;
|
||||
|
||||
_objMax = new int16[_numRoomAreas + 1];
|
||||
_areaMax = new int16[_numRoomAreas + 1];
|
||||
_area = new Area[_numRoomAreas + 1][MAX_AREAS_NUMBER];
|
||||
|
||||
_objMax[0] = 0;
|
||||
_areaMax[0] = 0;
|
||||
// _area[0][] cleared by default constructor
|
||||
for (i = 1; i <= _numRoomAreas; i++) {
|
||||
_objMax[i] = (int16)READ_BE_INT16(ptr); ptr += 2;
|
||||
_areaMax[i] = (int16)READ_BE_INT16(ptr); ptr += 2;
|
||||
// _area[i][0] cleared by default constructor
|
||||
for (j = 1; j <= _areaMax[i]; j++) {
|
||||
assert(j < MAX_AREAS_NUMBER);
|
||||
_area[i][j].readFromBE(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
_objectBox = new Box[numObjects + 1];
|
||||
// _objectBox[0] cleared by default constructor
|
||||
for (i = 1; i <= numObjects; i++) {
|
||||
_objectBox[i].readFromBE(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Grid::setZone(GridScreen screen, uint16 zoneNum, uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
|
||||
debug(9, "Grid::setZone(%d, %d, (%d,%d), (%d,%d))", screen, zoneNum, x1, y1, x2, y2);
|
||||
assert(zoneNum < MAX_ZONES_NUMBER);
|
||||
ZoneSlot *pzs = &_zones[screen][zoneNum];
|
||||
pzs->valid = true;
|
||||
pzs->box.x1 = x1;
|
||||
pzs->box.y1 = y1;
|
||||
pzs->box.x2 = x2;
|
||||
pzs->box.y2 = y2;
|
||||
}
|
||||
|
||||
void Grid::setZone(GridScreen screen, uint16 zoneNum, const Box &box) {
|
||||
debug(9, "Grid::setZone(%d, %d, (%d,%d), (%d,%d))", screen, zoneNum, box.x1, box.y1, box.x2, box.y2);
|
||||
assert(zoneNum < MAX_ZONES_NUMBER);
|
||||
ZoneSlot *pzs = &_zones[screen][zoneNum];
|
||||
pzs->valid = true;
|
||||
pzs->box = box;
|
||||
}
|
||||
|
||||
uint16 Grid::findZoneForPos(GridScreen screen, uint16 x, uint16 y) const {
|
||||
debug(9, "Logic::findZoneForPos(%d, (%d,%d))", screen, x, y);
|
||||
int i;
|
||||
if (screen == GS_PANEL) {
|
||||
y -= ROOM_ZONE_HEIGHT;
|
||||
}
|
||||
for (i = 1; i < MAX_ZONES_NUMBER; ++i) {
|
||||
const ZoneSlot *pzs = &_zones[screen][i];
|
||||
if (pzs->valid && pzs->box.contains(x, y)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16 Grid::findAreaForPos(GridScreen screen, uint16 x, uint16 y) const {
|
||||
uint16 room = _vm->logic()->currentRoom();
|
||||
uint16 zoneNum = findZoneForPos(screen, x, y);
|
||||
if (zoneNum <= _objMax[room]) {
|
||||
zoneNum = 0;
|
||||
} else {
|
||||
zoneNum -= _objMax[room];
|
||||
}
|
||||
return zoneNum;
|
||||
}
|
||||
|
||||
void Grid::clear(GridScreen screen) {
|
||||
debug(9, "Grid::clear(%d)", screen);
|
||||
for (int i = 1; i < MAX_ZONES_NUMBER; ++i) {
|
||||
_zones[screen][i].valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Grid::setupNewRoom(uint16 room, uint16 firstRoomObjNum) {
|
||||
debug(9, "Grid::setupNewRoom()");
|
||||
clear(GS_ROOM);
|
||||
|
||||
uint16 i;
|
||||
uint16 zoneNum;
|
||||
|
||||
// setup objects zones
|
||||
uint16 maxObjRoom = _objMax[room];
|
||||
zoneNum = 1;
|
||||
for (i = firstRoomObjNum + 1; i <= firstRoomObjNum + maxObjRoom; ++i) {
|
||||
if (_vm->logic()->objectData(i)->name != 0) {
|
||||
if (room == 41 && i == 303) {
|
||||
|
||||
// WORKAROUND bug #2913: In the room 41, the bounding box of the
|
||||
// stairs (object 303) doesn't match with the room picture. With the
|
||||
// original box dimensions, Joe could walk "above" the stairs, giving
|
||||
// the impression of floating in the air.
|
||||
// To fix this, the bounding box is set relative to the position of
|
||||
// the cabinet (object 295).
|
||||
|
||||
uint16 y1 = _objectBox[295].y2 + 1;
|
||||
setZone(GS_ROOM, zoneNum, _objectBox[i].x1, y1, _objectBox[i].x2, _objectBox[i].y2);
|
||||
} else {
|
||||
setZone(GS_ROOM, zoneNum, _objectBox[i]);
|
||||
}
|
||||
}
|
||||
++zoneNum;
|
||||
}
|
||||
|
||||
// setup room zones (areas)
|
||||
uint16 maxAreaRoom = _areaMax[room];
|
||||
for (zoneNum = 1; zoneNum <= maxAreaRoom; ++zoneNum) {
|
||||
setZone(GS_ROOM, maxObjRoom + zoneNum, _area[room][zoneNum].box);
|
||||
}
|
||||
}
|
||||
|
||||
void Grid::setupPanel() {
|
||||
for (int i = 0; i <= 7; ++i) {
|
||||
uint16 x = i * 20;
|
||||
setZone(GS_PANEL, i + 1, x, 10, x + 19, 49);
|
||||
}
|
||||
|
||||
// inventory scrolls
|
||||
setZone(GS_PANEL, 9, 160, 10, 179, 29);
|
||||
setZone(GS_PANEL, 10, 160, 30, 179, 49);
|
||||
|
||||
// inventory items
|
||||
setZone(GS_PANEL, 11, 180, 10, 213, 49);
|
||||
setZone(GS_PANEL, 12, 214, 10, 249, 49);
|
||||
setZone(GS_PANEL, 13, 250, 10, 284, 49);
|
||||
setZone(GS_PANEL, 14, 285, 10, 320, 49);
|
||||
}
|
||||
|
||||
void Grid::drawZones() {
|
||||
for (int i = 1; i < MAX_ZONES_NUMBER; ++i) {
|
||||
const ZoneSlot *pzs = &_zones[GS_ROOM][i];
|
||||
if (pzs->valid) {
|
||||
const Box *b = &pzs->box;
|
||||
_vm->display()->drawBox(b->x1, b->y1, b->x2, b->y2, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Box *Grid::zone(GridScreen screen, uint16 index) const {
|
||||
const ZoneSlot *zs = &_zones[screen][index];
|
||||
assert(zs->valid);
|
||||
return &zs->box;
|
||||
}
|
||||
|
||||
Verb Grid::findVerbUnderCursor(int16 cursorx, int16 cursory) const {
|
||||
static const Verb pv[] = {
|
||||
VERB_NONE,
|
||||
VERB_OPEN,
|
||||
VERB_CLOSE,
|
||||
VERB_MOVE,
|
||||
VERB_GIVE,
|
||||
VERB_LOOK_AT,
|
||||
VERB_PICK_UP,
|
||||
VERB_TALK_TO,
|
||||
VERB_USE,
|
||||
VERB_SCROLL_UP,
|
||||
VERB_SCROLL_DOWN,
|
||||
VERB_INV_1,
|
||||
VERB_INV_2,
|
||||
VERB_INV_3,
|
||||
VERB_INV_4,
|
||||
};
|
||||
return pv[findZoneForPos(GS_PANEL, cursorx, cursory)];
|
||||
}
|
||||
|
||||
uint16 Grid::findObjectUnderCursor(int16 cursorx, int16 cursory) const {
|
||||
uint16 roomObj = 0;
|
||||
if (cursory < ROOM_ZONE_HEIGHT) {
|
||||
int16 x = cursorx + _vm->display()->horizontalScroll();
|
||||
roomObj = findZoneForPos(GS_ROOM, x, cursory);
|
||||
}
|
||||
return roomObj;
|
||||
}
|
||||
|
||||
uint16 Grid::findObjectNumber(uint16 zoneNum) const {
|
||||
// l.316-327 select.c
|
||||
uint16 room = _vm->logic()->currentRoom();
|
||||
uint16 obj = zoneNum;
|
||||
uint16 objectMax = _objMax[room];
|
||||
debug(9, "Grid::findObjectNumber(%X, %X)", zoneNum, objectMax);
|
||||
if (zoneNum > objectMax) {
|
||||
// this is an area box, check for associated object
|
||||
obj = _area[room][zoneNum - objectMax].object;
|
||||
if (obj != 0) {
|
||||
// there is an object, get its number
|
||||
obj -= _vm->logic()->currentRoomData();
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
uint16 Grid::findScale(uint16 x, uint16 y) const {
|
||||
uint16 room = _vm->logic()->currentRoom();
|
||||
uint16 scale = 100;
|
||||
uint16 areaNum = findAreaForPos(GS_ROOM, x, y);
|
||||
if (areaNum != 0) {
|
||||
scale = _area[room][areaNum].calcScale(y);
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
|
||||
void Grid::saveState(byte *&ptr) {
|
||||
uint16 i, j;
|
||||
for (i = 1; i <= _numRoomAreas; ++i) {
|
||||
for (j = 1; j <= _areaMax[i]; ++j) {
|
||||
_area[i][j].writeToBE(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Grid::loadState(uint32 ver, byte *&ptr) {
|
||||
uint16 i, j;
|
||||
for (i = 1; i <= _numRoomAreas; ++i) {
|
||||
for (j = 1; j <= _areaMax[i]; ++j) {
|
||||
_area[i][j].readFromBE(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Queen
|
||||
135
engines/queen/grid.h
Normal file
135
engines/queen/grid.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_GRID_H
|
||||
#define QUEEN_GRID_H
|
||||
|
||||
#include "common/util.h"
|
||||
#include "queen/structs.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
enum GridScreen {
|
||||
GS_ROOM = 0,
|
||||
GS_PANEL = 1,
|
||||
GS_COUNT = 2
|
||||
};
|
||||
|
||||
class QueenEngine;
|
||||
|
||||
class Grid {
|
||||
public:
|
||||
|
||||
Grid(QueenEngine *vm);
|
||||
~Grid();
|
||||
|
||||
//! read areas data from specified stream
|
||||
void readDataFrom(uint16 numObjects, uint16 numRooms, byte *&ptr);
|
||||
|
||||
//! defines a new zone
|
||||
void setZone(GridScreen screen, uint16 zoneNum, uint16 x1, uint16 y1, uint16 x2, uint16 y2);
|
||||
|
||||
//! defines a new zone
|
||||
void setZone(GridScreen screen, uint16 zoneNum, const Box &box);
|
||||
|
||||
//! find the zone number containing the specified point
|
||||
uint16 findZoneForPos(GridScreen screen, uint16 x, uint16 y) const;
|
||||
|
||||
//! find the area number containing the specified point
|
||||
uint16 findAreaForPos(GridScreen screen, uint16 x, uint16 y) const;
|
||||
|
||||
//! clear the zones for current room
|
||||
void clear(GridScreen screen);
|
||||
|
||||
//! setup objects zones for the specified room
|
||||
void setupNewRoom(uint16 room, uint16 firstRoomObjNum);
|
||||
|
||||
//! setup panel zones
|
||||
void setupPanel();
|
||||
|
||||
//! draw the zones for current room (debug only)
|
||||
void drawZones();
|
||||
|
||||
//! retuns a reference to the specified zone
|
||||
const Box *zone(GridScreen screen, uint16 index) const;
|
||||
|
||||
//! get the verb for the specified cursor position
|
||||
Verb findVerbUnderCursor(int16 cursorx, int16 cursory) const;
|
||||
|
||||
//! get the object for the specified cursor position
|
||||
uint16 findObjectUnderCursor(int16 cursorx, int16 cursory) const;
|
||||
|
||||
//! get the object for the specified zone number
|
||||
uint16 findObjectNumber(uint16 zoneNum) const;
|
||||
|
||||
//! get scale for the specified position
|
||||
uint16 findScale(uint16 x, uint16 y) const;
|
||||
|
||||
//! returns a reference to the specfied room area
|
||||
Area *area(int room, int num) const { return &_area[room][num]; }
|
||||
|
||||
//! returns the number of areas in this room
|
||||
uint16 areaMax(int room) const { return _areaMax[room]; }
|
||||
|
||||
//! returns the number of objects in this room
|
||||
uint16 objMax(int room) const { return _objMax[room]; }
|
||||
|
||||
void saveState(byte *&ptr);
|
||||
void loadState(uint32 ver, byte *&ptr);
|
||||
|
||||
enum {
|
||||
MAX_ZONES_NUMBER = 32,
|
||||
MAX_AREAS_NUMBER = 11
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
|
||||
struct ZoneSlot {
|
||||
bool valid;
|
||||
Box box;
|
||||
};
|
||||
|
||||
//! current room zones
|
||||
ZoneSlot _zones[GS_COUNT][MAX_ZONES_NUMBER];
|
||||
|
||||
//! number of objects for each room
|
||||
int16 *_objMax;
|
||||
|
||||
//! number of areas for each room
|
||||
int16 *_areaMax;
|
||||
|
||||
//! areas for each room
|
||||
Area (*_area)[MAX_AREAS_NUMBER];
|
||||
|
||||
//! total number of room areas
|
||||
uint16 _numRoomAreas;
|
||||
|
||||
//! box/zone for each objects
|
||||
Box *_objectBox;
|
||||
|
||||
QueenEngine *_vm;
|
||||
};
|
||||
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
176
engines/queen/input.cpp
Normal file
176
engines/queen/input.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
/* 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 "common/events.h"
|
||||
#include "common/system.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "queen/queen.h"
|
||||
#include "queen/input.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
const verbAction Input::_verbActions[] = {
|
||||
{ VERB_OPEN, kActionOpen },
|
||||
{ VERB_CLOSE, kActionClose },
|
||||
{ VERB_MOVE, kActionMove },
|
||||
{ VERB_GIVE, kActionGive },
|
||||
{ VERB_LOOK_AT, kActionLook },
|
||||
{ VERB_PICK_UP, kActionPickUp },
|
||||
{ VERB_TALK_TO, kActionTalk },
|
||||
{ VERB_USE, kActionUse }
|
||||
};
|
||||
|
||||
Input::Input(Common::Language language, OSystem *system) :
|
||||
_system(system), _eventMan(system->getEventManager()), _fastMode(false),
|
||||
_keyVerb(VERB_NONE), _cutawayRunning(false), _canQuit(false),
|
||||
_cutawayQuit(false), _dialogueRunning(false), _talkQuit(false),
|
||||
_quickSave(false), _quickLoad(false), _inKey(kActionNone),
|
||||
_mouseButton(0), _idleTime(0) {
|
||||
}
|
||||
|
||||
void Input::delay(uint amount) {
|
||||
if (_fastMode && amount > DELAY_SHORT) {
|
||||
amount = DELAY_SHORT;
|
||||
}
|
||||
if (_idleTime < DELAY_SCREEN_BLANKER) {
|
||||
_idleTime += amount;
|
||||
}
|
||||
uint32 end = _system->getMillis() + amount;
|
||||
do {
|
||||
Common::Event event;
|
||||
while (_eventMan->pollEvent(event)) {
|
||||
_idleTime = 0;
|
||||
switch (event.type) {
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
if (event.customType == kActionFastMode) {
|
||||
_fastMode = !_fastMode;
|
||||
} else {
|
||||
_inKey = event.customType;
|
||||
}
|
||||
break;
|
||||
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
_mouseButton |= MOUSE_LBUTTON;
|
||||
break;
|
||||
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
_mouseButton |= MOUSE_RBUTTON;
|
||||
if (_dialogueRunning)
|
||||
_talkQuit = true;
|
||||
break;
|
||||
case Common::EVENT_RETURN_TO_LAUNCHER:
|
||||
case Common::EVENT_QUIT:
|
||||
if (_cutawayRunning)
|
||||
_cutawayQuit = true;
|
||||
// Allow using close button while dialogue is running
|
||||
if (_dialogueRunning)
|
||||
_talkQuit = true;
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_system->updateScreen();
|
||||
|
||||
if (amount == 0)
|
||||
break;
|
||||
|
||||
_system->delayMillis((amount > 10) ? 10 : amount);
|
||||
} while (_system->getMillis() < end);
|
||||
}
|
||||
|
||||
void Input::checkKeys() {
|
||||
|
||||
if (_inKey)
|
||||
debug(6, "[Input::checkKeys] _inKey = %i", _inKey);
|
||||
|
||||
switch (_inKey) {
|
||||
case kActionSkipText:
|
||||
_keyVerb = VERB_SKIP_TEXT;
|
||||
break;
|
||||
case kActionScrollUp:
|
||||
_keyVerb = VERB_SCROLL_UP;
|
||||
break;
|
||||
case kActionScrollDown:
|
||||
_keyVerb = VERB_SCROLL_DOWN;
|
||||
break;
|
||||
case kActionInvSlot1:
|
||||
_keyVerb = VERB_DIGIT_1;
|
||||
break;
|
||||
case kActionInvSlot2:
|
||||
_keyVerb = VERB_DIGIT_2;
|
||||
break;
|
||||
case kActionInvSlot3:
|
||||
_keyVerb = VERB_DIGIT_3;
|
||||
break;
|
||||
case kActionInvSlot4:
|
||||
_keyVerb = VERB_DIGIT_4;
|
||||
break;
|
||||
case kActionSkipCutaway: // skip cutaway / dialogue
|
||||
if (_canQuit) {
|
||||
if (_cutawayRunning) {
|
||||
debug(6, "[Input::checkKeys] Setting _cutawayQuit to true");
|
||||
_cutawayQuit = true;
|
||||
}
|
||||
if (_dialogueRunning)
|
||||
_talkQuit = true;
|
||||
}
|
||||
break;
|
||||
case kActionJournal: // use Journal
|
||||
if (_cutawayRunning) {
|
||||
if (_canQuit) {
|
||||
_keyVerb = VERB_USE_JOURNAL;
|
||||
_cutawayQuit = _talkQuit = true;
|
||||
}
|
||||
} else {
|
||||
_keyVerb = VERB_USE_JOURNAL;
|
||||
if (_canQuit)
|
||||
_talkQuit = true;
|
||||
}
|
||||
break;
|
||||
case kActionSave: // quicksave
|
||||
_quickSave = true;
|
||||
break;
|
||||
case kActionLoad: // quickload
|
||||
_quickLoad = true;
|
||||
break;
|
||||
default:
|
||||
for (int i = 0; i < ARRAYSIZE(_verbActions); ++i) {
|
||||
if (_inKey == _verbActions[i]._action) {
|
||||
_keyVerb = _verbActions[i]._verb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_inKey = kActionNone; // reset
|
||||
}
|
||||
|
||||
Common::Point Input::getMousePos() const {
|
||||
return _eventMan->getMousePos();
|
||||
}
|
||||
|
||||
} // End of namespace Queen
|
||||
143
engines/queen/input.h
Normal file
143
engines/queen/input.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_INPUT_H
|
||||
#define QUEEN_INPUT_H
|
||||
|
||||
#include "common/language.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/events.h"
|
||||
#include "queen/defs.h"
|
||||
|
||||
class OSystem;
|
||||
|
||||
namespace Queen {
|
||||
|
||||
struct verbAction {
|
||||
Verb _verb;
|
||||
Common::CustomEventType _action;
|
||||
};
|
||||
|
||||
class Input {
|
||||
public:
|
||||
|
||||
//! Adjust here to change delays!
|
||||
enum {
|
||||
DELAY_SHORT = 10,
|
||||
DELAY_NORMAL = 100, // 5 * 20ms
|
||||
DELAY_SCREEN_BLANKER = 5 * 60 * 1000
|
||||
};
|
||||
enum {
|
||||
MOUSE_LBUTTON = 1,
|
||||
MOUSE_RBUTTON = 2
|
||||
};
|
||||
|
||||
Input(Common::Language language, OSystem *system);
|
||||
|
||||
void delay(uint amount);
|
||||
|
||||
//! convert input to verb
|
||||
void checkKeys();
|
||||
|
||||
//! use instead of KEYVERB=0
|
||||
void clearKeyVerb() { _keyVerb = VERB_NONE; }
|
||||
|
||||
void canQuit(bool cq) { _canQuit = cq; }
|
||||
|
||||
bool cutawayRunning() const { return _cutawayRunning; }
|
||||
void cutawayRunning(bool running) { _cutawayRunning = running; }
|
||||
|
||||
bool cutawayQuit() const { return _cutawayQuit; }
|
||||
void cutawayQuitReset() { _cutawayQuit = false; }
|
||||
|
||||
void dialogueRunning(bool running) { _dialogueRunning = running; }
|
||||
|
||||
bool talkQuit() const { return _talkQuit; }
|
||||
void talkQuitReset() { _talkQuit = false; }
|
||||
|
||||
bool quickSave() const { return _quickSave; }
|
||||
void quickSaveReset() { _quickSave = false; }
|
||||
bool quickLoad() const { return _quickLoad; }
|
||||
void quickLoadReset() { _quickLoad = false; }
|
||||
|
||||
bool fastMode() const { return _fastMode; }
|
||||
void fastMode(bool fm) { _fastMode = fm; }
|
||||
|
||||
Verb keyVerb() const { return _keyVerb; }
|
||||
|
||||
Common::Point getMousePos() const;
|
||||
|
||||
int mouseButton() const { return _mouseButton; }
|
||||
void clearMouseButton() { _mouseButton = 0; }
|
||||
|
||||
//! returns user idle time (used by Display, to trigger the screensaver)
|
||||
uint32 idleTime() const { return _idleTime; }
|
||||
|
||||
private:
|
||||
|
||||
//! used to get keyboard and mouse events
|
||||
OSystem *_system;
|
||||
|
||||
Common::EventManager *_eventMan;
|
||||
|
||||
//! some cutaways require update() run faster
|
||||
bool _fastMode;
|
||||
|
||||
//! the current verb received from keyboard
|
||||
Verb _keyVerb;
|
||||
|
||||
//! set if a cutaway is running
|
||||
bool _cutawayRunning;
|
||||
|
||||
//! set this if we can quit
|
||||
bool _canQuit;
|
||||
|
||||
//! moved Cutaway::_quit here
|
||||
bool _cutawayQuit;
|
||||
|
||||
//! set if a dialogue is running
|
||||
bool _dialogueRunning;
|
||||
|
||||
//! moved Talk::_quit here
|
||||
bool _talkQuit;
|
||||
|
||||
//! set if quicksave requested
|
||||
bool _quickSave;
|
||||
|
||||
//! set if quickload requested
|
||||
bool _quickLoad;
|
||||
|
||||
//! set by delay();
|
||||
Common::CustomEventType _inKey;
|
||||
|
||||
//! set by delay();
|
||||
int _mouseButton;
|
||||
|
||||
//! user idle time
|
||||
uint32 _idleTime;
|
||||
|
||||
//! verbs matching the actions
|
||||
static const verbAction _verbActions[];
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
654
engines/queen/journal.cpp
Normal file
654
engines/queen/journal.cpp
Normal file
@@ -0,0 +1,654 @@
|
||||
/* 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 "common/error.h"
|
||||
#include "common/events.h"
|
||||
#include "common/system.h"
|
||||
#include "queen/journal.h"
|
||||
|
||||
#include "queen/bankman.h"
|
||||
#include "queen/display.h"
|
||||
#include "queen/graphics.h"
|
||||
#include "queen/grid.h"
|
||||
#include "queen/logic.h"
|
||||
#include "queen/music.h"
|
||||
#include "queen/queen.h"
|
||||
#include "queen/resource.h"
|
||||
#include "queen/sound.h"
|
||||
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
Journal::Journal(QueenEngine *vm)
|
||||
: _vm(vm) {
|
||||
_currentSavePage = 0;
|
||||
_currentSaveSlot = 0;
|
||||
}
|
||||
|
||||
void Journal::use() {
|
||||
BobSlot *joe = _vm->graphics()->bob(0);
|
||||
_prevJoeX = joe->x;
|
||||
_prevJoeY = joe->y;
|
||||
|
||||
_panelMode = PM_NORMAL;
|
||||
_system = g_system;
|
||||
|
||||
_panelTextCount = 0;
|
||||
memset(_panelTextY, 0, sizeof(_panelTextY));
|
||||
memset(&_textField, 0, sizeof(_textField));
|
||||
|
||||
memset(_saveDescriptions, 0, sizeof(_saveDescriptions));
|
||||
_vm->findGameStateDescriptions(_saveDescriptions);
|
||||
|
||||
setup();
|
||||
redraw();
|
||||
update();
|
||||
_vm->display()->palFadeIn(ROOM_JOURNAL);
|
||||
|
||||
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(false);
|
||||
keymapper->getKeymap("journal")->setEnabled(true);
|
||||
|
||||
_quitMode = QM_LOOP;
|
||||
while (_quitMode == QM_LOOP) {
|
||||
Common::Event event;
|
||||
Common::EventManager *eventMan = _system->getEventManager();
|
||||
while (eventMan->pollEvent(event)) {
|
||||
switch (event.type) {
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
handleAction(event.customType);
|
||||
break;
|
||||
case Common::EVENT_KEYDOWN:
|
||||
handleKeyDown(event.kbd.ascii, event.kbd.keycode);
|
||||
break;
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
handleMouseDown(event.mouse.x, event.mouse.y);
|
||||
break;
|
||||
case Common::EVENT_WHEELUP:
|
||||
handleMouseWheel(-1);
|
||||
break;
|
||||
case Common::EVENT_WHEELDOWN:
|
||||
handleMouseWheel(1);
|
||||
break;
|
||||
case Common::EVENT_RETURN_TO_LAUNCHER:
|
||||
case Common::EVENT_QUIT:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
_system->delayMillis(20);
|
||||
_system->updateScreen();
|
||||
}
|
||||
|
||||
keymapper->getKeymap("journal")->setEnabled(false);
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(true);
|
||||
|
||||
_vm->writeOptionSettings();
|
||||
|
||||
_vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
|
||||
_vm->graphics()->putCameraOnBob(0);
|
||||
if (_quitMode == QM_CONTINUE) {
|
||||
continueGame();
|
||||
}
|
||||
}
|
||||
|
||||
void Journal::continueGame() {
|
||||
_vm->display()->fullscreen(false);
|
||||
_vm->display()->forceFullRefresh();
|
||||
|
||||
_vm->logic()->joePos(_prevJoeX, _prevJoeY);
|
||||
_vm->logic()->joeCutFacing(_vm->logic()->joeFacing());
|
||||
|
||||
_vm->logic()->oldRoom(_vm->logic()->currentRoom());
|
||||
_vm->logic()->displayRoom(_vm->logic()->currentRoom(), RDM_FADE_JOE, 0, 0, false);
|
||||
}
|
||||
|
||||
void Journal::setup() {
|
||||
_vm->display()->palFadeOut(_vm->logic()->currentRoom());
|
||||
_vm->display()->horizontalScroll(0);
|
||||
_vm->display()->fullscreen(true);
|
||||
_vm->graphics()->clearBobs();
|
||||
_vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
|
||||
_vm->bankMan()->eraseFrames(false);
|
||||
_vm->display()->textCurrentColor(_vm->display()->getInkColor(INK_JOURNAL));
|
||||
|
||||
_vm->grid()->clear(GS_ROOM);
|
||||
for (int i = 0; i < MAX_ZONES; ++i) {
|
||||
const Zone *zn = &_zones[i];
|
||||
_vm->grid()->setZone(GS_ROOM, zn->num, zn->x1, zn->y1, zn->x2, zn->y2);
|
||||
}
|
||||
|
||||
_vm->display()->setupNewRoom("journal", ROOM_JOURNAL);
|
||||
_vm->bankMan()->load("journal.BBK", JOURNAL_BANK);
|
||||
for (int f = 1; f <= 20; ++f) {
|
||||
int frameNum = JOURNAL_FRAMES + f;
|
||||
_vm->bankMan()->unpack(f, frameNum, JOURNAL_BANK);
|
||||
BobFrame *bf = _vm->bankMan()->fetchFrame(frameNum);
|
||||
bf->xhotspot = 0;
|
||||
bf->yhotspot = 0;
|
||||
if (f == FRAME_INFO_BOX) { // adjust info box hot spot to put it always on top
|
||||
bf->yhotspot = 200;
|
||||
}
|
||||
}
|
||||
_vm->bankMan()->close(JOURNAL_BANK);
|
||||
|
||||
_textField.x = 136;
|
||||
_textField.y = 9;
|
||||
_textField.w = 146;
|
||||
_textField.h = 13;
|
||||
}
|
||||
|
||||
void Journal::redraw() {
|
||||
drawNormalPanel();
|
||||
drawConfigPanel();
|
||||
drawSaveDescriptions();
|
||||
drawSaveSlot();
|
||||
}
|
||||
|
||||
void Journal::update() {
|
||||
_vm->graphics()->sortBobs();
|
||||
_vm->display()->prepareUpdate();
|
||||
_vm->graphics()->drawBobs();
|
||||
if (_textField.enabled) {
|
||||
int16 x = _textField.x + _textField.posCursor;
|
||||
int16 y = _textField.y + _currentSaveSlot * _textField.h + 8;
|
||||
_vm->display()->drawBox(x, y, x + 6, y, _vm->display()->getInkColor(INK_JOURNAL));
|
||||
}
|
||||
_vm->display()->forceFullRefresh();
|
||||
_vm->display()->update();
|
||||
_system->updateScreen();
|
||||
}
|
||||
|
||||
void Journal::showBob(int bobNum, int16 x, int16 y, int frameNum) {
|
||||
BobSlot *bob = _vm->graphics()->bob(bobNum);
|
||||
bob->curPos(x, y);
|
||||
bob->frameNum = JOURNAL_FRAMES + frameNum;
|
||||
}
|
||||
|
||||
void Journal::hideBob(int bobNum) {
|
||||
_vm->graphics()->bob(bobNum)->active = false;
|
||||
}
|
||||
|
||||
void Journal::drawSaveDescriptions() {
|
||||
for (int i = 0; i < NUM_SAVES_PER_PAGE; ++i) {
|
||||
int n = _currentSavePage * 10 + i;
|
||||
char nb[4];
|
||||
Common::sprintf_s(nb, "%d", n + 1);
|
||||
int y = _textField.y + i * _textField.h;
|
||||
_vm->display()->setText(_textField.x, y, _saveDescriptions[n], false);
|
||||
_vm->display()->setText(_textField.x - 27, y + 1, nb, false);
|
||||
}
|
||||
// highlight current page
|
||||
showBob(BOB_SAVE_PAGE, 300, 3 + _currentSavePage * 15, 6 + _currentSavePage);
|
||||
}
|
||||
|
||||
void Journal::drawSaveSlot() {
|
||||
showBob(BOB_SAVE_DESC, 130, 6 + _currentSaveSlot * 13, 17);
|
||||
}
|
||||
|
||||
void Journal::enterYesNoPanelMode(int16 prevZoneNum, int titleNum) {
|
||||
_panelMode = PM_YES_NO;
|
||||
_prevZoneNum = prevZoneNum;
|
||||
drawYesNoPanel(titleNum);
|
||||
}
|
||||
|
||||
void Journal::exitYesNoPanelMode() {
|
||||
_panelMode = PM_NORMAL;
|
||||
if (_prevZoneNum == ZN_MAKE_ENTRY) {
|
||||
closeTextField();
|
||||
}
|
||||
redraw();
|
||||
}
|
||||
|
||||
void Journal::enterInfoPanelMode() {
|
||||
_panelMode = PM_INFO_BOX;
|
||||
_vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
|
||||
drawInfoPanel();
|
||||
}
|
||||
|
||||
void Journal::exitInfoPanelMode() {
|
||||
_vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
|
||||
hideBob(BOB_INFO_BOX);
|
||||
redraw();
|
||||
_panelMode = PM_NORMAL;
|
||||
}
|
||||
|
||||
void Journal::handleKeyDown(uint16 ascii, int keycode) {
|
||||
switch (_panelMode) {
|
||||
case PM_INFO_BOX:
|
||||
break;
|
||||
case PM_YES_NO:
|
||||
if (_textField.enabled) {
|
||||
updateTextField(ascii, keycode);
|
||||
}
|
||||
break;
|
||||
case PM_NORMAL:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Journal::handleAction(Common::CustomEventType action) {
|
||||
switch (_panelMode) {
|
||||
case PM_INFO_BOX:
|
||||
break;
|
||||
case PM_YES_NO:
|
||||
if (action == kActionCloseJournal) {
|
||||
exitYesNoPanelMode();
|
||||
}
|
||||
break;
|
||||
case PM_NORMAL:
|
||||
if (action == kActionCloseJournal) {
|
||||
_quitMode = QM_CONTINUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Journal::handleMouseWheel(int inc) {
|
||||
if (_panelMode == PM_NORMAL) {
|
||||
int curSave = _currentSavePage * NUM_SAVES_PER_PAGE + _currentSaveSlot + inc;
|
||||
if (curSave >= 0 && curSave < NUM_SAVES_PER_PAGE * 10) {
|
||||
_currentSavePage = curSave / NUM_SAVES_PER_PAGE;
|
||||
_currentSaveSlot = curSave % NUM_SAVES_PER_PAGE;
|
||||
drawSaveDescriptions();
|
||||
drawSaveSlot();
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Journal::handleMouseDown(int x, int y) {
|
||||
int val;
|
||||
int16 zoneNum = _vm->grid()->findZoneForPos(GS_ROOM, x, y);
|
||||
switch (_panelMode) {
|
||||
case PM_INFO_BOX:
|
||||
exitInfoPanelMode();
|
||||
break;
|
||||
case PM_YES_NO:
|
||||
if (zoneNum == ZN_YES) {
|
||||
_panelMode = PM_NORMAL;
|
||||
int currentSlot = _currentSavePage * 10 + _currentSaveSlot;
|
||||
switch (_prevZoneNum) {
|
||||
case ZN_REVIEW_ENTRY:
|
||||
if (_saveDescriptions[currentSlot][0]) {
|
||||
_vm->graphics()->clearBobs();
|
||||
_vm->display()->palFadeOut(ROOM_JOURNAL);
|
||||
_vm->sound()->stopSong();
|
||||
_vm->loadGameState(currentSlot);
|
||||
_vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
|
||||
_quitMode = QM_RESTORE;
|
||||
} else {
|
||||
exitYesNoPanelMode();
|
||||
}
|
||||
break;
|
||||
case ZN_MAKE_ENTRY:
|
||||
if (_textField.text[0]) {
|
||||
closeTextField();
|
||||
_vm->saveGameState(currentSlot, _textField.text);
|
||||
_quitMode = QM_CONTINUE;
|
||||
} else {
|
||||
exitYesNoPanelMode();
|
||||
}
|
||||
break;
|
||||
case ZN_GIVEUP:
|
||||
_quitMode = QM_CONTINUE;
|
||||
_vm->quitGame();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (zoneNum == ZN_NO) {
|
||||
exitYesNoPanelMode();
|
||||
}
|
||||
break;
|
||||
case PM_NORMAL:
|
||||
switch (zoneNum) {
|
||||
case ZN_REVIEW_ENTRY:
|
||||
enterYesNoPanelMode(zoneNum, TXT_REVIEW_ENTRY);
|
||||
break;
|
||||
case ZN_MAKE_ENTRY:
|
||||
initTextField(_saveDescriptions[_currentSavePage * 10 + _currentSaveSlot]);
|
||||
enterYesNoPanelMode(zoneNum, TXT_MAKE_ENTRY);
|
||||
break;
|
||||
case ZN_CLOSE:
|
||||
_quitMode = QM_CONTINUE;
|
||||
break;
|
||||
case ZN_GIVEUP:
|
||||
enterYesNoPanelMode(zoneNum, TXT_GIVE_UP);
|
||||
break;
|
||||
case ZN_TEXT_SPEED:
|
||||
val = (x - 136) * QueenEngine::MAX_TEXT_SPEED / (266 - 136);
|
||||
_vm->talkSpeed(val);
|
||||
drawConfigPanel();
|
||||
break;
|
||||
case ZN_SFX_TOGGLE:
|
||||
_vm->sound()->toggleSfx();
|
||||
drawConfigPanel();
|
||||
break;
|
||||
case ZN_MUSIC_VOLUME:
|
||||
val = (x - 136) * Audio::Mixer::kMaxMixerVolume / (266 - 136);
|
||||
_vm->sound()->setVolume(val);
|
||||
drawConfigPanel();
|
||||
break;
|
||||
case ZN_DESC_1:
|
||||
case ZN_DESC_2:
|
||||
case ZN_DESC_3:
|
||||
case ZN_DESC_4:
|
||||
case ZN_DESC_5:
|
||||
case ZN_DESC_6:
|
||||
case ZN_DESC_7:
|
||||
case ZN_DESC_8:
|
||||
case ZN_DESC_9:
|
||||
case ZN_DESC_10:
|
||||
_currentSaveSlot = zoneNum - ZN_DESC_1;
|
||||
drawSaveSlot();
|
||||
break;
|
||||
case ZN_PAGE_A:
|
||||
case ZN_PAGE_B:
|
||||
case ZN_PAGE_C:
|
||||
case ZN_PAGE_D:
|
||||
case ZN_PAGE_E:
|
||||
case ZN_PAGE_F:
|
||||
case ZN_PAGE_G:
|
||||
case ZN_PAGE_H:
|
||||
case ZN_PAGE_I:
|
||||
case ZN_PAGE_J:
|
||||
_currentSavePage = zoneNum - ZN_PAGE_A;
|
||||
drawSaveDescriptions();
|
||||
break;
|
||||
case ZN_INFO_BOX:
|
||||
enterInfoPanelMode();
|
||||
break;
|
||||
case ZN_MUSIC_TOGGLE:
|
||||
_vm->sound()->toggleMusic();
|
||||
if (_vm->sound()->musicOn()) {
|
||||
_vm->sound()->playLastSong();
|
||||
} else {
|
||||
_vm->sound()->stopSong();
|
||||
}
|
||||
drawConfigPanel();
|
||||
break;
|
||||
case ZN_VOICE_TOGGLE:
|
||||
_vm->sound()->toggleSpeech();
|
||||
drawConfigPanel();
|
||||
break;
|
||||
case ZN_TEXT_TOGGLE:
|
||||
_vm->subtitles(!_vm->subtitles());
|
||||
drawConfigPanel();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
static void removeLeadingAndTrailingSpaces(char *dst, size_t dstSize, const char* src) {
|
||||
assert(dstSize > 0);
|
||||
size_t srcLen = strlen(src);
|
||||
if (0 == srcLen) {
|
||||
dst[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
size_t firstNonSpaceIndex;
|
||||
for (firstNonSpaceIndex = 0; firstNonSpaceIndex < srcLen; ++firstNonSpaceIndex) {
|
||||
if (src[firstNonSpaceIndex] != ' ')
|
||||
break;
|
||||
}
|
||||
if (firstNonSpaceIndex == srcLen) {
|
||||
dst[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
size_t lastNonSpaceIndex = srcLen - 1;
|
||||
while (src[lastNonSpaceIndex] == ' ')
|
||||
--lastNonSpaceIndex;
|
||||
|
||||
uint newLen = lastNonSpaceIndex - firstNonSpaceIndex + 1;
|
||||
assert(newLen < dstSize);
|
||||
for (size_t i = 0; i < newLen; ++i) {
|
||||
dst[i] = src[firstNonSpaceIndex + i];
|
||||
}
|
||||
dst[newLen] = '\0';
|
||||
}
|
||||
|
||||
void Journal::drawPanelText(int y, const char *text) {
|
||||
debug(7, "Journal::drawPanelText(%d, '%s')", y, text);
|
||||
|
||||
char s[128];
|
||||
removeLeadingAndTrailingSpaces(s, 128, text); // necessary for spanish version
|
||||
|
||||
// draw the substrings
|
||||
char *p = strchr(s, ' ');
|
||||
if (!p) {
|
||||
int x = (128 - _vm->display()->textWidth(s)) / 2;
|
||||
_vm->display()->setText(x, y, s, false);
|
||||
assert(_panelTextCount < MAX_PANEL_TEXTS);
|
||||
_panelTextY[_panelTextCount++] = y;
|
||||
} else {
|
||||
*p++ = '\0';
|
||||
if (_vm->resource()->getLanguage() == Common::HE_ISR) {
|
||||
drawPanelText(y - 5, p);
|
||||
drawPanelText(y + 5, s);
|
||||
} else {
|
||||
drawPanelText(y - 5, s);
|
||||
drawPanelText(y + 5, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Journal::drawCheckBox(bool active, int bobNum, int16 x, int16 y, int frameNum) {
|
||||
if (active) {
|
||||
showBob(bobNum, x, y, frameNum);
|
||||
} else {
|
||||
hideBob(bobNum);
|
||||
}
|
||||
}
|
||||
|
||||
void Journal::drawSlideBar(int value, int maxValue, int bobNum, int16 y, int frameNum) {
|
||||
showBob(bobNum, 136 + value * (266 - 136) / maxValue, y, frameNum);
|
||||
}
|
||||
|
||||
void Journal::drawPanel(const int *frames, const int *titles, int n) {
|
||||
for (int i = 0; i < _panelTextCount; ++i) {
|
||||
_vm->display()->clearTexts(_panelTextY[i], _panelTextY[i]);
|
||||
}
|
||||
_panelTextCount = 0;
|
||||
int bobNum = 1;
|
||||
int y = 8;
|
||||
while (n--) {
|
||||
showBob(bobNum++, 32, y, *frames++);
|
||||
drawPanelText(y + 12, _vm->logic()->joeResponse(*titles++));
|
||||
y += 48;
|
||||
}
|
||||
}
|
||||
|
||||
void Journal::drawNormalPanel() {
|
||||
static const int frames[] = { FRAME_BLUE_1, FRAME_BLUE_2, FRAME_BLUE_1, FRAME_ORANGE };
|
||||
static const int titles[] = { TXT_REVIEW_ENTRY, TXT_MAKE_ENTRY, TXT_CLOSE, TXT_GIVE_UP };
|
||||
drawPanel(frames, titles, 4);
|
||||
}
|
||||
|
||||
void Journal::drawYesNoPanel(int titleNum) {
|
||||
static const int frames[] = { FRAME_GREY, FRAME_BLUE_1, FRAME_BLUE_2 };
|
||||
const int titles[] = { titleNum, TXT_YES, TXT_NO };
|
||||
drawPanel(frames, titles, 3);
|
||||
|
||||
hideBob(BOB_LEFT_RECT_4);
|
||||
hideBob(BOB_TALK_SPEED);
|
||||
hideBob(BOB_SFX_TOGGLE);
|
||||
hideBob(BOB_MUSIC_VOLUME);
|
||||
hideBob(BOB_SPEECH_TOGGLE);
|
||||
hideBob(BOB_TEXT_TOGGLE);
|
||||
hideBob(BOB_MUSIC_TOGGLE);
|
||||
}
|
||||
|
||||
void Journal::drawConfigPanel() {
|
||||
_vm->checkOptionSettings();
|
||||
|
||||
drawSlideBar(_vm->talkSpeed(), QueenEngine::MAX_TEXT_SPEED, BOB_TALK_SPEED, 164, FRAME_BLUE_PIN);
|
||||
drawSlideBar(_vm->sound()->getVolume(), Audio::Mixer::kMaxMixerVolume, BOB_MUSIC_VOLUME, 177, FRAME_GREEN_PIN);
|
||||
|
||||
drawCheckBox(_vm->sound()->sfxOn(), BOB_SFX_TOGGLE, 221, 155, FRAME_CHECK_BOX);
|
||||
drawCheckBox(_vm->sound()->speechOn(), BOB_SPEECH_TOGGLE, 158, 155, FRAME_CHECK_BOX);
|
||||
drawCheckBox(_vm->subtitles(), BOB_TEXT_TOGGLE, 125, 167, FRAME_CHECK_BOX);
|
||||
drawCheckBox(_vm->sound()->musicOn(), BOB_MUSIC_TOGGLE, 125, 181, FRAME_CHECK_BOX);
|
||||
}
|
||||
|
||||
void Journal::drawInfoPanel() {
|
||||
showBob(BOB_INFO_BOX, 72, 221, FRAME_INFO_BOX);
|
||||
const char *ver = _vm->resource()->getJASVersion();
|
||||
switch (ver[0]) {
|
||||
case 'P':
|
||||
_vm->display()->setTextCentered(132, "PC Hard Drive", false);
|
||||
break;
|
||||
case 'C':
|
||||
_vm->display()->setTextCentered(132, "PC CD-ROM", false);
|
||||
break;
|
||||
case 'a':
|
||||
_vm->display()->setTextCentered(132, "Amiga A500/600", false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (ver[1]) {
|
||||
case 'E':
|
||||
_vm->display()->setTextCentered(144, "English", false);
|
||||
break;
|
||||
case 'F' :
|
||||
_vm->display()->setTextCentered(144, "Fran\x87""ais", false);
|
||||
break;
|
||||
case 'G':
|
||||
_vm->display()->setTextCentered(144, "Deutsch", false);
|
||||
break;
|
||||
case 'H':
|
||||
_vm->display()->setTextCentered(144, "Hebrew", false);
|
||||
break;
|
||||
case 'I':
|
||||
_vm->display()->setTextCentered(144, "Italiano", false);
|
||||
break;
|
||||
case 'S':
|
||||
_vm->display()->setTextCentered(144, "Espa\xA4""ol", false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
char versionId[13];
|
||||
Common::sprintf_s(versionId, "Version %c.%c%c", ver[2], ver[3], ver[4]);
|
||||
_vm->display()->setTextCentered(156, versionId, false);
|
||||
}
|
||||
|
||||
void Journal::initTextField(const char *desc) {
|
||||
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
|
||||
_textField.enabled = true;
|
||||
_textField.posCursor = _vm->display()->textWidth(desc);
|
||||
_textField.textCharsCount = strlen(desc);
|
||||
memset(_textField.text, 0, sizeof(_textField.text));
|
||||
Common::strcpy_s(_textField.text, desc);
|
||||
}
|
||||
|
||||
void Journal::updateTextField(uint16 ascii, int keycode) {
|
||||
bool dirty = false;
|
||||
switch (keycode) {
|
||||
case Common::KEYCODE_BACKSPACE:
|
||||
if (_textField.textCharsCount > 0) {
|
||||
--_textField.textCharsCount;
|
||||
_textField.text[_textField.textCharsCount] = '\0';
|
||||
dirty = true;
|
||||
}
|
||||
break;
|
||||
case Common::KEYCODE_RETURN:
|
||||
case Common::KEYCODE_KP_ENTER:
|
||||
if (_textField.text[0]) {
|
||||
closeTextField();
|
||||
int currentSlot = _currentSavePage * 10 + _currentSaveSlot;
|
||||
_vm->saveGameState(currentSlot, _textField.text);
|
||||
_quitMode = QM_CONTINUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (Common::isPrint((char)ascii) &&
|
||||
_textField.textCharsCount < (sizeof(_textField.text) - 1) &&
|
||||
_vm->display()->textWidth(_textField.text) < _textField.w) {
|
||||
_textField.text[_textField.textCharsCount] = (char)ascii;
|
||||
++_textField.textCharsCount;
|
||||
dirty = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (dirty) {
|
||||
_vm->display()->setText(_textField.x, _textField.y + _currentSaveSlot * _textField.h, _textField.text, false);
|
||||
_textField.posCursor = _vm->display()->textWidth(_textField.text);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void Journal::closeTextField() {
|
||||
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
|
||||
_textField.enabled = false;
|
||||
}
|
||||
|
||||
const Journal::Zone Journal::_zones[] = {
|
||||
{ ZN_REVIEW_ENTRY, 32, 8, 96, 40 },
|
||||
{ ZN_MAKE_ENTRY, 32, 56, 96, 88 }, // == ZN_YES
|
||||
{ ZN_CLOSE, 32, 104, 96, 136 }, // == ZN_NO
|
||||
{ ZN_GIVEUP, 32, 152, 96, 184 },
|
||||
{ ZN_TEXT_SPEED, 136, 169, 265, 176 },
|
||||
{ ZN_SFX_TOGGLE, 197, 155, 231, 164 },
|
||||
{ ZN_MUSIC_VOLUME, 136, 182, 265, 189 },
|
||||
{ ZN_DESC_1, 131, 7, 290, 18 },
|
||||
{ ZN_DESC_2, 131, 20, 290, 31 },
|
||||
{ ZN_DESC_3, 131, 33, 290, 44 },
|
||||
{ ZN_DESC_4, 131, 46, 290, 57 },
|
||||
{ ZN_DESC_5, 131, 59, 290, 70 },
|
||||
{ ZN_DESC_6, 131, 72, 290, 83 },
|
||||
{ ZN_DESC_7, 131, 85, 290, 96 },
|
||||
{ ZN_DESC_8, 131, 98, 290, 109 },
|
||||
{ ZN_DESC_9, 131, 111, 290, 122 },
|
||||
{ ZN_DESC_10, 131, 124, 290, 135 },
|
||||
{ ZN_PAGE_A, 300, 4, 319, 17 },
|
||||
{ ZN_PAGE_B, 300, 19, 319, 32 },
|
||||
{ ZN_PAGE_C, 300, 34, 319, 47 },
|
||||
{ ZN_PAGE_D, 300, 49, 319, 62 },
|
||||
{ ZN_PAGE_E, 300, 64, 319, 77 },
|
||||
{ ZN_PAGE_F, 300, 79, 319, 92 },
|
||||
{ ZN_PAGE_G, 300, 94, 319, 107 },
|
||||
{ ZN_PAGE_H, 300, 109, 319, 122 },
|
||||
{ ZN_PAGE_I, 300, 124, 319, 137 },
|
||||
{ ZN_PAGE_J, 300, 139, 319, 152 },
|
||||
{ ZN_INFO_BOX, 273, 146, 295, 189 },
|
||||
{ ZN_MUSIC_TOGGLE, 109, 181, 135, 190 },
|
||||
{ ZN_VOICE_TOGGLE, 134, 155, 168, 164 },
|
||||
{ ZN_TEXT_TOGGLE, 109, 168, 135, 177 }
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
208
engines/queen/journal.h
Normal file
208
engines/queen/journal.h
Normal file
@@ -0,0 +1,208 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_JOURNAL_H
|
||||
#define QUEEN_JOURNAL_H
|
||||
|
||||
#include "common/util.h"
|
||||
|
||||
class OSystem;
|
||||
|
||||
namespace Queen {
|
||||
|
||||
class QueenEngine;
|
||||
|
||||
class Journal {
|
||||
public:
|
||||
|
||||
Journal(QueenEngine *vm);
|
||||
void use();
|
||||
|
||||
enum {
|
||||
JOURNAL_BANK = 8,
|
||||
JOURNAL_FRAMES = 40
|
||||
};
|
||||
|
||||
enum {
|
||||
ZN_REVIEW_ENTRY = 1,
|
||||
ZN_MAKE_ENTRY = 2,
|
||||
ZN_YES = ZN_MAKE_ENTRY,
|
||||
ZN_CLOSE = 3,
|
||||
ZN_NO = ZN_CLOSE,
|
||||
ZN_GIVEUP = 4,
|
||||
ZN_TEXT_SPEED = 5,
|
||||
ZN_SFX_TOGGLE = 6,
|
||||
ZN_MUSIC_VOLUME = 7,
|
||||
ZN_DESC_1 = 8,
|
||||
ZN_DESC_2 = 9,
|
||||
ZN_DESC_3 = 10,
|
||||
ZN_DESC_4 = 11,
|
||||
ZN_DESC_5 = 12,
|
||||
ZN_DESC_6 = 13,
|
||||
ZN_DESC_7 = 14,
|
||||
ZN_DESC_8 = 15,
|
||||
ZN_DESC_9 = 16,
|
||||
ZN_DESC_10 = 17,
|
||||
ZN_PAGE_A = 18,
|
||||
ZN_PAGE_B = 19,
|
||||
ZN_PAGE_C = 20,
|
||||
ZN_PAGE_D = 21,
|
||||
ZN_PAGE_E = 22,
|
||||
ZN_PAGE_F = 23,
|
||||
ZN_PAGE_G = 24,
|
||||
ZN_PAGE_H = 25,
|
||||
ZN_PAGE_I = 26,
|
||||
ZN_PAGE_J = 27,
|
||||
ZN_INFO_BOX = 28,
|
||||
ZN_MUSIC_TOGGLE = 29,
|
||||
ZN_VOICE_TOGGLE = 30,
|
||||
ZN_TEXT_TOGGLE = 31
|
||||
};
|
||||
|
||||
enum {
|
||||
BOB_LEFT_RECT_1 = 1,
|
||||
BOB_LEFT_RECT_2 = 2,
|
||||
BOB_LEFT_RECT_3 = 3,
|
||||
BOB_LEFT_RECT_4 = 4,
|
||||
BOB_TALK_SPEED = 5,
|
||||
BOB_SFX_TOGGLE = 6,
|
||||
BOB_MUSIC_VOLUME = 7,
|
||||
BOB_SAVE_DESC = 8,
|
||||
BOB_SAVE_PAGE = 9,
|
||||
BOB_SPEECH_TOGGLE = 10,
|
||||
BOB_TEXT_TOGGLE = 11,
|
||||
BOB_MUSIC_TOGGLE = 12,
|
||||
BOB_INFO_BOX = 13
|
||||
};
|
||||
|
||||
enum {
|
||||
FRAME_BLUE_1 = 1,
|
||||
FRAME_BLUE_2 = 2,
|
||||
FRAME_ORANGE = 3,
|
||||
FRAME_GREY = 5,
|
||||
FRAME_CHECK_BOX = 16,
|
||||
FRAME_BLUE_PIN = 18,
|
||||
FRAME_GREEN_PIN = 19,
|
||||
FRAME_INFO_BOX = 20
|
||||
};
|
||||
|
||||
enum {
|
||||
TXT_CLOSE = 30,
|
||||
TXT_GIVE_UP = 31,
|
||||
TXT_MAKE_ENTRY = 32,
|
||||
TXT_REVIEW_ENTRY = 33,
|
||||
TXT_YES = 34,
|
||||
TXT_NO = 35
|
||||
};
|
||||
|
||||
enum {
|
||||
NUM_SAVES_PER_PAGE = 10,
|
||||
MAX_PANEL_TEXTS = 8,
|
||||
MAX_ZONES = 31
|
||||
};
|
||||
|
||||
enum PanelMode {
|
||||
PM_NORMAL,
|
||||
PM_INFO_BOX,
|
||||
PM_YES_NO
|
||||
};
|
||||
|
||||
enum QuitMode {
|
||||
QM_LOOP,
|
||||
QM_RESTORE,
|
||||
QM_CONTINUE
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void continueGame();
|
||||
|
||||
void setup();
|
||||
void redraw();
|
||||
void update();
|
||||
|
||||
void showBob(int bobNum, int16 x, int16 y, int frameNum);
|
||||
void hideBob(int bobNum);
|
||||
|
||||
void drawSaveDescriptions();
|
||||
void drawSaveSlot();
|
||||
|
||||
void enterYesNoPanelMode(int16 prevZoneNum, int titleNum);
|
||||
void exitYesNoPanelMode();
|
||||
void enterInfoPanelMode();
|
||||
void exitInfoPanelMode();
|
||||
|
||||
void handleMouseWheel(int inc);
|
||||
void handleMouseDown(int x, int y);
|
||||
void handleKeyDown(uint16 ascii, int keycode);
|
||||
void handleAction(Common::CustomEventType action);
|
||||
|
||||
void drawPanelText(int y, const char *text);
|
||||
void drawCheckBox(bool active, int bobNum, int16 x, int16 y, int frameNum);
|
||||
void drawSlideBar(int value, int maxValue, int bobNum, int16 y, int frameNum);
|
||||
void drawPanel(const int *frames, const int *titles, int n);
|
||||
void drawNormalPanel();
|
||||
void drawYesNoPanel(int titleNum);
|
||||
void drawConfigPanel();
|
||||
void drawInfoPanel();
|
||||
|
||||
void initTextField(const char *desc);
|
||||
void updateTextField(uint16 ascii, int keycode);
|
||||
void closeTextField();
|
||||
|
||||
struct TextField {
|
||||
bool enabled;
|
||||
int posCursor;
|
||||
uint textCharsCount;
|
||||
char text[32];
|
||||
int x, y;
|
||||
int w, h;
|
||||
};
|
||||
|
||||
struct Zone {
|
||||
int num;
|
||||
int16 x1, y1, x2, y2;
|
||||
};
|
||||
|
||||
PanelMode _panelMode;
|
||||
QuitMode _quitMode;
|
||||
|
||||
int _currentSavePage;
|
||||
int _currentSaveSlot;
|
||||
|
||||
int _prevJoeX, _prevJoeY;
|
||||
|
||||
int _panelTextCount;
|
||||
int _panelTextY[MAX_PANEL_TEXTS];
|
||||
TextField _textField;
|
||||
uint16 _prevZoneNum;
|
||||
char _saveDescriptions[100][32];
|
||||
|
||||
OSystem *_system;
|
||||
QueenEngine *_vm;
|
||||
|
||||
static const Zone _zones[MAX_ZONES];
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
2225
engines/queen/logic.cpp
Normal file
2225
engines/queen/logic.cpp
Normal file
File diff suppressed because it is too large
Load Diff
412
engines/queen/logic.h
Normal file
412
engines/queen/logic.h
Normal file
@@ -0,0 +1,412 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_LOGIC_H
|
||||
#define QUEEN_LOGIC_H
|
||||
|
||||
#include "common/str-array.h"
|
||||
#include "common/util.h"
|
||||
#include "queen/structs.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
enum RoomDisplayMode {
|
||||
RDM_FADE_NOJOE = 0, // fade in, hide Joe
|
||||
RDM_FADE_JOE = 1, // fade in, display Joe
|
||||
RDM_NOFADE_JOE = 2, // screen does not dissolve into view
|
||||
RDM_FADE_JOE_XY = 3 // display Joe at the current X, Y coords
|
||||
};
|
||||
|
||||
enum JoeWalkMode {
|
||||
JWM_NORMAL = 0,
|
||||
JWM_MOVE = 1,
|
||||
JWM_EXECUTE = 2,
|
||||
JWM_SPEAK = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
JSO_OBJECT_DESCRIPTION = 0,
|
||||
JSO_OBJECT_NAME,
|
||||
JSO_ROOM_NAME,
|
||||
JSO_VERB_NAME,
|
||||
JSO_JOE_RESPONSE,
|
||||
JSO_ACTOR_ANIM,
|
||||
JSO_ACTOR_NAME,
|
||||
JSO_ACTOR_FILE,
|
||||
JSO_COUNT
|
||||
};
|
||||
|
||||
class Credits;
|
||||
class Journal;
|
||||
class QueenEngine;
|
||||
|
||||
class Logic {
|
||||
public:
|
||||
|
||||
Logic(QueenEngine *vm);
|
||||
virtual ~Logic();
|
||||
|
||||
uint16 currentRoom() const { return _currentRoom; }
|
||||
void currentRoom(uint16 room) {
|
||||
assert(room >= 1 && room <= _numRooms);
|
||||
_currentRoom = room;
|
||||
}
|
||||
|
||||
uint16 oldRoom() const { return _oldRoom; }
|
||||
void oldRoom(uint16 room) {
|
||||
assert(room <= _numRooms);
|
||||
_oldRoom = room;
|
||||
}
|
||||
|
||||
uint16 newRoom() const { return _newRoom; }
|
||||
void newRoom(uint16 room) {
|
||||
assert(room <= _numRooms);
|
||||
_newRoom = room;
|
||||
}
|
||||
|
||||
ObjectData *objectData(int index) const { return &_objectData[index]; }
|
||||
uint16 roomData(int room) const { return _roomData[room]; }
|
||||
GraphicData *graphicData(int index) const { return &_graphicData[index]; }
|
||||
ItemData *itemData(int index) const { return &_itemData[index]; }
|
||||
uint16 itemDataCount() const { return _numItems; }
|
||||
|
||||
uint16 findBob(uint16 obj) const;
|
||||
uint16 findFrame(uint16 obj) const;
|
||||
uint16 objectForPerson(uint16 bobnum) const;
|
||||
WalkOffData *walkOffPointForObject(int16 obj) const;
|
||||
|
||||
uint16 walkOffCount() const { return _numWalkOffs; }
|
||||
WalkOffData *walkOffData(int index) const { return &_walkOffData[index]; }
|
||||
uint16 currentRoomData() const { return _roomData[_currentRoom]; }
|
||||
GraphicAnim *graphicAnim(int index) const { return &_graphicAnim[index]; }
|
||||
uint16 graphicAnimCount() const { return _numGraphicAnim; }
|
||||
ObjectDescription *objectDescription(uint16 objNum) const { return &_objectDescription[objNum]; }
|
||||
uint16 objectDescriptionCount() const { return _numObjDesc; }
|
||||
uint16 currentRoomSfx() const { return _sfxName[_currentRoom]; }
|
||||
|
||||
uint16 joeFacing() const { return _joe.facing; }
|
||||
uint16 joeX() const { return _joe.x; }
|
||||
uint16 joeY() const { return _joe.y; }
|
||||
JoeWalkMode joeWalk() const { return _joe.walk; }
|
||||
uint16 joeScale() const { return _joe.scale; }
|
||||
uint16 joeCutFacing() const { return _joe.cutFacing; }
|
||||
uint16 joePrevFacing() const { return _joe.prevFacing; }
|
||||
|
||||
void joeFacing(uint16 dir) { _joe.facing = dir; }
|
||||
void joePos(uint16 x, uint16 y) { _joe.x = x; _joe.y = y; }
|
||||
void joeWalk(JoeWalkMode walking);
|
||||
void joeScale(uint16 scale) { _joe.scale = scale; }
|
||||
void joeCutFacing(uint16 dir) { _joe.cutFacing = dir; }
|
||||
void joePrevFacing(uint16 dir) { _joe.prevFacing = dir; }
|
||||
|
||||
int16 gameState(int index) const;
|
||||
void gameState(int index, int16 newValue);
|
||||
|
||||
TalkSelected *talkSelected(int index) { return &_talkSelected[index]; }
|
||||
|
||||
const char *roomName(uint16 roomNum) const;
|
||||
const char *objectName(uint16 objNum) const;
|
||||
const char *objectTextualDescription(uint16 objNum) const;
|
||||
const char *joeResponse(int i) const;
|
||||
const char *verbName(Verb v) const;
|
||||
const char *actorAnim(int num) const;
|
||||
const char *actorName(int num) const;
|
||||
const char *actorFile(int num) const;
|
||||
|
||||
void eraseRoom();
|
||||
void setupRoom(const char *room, int comPanel, bool inCutaway);
|
||||
void displayRoom(uint16 room, RoomDisplayMode mode, uint16 joeScale, int comPanel, bool inCutaway);
|
||||
|
||||
int16 entryObj() const { return _entryObj; }
|
||||
void entryObj(int16 obj) { _entryObj = obj; }
|
||||
|
||||
ActorData *findActor(uint16 noun, const char *name = NULL) const;
|
||||
bool initPerson(uint16 noun, const char *actorName, bool loadBank, Person *pp);
|
||||
uint16 findPersonNumber(uint16 obj, uint16 room) const;
|
||||
|
||||
//! load banks used for Joe animation
|
||||
void loadJoeBanks(const char *animBank, const char *standBank);
|
||||
|
||||
//! load the various bobs needed to animate Joe
|
||||
void setupJoe();
|
||||
|
||||
//! setup Joe at the right place when entering a room
|
||||
void setupJoeInRoom(bool autoPosition, uint16 scale);
|
||||
|
||||
uint16 joeFace();
|
||||
void joeGrab(int16 grabState);
|
||||
|
||||
//! change Joe clothes to dress
|
||||
void joeUseDress(bool showCut);
|
||||
|
||||
//! restore Joe clothes
|
||||
void joeUseClothes(bool showCut);
|
||||
|
||||
//! change Joe clothes to underwear
|
||||
void joeUseUnderwear();
|
||||
|
||||
void makeJoeSpeak(uint16 descNum, bool objectType = false);
|
||||
void makePersonSpeak(const char *sentence, Person *person, const char *voiceFilePrefix);
|
||||
|
||||
//! start the specified dialogue
|
||||
void startDialogue(const char *dlgFile, int personInRoom, char *cutaway);
|
||||
|
||||
//! play the specified cutaway
|
||||
void playCutaway(const char *cutFile, char *next = NULL);
|
||||
|
||||
//! initialize the inventory
|
||||
void inventorySetup();
|
||||
|
||||
//! get the inventory item for the specified inventory slot
|
||||
uint16 findInventoryItem(int invSlot) const;
|
||||
|
||||
//! refresh inventory contents
|
||||
void inventoryRefresh();
|
||||
int16 previousInventoryItem(int16 first) const;
|
||||
int16 nextInventoryItem(int16 first) const;
|
||||
void removeDuplicateItems();
|
||||
uint16 numItemsInventory() const;
|
||||
void inventoryInsertItem(uint16 itemNum, bool refresh = true);
|
||||
void inventoryDeleteItem(uint16 itemNum, bool refresh = true);
|
||||
void inventoryScroll(uint16 count, bool up);
|
||||
void removeHotelItemsFromInventory();
|
||||
|
||||
//! copy data from dummy object to object
|
||||
void objectCopy(int dummyObjectIndex, int objectIndex);
|
||||
|
||||
//! handle a particular event when Joe walks on this area
|
||||
void handleSpecialArea(Direction facing, uint16 areaNum, uint16 walkDataNum);
|
||||
|
||||
//! handle the pinnacle room (== room chooser in the jungle)
|
||||
void handlePinnacleRoom();
|
||||
|
||||
void update();
|
||||
|
||||
void saveState(byte *&ptr);
|
||||
void loadState(uint32 ver, byte *&ptr);
|
||||
|
||||
//! called after a save state has been loaded
|
||||
void setupRestoredGame();
|
||||
|
||||
//! ugly hack from original code
|
||||
void sceneReset() { _scene = 0; }
|
||||
|
||||
//! make a scene
|
||||
void sceneStart();
|
||||
|
||||
//! stop making a scene
|
||||
void sceneStop();
|
||||
|
||||
void changeRoom();
|
||||
|
||||
//! enter the Journal (save/load, configuration)
|
||||
virtual void useJournal() = 0;
|
||||
|
||||
//! execute a special move
|
||||
void executeSpecialMove(uint16 sm);
|
||||
|
||||
void startCredits(const char *filename);
|
||||
void stopCredits();
|
||||
|
||||
void start();
|
||||
|
||||
enum {
|
||||
JOE_RESPONSE_MAX = 40,
|
||||
DEFAULT_TALK_SPEED = 7 * 3,
|
||||
GAME_STATE_COUNT = 211,
|
||||
TALK_SELECTED_COUNT = 86
|
||||
};
|
||||
|
||||
typedef void (Logic::*SpecialMoveProc)();
|
||||
|
||||
protected:
|
||||
|
||||
void readQueenJas();
|
||||
|
||||
void asmMakeJoeUseDress();
|
||||
void asmMakeJoeUseNormalClothes();
|
||||
void asmMakeJoeUseUnderwear();
|
||||
void asmSwitchToDressPalette();
|
||||
void asmSwitchToNormalPalette();
|
||||
void asmStartCarAnimation();
|
||||
void asmStopCarAnimation();
|
||||
void asmStartFightAnimation();
|
||||
void asmWaitForFrankPosition();
|
||||
void asmMakeFrankGrowing();
|
||||
void asmMakeRobotGrowing();
|
||||
void asmShrinkRobot();
|
||||
void asmEndGame();
|
||||
void asmPutCameraOnDino();
|
||||
void asmPutCameraOnJoe();
|
||||
void asmAltIntroPanRight();
|
||||
void asmAltIntroPanLeft();
|
||||
void asmSetAzuraInLove();
|
||||
void asmPanRightFromJoe();
|
||||
void asmSetLightsOff();
|
||||
void asmSetLightsOn();
|
||||
void asmSetManequinAreaOn();
|
||||
void asmPanToJoe();
|
||||
void asmTurnGuardOn();
|
||||
void asmPanLeft320To144();
|
||||
void asmSmooch();
|
||||
void asmSmoochNoScroll();
|
||||
void asmMakeLightningHitPlane();
|
||||
void asmScaleBlimp();
|
||||
void asmScaleEnding();
|
||||
void asmWaitForCarPosition();
|
||||
void asmShakeScreen();
|
||||
void asmAttemptPuzzle();
|
||||
void asmScaleTitle();
|
||||
void asmScrollTitle();
|
||||
void asmPanRightToHugh();
|
||||
void asmMakeWhiteFlash();
|
||||
void asmPanRightToJoeAndRita();
|
||||
void asmPanLeftToBomb();
|
||||
void asmEndDemo();
|
||||
void asmInterviewIntro();
|
||||
void asmEndInterview();
|
||||
|
||||
virtual bool changeToSpecialRoom() = 0;
|
||||
virtual void setupSpecialMoveTable() = 0;
|
||||
|
||||
|
||||
uint16 _currentRoom;
|
||||
uint16 _oldRoom;
|
||||
uint16 _newRoom;
|
||||
|
||||
//! total number of room in game
|
||||
uint16 _numRooms;
|
||||
|
||||
//! first object number in room
|
||||
uint16 *_roomData;
|
||||
|
||||
//! background music to play in room
|
||||
uint16 *_sfxName;
|
||||
|
||||
//! bounding box of object
|
||||
Box *_objectBox;
|
||||
|
||||
//! inventory items
|
||||
ItemData *_itemData;
|
||||
uint16 _numItems;
|
||||
|
||||
GraphicData *_graphicData;
|
||||
uint16 _numGraphics;
|
||||
|
||||
ObjectData *_objectData;
|
||||
uint16 _numObjects;
|
||||
|
||||
ObjectDescription *_objectDescription;
|
||||
uint16 _numObjDesc;
|
||||
|
||||
ActorData *_actorData;
|
||||
uint16 _numActors;
|
||||
|
||||
//! walk off point for an object
|
||||
WalkOffData *_walkOffData;
|
||||
uint16 _numWalkOffs;
|
||||
|
||||
FurnitureData *_furnitureData;
|
||||
uint16 _numFurniture;
|
||||
|
||||
GraphicAnim *_graphicAnim;
|
||||
uint16 _numGraphicAnim;
|
||||
|
||||
//! actor initial position in room is _walkOffData[_entryObj]
|
||||
int16 _entryObj;
|
||||
|
||||
Common::StringArray _jasStringList;
|
||||
int _jasStringOffset[JSO_COUNT];
|
||||
|
||||
uint16 _numDescriptions;
|
||||
uint16 _numNames;
|
||||
uint16 _numAAnim;
|
||||
uint16 _numAName;
|
||||
uint16 _numAFile;
|
||||
|
||||
struct {
|
||||
uint16 x, y;
|
||||
uint16 facing, cutFacing, prevFacing;
|
||||
JoeWalkMode walk;
|
||||
uint16 scale;
|
||||
} _joe;
|
||||
|
||||
int16 _gameState[GAME_STATE_COUNT];
|
||||
|
||||
TalkSelected _talkSelected[TALK_SELECTED_COUNT];
|
||||
|
||||
//! inventory items
|
||||
int16 _inventoryItem[4];
|
||||
|
||||
//! puzzle counter for room T7
|
||||
uint8 _puzzleAttemptCount;
|
||||
|
||||
//! cutscene counter
|
||||
int _scene;
|
||||
|
||||
SpecialMoveProc _specialMoves[40];
|
||||
|
||||
Credits *_credits;
|
||||
Journal *_journal;
|
||||
|
||||
QueenEngine *_vm;
|
||||
};
|
||||
|
||||
class LogicDemo : public Logic {
|
||||
public:
|
||||
|
||||
LogicDemo(QueenEngine *vm) : Logic(vm) {}
|
||||
void useJournal() override;
|
||||
|
||||
protected:
|
||||
|
||||
bool changeToSpecialRoom() override;
|
||||
void setupSpecialMoveTable() override;
|
||||
};
|
||||
|
||||
class LogicInterview : public Logic {
|
||||
public:
|
||||
|
||||
LogicInterview(QueenEngine *vm) : Logic(vm) {}
|
||||
void useJournal() override;
|
||||
|
||||
protected:
|
||||
|
||||
bool changeToSpecialRoom() override;
|
||||
void setupSpecialMoveTable() override;
|
||||
};
|
||||
|
||||
class LogicGame : public Logic {
|
||||
public:
|
||||
|
||||
LogicGame(QueenEngine *vm) : Logic(vm) {}
|
||||
void useJournal() override;
|
||||
|
||||
protected:
|
||||
|
||||
bool changeToSpecialRoom() override;
|
||||
void setupSpecialMoveTable() override;
|
||||
};
|
||||
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
321
engines/queen/metaengine.cpp
Normal file
321
engines/queen/metaengine.cpp
Normal file
@@ -0,0 +1,321 @@
|
||||
/* 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 "engines/advancedDetector.h"
|
||||
|
||||
#include "common/savefile.h"
|
||||
#include "common/system.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "queen/input.h"
|
||||
#include "queen/queen.h"
|
||||
#include "queen/resource.h"
|
||||
#include "queen/detection.h"
|
||||
|
||||
#include "backends/keymapper/action.h"
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
#include "backends/keymapper/standard-actions.h"
|
||||
|
||||
static const ADExtraGuiOptionsMap optionsList[] = {
|
||||
{
|
||||
GAMEOPTION_ALT_INTRO,
|
||||
{
|
||||
_s("Alternative intro"),
|
||||
_s("Use an alternative game intro (CD version only)"),
|
||||
"alt_intro",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_ALT_FONT,
|
||||
{
|
||||
_s("Improved font"),
|
||||
_s("Use an easier to read custom font"),
|
||||
"alt_font",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
|
||||
AD_EXTRA_GUI_OPTIONS_TERMINATOR
|
||||
};
|
||||
|
||||
class QueenMetaEngine : public AdvancedMetaEngine<Queen::QueenGameDescription> {
|
||||
public:
|
||||
const char *getName() const override {
|
||||
return "queen";
|
||||
}
|
||||
|
||||
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
|
||||
return optionsList;
|
||||
}
|
||||
|
||||
bool hasFeature(MetaEngineFeature f) const override;
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const Queen::QueenGameDescription *desc) const override;
|
||||
SaveStateList listSaves(const char *target) const override;
|
||||
int getMaximumSaveSlot() const override { return 99; }
|
||||
bool removeSaveState(const char *target, int slot) const override;
|
||||
int getAutosaveSlot() const override { return 99; }
|
||||
Common::KeymapArray initKeymaps(const char *target) const override;
|
||||
};
|
||||
|
||||
bool QueenMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsListSaves) ||
|
||||
(f == kSupportsLoadingDuringStartup) ||
|
||||
(f == kSupportsDeleteSave);
|
||||
}
|
||||
|
||||
SaveStateList QueenMetaEngine::listSaves(const char *target) const {
|
||||
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
|
||||
Common::StringArray filenames;
|
||||
char saveDesc[32];
|
||||
Common::String pattern("queen.s##");
|
||||
|
||||
filenames = saveFileMan->listSavefiles(pattern);
|
||||
|
||||
SaveStateList saveList;
|
||||
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
|
||||
// Obtain the last 2 digits of the filename, since they correspond to the save slot
|
||||
int slotNum = atoi(file->c_str() + file->size() - 2);
|
||||
|
||||
if (slotNum >= 0 && slotNum <= 99) {
|
||||
Common::InSaveFile *in = saveFileMan->openForLoading(*file);
|
||||
if (in) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
in->readUint32BE();
|
||||
in->read(saveDesc, 32);
|
||||
saveList.push_back(SaveStateDescriptor(this, slotNum, saveDesc));
|
||||
delete in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort saves based on slot number.
|
||||
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
|
||||
return saveList;
|
||||
}
|
||||
|
||||
bool QueenMetaEngine::removeSaveState(const char *target, int slot) const {
|
||||
Common::String filename = Common::String::format("queen.s%02d", slot);
|
||||
|
||||
return g_system->getSavefileManager()->removeSavefile(filename);
|
||||
}
|
||||
|
||||
Common::Error QueenMetaEngine::createInstance(OSystem *syst, Engine **engine, const Queen::QueenGameDescription *desc) const {
|
||||
*engine = new Queen::QueenEngine(syst); //FIXME ,desc);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
static const char *const CommandKeys[] = {
|
||||
"ocmglptu", // English
|
||||
"osbgpnre", // German
|
||||
"ofdnepau", // French
|
||||
"acsdgpqu", // Italian
|
||||
"ocmglptu", // Hebrew
|
||||
"acodmthu" // Spanish
|
||||
};
|
||||
|
||||
const char *CurrentCommandKeys;
|
||||
|
||||
Common::KeymapArray QueenMetaEngine::initKeymaps(const char *target) const {
|
||||
using namespace Common;
|
||||
using namespace Queen;
|
||||
|
||||
Keymap *engineKeymap = new Keymap(Keymap::kKeymapTypeGame, "queen-default", _("Default keymappings"));
|
||||
Keymap *gameKeymap = new Keymap(Keymap::kKeymapTypeGame, "game-shortcuts", _("Game keymappings"));
|
||||
Keymap *journalKeymap = new Keymap(Keymap::kKeymapTypeGame, "journal", _("Journal keymappings"));
|
||||
|
||||
Action *act;
|
||||
|
||||
Language language = parseLanguage(ConfMan.get("language"));
|
||||
|
||||
switch (language) {
|
||||
case EN_ANY:
|
||||
case EL_GRC:
|
||||
case RU_RUS:
|
||||
CurrentCommandKeys = CommandKeys[0];
|
||||
break;
|
||||
case DE_DEU:
|
||||
CurrentCommandKeys = CommandKeys[1];
|
||||
break;
|
||||
case FR_FRA:
|
||||
CurrentCommandKeys = CommandKeys[2];
|
||||
break;
|
||||
case IT_ITA:
|
||||
CurrentCommandKeys = CommandKeys[3];
|
||||
break;
|
||||
case HE_ISR:
|
||||
CurrentCommandKeys = CommandKeys[4];
|
||||
break;
|
||||
case ES_ESP:
|
||||
CurrentCommandKeys = CommandKeys[5];
|
||||
break;
|
||||
default:
|
||||
error("Unknown language");
|
||||
break;
|
||||
}
|
||||
|
||||
act = new Action(kStandardActionLeftClick, _("Move / Interact"));
|
||||
act->setLeftClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_LEFT");
|
||||
act->addDefaultInputMapping("JOY_A");
|
||||
engineKeymap->addAction(act);
|
||||
|
||||
act = new Action(kStandardActionRightClick, _("Move / Skip / Use default action with inventory item"));
|
||||
act->setRightClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_RIGHT");
|
||||
act->addDefaultInputMapping("JOY_B");
|
||||
engineKeymap->addAction(act);
|
||||
|
||||
act = new Action("FASTMODE", _("Toggle fast mode"));
|
||||
act->setCustomEngineActionEvent(kActionFastMode);
|
||||
act->addDefaultInputMapping("C+f");
|
||||
act->addDefaultInputMapping("JOY_Y");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("SKIPTEXT", _("Skip text"));
|
||||
act->setCustomEngineActionEvent(kActionSkipText);
|
||||
act->addDefaultInputMapping("SPACE");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("INVSCROLLUP", _("Scroll inventory up"));
|
||||
act->setCustomEngineActionEvent(kActionScrollUp);
|
||||
act->addDefaultInputMapping("COMMA");
|
||||
act->addDefaultInputMapping("JOY_UP");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("INVSCROLLDOWN", _("Scroll inventory down"));
|
||||
act->setCustomEngineActionEvent(kActionScrollDown);
|
||||
act->addDefaultInputMapping("PERIOD");
|
||||
act->addDefaultInputMapping("JOY_DOWN");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("INVITEM1", _("Inventory item 1"));
|
||||
act->setCustomEngineActionEvent(kActionInvSlot1);
|
||||
act->addDefaultInputMapping("1");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("INVITEM2", _("Inventory item 2"));
|
||||
act->setCustomEngineActionEvent(kActionInvSlot2);
|
||||
act->addDefaultInputMapping("2");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("INVITEM3", _("Inventory item 3"));
|
||||
act->setCustomEngineActionEvent(kActionInvSlot3);
|
||||
act->addDefaultInputMapping("3");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("INVITEM4", _("Inventory item 4"));
|
||||
act->setCustomEngineActionEvent(kActionInvSlot4);
|
||||
act->addDefaultInputMapping("4");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("SKIPCUTAWAY", _("Skip cutaway / dialog"));
|
||||
act->setCustomEngineActionEvent(kActionSkipCutaway);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("USEJOURNAL", _("Use journal"));
|
||||
act->setCustomEngineActionEvent(kActionJournal);
|
||||
act->addDefaultInputMapping("F1");
|
||||
act->addDefaultInputMapping("F5");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("QUICKSAVE", _("Quick save"));
|
||||
act->setCustomEngineActionEvent(kActionSave);
|
||||
act->addDefaultInputMapping("F11");
|
||||
act->addDefaultInputMapping("JOY_LEFT_TRIGGER");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("QUICKLOAD", _("Quick load"));
|
||||
act->setCustomEngineActionEvent(kActionLoad);
|
||||
act->addDefaultInputMapping("F12");
|
||||
act->addDefaultInputMapping("JOY_RIGHT_TRIGGER");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("OPEN", _("Open"));
|
||||
act->setCustomEngineActionEvent(kActionOpen);
|
||||
act->addDefaultInputMapping(String(CurrentCommandKeys[0]));
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("CLOSE", _("Close"));
|
||||
act->setCustomEngineActionEvent(kActionClose);
|
||||
act->addDefaultInputMapping(String(CurrentCommandKeys[1]));
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("MOVE", _("Move"));
|
||||
act->setCustomEngineActionEvent(kActionMove);
|
||||
act->addDefaultInputMapping(String(CurrentCommandKeys[2]));
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("GIVE", _("Give"));
|
||||
act->setCustomEngineActionEvent(kActionGive);
|
||||
act->addDefaultInputMapping(String(CurrentCommandKeys[3]));
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("LOOK", _("Look at"));
|
||||
act->setCustomEngineActionEvent(kActionLook);
|
||||
act->addDefaultInputMapping(String(CurrentCommandKeys[4]));
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("PICKUP", _("Pick up"));
|
||||
act->setCustomEngineActionEvent(kActionPickUp);
|
||||
act->addDefaultInputMapping(String(CurrentCommandKeys[5]));
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("TALK", _("Talk to"));
|
||||
act->setCustomEngineActionEvent(kActionTalk);
|
||||
act->addDefaultInputMapping(String(CurrentCommandKeys[6]));
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("USE", _("Use"));
|
||||
act->setCustomEngineActionEvent(kActionUse);
|
||||
act->addDefaultInputMapping(String(CurrentCommandKeys[7]));
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Action("CLOSE", _("Close journal"));
|
||||
act->setCustomEngineActionEvent(kActionCloseJournal);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
journalKeymap->addAction(act);
|
||||
|
||||
KeymapArray keymaps(3);
|
||||
|
||||
keymaps[0] = engineKeymap;
|
||||
keymaps[1] = gameKeymap;
|
||||
keymaps[2] = journalKeymap;
|
||||
|
||||
journalKeymap->setEnabled(false);
|
||||
|
||||
return keymaps;
|
||||
}
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(QUEEN)
|
||||
REGISTER_PLUGIN_DYNAMIC(QUEEN, PLUGIN_TYPE_ENGINE, QueenMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(QUEEN, PLUGIN_TYPE_ENGINE, QueenMetaEngine);
|
||||
#endif
|
||||
|
||||
544
engines/queen/midiadlib.cpp
Normal file
544
engines/queen/midiadlib.cpp
Normal file
@@ -0,0 +1,544 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "engines/queen/midiadlib.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
int AdLibMidiDriver::open() {
|
||||
_isOpen = true;
|
||||
_opl = OPL::Config::create();
|
||||
if (!_opl || !_opl->init())
|
||||
error("Failed to create OPL");
|
||||
|
||||
adlibSetupCard();
|
||||
for (int i = 0; i < 11; ++i) {
|
||||
_adlibChannelsVolume[i] = 0;
|
||||
adlibSetNoteVolume(i, 0);
|
||||
adlibTurnNoteOff(i);
|
||||
}
|
||||
|
||||
_opl->start(new Common::Functor0Mem<void, AdLibMidiDriver>(this, &AdLibMidiDriver::onTimer));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::close() {
|
||||
delete _opl;
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::send(uint32 b) {
|
||||
int channel = b & 15;
|
||||
int cmd = (b >> 4) & 7;
|
||||
int param1 = (b >> 8) & 255;
|
||||
int param2 = (b >> 16) & 255;
|
||||
switch (cmd) {
|
||||
case 0:
|
||||
adlibTurnNoteOff(channel);
|
||||
break;
|
||||
case 1:
|
||||
handleMidiEvent0x90_NoteOn(channel, param1, param2);
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 5:
|
||||
adlibSetNoteVolume(channel, param1);
|
||||
_adlibChannelsVolume[channel] = param1;
|
||||
break;
|
||||
case 6:
|
||||
adlibSetPitchBend(channel, param1 | (param2 << 7));
|
||||
break;
|
||||
default:
|
||||
// warning("Unhandled cmd %d channel %d (0x%X)", cmd, channel, b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::setVolume(uint32 volume) {
|
||||
for (int i = 0; i < _midiNumberOfChannels; ++i)
|
||||
adlibSetChannelVolume(i, volume * 64 / 256 + 64);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::metaEvent(byte type, const byte *data, uint16 length) {
|
||||
int event = 0;
|
||||
if (length > 4 && READ_BE_UINT32(data) == 0x3F00) {
|
||||
event = data[4];
|
||||
switch (event) {
|
||||
case 1:
|
||||
if (length == 34) {
|
||||
handleSequencerSpecificMetaEvent1(data[5], data + 6);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (length == 6) {
|
||||
handleSequencerSpecificMetaEvent2(data[5]);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (length == 6) {
|
||||
handleSequencerSpecificMetaEvent3(data[5]);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
warning("Unhandled meta event %d len %d", event, length);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
|
||||
_adlibTimerProc = timerProc;
|
||||
_adlibTimerParam = timerParam;
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::onTimer() {
|
||||
if (_adlibTimerProc)
|
||||
(*_adlibTimerProc)(_adlibTimerParam);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::handleSequencerSpecificMetaEvent1(int channel, const uint8 *data) {
|
||||
for (int i = 0; i < 28; ++i) {
|
||||
_adlibMetaSequenceData[i] = data[i];
|
||||
}
|
||||
if (_midiNumberOfChannels > channel) {
|
||||
const uint8 *p;
|
||||
if (_adlibRhythmEnabled) {
|
||||
p = &_adlibChannelsKeyScalingTable2[channel * 2];
|
||||
} else {
|
||||
p = &_adlibChannelsKeyScalingTable1[channel * 2];
|
||||
}
|
||||
adlibSetupChannel(p[0], _adlibMetaSequenceData, _adlibMetaSequenceData[26]);
|
||||
if (p[1] != 255) {
|
||||
adlibSetupChannel(p[1], _adlibMetaSequenceData + 13, _adlibMetaSequenceData[27]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::handleSequencerSpecificMetaEvent2(uint8 value) {
|
||||
_adlibRhythmEnabled = value;
|
||||
_midiNumberOfChannels = _adlibRhythmEnabled ? 11 : 9;
|
||||
adlibSetAmpVibratoRhythm();
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::handleSequencerSpecificMetaEvent3(uint8 value) {
|
||||
adlibSetNoteMul(value);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::handleMidiEvent0x90_NoteOn(int channel, int param1, int param2) { // note, volume
|
||||
if (param2 == 0) {
|
||||
adlibTurnNoteOff(channel);
|
||||
_adlibChannelsVolume[channel] = param2;
|
||||
} else {
|
||||
adlibSetNoteVolume(channel, param2);
|
||||
_adlibChannelsVolume[channel] = param2;
|
||||
adlibTurnNoteOff(channel);
|
||||
adlibTurnNoteOn(channel, param1);
|
||||
}
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibWrite(uint8 port, uint8 value) {
|
||||
_opl->writeReg(port, value);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetupCard() {
|
||||
for (int i = 1; i <= 0xF5; ++i) {
|
||||
adlibWrite(i, 0);
|
||||
}
|
||||
adlibWrite(4, 6);
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
_midiChannelsNote2Table[i] = 8192;
|
||||
_midiChannelsOctTable[i] = 0;
|
||||
_midiChannelsNote1Table[i] = 0;
|
||||
_midiChannelsFreqTable[i] = 0;
|
||||
}
|
||||
memset(_adlibChannelsLevelKeyScalingTable, 127, 11);
|
||||
memset(_adlibChannelsVolumeTable, 128, 11);
|
||||
adlibSetupChannels(0);
|
||||
adlibResetAmpVibratoRhythm(0, 0, 0);
|
||||
adlibSetNoteMul(1);
|
||||
adlibSetWaveformSelect(1);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetupChannels(int fl) {
|
||||
if (fl != 0) {
|
||||
_midiChannelsNote1Table[8] = 24;
|
||||
_midiChannelsNote2Table[8] = 8192;
|
||||
adlibPlayNote(8);
|
||||
_midiChannelsNote1Table[7] = 31;
|
||||
_midiChannelsNote2Table[7] = 8192;
|
||||
adlibPlayNote(7);
|
||||
}
|
||||
_adlibRhythmEnabled = fl;
|
||||
_midiNumberOfChannels = fl ? 11 : 9;
|
||||
_adlibVibratoRhythm = 0;
|
||||
_adlibAMDepthEq48 = 0;
|
||||
_adlibVibratoDepthEq14 = 0;
|
||||
_adlibKeyboardSplitOn = 0;
|
||||
adlibResetChannels();
|
||||
adlibSetAmpVibratoRhythm();
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibResetAmpVibratoRhythm(int am, int vib, int kso) {
|
||||
_adlibAMDepthEq48 = am;
|
||||
_adlibVibratoDepthEq14 = vib;
|
||||
_adlibKeyboardSplitOn = kso;
|
||||
adlibSetAmpVibratoRhythm();
|
||||
adlibSetCSMKeyboardSplit();
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibResetChannels() {
|
||||
for (int i = 0; i < 18; ++i) {
|
||||
adlibSetupChannelFromSequence(i, _adlibChannelsNoFeedback[i] ? _adlibInitSequenceData2 : _adlibInitSequenceData1, 0);
|
||||
}
|
||||
if (_adlibRhythmEnabled) {
|
||||
adlibSetupChannelFromSequence(12, _adlibInitSequenceData3, 0);
|
||||
adlibSetupChannelFromSequence(15, _adlibInitSequenceData4, 0);
|
||||
adlibSetupChannelFromSequence(16, _adlibInitSequenceData5, 0);
|
||||
adlibSetupChannelFromSequence(14, _adlibInitSequenceData6, 0);
|
||||
adlibSetupChannelFromSequence(17, _adlibInitSequenceData7, 0);
|
||||
adlibSetupChannelFromSequence(13, _adlibInitSequenceData8, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetAmpVibratoRhythm() {
|
||||
uint8 value = 0;
|
||||
if (_adlibAMDepthEq48) {
|
||||
value |= 0x80;
|
||||
}
|
||||
if (_adlibVibratoDepthEq14) {
|
||||
value |= 0x40;
|
||||
}
|
||||
if (_adlibRhythmEnabled) {
|
||||
value |= 0x20;
|
||||
}
|
||||
adlibWrite(0xBD, value | _adlibVibratoRhythm);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetCSMKeyboardSplit() {
|
||||
uint8 value = _adlibKeyboardSplitOn ? 0x40 : 0;
|
||||
adlibWrite(8, value);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetNoteMul(int mul) {
|
||||
if (mul > 12) {
|
||||
mul = 12;
|
||||
} else if (mul < 1) {
|
||||
mul = 1;
|
||||
}
|
||||
_adlibNoteMul = mul;
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetWaveformSelect(int fl) {
|
||||
_adlibWaveformSelect = fl ? 0x20 : 0;
|
||||
for (int i = 0; i < 18; ++i) {
|
||||
adlibWrite(0xE0 + _adlibChannelsMappingTable1[i], 0);
|
||||
}
|
||||
adlibWrite(1, _adlibWaveformSelect);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetPitchBend(int channel, int range) {
|
||||
if ((_adlibRhythmEnabled && channel <= 6) || channel < 9) {
|
||||
if (range > 16383) {
|
||||
range = 16383;
|
||||
}
|
||||
_midiChannelsNote2Table[channel] = range;
|
||||
adlibPlayNote(channel);
|
||||
}
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibPlayNote(int channel) {
|
||||
_midiChannelsFreqTable[channel] = adlibPlayNoteHelper(channel, _midiChannelsNote1Table[channel], _midiChannelsNote2Table[channel], _midiChannelsOctTable[channel]);
|
||||
}
|
||||
|
||||
uint8 AdLibMidiDriver::adlibPlayNoteHelper(int channel, int note1, int note2, int oct) {
|
||||
int n = ((note2 * _midiChannelsNoteTable[channel]) >> 8) - 8192;
|
||||
if (n != 0) {
|
||||
n >>= 5;
|
||||
n *= _adlibNoteMul;
|
||||
}
|
||||
n += (note1 << 8) + 8;
|
||||
n >>= 4;
|
||||
if (n < 0) {
|
||||
n = 0;
|
||||
} else if (n > 1535) {
|
||||
n = 1535;
|
||||
}
|
||||
int index = (((n >> 4) % 12) << 4) | (n & 0xF);
|
||||
int f = _midiNoteFreqTable[index];
|
||||
int o = (n >> 4) / 12 - 1;
|
||||
if (f < 0) {
|
||||
++o;
|
||||
}
|
||||
if (o < 0) {
|
||||
++o;
|
||||
f >>= 1;
|
||||
}
|
||||
adlibWrite(0xA0 + channel, f & 0xFF);
|
||||
int value = ((f >> 8) & 3) | (o << 2) | oct;
|
||||
adlibWrite(0xB0 + channel, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibTurnNoteOff(int channel) {
|
||||
if ((_adlibRhythmEnabled && channel <= 6) || channel < 9) {
|
||||
_midiChannelsOctTable[channel] = 0;
|
||||
_midiChannelsFreqTable[channel] &= ~0x20;
|
||||
adlibWrite(0xB0 + channel, _midiChannelsFreqTable[channel]);
|
||||
} else if (_adlibRhythmEnabled && channel <= 10) {
|
||||
_adlibVibratoRhythm &= ~(1 << (4 - (channel - 6)));
|
||||
adlibSetAmpVibratoRhythm();
|
||||
}
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibTurnNoteOn(int channel, int note) {
|
||||
note -= 12;
|
||||
if (note < 0) {
|
||||
note = 0;
|
||||
}
|
||||
if ((_adlibRhythmEnabled && channel <= 6) || channel < 9) {
|
||||
_midiChannelsNote1Table[channel] = note;
|
||||
_midiChannelsOctTable[channel] = 0x20;
|
||||
adlibPlayNote(channel);
|
||||
} else if (_adlibRhythmEnabled && channel <= 10) {
|
||||
if (channel == 6) {
|
||||
_midiChannelsNote1Table[6] = note;
|
||||
adlibPlayNote(channel);
|
||||
} else if (channel == 8 && _midiChannelsNote1Table[8] == note) {
|
||||
_midiChannelsNote1Table[8] = note;
|
||||
_midiChannelsNote1Table[7] = note + 7;
|
||||
adlibPlayNote(8);
|
||||
adlibPlayNote(7);
|
||||
}
|
||||
_adlibVibratoRhythm = 1 << (4 - (channel - 6));
|
||||
adlibSetAmpVibratoRhythm();
|
||||
}
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetupChannelFromSequence(int channel, const uint8 *src, int fl) {
|
||||
for (int i = 0; i < 13; ++i) {
|
||||
_adlibSetupChannelSequence2[i] = src[i];
|
||||
}
|
||||
adlibSetupChannel(channel, _adlibSetupChannelSequence2, fl);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetupChannel(int channel, const uint16 *src, int fl) {
|
||||
for (int i = 0; i < 13; ++i) {
|
||||
_adlibSetupChannelSequence1[14 * channel + i] = src[i];
|
||||
}
|
||||
_adlibSetupChannelSequence1[14 * channel + 13] = fl & 3;
|
||||
adlibSetupChannelHelper(channel);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetNoteVolume(int channel, int volume) {
|
||||
if (_midiNumberOfChannels > channel) {
|
||||
if (volume > 127) {
|
||||
volume = 127;
|
||||
}
|
||||
_adlibChannelsLevelKeyScalingTable[channel] = volume;
|
||||
const uint8 *p;
|
||||
if (_adlibRhythmEnabled) {
|
||||
p = &_adlibChannelsKeyScalingTable2[channel * 2];
|
||||
} else {
|
||||
p = &_adlibChannelsKeyScalingTable1[channel * 2];
|
||||
}
|
||||
adlibSetChannel0x40(p[0]);
|
||||
if (p[1] != 255) {
|
||||
adlibSetChannel0x40(p[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetChannelVolume(int channel, uint8 volume) {
|
||||
if (channel < (_adlibRhythmEnabled ? 11 : 9))
|
||||
_adlibChannelsVolumeTable[channel] = volume;
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetupChannelHelper(int channel) {
|
||||
adlibSetAmpVibratoRhythm();
|
||||
adlibSetCSMKeyboardSplit();
|
||||
adlibSetChannel0x40(channel);
|
||||
adlibSetChannel0xC0(channel);
|
||||
adlibSetChannel0x60(channel);
|
||||
adlibSetChannel0x80(channel);
|
||||
adlibSetChannel0x20(channel);
|
||||
adlibSetChannel0xE0(channel);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetChannel0x40(int channel) {
|
||||
int index, value, fl;
|
||||
|
||||
if (_adlibRhythmEnabled) {
|
||||
index = _adlibChannelsMappingTable3[channel];
|
||||
} else {
|
||||
index = _adlibChannelsMappingTable2[channel];
|
||||
}
|
||||
value = 63 - (_adlibSetupChannelSequence1[channel * 14 + 8] & 63);
|
||||
fl = 0;
|
||||
if (_adlibRhythmEnabled && index > 6) {
|
||||
fl = -1;
|
||||
}
|
||||
if (_adlibChannelsNoFeedback[channel] || _adlibSetupChannelSequence1[channel * 14 + 12] == 0 || fl != 0) {
|
||||
value = ((_adlibChannelsLevelKeyScalingTable[index] * value) + 64) >> 7;
|
||||
}
|
||||
value = (_adlibChannelsVolumeTable[index] * value * 2) >> 8;
|
||||
if (value > 63) {
|
||||
value = 63;
|
||||
}
|
||||
value = 63 - value;
|
||||
value |= _adlibSetupChannelSequence1[channel * 14] << 6;
|
||||
adlibWrite(0x40 + _adlibChannelsMappingTable1[channel], value);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetChannel0xC0(int channel) {
|
||||
if (_adlibChannelsNoFeedback[channel] == 0) {
|
||||
const uint8 *p = &_adlibSetupChannelSequence1[channel * 14];
|
||||
uint8 value = p[2] << 1;
|
||||
if (p[12] == 0) {
|
||||
value |= 1;
|
||||
}
|
||||
adlibWrite(0xC0 + _adlibChannelsMappingTable2[channel], value);
|
||||
}
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetChannel0x60(int channel) {
|
||||
const uint8 *p = &_adlibSetupChannelSequence1[channel * 14];
|
||||
uint8 value = (p[3] << 4) | (p[6] & 15);
|
||||
adlibWrite(0x60 + _adlibChannelsMappingTable1[channel], value);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetChannel0x80(int channel) {
|
||||
const uint8 *p = &_adlibSetupChannelSequence1[channel * 14];
|
||||
uint8 value = (p[4] << 4) | (p[7] & 15);
|
||||
adlibWrite(0x80 + _adlibChannelsMappingTable1[channel], value);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetChannel0x20(int channel) {
|
||||
const uint8 *p = &_adlibSetupChannelSequence1[channel * 14];
|
||||
uint8 value = p[1] & 15;
|
||||
if (p[9]) {
|
||||
value |= 0x80;
|
||||
}
|
||||
if (p[10]) {
|
||||
value |= 0x40;
|
||||
}
|
||||
if (p[5]) {
|
||||
value |= 0x20;
|
||||
}
|
||||
if (p[11]) {
|
||||
value |= 0x10;
|
||||
}
|
||||
adlibWrite(0x20 + _adlibChannelsMappingTable1[channel], value);
|
||||
}
|
||||
|
||||
void AdLibMidiDriver::adlibSetChannel0xE0(int channel) {
|
||||
uint8 value = 0;
|
||||
if (_adlibWaveformSelect) {
|
||||
const uint8 *p = &_adlibSetupChannelSequence1[channel * 14];
|
||||
value = p[13] & 3;
|
||||
}
|
||||
adlibWrite(0xE0 + _adlibChannelsMappingTable1[channel], value);
|
||||
}
|
||||
|
||||
const uint8 AdLibMidiDriver::_adlibChannelsMappingTable1[] = {
|
||||
0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21
|
||||
};
|
||||
|
||||
const uint8 AdLibMidiDriver::_adlibChannelsNoFeedback[] = {
|
||||
0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1
|
||||
};
|
||||
|
||||
const uint8 AdLibMidiDriver::_adlibChannelsMappingTable2[] = {
|
||||
0, 1, 2, 0, 1, 2, 3, 4, 5, 3, 4, 5, 6, 7, 8, 6, 7, 8
|
||||
};
|
||||
|
||||
const uint8 AdLibMidiDriver::_adlibChannelsMappingTable3[] = {
|
||||
0, 1, 2, 0, 1, 2, 3, 4, 5, 3, 4, 5, 6, 10, 8, 6, 7, 9
|
||||
};
|
||||
|
||||
const uint8 AdLibMidiDriver::_adlibChannelsKeyScalingTable1[] = {
|
||||
0, 3, 1, 4, 2, 5, 6, 9, 7, 10, 8, 11, 12, 15, 13, 16, 14, 17
|
||||
};
|
||||
|
||||
const uint8 AdLibMidiDriver::_adlibChannelsKeyScalingTable2[] = {
|
||||
0, 3, 1, 4, 2, 5, 6, 9, 7, 10, 8, 11, 12, 15, 16, 255, 14, 255, 17, 255, 13, 255
|
||||
};
|
||||
|
||||
const uint8 AdLibMidiDriver::_adlibInitSequenceData1[] = {
|
||||
1, 1, 3, 15, 5, 0, 1, 3, 15, 0, 0, 0, 1, 0
|
||||
};
|
||||
|
||||
const uint8 AdLibMidiDriver::_adlibInitSequenceData2[] = {
|
||||
0, 1, 1, 15, 7, 0, 2, 4, 0, 0, 0, 1, 0, 0
|
||||
};
|
||||
|
||||
const uint8 AdLibMidiDriver::_adlibInitSequenceData3[] = {
|
||||
0, 0, 0, 10, 4, 0, 8, 12, 11, 0, 0, 0, 1, 0
|
||||
};
|
||||
|
||||
const uint8 AdLibMidiDriver::_adlibInitSequenceData4[] = {
|
||||
0, 0, 0, 13, 4, 0, 6, 15, 0, 0, 0, 0, 1, 0
|
||||
};
|
||||
|
||||
const uint8 AdLibMidiDriver::_adlibInitSequenceData5[] = {
|
||||
0, 12, 0, 15, 11, 0, 8, 5, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
const uint8 AdLibMidiDriver::_adlibInitSequenceData6[] = {
|
||||
0, 4, 0, 15, 11, 0, 7, 5, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
const uint8 AdLibMidiDriver::_adlibInitSequenceData7[] = {
|
||||
0, 1, 0, 15, 11, 0, 5, 5, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
const uint8 AdLibMidiDriver::_adlibInitSequenceData8[] = {
|
||||
0, 1, 0, 15, 11, 0, 7, 5, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
const int16 AdLibMidiDriver::_midiChannelsNoteTable[] = {
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256
|
||||
};
|
||||
|
||||
const int16 AdLibMidiDriver::_midiNoteFreqTable[] = {
|
||||
690, 692, 695, 697, 700, 702, 705, 707, 710, 713, 715, 718,
|
||||
720, 723, 726, 728, 731, 733, 736, 739, 741, 744, 747, 749,
|
||||
752, 755, 758, 760, 763, 766, 769, 771, 774, 777, 780, 783,
|
||||
785, 788, 791, 794, 797, 800, 803, 806, 809, 811, 814, 817,
|
||||
820, 823, 826, 829, 832, 835, 838, 841, 844, 847, 850, 854,
|
||||
857, 860, 863, 866, 869, 872, 875, 879, 882, 885, 888, 891,
|
||||
895, 898, 901, 904, 908, 911, 914, 917, 921, 924, 927, 931,
|
||||
934, 937, 941, 944, 948, 951, 955, 958, 961, 965, 968, 972,
|
||||
975, 979, 983, 986, 990, 993, 997, 1000, 1004, 1008, 1011, 1015,
|
||||
1019, 1022, -511, -509, -507, -505, -504, -502, -500, -498, -496, -494,
|
||||
-492, -490, -488, -486, -484, -482, -480, -479, -477, -475, -473, -471,
|
||||
-469, -467, -465, -463, -460, -458, -456, -454, -452, -450, -448, -446,
|
||||
-444, -442, -440, -438, -436, -433, -431, -429, -427, -425, -423, -420,
|
||||
-418, -416, -414, -412, -409, -407, -405, -403, -401, -398, -396, -394,
|
||||
-391, -389, -387, -385, -382, -380, -378, -375, -373, -371, -368, -366,
|
||||
-363, -361, -359, -356, -354, -351, -349, -347, -344, -342, -339, -337
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
127
engines/queen/midiadlib.h
Normal file
127
engines/queen/midiadlib.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/* 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 "audio/fmopl.h"
|
||||
#include "audio/mididrv.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
class AdLibMidiDriver : public MidiDriver {
|
||||
public:
|
||||
|
||||
AdLibMidiDriver() {
|
||||
_adlibWaveformSelect = 0;
|
||||
_isOpen = false;
|
||||
}
|
||||
|
||||
~AdLibMidiDriver() override {}
|
||||
|
||||
// MidiDriver
|
||||
int open() override;
|
||||
void close() override;
|
||||
void send(uint32 b) override;
|
||||
void metaEvent(byte type, const byte *data, uint16 length) override;
|
||||
MidiChannel *allocateChannel() override { return 0; }
|
||||
MidiChannel *getPercussionChannel() override { return 0; }
|
||||
void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) override;
|
||||
bool isOpen() const override { return _isOpen; }
|
||||
uint32 getBaseTempo() override { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
|
||||
|
||||
void setVolume(uint32 volume);
|
||||
|
||||
private:
|
||||
|
||||
void handleMidiEvent0x90_NoteOn(int channel, int param1, int param2);
|
||||
void handleSequencerSpecificMetaEvent1(int channel, const uint8 *data);
|
||||
void handleSequencerSpecificMetaEvent2(uint8 value);
|
||||
void handleSequencerSpecificMetaEvent3(uint8 value);
|
||||
|
||||
void adlibWrite(uint8 port, uint8 value);
|
||||
void adlibSetupCard();
|
||||
void adlibSetupChannels(int fl);
|
||||
void adlibResetAmpVibratoRhythm(int am, int vib, int kso);
|
||||
void adlibResetChannels();
|
||||
void adlibSetAmpVibratoRhythm();
|
||||
void adlibSetCSMKeyboardSplit();
|
||||
void adlibSetNoteMul(int mul);
|
||||
void adlibSetWaveformSelect(int fl);
|
||||
void adlibSetPitchBend(int channel, int range);
|
||||
void adlibPlayNote(int channel);
|
||||
uint8 adlibPlayNoteHelper(int channel, int note1, int note2, int oct);
|
||||
void adlibTurnNoteOff(int channel);
|
||||
void adlibTurnNoteOn(int channel, int note);
|
||||
void adlibSetupChannelFromSequence(int channel, const uint8 *src, int fl);
|
||||
void adlibSetupChannel(int channel, const uint16 *src, int fl);
|
||||
void adlibSetNoteVolume(int channel, int volume);
|
||||
void adlibSetChannelVolume(int channel, uint8 volume);
|
||||
void adlibSetupChannelHelper(int channel);
|
||||
void adlibSetChannel0x40(int channel);
|
||||
void adlibSetChannel0xC0(int channel);
|
||||
void adlibSetChannel0x60(int channel);
|
||||
void adlibSetChannel0x80(int channel);
|
||||
void adlibSetChannel0x20(int channel);
|
||||
void adlibSetChannel0xE0(int channel);
|
||||
|
||||
void onTimer();
|
||||
|
||||
OPL::OPL *_opl;
|
||||
int _midiNumberOfChannels;
|
||||
int _adlibNoteMul;
|
||||
int _adlibWaveformSelect;
|
||||
int _adlibAMDepthEq48;
|
||||
int _adlibVibratoDepthEq14;
|
||||
int _adlibRhythmEnabled;
|
||||
int _adlibKeyboardSplitOn;
|
||||
int _adlibVibratoRhythm;
|
||||
uint8 _midiChannelsFreqTable[9];
|
||||
uint8 _adlibChannelsLevelKeyScalingTable[11];
|
||||
uint8 _adlibSetupChannelSequence1[14 * 18];
|
||||
uint16 _adlibSetupChannelSequence2[14];
|
||||
int16 _midiChannelsNote2Table[9];
|
||||
uint8 _midiChannelsNote1Table[9];
|
||||
uint8 _midiChannelsOctTable[9];
|
||||
uint16 _adlibChannelsVolume[11];
|
||||
uint16 _adlibMetaSequenceData[28];
|
||||
uint8 _adlibChannelsVolumeTable[11];
|
||||
|
||||
bool _isOpen;
|
||||
Common::TimerManager::TimerProc _adlibTimerProc;
|
||||
void *_adlibTimerParam;
|
||||
|
||||
static const uint8 _adlibChannelsMappingTable1[];
|
||||
static const uint8 _adlibChannelsNoFeedback[];
|
||||
static const uint8 _adlibChannelsMappingTable2[];
|
||||
static const uint8 _adlibChannelsMappingTable3[];
|
||||
static const uint8 _adlibChannelsKeyScalingTable1[];
|
||||
static const uint8 _adlibChannelsKeyScalingTable2[];
|
||||
static const uint8 _adlibInitSequenceData1[];
|
||||
static const uint8 _adlibInitSequenceData2[];
|
||||
static const uint8 _adlibInitSequenceData3[];
|
||||
static const uint8 _adlibInitSequenceData4[];
|
||||
static const uint8 _adlibInitSequenceData5[];
|
||||
static const uint8 _adlibInitSequenceData6[];
|
||||
static const uint8 _adlibInitSequenceData7[];
|
||||
static const uint8 _adlibInitSequenceData8[];
|
||||
static const int16 _midiChannelsNoteTable[];
|
||||
static const int16 _midiNoteFreqTable[];
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
44
engines/queen/module.mk
Normal file
44
engines/queen/module.mk
Normal file
@@ -0,0 +1,44 @@
|
||||
MODULE := engines/queen
|
||||
|
||||
MODULE_OBJS := \
|
||||
bankman.o \
|
||||
command.o \
|
||||
credits.o \
|
||||
cutaway.o \
|
||||
debug.o \
|
||||
display.o \
|
||||
graphics.o \
|
||||
grid.o \
|
||||
input.o \
|
||||
journal.o \
|
||||
logic.o \
|
||||
metaengine.o \
|
||||
midiadlib.o \
|
||||
music.o \
|
||||
musicdata.o \
|
||||
queen.o \
|
||||
resource.o \
|
||||
restables.o \
|
||||
sound.o \
|
||||
state.o \
|
||||
talk.o \
|
||||
version.o \
|
||||
walk.o
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_QUEEN), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objecs
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
|
||||
# Skip building the following objects if a static
|
||||
# module is enabled, because it already has the contents.
|
||||
ifneq ($(ENABLE_QUEEN), STATIC_PLUGIN)
|
||||
# External dependencies for detection.
|
||||
DETECT_OBJS += $(MODULE)/version.o
|
||||
endif
|
||||
370
engines/queen/music.cpp
Normal file
370
engines/queen/music.cpp
Normal file
@@ -0,0 +1,370 @@
|
||||
/* 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 "common/config-manager.h"
|
||||
#include "common/events.h"
|
||||
|
||||
#include "queen/midiadlib.h"
|
||||
#include "queen/music.h"
|
||||
#include "queen/queen.h"
|
||||
#include "queen/resource.h"
|
||||
#include "queen/sound.h"
|
||||
|
||||
#include "audio/midiparser.h"
|
||||
|
||||
|
||||
namespace Queen {
|
||||
|
||||
MidiMusic::MidiMusic(QueenEngine *vm)
|
||||
: _isPlaying(false), _isLooping(false),
|
||||
_randomLoop(false), _masterVolume(192),
|
||||
_buf(nullptr), _rnd("queenMusic") {
|
||||
|
||||
memset(_channelsTable, 0, sizeof(_channelsTable));
|
||||
_queuePos = _lastSong = _currentSong = 0;
|
||||
queueClear();
|
||||
|
||||
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MT32);
|
||||
_adlib = (MidiDriver::getMusicType(dev) == MT_ADLIB);
|
||||
_nativeMT32 = ((MidiDriver::getMusicType(dev) == MT_MT32) || ConfMan.getBool("native_mt32"));
|
||||
|
||||
const char *musicDataFile;
|
||||
if (vm->resource()->isDemo()) {
|
||||
_tune = Sound::_tuneDemo;
|
||||
musicDataFile = "AQ8.RL";
|
||||
} else {
|
||||
_tune = Sound::_tune;
|
||||
musicDataFile = "AQ.RL";
|
||||
}
|
||||
if (_adlib) {
|
||||
musicDataFile = "AQBANK.MUS";
|
||||
}
|
||||
_musicData = vm->resource()->loadFile(musicDataFile, 0, &_musicDataSize);
|
||||
_numSongs = READ_LE_UINT16(_musicData);
|
||||
|
||||
_tune = vm->resource()->isDemo() ? Sound::_tuneDemo : Sound::_tune;
|
||||
|
||||
if (_adlib) {
|
||||
// int infoOffset = _numSongs * 4 + 2;
|
||||
// if (READ_LE_UINT16(_musicData + 2) != infoOffset) {
|
||||
// defaultAdLibVolume = _musicData[infoOffset];
|
||||
// }
|
||||
_driver = new AdLibMidiDriver();
|
||||
} else {
|
||||
_driver = MidiDriver::createMidi(dev);
|
||||
if (_nativeMT32) {
|
||||
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
|
||||
}
|
||||
}
|
||||
assert(_driver);
|
||||
|
||||
int ret = _driver->open();
|
||||
assert(ret == 0);
|
||||
_driver->setTimerCallback(this, &timerCallback);
|
||||
|
||||
if (_nativeMT32)
|
||||
_driver->sendMT32Reset();
|
||||
else
|
||||
_driver->sendGMReset();
|
||||
|
||||
_parser = MidiParser::createParser_SMF();
|
||||
_parser->setMidiDriver(this);
|
||||
_parser->setTimerRate(_driver->getBaseTempo());
|
||||
}
|
||||
|
||||
MidiMusic::~MidiMusic() {
|
||||
_driver->setTimerCallback(nullptr, nullptr);
|
||||
_parser->unloadMusic();
|
||||
delete _parser;
|
||||
_driver->close();
|
||||
delete _driver;
|
||||
delete[] _buf;
|
||||
delete[] _musicData;
|
||||
}
|
||||
|
||||
void MidiMusic::setVolume(int volume) {
|
||||
volume = CLIP(volume, 0, 255);
|
||||
|
||||
if (_masterVolume == volume)
|
||||
return;
|
||||
|
||||
_masterVolume = volume;
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (_channelsTable[i])
|
||||
_channelsTable[i]->volume(_channelsVolume[i] * _masterVolume / 255);
|
||||
}
|
||||
|
||||
if (_adlib)
|
||||
static_cast<AdLibMidiDriver*>(_driver)->setVolume(volume);
|
||||
}
|
||||
|
||||
void MidiMusic::playSong(uint16 songNum) {
|
||||
queueClear();
|
||||
queueSong(songNum);
|
||||
playMusic();
|
||||
}
|
||||
|
||||
bool MidiMusic::queueSong(uint16 songNum) {
|
||||
if (songNum >= _numSongs && songNum < 1000) {
|
||||
// this happens at the end of the car chase, where we try to play song 176,
|
||||
// see Sound::_tune[], entry 39
|
||||
debug(3, "Trying to queue an invalid song number %d, max %d", songNum, _numSongs);
|
||||
return false;
|
||||
}
|
||||
uint8 emptySlots = 0;
|
||||
for (int i = 0; i < MUSIC_QUEUE_SIZE; i++)
|
||||
if (!_songQueue[i])
|
||||
emptySlots++;
|
||||
|
||||
if (!emptySlots)
|
||||
return false;
|
||||
|
||||
// Work around bug in Roland music, note that these numbers are 'one-off'
|
||||
// from the original code
|
||||
if (!_adlib && (songNum == 88 || songNum == 89))
|
||||
songNum = 62;
|
||||
|
||||
_songQueue[MUSIC_QUEUE_SIZE - emptySlots] = songNum;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MidiMusic::queueClear() {
|
||||
_lastSong = _songQueue[0];
|
||||
_queuePos = 0;
|
||||
_isLooping = _randomLoop = false;
|
||||
memset(_songQueue, 0, sizeof(_songQueue));
|
||||
}
|
||||
|
||||
void MidiMusic::send(uint32 b) {
|
||||
if (_adlib) {
|
||||
_driver->send(b);
|
||||
return;
|
||||
}
|
||||
|
||||
byte channel = (byte)(b & 0x0F);
|
||||
if ((b & 0xFFF0) == 0x07B0) {
|
||||
// Adjust volume changes by master volume
|
||||
byte volume = (byte)((b >> 16) & 0x7F);
|
||||
_channelsVolume[channel] = volume;
|
||||
volume = volume * _masterVolume / 255;
|
||||
b = (b & 0xFF00FFFF) | (volume << 16);
|
||||
} else if ((b & 0xF0) == 0xC0 && !_nativeMT32) {
|
||||
b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
|
||||
} else if ((b & 0xFFF0) == 0x007BB0) {
|
||||
//Only respond to All Notes Off if this channel
|
||||
//has currently been allocated
|
||||
if (!_channelsTable[channel])
|
||||
return;
|
||||
}
|
||||
|
||||
//Work around annoying loud notes in certain Roland Floda tunes
|
||||
if (channel == 3 && _currentSong == 90)
|
||||
return;
|
||||
if (channel == 4 && _currentSong == 27)
|
||||
return;
|
||||
if (channel == 5 && _currentSong == 38)
|
||||
return;
|
||||
|
||||
if (!_channelsTable[channel])
|
||||
_channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
|
||||
|
||||
if (_channelsTable[channel])
|
||||
_channelsTable[channel]->send(b);
|
||||
}
|
||||
|
||||
void MidiMusic::metaEvent(byte type, const byte *data, uint16 length) {
|
||||
switch (type) {
|
||||
case 0x2F: // End of Track
|
||||
if (_isLooping || _songQueue[1]) {
|
||||
playMusic();
|
||||
} else {
|
||||
stopMusic();
|
||||
}
|
||||
break;
|
||||
case 0x7F: // Specific
|
||||
if (_adlib) {
|
||||
_driver->metaEvent(type, data, length);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// warning("Unhandled meta event: %02x", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MidiMusic::onTimer() {
|
||||
Common::StackLock lock(_mutex);
|
||||
if (_isPlaying)
|
||||
_parser->onTimer();
|
||||
}
|
||||
|
||||
void MidiMusic::queueTuneList(int16 tuneList) {
|
||||
queueClear();
|
||||
|
||||
//Jungle is the only part of the game that uses multiple tunelists.
|
||||
//For the sake of code simplification we just hardcode the extended list ourselves
|
||||
if ((tuneList + 1) == 3) {
|
||||
_randomLoop = true;
|
||||
int i = 0;
|
||||
while (Sound::_jungleList[i])
|
||||
queueSong(Sound::_jungleList[i++] - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
int mode = _tune[tuneList].mode;
|
||||
switch (mode) {
|
||||
case 0: // random loop
|
||||
_randomLoop = true;
|
||||
setLoop(false);
|
||||
break;
|
||||
case 1: // sequential loop
|
||||
setLoop(_songQueue[1] == 0);
|
||||
break;
|
||||
case 2: // play once
|
||||
default:
|
||||
setLoop(false);
|
||||
break;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while (_tune[tuneList].tuneNum[i])
|
||||
queueSong(_tune[tuneList].tuneNum[i++] - 1);
|
||||
|
||||
if (_randomLoop)
|
||||
_queuePos = randomQueuePos();
|
||||
}
|
||||
|
||||
void MidiMusic::playMusic() {
|
||||
if (!_songQueue[0]) {
|
||||
debug(5, "MidiMusic::playMusic - Music queue is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
uint16 songNum = _songQueue[_queuePos];
|
||||
|
||||
//Special type
|
||||
// > 1000 && < 2000 -> queue different tunelist
|
||||
// 2000 -> repeat music from previous queue
|
||||
if (songNum > 999) {
|
||||
if ((songNum + 1) == 2000) {
|
||||
songNum = _lastSong;
|
||||
queueClear();
|
||||
queueSong(songNum);
|
||||
} else {
|
||||
queueTuneList(songNum - 1000);
|
||||
_queuePos = _randomLoop ? randomQueuePos() : 0;
|
||||
songNum = _songQueue[_queuePos];
|
||||
}
|
||||
}
|
||||
|
||||
byte *prevSong = _musicData + songOffset(_currentSong);
|
||||
if (*prevSong == 'C' || *prevSong == 'c') {
|
||||
if (_buf) {
|
||||
delete[] _buf;
|
||||
_buf = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
_currentSong = songNum;
|
||||
if (!songNum) {
|
||||
stopMusic();
|
||||
return;
|
||||
}
|
||||
|
||||
byte *musicPtr = _musicData + songOffset(songNum);
|
||||
uint32 size = songLength(songNum);
|
||||
if (*musicPtr == 'C' || *musicPtr == 'c') {
|
||||
uint32 packedSize = songLength(songNum) - 0x200;
|
||||
_buf = new uint16[packedSize];
|
||||
|
||||
uint16 *data = (uint16 *)(musicPtr + 1);
|
||||
byte *idx = ((byte *)data) + 0x200;
|
||||
|
||||
for (uint i = 0; i < packedSize; i++)
|
||||
#if defined(SCUMM_NEED_ALIGNMENT)
|
||||
memcpy(&_buf[i], (byte *)((byte *)data + *(idx + i) * sizeof(uint16)), sizeof(uint16));
|
||||
#else
|
||||
_buf[i] = data[*(idx + i)];
|
||||
#endif
|
||||
|
||||
musicPtr = ((byte *)_buf) + ((*musicPtr == 'c') ? 1 : 0);
|
||||
size = packedSize * 2;
|
||||
}
|
||||
|
||||
stopMusic();
|
||||
|
||||
Common::StackLock lock(_mutex);
|
||||
_parser->loadMusic(musicPtr, size);
|
||||
_parser->setTrack(0);
|
||||
_isPlaying = true;
|
||||
|
||||
debug(8, "Playing song %d [queue position: %d]", songNum, _queuePos);
|
||||
queueUpdatePos();
|
||||
}
|
||||
|
||||
void MidiMusic::queueUpdatePos() {
|
||||
if (_randomLoop) {
|
||||
_queuePos = randomQueuePos();
|
||||
} else {
|
||||
if (_queuePos < (MUSIC_QUEUE_SIZE - 1) && _songQueue[_queuePos + 1])
|
||||
_queuePos++;
|
||||
else if (_isLooping)
|
||||
_queuePos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 MidiMusic::randomQueuePos() {
|
||||
int queueSize = 0;
|
||||
for (int i = 0; i < MUSIC_QUEUE_SIZE; i++)
|
||||
if (_songQueue[i])
|
||||
queueSize++;
|
||||
|
||||
if (!queueSize)
|
||||
return 0;
|
||||
|
||||
return (uint8)_rnd.getRandomNumber(queueSize - 1) & 0xFF;
|
||||
}
|
||||
|
||||
void MidiMusic::stopMusic() {
|
||||
Common::StackLock lock(_mutex);
|
||||
_isPlaying = false;
|
||||
_parser->unloadMusic();
|
||||
}
|
||||
|
||||
uint32 MidiMusic::songOffset(uint16 songNum) const {
|
||||
uint16 offsLo = READ_LE_UINT16(_musicData + (songNum * 4) + 2);
|
||||
uint16 offsHi = READ_LE_UINT16(_musicData + (songNum * 4) + 4);
|
||||
return (offsHi << 4) | offsLo;
|
||||
}
|
||||
|
||||
uint32 MidiMusic::songLength(uint16 songNum) const {
|
||||
if (songNum < _numSongs)
|
||||
return (songOffset(songNum + 1) - songOffset(songNum));
|
||||
return (_musicDataSize - songOffset(songNum));
|
||||
}
|
||||
|
||||
void MidiMusic::toggleVChange() {
|
||||
setVolume(_vToggle ? (getVolume() * 2) : (getVolume() / 2));
|
||||
_vToggle = !_vToggle;
|
||||
}
|
||||
|
||||
} // End of namespace Queen
|
||||
101
engines/queen/music.h
Normal file
101
engines/queen/music.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_MUSIC_H
|
||||
#define QUEEN_MUSIC_H
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/mutex.h"
|
||||
#include "common/random.h"
|
||||
#include "audio/mididrv.h"
|
||||
|
||||
class MidiParser;
|
||||
|
||||
namespace Queen {
|
||||
|
||||
struct TuneData;
|
||||
|
||||
class QueenEngine;
|
||||
|
||||
class MidiMusic : public MidiDriver_BASE {
|
||||
public:
|
||||
MidiMusic(QueenEngine *vm);
|
||||
~MidiMusic() override;
|
||||
void setVolume(int volume);
|
||||
int getVolume() const { return _masterVolume; }
|
||||
|
||||
void playSong(uint16 songNum);
|
||||
void stopSong() { stopMusic(); }
|
||||
void playMusic();
|
||||
void stopMusic();
|
||||
void setLoop(bool loop) { _isLooping = loop; }
|
||||
void queueTuneList(int16 tuneList);
|
||||
bool queueSong(uint16 songNum);
|
||||
void queueClear();
|
||||
void toggleVChange();
|
||||
|
||||
// MidiDriver_BASE interface implementation
|
||||
void send(uint32 b) override;
|
||||
void metaEvent(byte type, const byte *data, uint16 length) override;
|
||||
|
||||
protected:
|
||||
|
||||
enum {
|
||||
MUSIC_QUEUE_SIZE = 14
|
||||
};
|
||||
|
||||
void queueUpdatePos();
|
||||
uint8 randomQueuePos();
|
||||
void onTimer();
|
||||
uint32 songOffset(uint16 songNum) const;
|
||||
uint32 songLength(uint16 songNum) const;
|
||||
|
||||
static void timerCallback(void *refCon) { ((MidiMusic *)refCon)->onTimer(); }
|
||||
|
||||
MidiDriver *_driver;
|
||||
MidiParser *_parser;
|
||||
MidiChannel *_channelsTable[16];
|
||||
byte _channelsVolume[16];
|
||||
bool _adlib;
|
||||
bool _nativeMT32;
|
||||
Common::Mutex _mutex;
|
||||
Common::RandomSource _rnd;
|
||||
|
||||
bool _isPlaying;
|
||||
bool _isLooping;
|
||||
bool _randomLoop;
|
||||
byte _masterVolume;
|
||||
uint8 _queuePos;
|
||||
int16 _currentSong;
|
||||
int16 _lastSong; //first song from previous queue
|
||||
int16 _songQueue[MUSIC_QUEUE_SIZE];
|
||||
|
||||
uint16 _numSongs;
|
||||
uint16 *_buf;
|
||||
uint32 _musicDataSize;
|
||||
bool _vToggle;
|
||||
byte *_musicData;
|
||||
const TuneData *_tune;
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
1910
engines/queen/musicdata.cpp
Normal file
1910
engines/queen/musicdata.cpp
Normal file
File diff suppressed because it is too large
Load Diff
382
engines/queen/queen.cpp
Normal file
382
engines/queen/queen.cpp
Normal file
@@ -0,0 +1,382 @@
|
||||
/* 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 "base/plugins.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/events.h"
|
||||
#include "common/file.h"
|
||||
#include "common/fs.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/system.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "engines/util.h"
|
||||
|
||||
#include "queen/queen.h"
|
||||
#include "queen/bankman.h"
|
||||
#include "queen/command.h"
|
||||
#include "queen/cutaway.h"
|
||||
#include "queen/debug.h"
|
||||
#include "queen/display.h"
|
||||
#include "queen/graphics.h"
|
||||
#include "queen/grid.h"
|
||||
#include "queen/input.h"
|
||||
#include "queen/logic.h"
|
||||
#include "queen/resource.h"
|
||||
#include "queen/sound.h"
|
||||
#include "queen/talk.h"
|
||||
#include "queen/walk.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
QueenEngine::QueenEngine(OSystem *syst)
|
||||
: Engine(syst), _bam(nullptr), _bankMan(nullptr), _command(nullptr), _debugger(nullptr),
|
||||
_display(nullptr), _graphics(nullptr), _grid(nullptr), _input(nullptr), _logic(nullptr),
|
||||
_sound(nullptr), _resource(nullptr), _walk(nullptr), _gameStarted(false),
|
||||
randomizer("queen") {
|
||||
}
|
||||
|
||||
QueenEngine::~QueenEngine() {
|
||||
delete _bam;
|
||||
delete _resource;
|
||||
delete _bankMan;
|
||||
delete _command;
|
||||
delete _display;
|
||||
delete _graphics;
|
||||
delete _grid;
|
||||
delete _input;
|
||||
delete _logic;
|
||||
delete _sound;
|
||||
delete _walk;
|
||||
//_debugger is deleted by Engine
|
||||
}
|
||||
|
||||
void QueenEngine::registerDefaultSettings() {
|
||||
ConfMan.registerDefault("talkspeed", Logic::DEFAULT_TALK_SPEED);
|
||||
ConfMan.registerDefault("subtitles", true);
|
||||
_subtitles = true;
|
||||
}
|
||||
|
||||
void QueenEngine::checkOptionSettings() {
|
||||
// check talkspeed value
|
||||
if (_talkSpeed < MIN_TEXT_SPEED) {
|
||||
_talkSpeed = MIN_TEXT_SPEED;
|
||||
} else if (_talkSpeed > MAX_TEXT_SPEED) {
|
||||
_talkSpeed = MAX_TEXT_SPEED;
|
||||
}
|
||||
|
||||
// demo and interview versions don't have speech at all
|
||||
if (_sound->speechOn() && (_resource->isDemo() || _resource->isInterview())) {
|
||||
_sound->speechToggle(false);
|
||||
}
|
||||
|
||||
// ensure text is always on when voice is off
|
||||
if (!_sound->speechOn()) {
|
||||
_subtitles = true;
|
||||
}
|
||||
}
|
||||
|
||||
void QueenEngine::syncSoundSettings() {
|
||||
Engine::syncSoundSettings();
|
||||
|
||||
readOptionSettings();
|
||||
}
|
||||
|
||||
void QueenEngine::readOptionSettings() {
|
||||
bool mute = false;
|
||||
if (ConfMan.hasKey("mute"))
|
||||
mute = ConfMan.getBool("mute");
|
||||
|
||||
_sound->setVolume(ConfMan.getInt("music_volume"));
|
||||
_sound->musicToggle(!(mute || ConfMan.getBool("music_mute")));
|
||||
_sound->sfxToggle(!(mute || ConfMan.getBool("sfx_mute")));
|
||||
_sound->speechToggle(!(mute || ConfMan.getBool("speech_mute")));
|
||||
_talkSpeed = (ConfMan.getInt("talkspeed") * (MAX_TEXT_SPEED - MIN_TEXT_SPEED) + 255 / 2) / 255 + MIN_TEXT_SPEED;
|
||||
_subtitles = ConfMan.getBool("subtitles");
|
||||
checkOptionSettings();
|
||||
}
|
||||
|
||||
void QueenEngine::writeOptionSettings() {
|
||||
ConfMan.setInt("music_volume", _sound->getVolume());
|
||||
ConfMan.setBool("music_mute", !_sound->musicOn());
|
||||
ConfMan.setBool("sfx_mute", !_sound->sfxOn());
|
||||
ConfMan.setInt("talkspeed", ((_talkSpeed - MIN_TEXT_SPEED) * 255 + (MAX_TEXT_SPEED - MIN_TEXT_SPEED) / 2) / (MAX_TEXT_SPEED - MIN_TEXT_SPEED));
|
||||
ConfMan.setBool("speech_mute", !_sound->speechOn());
|
||||
ConfMan.setBool("subtitles", _subtitles);
|
||||
ConfMan.flushToDisk();
|
||||
}
|
||||
|
||||
void QueenEngine::update(bool checkPlayerInput) {
|
||||
_graphics->update(_logic->currentRoom());
|
||||
_logic->update();
|
||||
|
||||
int frameDelay = (_lastUpdateTime + Input::DELAY_NORMAL - _system->getMillis());
|
||||
if (frameDelay <= 0) {
|
||||
frameDelay = 1;
|
||||
}
|
||||
_input->delay(frameDelay);
|
||||
_lastUpdateTime = _system->getMillis();
|
||||
|
||||
if (!_resource->isInterview()) {
|
||||
_display->palCustomScroll(_logic->currentRoom());
|
||||
}
|
||||
BobSlot *joe = _graphics->bob(0);
|
||||
_display->update(joe->active, joe->x, joe->y);
|
||||
|
||||
_input->checkKeys();
|
||||
|
||||
if (canLoadOrSave()) {
|
||||
if (_input->quickSave()) {
|
||||
_input->quickSaveReset();
|
||||
saveGameState(SLOT_QUICKSAVE, "Quicksave");
|
||||
}
|
||||
if (_input->quickLoad()) {
|
||||
_input->quickLoadReset();
|
||||
loadGameState(SLOT_QUICKSAVE);
|
||||
}
|
||||
}
|
||||
if (!_input->cutawayRunning()) {
|
||||
if (checkPlayerInput) {
|
||||
_command->updatePlayer();
|
||||
}
|
||||
if (_input->idleTime() >= Input::DELAY_SCREEN_BLANKER) {
|
||||
_display->blankScreen();
|
||||
}
|
||||
}
|
||||
_sound->updateMusic();
|
||||
}
|
||||
|
||||
bool QueenEngine::canLoadOrSave() const {
|
||||
return !_input->cutawayRunning() && !(_resource->isDemo() || _resource->isInterview()) && _gameStarted;
|
||||
}
|
||||
|
||||
bool QueenEngine::canLoadGameStateCurrently(Common::U32String *msg) {
|
||||
return canLoadOrSave();
|
||||
}
|
||||
|
||||
bool QueenEngine::canSaveGameStateCurrently(Common::U32String *msg) {
|
||||
return canLoadOrSave();
|
||||
}
|
||||
|
||||
Common::Error QueenEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
|
||||
debug(3, "Saving game to slot %d", slot);
|
||||
char name[20];
|
||||
Common::Error err = Common::kNoError;
|
||||
makeGameStateName(slot, name);
|
||||
Common::OutSaveFile *file = _saveFileMan->openForSaving(name);
|
||||
if (file) {
|
||||
// save data
|
||||
byte *saveData = new byte[SAVESTATE_MAX_SIZE];
|
||||
byte *p = saveData;
|
||||
_bam->saveState(p);
|
||||
_grid->saveState(p);
|
||||
_logic->saveState(p);
|
||||
_sound->saveState(p);
|
||||
uint32 dataSize = p - saveData;
|
||||
assert(dataSize < SAVESTATE_MAX_SIZE);
|
||||
|
||||
// write header
|
||||
file->writeUint32BE('SCVM');
|
||||
file->writeUint32BE(SAVESTATE_CUR_VER);
|
||||
file->writeUint32BE(0);
|
||||
file->writeUint32BE(dataSize);
|
||||
char description[32];
|
||||
Common::strlcpy(description, desc.c_str(), sizeof(description));
|
||||
file->write(description, sizeof(description));
|
||||
|
||||
// write save data
|
||||
file->write(saveData, dataSize);
|
||||
file->finalize();
|
||||
|
||||
// check for errors
|
||||
if (file->err()) {
|
||||
warning("Can't write file '%s'. (Disk full?)", name);
|
||||
err = Common::kWritingFailed;
|
||||
}
|
||||
delete[] saveData;
|
||||
delete file;
|
||||
} else {
|
||||
warning("Can't create file '%s', game not saved", name);
|
||||
err = Common::kCreatingFileFailed;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
Common::Error QueenEngine::loadGameState(int slot) {
|
||||
debug(3, "Loading game from slot %d", slot);
|
||||
Common::Error err = Common::kNoError;
|
||||
GameStateHeader header;
|
||||
Common::InSaveFile *file = readGameStateHeader(slot, &header);
|
||||
if (file && header.dataSize != 0) {
|
||||
byte *saveData = new byte[header.dataSize];
|
||||
byte *p = saveData;
|
||||
if (file->read(saveData, header.dataSize) != header.dataSize) {
|
||||
warning("Error reading savegame file");
|
||||
err = Common::kReadingFailed;
|
||||
} else {
|
||||
_bam->loadState(header.version, p);
|
||||
_grid->loadState(header.version, p);
|
||||
_logic->loadState(header.version, p);
|
||||
_sound->loadState(header.version, p);
|
||||
if (header.dataSize != (uint32)(p - saveData)) {
|
||||
warning("Corrupted savegame file");
|
||||
err = Common::kReadingFailed; // FIXME
|
||||
} else {
|
||||
_logic->setupRestoredGame();
|
||||
}
|
||||
}
|
||||
delete[] saveData;
|
||||
delete file;
|
||||
} else {
|
||||
err = Common::kReadingFailed;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
Common::InSaveFile *QueenEngine::readGameStateHeader(int slot, GameStateHeader *gsh) {
|
||||
char name[20];
|
||||
makeGameStateName(slot, name);
|
||||
Common::InSaveFile *file = _saveFileMan->openForLoading(name);
|
||||
if (file && file->readUint32BE() == MKTAG('S','C','V','M')) {
|
||||
gsh->version = file->readUint32BE();
|
||||
gsh->flags = file->readUint32BE();
|
||||
gsh->dataSize = file->readUint32BE();
|
||||
file->read(gsh->description, sizeof(gsh->description));
|
||||
} else {
|
||||
memset(gsh, 0, sizeof(GameStateHeader));
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
Common::String QueenEngine::getSaveStateName(int slot) const {
|
||||
if (slot == SLOT_LISTPREFIX) {
|
||||
return "queen.s??";
|
||||
} else if (slot == SLOT_AUTOSAVE) {
|
||||
slot = getAutosaveSlot();
|
||||
}
|
||||
|
||||
assert(slot >= 0);
|
||||
return Common::String::format("queen.s%02d", slot);
|
||||
}
|
||||
|
||||
void QueenEngine::makeGameStateName(int slot, char *buf) const {
|
||||
Common::String name = getSaveStateName(slot);
|
||||
Common::strcpy_s(buf, 20, name.c_str());
|
||||
}
|
||||
|
||||
int QueenEngine::getGameStateSlot(const char *filename) const {
|
||||
int i = -1;
|
||||
const char *slot = strrchr(filename, '.');
|
||||
if (slot && (slot[1] == 's' || slot[1] == 'S')) {
|
||||
i = atoi(slot + 2);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void QueenEngine::findGameStateDescriptions(char descriptions[100][32]) {
|
||||
char prefix[20];
|
||||
makeGameStateName(SLOT_LISTPREFIX, prefix);
|
||||
Common::StringArray filenames = _saveFileMan->listSavefiles(prefix);
|
||||
for (Common::StringArray::const_iterator it = filenames.begin(); it != filenames.end(); ++it) {
|
||||
int i = getGameStateSlot(it->c_str());
|
||||
if (i >= 0 && i < SAVESTATE_MAX_NUM) {
|
||||
GameStateHeader header;
|
||||
Common::InSaveFile *f = readGameStateHeader(i, &header);
|
||||
Common::strcpy_s(descriptions[i], header.description);
|
||||
delete f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Queen::QueenEngine::hasFeature(EngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsReturnToLauncher) ||
|
||||
(f == kSupportsLoadingDuringRuntime) ||
|
||||
(f == kSupportsSavingDuringRuntime) ||
|
||||
(f == kSupportsSubtitleOptions);
|
||||
}
|
||||
|
||||
Common::Error QueenEngine::run() {
|
||||
initGraphics(GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT);
|
||||
|
||||
_resource = new Resource();
|
||||
|
||||
_bam = new BamScene(this);
|
||||
_bankMan = new BankManager(_resource);
|
||||
_command = new Command(this);
|
||||
_debugger = new Debugger(this);
|
||||
setDebugger(_debugger);
|
||||
_display = new Display(this, _system);
|
||||
_graphics = new Graphics(this);
|
||||
_grid = new Grid(this);
|
||||
_input = new Input(_resource->getLanguage(), _system);
|
||||
|
||||
if (_resource->isDemo()) {
|
||||
_logic = new LogicDemo(this);
|
||||
} else if (_resource->isInterview()) {
|
||||
_logic = new LogicInterview(this);
|
||||
} else {
|
||||
_logic = new LogicGame(this);
|
||||
}
|
||||
|
||||
_sound = Sound::makeSoundInstance(_mixer, this, _resource->getCompression());
|
||||
|
||||
_walk = new Walk(this);
|
||||
//_talkspeedScale = (MAX_TEXT_SPEED - MIN_TEXT_SPEED) / 255.0;
|
||||
|
||||
registerDefaultSettings();
|
||||
|
||||
// Setup mixer
|
||||
syncSoundSettings();
|
||||
|
||||
_logic->start();
|
||||
_gameStarted = true;
|
||||
if (ConfMan.hasKey("save_slot") && canLoadOrSave()) {
|
||||
loadGameState(ConfMan.getInt("save_slot"));
|
||||
}
|
||||
_lastUpdateTime = _system->getMillis();
|
||||
|
||||
while (!shouldQuit()) {
|
||||
if (_logic->newRoom() > 0) {
|
||||
_logic->update();
|
||||
_logic->oldRoom(_logic->currentRoom());
|
||||
_logic->currentRoom(_logic->newRoom());
|
||||
_logic->changeRoom();
|
||||
_display->fullscreen(false);
|
||||
if (_logic->currentRoom() == _logic->newRoom()) {
|
||||
_logic->newRoom(0);
|
||||
}
|
||||
} else if (_logic->joeWalk() == JWM_EXECUTE) {
|
||||
_logic->joeWalk(JWM_NORMAL);
|
||||
_command->executeCurrentAction();
|
||||
} else {
|
||||
_logic->joeWalk(JWM_NORMAL);
|
||||
update(true);
|
||||
}
|
||||
}
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
} // End of namespace Queen
|
||||
174
engines/queen/queen.h
Normal file
174
engines/queen/queen.h
Normal file
@@ -0,0 +1,174 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_QUEEN_H
|
||||
#define QUEEN_QUEEN_H
|
||||
|
||||
#include "engines/engine.h"
|
||||
#include "common/random.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the namespace of the Queen engine.
|
||||
*
|
||||
* Status of this engine: ???
|
||||
*
|
||||
* Games using this engine:
|
||||
* - Flight of the Amazon Queen
|
||||
*/
|
||||
namespace Queen {
|
||||
|
||||
enum QUEENActions {
|
||||
kActionNone,
|
||||
kActionFastMode,
|
||||
kActionSkipText,
|
||||
kActionScrollUp,
|
||||
kActionScrollDown,
|
||||
kActionInvSlot1,
|
||||
kActionInvSlot2,
|
||||
kActionInvSlot3,
|
||||
kActionInvSlot4,
|
||||
kActionSkipCutaway,
|
||||
kActionJournal,
|
||||
kActionSave,
|
||||
kActionLoad,
|
||||
kActionOpen,
|
||||
kActionClose,
|
||||
kActionMove,
|
||||
kActionGive,
|
||||
kActionLook,
|
||||
kActionPickUp,
|
||||
kActionTalk,
|
||||
kActionUse,
|
||||
kActionCloseJournal,
|
||||
};
|
||||
|
||||
struct GameStateHeader {
|
||||
uint32 version;
|
||||
uint32 flags;
|
||||
uint32 dataSize;
|
||||
char description[32];
|
||||
};
|
||||
|
||||
class BamScene;
|
||||
class BankManager;
|
||||
class Command;
|
||||
class Debugger;
|
||||
class Display;
|
||||
class Graphics;
|
||||
class Grid;
|
||||
class Input;
|
||||
class Logic;
|
||||
class Resource;
|
||||
class Sound;
|
||||
class Walk;
|
||||
|
||||
class QueenEngine : public Engine {
|
||||
public:
|
||||
|
||||
QueenEngine(OSystem *syst);
|
||||
~QueenEngine() override;
|
||||
|
||||
BamScene *bam() const { return _bam; }
|
||||
BankManager *bankMan() const { return _bankMan; }
|
||||
Command *command() const { return _command; }
|
||||
Debugger *debugger() const { return _debugger; }
|
||||
Display *display() const { return _display; }
|
||||
Graphics *graphics() const { return _graphics; }
|
||||
Grid *grid() const { return _grid; }
|
||||
Input *input() const { return _input; }
|
||||
Logic *logic() const { return _logic; }
|
||||
Resource *resource() const { return _resource; }
|
||||
Sound *sound() const { return _sound; }
|
||||
Walk *walk() const { return _walk; }
|
||||
|
||||
Common::RandomSource randomizer;
|
||||
|
||||
void registerDefaultSettings();
|
||||
void checkOptionSettings();
|
||||
void readOptionSettings();
|
||||
void writeOptionSettings();
|
||||
|
||||
int talkSpeed() const { return _talkSpeed; }
|
||||
void talkSpeed(int speed) { _talkSpeed = speed; }
|
||||
bool subtitles() const { return _subtitles; }
|
||||
void subtitles(bool enable) { _subtitles = enable; }
|
||||
|
||||
void update(bool checkPlayerInput = false);
|
||||
|
||||
bool canLoadOrSave() const;
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
|
||||
Common::Error loadGameState(int slot) override;
|
||||
int getAutosaveSlot() const override { return 99; }
|
||||
Common::String getSaveStateName(int slot) const override;
|
||||
void makeGameStateName(int slot, char *buf) const;
|
||||
int getGameStateSlot(const char *filename) const;
|
||||
void findGameStateDescriptions(char descriptions[100][32]);
|
||||
Common::SeekableReadStream *readGameStateHeader(int slot, GameStateHeader *gsh);
|
||||
|
||||
enum {
|
||||
SAVESTATE_CUR_VER = 1,
|
||||
SAVESTATE_MAX_NUM = 100,
|
||||
SAVESTATE_MAX_SIZE = 30000,
|
||||
|
||||
SLOT_LISTPREFIX = -2,
|
||||
SLOT_AUTOSAVE = -1,
|
||||
SLOT_QUICKSAVE = 0,
|
||||
|
||||
MIN_TEXT_SPEED = 4,
|
||||
MAX_TEXT_SPEED = 100
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
// Engine APIs
|
||||
Common::Error run() override;
|
||||
bool hasFeature(EngineFeature f) const override;
|
||||
void syncSoundSettings() override;
|
||||
|
||||
|
||||
int _talkSpeed;
|
||||
bool _subtitles;
|
||||
uint32 _lastUpdateTime;
|
||||
bool _gameStarted;
|
||||
|
||||
BamScene *_bam;
|
||||
BankManager *_bankMan;
|
||||
Command *_command;
|
||||
Debugger *_debugger;
|
||||
Display *_display;
|
||||
Graphics *_graphics;
|
||||
Grid *_grid;
|
||||
Input *_input;
|
||||
Logic *_logic;
|
||||
Resource *_resource;
|
||||
Sound *_sound;
|
||||
Walk *_walk;
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
193
engines/queen/resource.cpp
Normal file
193
engines/queen/resource.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
/* 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 "common/debug.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/substream.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "queen/resource.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
|
||||
const char *const Resource::_tableFilename = "queen.tbl";
|
||||
|
||||
static int compareResourceEntry(const void *a, const void *b) {
|
||||
const char *filename = (const char *)a;
|
||||
const ResourceEntry *entry = (const ResourceEntry *)b;
|
||||
return strcmp(filename, entry->filename);
|
||||
}
|
||||
|
||||
Resource::Resource()
|
||||
: _resourceEntries(0), _resourceTable(nullptr) {
|
||||
memset(&_version, 0, sizeof(_version));
|
||||
|
||||
_currentResourceFileNum = 1;
|
||||
if (!_resourceFile.open("queen.1c")) {
|
||||
if (!_resourceFile.open("queen.1")) {
|
||||
error("Could not open resource file 'queen.1[c]'");
|
||||
}
|
||||
}
|
||||
if (!detectVersion(&_version, &_resourceFile)) {
|
||||
error("Unable to detect game version");
|
||||
}
|
||||
|
||||
if (_version.features & GF_REBUILT) {
|
||||
readTableEntries(&_resourceFile);
|
||||
} else {
|
||||
readTableFile(_version.queenTblVersion, _version.queenTblOffset);
|
||||
}
|
||||
|
||||
checkJASVersion();
|
||||
debug(5, "Detected game version: %s, which has %d resource entries", _version.str, _resourceEntries);
|
||||
}
|
||||
|
||||
Resource::~Resource() {
|
||||
_resourceFile.close();
|
||||
|
||||
if (_resourceTable != _resourceTablePEM10)
|
||||
delete[] _resourceTable;
|
||||
}
|
||||
|
||||
ResourceEntry *Resource::resourceEntry(const char *filename) const {
|
||||
assert(filename[0] && strlen(filename) < 14);
|
||||
|
||||
Common::String entryName(filename);
|
||||
entryName.toUppercase();
|
||||
|
||||
ResourceEntry *re = nullptr;
|
||||
re = (ResourceEntry *)bsearch(entryName.c_str(), _resourceTable, _resourceEntries, sizeof(ResourceEntry), compareResourceEntry);
|
||||
return re;
|
||||
}
|
||||
|
||||
uint8 *Resource::loadFile(const char *filename, uint32 skipBytes, uint32 *size) {
|
||||
debug(7, "Resource::loadFile('%s')", filename);
|
||||
ResourceEntry *re = resourceEntry(filename);
|
||||
assert(re != nullptr);
|
||||
uint32 sz = re->size - skipBytes;
|
||||
if (size != nullptr) {
|
||||
*size = sz;
|
||||
}
|
||||
byte *dstBuf = new byte[sz];
|
||||
seekResourceFile(re->bundle, re->offset + skipBytes);
|
||||
_resourceFile.read(dstBuf, sz);
|
||||
return dstBuf;
|
||||
}
|
||||
|
||||
void Resource::loadTextFile(const char *filename, Common::StringArray &stringList) {
|
||||
debug(7, "Resource::loadTextFile('%s')", filename);
|
||||
ResourceEntry *re = resourceEntry(filename);
|
||||
assert(re != nullptr);
|
||||
seekResourceFile(re->bundle, re->offset);
|
||||
Common::SeekableSubReadStream stream(&_resourceFile, re->offset, re->offset + re->size);
|
||||
while (true) {
|
||||
Common::String tmp = stream.readLine();
|
||||
if (stream.eos() || stream.err())
|
||||
break;
|
||||
stringList.push_back(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::checkJASVersion() {
|
||||
if (_version.platform == Common::kPlatformAmiga) {
|
||||
// don't bother verifying the JAS version string with these versions,
|
||||
// it will be done at the end of Logic::readQueenJas, anyway
|
||||
return;
|
||||
}
|
||||
ResourceEntry *re = resourceEntry("QUEEN.JAS");
|
||||
assert(re != nullptr);
|
||||
uint32 offset = re->offset;
|
||||
if (isDemo())
|
||||
offset += JAS_VERSION_OFFSET_DEMO;
|
||||
else if (isInterview())
|
||||
offset += JAS_VERSION_OFFSET_INTV;
|
||||
else
|
||||
offset += JAS_VERSION_OFFSET_PC;
|
||||
seekResourceFile(re->bundle, offset);
|
||||
|
||||
char versionStr[6];
|
||||
_resourceFile.read(versionStr, 6);
|
||||
if (strcmp(_version.str, versionStr))
|
||||
error("Verifying game version failed! (expected: '%s', found: '%s')", _version.str, versionStr);
|
||||
}
|
||||
|
||||
void Resource::seekResourceFile(int num, uint32 offset) {
|
||||
if (_currentResourceFileNum != num) {
|
||||
debug(7, "Opening resource file %d, current %d", num, _currentResourceFileNum);
|
||||
_resourceFile.close();
|
||||
char name[20];
|
||||
Common::sprintf_s(name, "queen.%d", num);
|
||||
if (!_resourceFile.open(name)) {
|
||||
error("Could not open resource file '%s'", name);
|
||||
}
|
||||
_currentResourceFileNum = num;
|
||||
}
|
||||
_resourceFile.seek(offset);
|
||||
}
|
||||
|
||||
void Resource::readTableFile(uint8 version, uint32 offset) {
|
||||
Common::File tableFile;
|
||||
tableFile.open(_tableFilename);
|
||||
if (tableFile.isOpen() && tableFile.readUint32BE() == MKTAG('Q','T','B','L')) {
|
||||
uint32 tableVersion = tableFile.readUint32BE();
|
||||
if (version > tableVersion) {
|
||||
error("The game you are trying to play requires version %d of queen.tbl, "
|
||||
"you have version %d ; please update it", version, tableVersion);
|
||||
}
|
||||
tableFile.seek(offset);
|
||||
readTableEntries(&tableFile);
|
||||
} else {
|
||||
// check if it is the english floppy version, for which we have a hardcoded version of the table
|
||||
if (strcmp(_version.str, "PEM10") == 0) {
|
||||
_resourceEntries = 1076;
|
||||
_resourceTable = _resourceTablePEM10;
|
||||
} else {
|
||||
error("Could not find tablefile '%s'", _tableFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::readTableEntries(Common::File *file) {
|
||||
_resourceEntries = file->readUint16BE();
|
||||
_resourceTable = new ResourceEntry[_resourceEntries];
|
||||
for (uint16 i = 0; i < _resourceEntries; ++i) {
|
||||
ResourceEntry *re = &_resourceTable[i];
|
||||
file->read(re->filename, 12);
|
||||
re->filename[12] = '\0';
|
||||
re->bundle = file->readByte();
|
||||
re->offset = file->readUint32BE();
|
||||
re->size = file->readUint32BE();
|
||||
}
|
||||
}
|
||||
|
||||
Common::File *Resource::findSound(const char *filename, uint32 *size) {
|
||||
assert(strstr(filename, ".SB") != nullptr || strstr(filename, ".AMR") != nullptr || strstr(filename, ".INS") != nullptr);
|
||||
ResourceEntry *re = resourceEntry(filename);
|
||||
if (re) {
|
||||
*size = re->size;
|
||||
seekResourceFile(re->bundle, re->offset);
|
||||
return &_resourceFile;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace Queen
|
||||
118
engines/queen/resource.h
Normal file
118
engines/queen/resource.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_RESOURCE_H
|
||||
#define QUEEN_RESOURCE_H
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/str-array.h"
|
||||
#include "common/language.h"
|
||||
#include "common/platform.h"
|
||||
#include "queen/defs.h"
|
||||
#include "queen/version.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
struct ResourceEntry {
|
||||
char filename[13];
|
||||
uint8 bundle;
|
||||
uint32 offset;
|
||||
uint32 size;
|
||||
};
|
||||
|
||||
class Resource {
|
||||
public:
|
||||
|
||||
Resource();
|
||||
~Resource();
|
||||
|
||||
//! loads a binary file
|
||||
uint8 *loadFile(const char *filename, uint32 skipBytes = 0, uint32 *size = NULL);
|
||||
|
||||
//! loads a text file
|
||||
void loadTextFile(const char *filename, Common::StringArray &stringList);
|
||||
|
||||
//! returns true if the file is present in the resource
|
||||
bool fileExists(const char *filename) const { return resourceEntry(filename) != NULL; }
|
||||
|
||||
//! returns a reference to a sound file
|
||||
Common::File *findSound(const char *filename, uint32 *size);
|
||||
|
||||
bool isDemo() const { return (_version.features & GF_DEMO) != 0; }
|
||||
bool isInterview() const { return (_version.features & GF_INTERVIEW) != 0; }
|
||||
bool isFloppy() const { return (_version.features & GF_FLOPPY) != 0; }
|
||||
bool isCD() const { return (_version.features & GF_TALKIE) != 0; }
|
||||
|
||||
//! returns compression type for audio files
|
||||
uint8 getCompression() const { return _version.compression; }
|
||||
|
||||
//! returns JAS version string (contains language, platform and version information)
|
||||
const char *getJASVersion() const { return _version.str; }
|
||||
|
||||
//! returns the language of the game
|
||||
Common::Language getLanguage() const { return _version.language; }
|
||||
|
||||
Common::Platform getPlatform() const { return _version.platform; }
|
||||
|
||||
enum {
|
||||
JAS_VERSION_OFFSET_DEMO = 0x119A8,
|
||||
JAS_VERSION_OFFSET_INTV = 0xCF8,
|
||||
JAS_VERSION_OFFSET_PC = 0x12484
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
Common::File _resourceFile;
|
||||
|
||||
int _currentResourceFileNum;
|
||||
|
||||
DetectedGameVersion _version;
|
||||
|
||||
//! number of entries in resource table
|
||||
uint32 _resourceEntries;
|
||||
|
||||
ResourceEntry *_resourceTable;
|
||||
|
||||
//! verify the version of the selected game
|
||||
void checkJASVersion();
|
||||
|
||||
//! returns a reference to the ReseourceEntry for the specified filename
|
||||
ResourceEntry *resourceEntry(const char *filename) const;
|
||||
|
||||
//! seeks resource file to specific bundle and file offset
|
||||
void seekResourceFile(int num, uint32 offset);
|
||||
|
||||
//! extract the resource table for the specified game version
|
||||
void readTableFile(uint8 version, uint32 offset);
|
||||
|
||||
//! read the resource table from the specified file
|
||||
void readTableEntries(Common::File *file);
|
||||
|
||||
//! resource table filename (queen.tbl)
|
||||
static const char *const _tableFilename;
|
||||
|
||||
//! resource table for english floppy version
|
||||
static ResourceEntry _resourceTablePEM10[];
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
1106
engines/queen/restables.cpp
Normal file
1106
engines/queen/restables.cpp
Normal file
File diff suppressed because it is too large
Load Diff
777
engines/queen/sound.cpp
Normal file
777
engines/queen/sound.cpp
Normal file
@@ -0,0 +1,777 @@
|
||||
/* 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 "common/config-manager.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "queen/sound.h"
|
||||
#include "queen/input.h"
|
||||
#include "queen/logic.h"
|
||||
#include "queen/music.h"
|
||||
#include "queen/queen.h"
|
||||
#include "queen/resource.h"
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/decoders/flac.h"
|
||||
#include "audio/decoders/mp3.h"
|
||||
#include "audio/decoders/raw.h"
|
||||
#include "audio/decoders/vorbis.h"
|
||||
#include "audio/mods/rjp1.h"
|
||||
|
||||
#define SB_HEADER_SIZE_V104 110
|
||||
#define SB_HEADER_SIZE_V110 122
|
||||
|
||||
namespace Queen {
|
||||
|
||||
// The sounds in the PC versions are all played at 11840 Hz. Unfortunately, we
|
||||
// did not know that at the time, so there are plenty of compressed versions
|
||||
// which claim that they should be played at 11025 Hz. This "wrapper" class
|
||||
// works around that.
|
||||
|
||||
class AudioStreamWrapper : public Audio::AudioStream {
|
||||
protected:
|
||||
Audio::AudioStream *_stream;
|
||||
int _rate;
|
||||
|
||||
public:
|
||||
AudioStreamWrapper(Audio::AudioStream *stream) {
|
||||
_stream = stream;
|
||||
|
||||
int rate = _stream->getRate();
|
||||
|
||||
// A file where the sample rate claims to be 11025 Hz is
|
||||
// probably compressed with the old tool. We force the real
|
||||
// sample rate, which is 11840 Hz.
|
||||
//
|
||||
// However, a file compressed with the newer tool is not
|
||||
// guaranteed to have a sample rate of 11840 Hz. LAME will
|
||||
// automatically resample it to 12000 Hz. So in all other
|
||||
// cases, we use the rate from the file.
|
||||
|
||||
if (rate == 11025)
|
||||
_rate = 11840;
|
||||
else
|
||||
_rate = rate;
|
||||
}
|
||||
~AudioStreamWrapper() override {
|
||||
delete _stream;
|
||||
}
|
||||
int readBuffer(int16 *buffer, const int numSamples) override {
|
||||
return _stream->readBuffer(buffer, numSamples);
|
||||
}
|
||||
bool isStereo() const override {
|
||||
return _stream->isStereo();
|
||||
}
|
||||
bool endOfData() const override {
|
||||
return _stream->endOfData();
|
||||
}
|
||||
bool endOfStream() const override {
|
||||
return _stream->endOfStream();
|
||||
}
|
||||
int getRate() const override {
|
||||
return _rate;
|
||||
}
|
||||
};
|
||||
|
||||
class SilentSound : public PCSound {
|
||||
public:
|
||||
SilentSound(Audio::Mixer *mixer, QueenEngine *vm) : PCSound(mixer, vm) {}
|
||||
protected:
|
||||
void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) override {
|
||||
// Do nothing
|
||||
}
|
||||
};
|
||||
|
||||
class SBSound : public PCSound {
|
||||
public:
|
||||
SBSound(Audio::Mixer *mixer, QueenEngine *vm) : PCSound(mixer, vm) {}
|
||||
protected:
|
||||
void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) override;
|
||||
};
|
||||
|
||||
#ifdef USE_MAD
|
||||
class MP3Sound : public PCSound {
|
||||
public:
|
||||
MP3Sound(Audio::Mixer *mixer, QueenEngine *vm) : PCSound(mixer, vm) {}
|
||||
protected:
|
||||
void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) override {
|
||||
Common::SeekableReadStream *tmp = f->readStream(size);
|
||||
assert(tmp);
|
||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, soundHandle, new AudioStreamWrapper(Audio::makeMP3Stream(tmp, DisposeAfterUse::YES)));
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef USE_VORBIS
|
||||
class OGGSound : public PCSound {
|
||||
public:
|
||||
OGGSound(Audio::Mixer *mixer, QueenEngine *vm) : PCSound(mixer, vm) {}
|
||||
protected:
|
||||
void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) override {
|
||||
Common::SeekableReadStream *tmp = f->readStream(size);
|
||||
assert(tmp);
|
||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, soundHandle, new AudioStreamWrapper(Audio::makeVorbisStream(tmp, DisposeAfterUse::YES)));
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef USE_FLAC
|
||||
class FLACSound : public PCSound {
|
||||
public:
|
||||
FLACSound(Audio::Mixer *mixer, QueenEngine *vm) : PCSound(mixer, vm) {}
|
||||
protected:
|
||||
void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) override {
|
||||
Common::SeekableReadStream *tmp = f->readStream(size);
|
||||
assert(tmp);
|
||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, soundHandle, new AudioStreamWrapper(Audio::makeFLACStream(tmp, DisposeAfterUse::YES)));
|
||||
}
|
||||
};
|
||||
#endif // #ifdef USE_FLAC
|
||||
|
||||
Sound::Sound(Audio::Mixer *mixer, QueenEngine *vm) :
|
||||
_mixer(mixer), _vm(vm), _sfxToggle(true), _speechToggle(true), _musicToggle(true),
|
||||
_speechSfxExists(false), _lastOverride(0), _musicVolume(0) {
|
||||
}
|
||||
|
||||
Sound *Sound::makeSoundInstance(Audio::Mixer *mixer, QueenEngine *vm, uint8 compression) {
|
||||
if (vm->resource()->getPlatform() == Common::kPlatformAmiga)
|
||||
return new AmigaSound(mixer, vm);
|
||||
|
||||
switch (compression) {
|
||||
case COMPRESSION_NONE:
|
||||
return new SBSound(mixer, vm);
|
||||
case COMPRESSION_MP3:
|
||||
#ifndef USE_MAD
|
||||
warning("Using MP3 compressed datafile, but MP3 support not compiled in");
|
||||
return new SilentSound(mixer, vm);
|
||||
#else
|
||||
return new MP3Sound(mixer, vm);
|
||||
#endif
|
||||
case COMPRESSION_OGG:
|
||||
#ifndef USE_VORBIS
|
||||
warning("Using OGG compressed datafile, but OGG support not compiled in");
|
||||
return new SilentSound(mixer, vm);
|
||||
#else
|
||||
return new OGGSound(mixer, vm);
|
||||
#endif
|
||||
case COMPRESSION_FLAC:
|
||||
#ifndef USE_FLAC
|
||||
warning("Using FLAC compressed datafile, but FLAC support not compiled in");
|
||||
return new SilentSound(mixer, vm);
|
||||
#else
|
||||
return new FLACSound(mixer, vm);
|
||||
#endif
|
||||
default:
|
||||
warning("Unknown compression type");
|
||||
return new SilentSound(mixer, vm);
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::setVolume(int vol) {
|
||||
if (ConfMan.hasKey("mute") && ConfMan.getBool("mute"))
|
||||
_musicVolume = 0;
|
||||
else
|
||||
_musicVolume = vol;
|
||||
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, _musicVolume);
|
||||
}
|
||||
|
||||
void Sound::saveState(byte *&ptr) {
|
||||
WRITE_BE_UINT16(ptr, _lastOverride); ptr += 2;
|
||||
}
|
||||
|
||||
void Sound::loadState(uint32 ver, byte *&ptr) {
|
||||
_lastOverride = (int16)READ_BE_INT16(ptr); ptr += 2;
|
||||
}
|
||||
|
||||
PCSound::PCSound(Audio::Mixer *mixer, QueenEngine *vm)
|
||||
: Sound(mixer, vm) {
|
||||
|
||||
_music = new MidiMusic(vm);
|
||||
}
|
||||
|
||||
PCSound::~PCSound() {
|
||||
delete _music;
|
||||
}
|
||||
|
||||
void PCSound::playSfx(uint16 sfx) {
|
||||
if (sfxOn() && sfx != 0)
|
||||
playSound(_sfxName[sfx - 1], false);
|
||||
}
|
||||
|
||||
void PCSound::playSong(int16 songNum) {
|
||||
if (songNum <= 0) {
|
||||
_music->stopSong();
|
||||
return;
|
||||
}
|
||||
|
||||
int16 newTune;
|
||||
if (_vm->resource()->isDemo()) {
|
||||
if (songNum == 17) {
|
||||
_music->stopSong();
|
||||
return;
|
||||
}
|
||||
newTune = _songDemo[songNum - 1].tuneList[0] - 1;
|
||||
} else {
|
||||
newTune = _song[songNum - 1].tuneList[0] - 1;
|
||||
}
|
||||
|
||||
if (_tune[newTune].sfx[0]) {
|
||||
playSfx(_tune[newTune].sfx[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!musicOn())
|
||||
return;
|
||||
|
||||
int overrideCmd = (_vm->resource()->isDemo()) ? _songDemo[songNum - 1].overrideCmd : _song[songNum - 1].overrideCmd;
|
||||
switch (overrideCmd) {
|
||||
// Override all songs
|
||||
case 1:
|
||||
break;
|
||||
// Alter song settings (such as volume) and exit
|
||||
case 2:
|
||||
_music->toggleVChange();
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
_lastOverride = songNum;
|
||||
|
||||
_music->queueTuneList(newTune);
|
||||
_music->playMusic();
|
||||
}
|
||||
|
||||
void PCSound::stopSong() {
|
||||
_music->stopSong();
|
||||
}
|
||||
|
||||
void PCSound::playSpeech(const char *base) {
|
||||
if (speechOn()) {
|
||||
playSound(base, true);
|
||||
}
|
||||
}
|
||||
|
||||
void PCSound::setVolume(int vol) {
|
||||
Sound::setVolume(vol);
|
||||
_music->setVolume(vol);
|
||||
}
|
||||
|
||||
void PCSound::playSound(const char *base, bool isSpeech) {
|
||||
char name[13];
|
||||
Common::strcpy_s(name, base);
|
||||
// alter filename to add zeros and append ".SB"
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (name[i] == ' ')
|
||||
name[i] = '0';
|
||||
}
|
||||
Common::strcat_s(name, ".SB");
|
||||
if (isSpeech) {
|
||||
// Add _vm->shouldQuit() check here, otherwise game gets stuck
|
||||
// in an infinite loop if we try to quit while a sound is playing...
|
||||
while (_mixer->isSoundHandleActive(_speechHandle) && !_vm->shouldQuit()) {
|
||||
_vm->input()->delay(10);
|
||||
}
|
||||
} else {
|
||||
_mixer->stopHandle(_sfxHandle);
|
||||
}
|
||||
uint32 size;
|
||||
Common::File *f = _vm->resource()->findSound(name, &size);
|
||||
if (f) {
|
||||
playSoundData(f, size, isSpeech ? &_speechHandle : &_sfxHandle);
|
||||
_speechSfxExists = isSpeech;
|
||||
} else {
|
||||
_speechSfxExists = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SBSound::playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) {
|
||||
// In order to simplify the code, we don't parse the .sb header but hard-code the
|
||||
// values. Refer to tracker item #3590 for details on the format/fields.
|
||||
int headerSize;
|
||||
f->seek(2, SEEK_CUR);
|
||||
uint16 version = f->readUint16LE();
|
||||
switch (version) {
|
||||
case 104:
|
||||
headerSize = SB_HEADER_SIZE_V104;
|
||||
break;
|
||||
case 110:
|
||||
headerSize = SB_HEADER_SIZE_V110;
|
||||
break;
|
||||
default:
|
||||
warning("Unhandled SB file version %d, defaulting to 104", version);
|
||||
headerSize = SB_HEADER_SIZE_V104;
|
||||
break;
|
||||
}
|
||||
f->seek(headerSize - 4, SEEK_CUR);
|
||||
size -= headerSize;
|
||||
uint8 *sound = (uint8 *)malloc(size);
|
||||
if (sound) {
|
||||
f->read(sound, size);
|
||||
Audio::Mixer::SoundType type = (soundHandle == &_speechHandle) ? Audio::Mixer::kSpeechSoundType : Audio::Mixer::kSFXSoundType;
|
||||
|
||||
Audio::AudioStream *stream = Audio::makeRawStream(sound, size, 11840, Audio::FLAG_UNSIGNED);
|
||||
_mixer->playStream(type, soundHandle, stream);
|
||||
}
|
||||
}
|
||||
|
||||
AmigaSound::AmigaSound(Audio::Mixer *mixer, QueenEngine *vm)
|
||||
: Sound(mixer, vm), _fanfareRestore(0), _fanfareCount(0), _fluteCount(0) {
|
||||
}
|
||||
|
||||
void AmigaSound::playSfx(uint16 sfx) {
|
||||
if (_vm->logic()->currentRoom() == 111) {
|
||||
// lightning sound
|
||||
playSound("88SSSSSS");
|
||||
}
|
||||
}
|
||||
|
||||
void AmigaSound::playSong(int16 song) {
|
||||
debug(2, "Sound::playSong %d override %d", song, _lastOverride);
|
||||
|
||||
if (song < 0) {
|
||||
stopSong();
|
||||
return;
|
||||
}
|
||||
|
||||
// remap song numbers for the Amiga
|
||||
switch (song) {
|
||||
case 1:
|
||||
case 2:
|
||||
song = 39;
|
||||
break;
|
||||
case 37:
|
||||
case 52:
|
||||
case 196:
|
||||
song = 90;
|
||||
break;
|
||||
case 38:
|
||||
case 89:
|
||||
song = 3;
|
||||
break;
|
||||
case 24:
|
||||
case 158:
|
||||
song = 117;
|
||||
break;
|
||||
case 71:
|
||||
case 72:
|
||||
case 73:
|
||||
case 75:
|
||||
song = 133;
|
||||
break;
|
||||
case 203:
|
||||
song = 67;
|
||||
break;
|
||||
case 145:
|
||||
song = 140;
|
||||
break;
|
||||
case 53:
|
||||
case 204:
|
||||
song = 44;
|
||||
break;
|
||||
case 136:
|
||||
case 142:
|
||||
case 179:
|
||||
song = 86;
|
||||
break;
|
||||
case 101:
|
||||
case 102:
|
||||
case 143:
|
||||
song = 188;
|
||||
break;
|
||||
case 65:
|
||||
case 62:
|
||||
song = 69;
|
||||
break;
|
||||
case 118:
|
||||
case 119:
|
||||
song = 137;
|
||||
break;
|
||||
case 130:
|
||||
case 131:
|
||||
song = 59;
|
||||
break;
|
||||
case 174:
|
||||
case 175:
|
||||
song = 57;
|
||||
break;
|
||||
case 171:
|
||||
case 121:
|
||||
song = 137;
|
||||
break;
|
||||
case 138:
|
||||
case 170:
|
||||
case 149:
|
||||
song = 28;
|
||||
break;
|
||||
case 122:
|
||||
case 180:
|
||||
case 83:
|
||||
case 98:
|
||||
song = 83;
|
||||
break;
|
||||
case 20:
|
||||
case 33:
|
||||
song = 34;
|
||||
break;
|
||||
case 29:
|
||||
case 35:
|
||||
song = 36;
|
||||
break;
|
||||
case 7:
|
||||
case 9:
|
||||
case 10:
|
||||
song = 11;
|
||||
break;
|
||||
case 110:
|
||||
song = 94;
|
||||
break;
|
||||
case 111:
|
||||
song = 95;
|
||||
break;
|
||||
case 30:
|
||||
song = 43;
|
||||
break;
|
||||
case 76:
|
||||
song = 27;
|
||||
break;
|
||||
case 194:
|
||||
case 195:
|
||||
song = 32;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (_lastOverride != 32 && _lastOverride != 44) {
|
||||
if (playSpecialSfx(song)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_lastOverride == song && _mixer->isSoundHandleActive(_modHandle)) {
|
||||
return;
|
||||
}
|
||||
switch (song) {
|
||||
// hotel
|
||||
case 39:
|
||||
playModule("HOTEL", 1);
|
||||
break;
|
||||
case 19:
|
||||
playModule("HOTEL", 3);
|
||||
break;
|
||||
case 34:
|
||||
playModule("HOTEL", 2);
|
||||
break;
|
||||
case 36:
|
||||
playModule("HOTEL", 4);
|
||||
_fanfareRestore = _lastOverride;
|
||||
_fanfareCount = 60;
|
||||
break;
|
||||
// jungle
|
||||
case 40:
|
||||
playModule("JUNG", 1);
|
||||
_fanfareRestore = _lastOverride;
|
||||
_fanfareCount = 80;
|
||||
_fluteCount = 100;
|
||||
break;
|
||||
case 3:
|
||||
playModule("JUNG", 2);
|
||||
_fluteCount = 100;
|
||||
break;
|
||||
// temple
|
||||
case 54:
|
||||
playModule("TEMPLE", 1);
|
||||
break;
|
||||
case 12:
|
||||
playModule("TEMPLE", 2);
|
||||
break;
|
||||
case 11:
|
||||
playModule("TEMPLE", 3);
|
||||
break;
|
||||
case 31:
|
||||
playModule("TEMPLE", 4);
|
||||
_fanfareRestore = _lastOverride;
|
||||
_fanfareCount = 80;
|
||||
break;
|
||||
// floda
|
||||
case 41:
|
||||
playModule("FLODA", 4);
|
||||
_fanfareRestore = _lastOverride;
|
||||
_fanfareCount = 60;
|
||||
break;
|
||||
case 13:
|
||||
playModule("FLODA", 3);
|
||||
break;
|
||||
case 16:
|
||||
playModule("FLODA", 1);
|
||||
break;
|
||||
case 17:
|
||||
playModule("FLODA", 2);
|
||||
break;
|
||||
case 43:
|
||||
playModule("FLODA", 5);
|
||||
break;
|
||||
// end credits
|
||||
case 67:
|
||||
playModule("TITLE", 1);
|
||||
break;
|
||||
// intro credits
|
||||
case 88:
|
||||
playModule("TITLE", 1);
|
||||
break;
|
||||
// valley
|
||||
case 90:
|
||||
playModule("AWESTRUK", 1);
|
||||
break;
|
||||
// confrontation
|
||||
case 91:
|
||||
playModule("'JUNGLE'", 1);
|
||||
break;
|
||||
// Frank
|
||||
case 46:
|
||||
playModule("FRANK", 1);
|
||||
break;
|
||||
// trader bob
|
||||
case 6:
|
||||
playModule("BOB", 1);
|
||||
break;
|
||||
// azura
|
||||
case 44:
|
||||
playModule("AZURA", 1);
|
||||
break;
|
||||
// amazon fortress
|
||||
case 21:
|
||||
playModule("FORT", 1);
|
||||
break;
|
||||
// rocket
|
||||
case 32:
|
||||
playModule("ROCKET", 1);
|
||||
break;
|
||||
// robot
|
||||
case 92:
|
||||
playModule("ROBOT", 1);
|
||||
break;
|
||||
default:
|
||||
// song not available in the amiga version
|
||||
return;
|
||||
}
|
||||
_lastOverride = song;
|
||||
}
|
||||
|
||||
void AmigaSound::stopSfx() {
|
||||
_mixer->stopHandle(_sfxHandle);
|
||||
}
|
||||
|
||||
void AmigaSound::stopSong() {
|
||||
_mixer->stopHandle(_modHandle);
|
||||
_fanfareCount = _fluteCount = 0;
|
||||
}
|
||||
|
||||
void AmigaSound::updateMusic() {
|
||||
if (_fanfareCount > 0) {
|
||||
--_fanfareCount;
|
||||
if (_fanfareCount == 0) {
|
||||
playSong(_fanfareRestore);
|
||||
}
|
||||
}
|
||||
if (_fluteCount > 0 && (_lastOverride == 40 || _lastOverride == 3)) {
|
||||
--_fluteCount;
|
||||
if (_fluteCount == 0) {
|
||||
playPattern("JUNG", 5 + _vm->randomizer.getRandomNumber(6));
|
||||
_fluteCount = 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AmigaSound::playSound(const char *base) {
|
||||
debug(7, "AmigaSound::playSound(%s)", base);
|
||||
char soundName[20];
|
||||
Common::sprintf_s(soundName, "%s.AMR", base);
|
||||
|
||||
uint32 soundSize;
|
||||
Common::File *f = _vm->resource()->findSound(soundName, &soundSize);
|
||||
if (f) {
|
||||
uint8 *soundData = (uint8 *)malloc(soundSize);
|
||||
if (soundData) {
|
||||
f->read(soundData, soundSize);
|
||||
|
||||
Audio::AudioStream *stream = Audio::makeRawStream(soundData, soundSize, 11025, 0);
|
||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Audio::AudioStream *AmigaSound::loadModule(const char *base, int num) {
|
||||
debug(7, "AmigaSound::loadModule(%s, %d)", base, num);
|
||||
char name[20];
|
||||
|
||||
// load song/pattern data
|
||||
uint32 sngDataSize;
|
||||
Common::sprintf_s(name, "%s.SNG", base);
|
||||
uint8 *sngData = _vm->resource()->loadFile(name, 0, &sngDataSize);
|
||||
Common::MemoryReadStream sngStr(sngData, sngDataSize);
|
||||
|
||||
// load instruments/wave data
|
||||
uint32 insDataSize;
|
||||
Common::sprintf_s(name, "%s.INS", base);
|
||||
uint8 *insData = _vm->resource()->loadFile(name, 0, &insDataSize);
|
||||
Common::MemoryReadStream insStr(insData, insDataSize);
|
||||
|
||||
Audio::AudioStream *stream = Audio::makeRjp1Stream(&sngStr, &insStr, num, _mixer->getOutputRate());
|
||||
|
||||
delete[] sngData;
|
||||
delete[] insData;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
void AmigaSound::playModule(const char *base, int song) {
|
||||
_mixer->stopHandle(_modHandle);
|
||||
Audio::AudioStream *stream = loadModule(base, song);
|
||||
if (stream) {
|
||||
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_modHandle, stream);
|
||||
}
|
||||
_fanfareCount = 0;
|
||||
}
|
||||
|
||||
void AmigaSound::playPattern(const char *base, int pattern) {
|
||||
_mixer->stopHandle(_patHandle);
|
||||
Audio::AudioStream *stream = loadModule(base, -pattern);
|
||||
if (stream) {
|
||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_patHandle, stream);
|
||||
}
|
||||
}
|
||||
|
||||
bool AmigaSound::playSpecialSfx(int16 sfx) {
|
||||
switch (sfx) {
|
||||
case 5: // normal volume
|
||||
break;
|
||||
case 15: // soft volume
|
||||
break;
|
||||
case 14: // medium volume
|
||||
break;
|
||||
case 25: // open door
|
||||
playSound("116BSSSS");
|
||||
break;
|
||||
case 26: // close door
|
||||
playSound("105ASSSS");
|
||||
break;
|
||||
case 56: // light switch
|
||||
playSound("27SSSSSS");
|
||||
break;
|
||||
case 57: // hydraulic doors open
|
||||
playSound("96SSSSSS");
|
||||
break;
|
||||
case 58: // hydraulic doors close
|
||||
playSound("97SSSSSS");
|
||||
break;
|
||||
case 59: // metallic door slams
|
||||
playSound("105SSSSS");
|
||||
break;
|
||||
case 63: // oracle rezzes in
|
||||
playSound("132SSSSS");
|
||||
break;
|
||||
case 27: // cloth slide 1
|
||||
playSound("135SSSSS");
|
||||
break;
|
||||
case 83: // splash
|
||||
playSound("18SSSSSS");
|
||||
break;
|
||||
case 85: // aggression enhancer
|
||||
playSound("138BSSSS");
|
||||
break;
|
||||
case 68: // dino ray
|
||||
playSound("138SSSSS");
|
||||
break;
|
||||
case 140: // dino transformation
|
||||
playSound("55BSSSSS");
|
||||
break;
|
||||
case 141: // experimental laser
|
||||
playSound("55SSSSSS");
|
||||
break;
|
||||
case 94: // plane hatch open
|
||||
playSound("3SSSSSSS");
|
||||
break;
|
||||
case 95: // plane hatch close
|
||||
playSound("4SSSSSSS");
|
||||
break;
|
||||
case 117: // oracle rezzes out
|
||||
playSound("70SSSSSS");
|
||||
break;
|
||||
case 124: // dino horn
|
||||
playSound("103SSSSS");
|
||||
break;
|
||||
case 127: // punch
|
||||
playSound("128SSSSS");
|
||||
break;
|
||||
case 128: // body hits ground
|
||||
playSound("129SSSSS");
|
||||
break;
|
||||
case 137: // explosion
|
||||
playSound("88SSSSSS");
|
||||
break;
|
||||
case 86: // stone door grind 1
|
||||
playSound("1001SSSS");
|
||||
break;
|
||||
case 188: // stone door grind 2
|
||||
playSound("1002SSSS");
|
||||
break;
|
||||
case 28: // cloth slide 2
|
||||
playSound("1005SSSS");
|
||||
break;
|
||||
case 151: // rattle bars
|
||||
playSound("115SSSSS");
|
||||
break;
|
||||
case 152: // door dissolves
|
||||
playSound("56SSSSSS");
|
||||
break;
|
||||
case 153: // altar slides
|
||||
playSound("85SSSSSS");
|
||||
break;
|
||||
case 166 : // pull lever
|
||||
playSound("1008SSSS");
|
||||
break;
|
||||
case 182: // zap Frank
|
||||
playSound("1023SSSS");
|
||||
break;
|
||||
case 69: // splorch
|
||||
playSound("137ASSSS");
|
||||
break;
|
||||
case 70: // robot laser
|
||||
playSound("61SSSSSS");
|
||||
break;
|
||||
case 133: // pick hits stone
|
||||
playSound("71SSSSSS");
|
||||
break;
|
||||
case 165: // press button
|
||||
playSound("1007SSSS");
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Queen
|
||||
183
engines/queen/sound.h
Normal file
183
engines/queen/sound.h
Normal file
@@ -0,0 +1,183 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_SOUND_H
|
||||
#define QUEEN_SOUND_H
|
||||
|
||||
#include "audio/mixer.h"
|
||||
|
||||
namespace Audio {
|
||||
class AudioStream;
|
||||
}
|
||||
|
||||
namespace Common {
|
||||
class File;
|
||||
}
|
||||
|
||||
namespace Queen {
|
||||
|
||||
struct SongData {
|
||||
int16 tuneList[5];
|
||||
int16 volume;
|
||||
int16 tempo;
|
||||
int16 reverb;
|
||||
int16 overrideCmd;
|
||||
int16 ignore;
|
||||
};
|
||||
|
||||
struct TuneData {
|
||||
int16 tuneNum[9];
|
||||
int16 sfx[2];
|
||||
int16 mode;
|
||||
int16 delay;
|
||||
};
|
||||
|
||||
class MidiMusic;
|
||||
class QueenEngine;
|
||||
|
||||
class Sound {
|
||||
public:
|
||||
Sound(Audio::Mixer *mixer, QueenEngine *vm);
|
||||
virtual ~Sound() {}
|
||||
|
||||
/**
|
||||
* Factory method for subclasses of class Sound.
|
||||
*/
|
||||
static Sound *makeSoundInstance(Audio::Mixer *mixer, QueenEngine *vm, uint8 compression);
|
||||
|
||||
virtual void playSfx(uint16 sfx) {}
|
||||
virtual void playSong(int16 songNum) {}
|
||||
virtual void playSpeech(const char *base) {}
|
||||
|
||||
virtual void stopSfx() {}
|
||||
virtual void stopSong() {}
|
||||
virtual void stopSpeech() {}
|
||||
|
||||
virtual bool isSpeechActive() const { return false; }
|
||||
virtual bool isSfxActive() const { return false; }
|
||||
|
||||
virtual void updateMusic() {}
|
||||
|
||||
virtual void setVolume(int vol);
|
||||
virtual int getVolume() { return _musicVolume; }
|
||||
|
||||
void playLastSong() { playSong(_lastOverride); }
|
||||
|
||||
bool sfxOn() const { return _sfxToggle; }
|
||||
void sfxToggle(bool val) { _sfxToggle = val; }
|
||||
void toggleSfx() { _sfxToggle = !_sfxToggle; }
|
||||
|
||||
bool speechOn() const { return _speechToggle; }
|
||||
void speechToggle(bool val) { _speechToggle = val; }
|
||||
void toggleSpeech() { _speechToggle = !_speechToggle; }
|
||||
|
||||
bool musicOn() const { return _musicToggle; }
|
||||
void musicToggle(bool val) { _musicToggle = val; }
|
||||
void toggleMusic() { _musicToggle = !_musicToggle; }
|
||||
|
||||
bool speechSfxExists() const { return _speechSfxExists; }
|
||||
|
||||
int16 lastOverride() const { return _lastOverride; }
|
||||
|
||||
void saveState(byte *&ptr);
|
||||
void loadState(uint32 ver, byte *&ptr);
|
||||
|
||||
static const SongData _songDemo[];
|
||||
static const SongData _song[];
|
||||
static const TuneData _tuneDemo[];
|
||||
static const TuneData _tune[];
|
||||
static const char *const _sfxName[];
|
||||
static const int16 _jungleList[];
|
||||
|
||||
protected:
|
||||
|
||||
Audio::Mixer *_mixer;
|
||||
QueenEngine *_vm;
|
||||
|
||||
bool _sfxToggle;
|
||||
bool _speechToggle;
|
||||
bool _musicToggle;
|
||||
bool _speechSfxExists;
|
||||
|
||||
int16 _lastOverride;
|
||||
int _musicVolume;
|
||||
};
|
||||
|
||||
class PCSound : public Sound {
|
||||
public:
|
||||
PCSound(Audio::Mixer *mixer, QueenEngine *vm);
|
||||
~PCSound() override;
|
||||
|
||||
void playSfx(uint16 sfx) override;
|
||||
void playSpeech(const char *base) override;
|
||||
void playSong(int16 songNum) override;
|
||||
|
||||
void stopSfx() override { _mixer->stopHandle(_sfxHandle); }
|
||||
void stopSong() override;
|
||||
void stopSpeech() override { _mixer->stopHandle(_speechHandle); }
|
||||
|
||||
bool isSpeechActive() const override { return _mixer->isSoundHandleActive(_speechHandle); }
|
||||
bool isSfxActive() const override { return _mixer->isSoundHandleActive(_sfxHandle); }
|
||||
|
||||
void setVolume(int vol) override;
|
||||
|
||||
protected:
|
||||
void playSound(const char *base, bool isSpeech);
|
||||
|
||||
virtual void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) = 0;
|
||||
|
||||
Audio::SoundHandle _sfxHandle;
|
||||
Audio::SoundHandle _speechHandle;
|
||||
MidiMusic *_music;
|
||||
};
|
||||
|
||||
class AmigaSound : public Sound {
|
||||
public:
|
||||
AmigaSound(Audio::Mixer *mixer, QueenEngine *vm);
|
||||
|
||||
void playSfx(uint16 sfx) override;
|
||||
void playSong(int16 song) override;
|
||||
|
||||
void stopSfx() override;
|
||||
void stopSong() override;
|
||||
|
||||
bool isSfxActive() const override { return _mixer->isSoundHandleActive(_sfxHandle); }
|
||||
|
||||
void updateMusic() override;
|
||||
|
||||
protected:
|
||||
|
||||
void playSound(const char *base);
|
||||
Audio::AudioStream *loadModule(const char *base, int song);
|
||||
void playModule(const char *base, int song);
|
||||
void playPattern(const char *base, int pattern);
|
||||
bool playSpecialSfx(int16 sfx);
|
||||
|
||||
int16 _fanfareRestore;
|
||||
int _fanfareCount, _fluteCount;
|
||||
Audio::SoundHandle _modHandle;
|
||||
Audio::SoundHandle _patHandle;
|
||||
Audio::SoundHandle _sfxHandle;
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
131
engines/queen/state.cpp
Normal file
131
engines/queen/state.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/* 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 "queen/state.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
Direction State::findDirection(uint16 state) {
|
||||
static const Direction sd[] = {
|
||||
DIR_BACK,
|
||||
DIR_RIGHT,
|
||||
DIR_LEFT,
|
||||
DIR_FRONT
|
||||
};
|
||||
return sd[(state >> 2) & 3];
|
||||
}
|
||||
|
||||
StateTalk State::findTalk(uint16 state) {
|
||||
return (state & (1 << 9)) ? STATE_TALK_TALK : STATE_TALK_MUTE;
|
||||
}
|
||||
|
||||
StateGrab State::findGrab(uint16 state) {
|
||||
static const StateGrab sg[] = {
|
||||
STATE_GRAB_NONE,
|
||||
STATE_GRAB_DOWN,
|
||||
STATE_GRAB_UP,
|
||||
STATE_GRAB_MID
|
||||
};
|
||||
return sg[state & 3];
|
||||
}
|
||||
|
||||
StateOn State::findOn(uint16 state) {
|
||||
return (state & (1 << 8)) ? STATE_ON_ON : STATE_ON_OFF;
|
||||
}
|
||||
|
||||
Verb State::findDefaultVerb(uint16 state) {
|
||||
static const Verb sdv[] = {
|
||||
VERB_NONE,
|
||||
VERB_OPEN,
|
||||
VERB_NONE,
|
||||
VERB_CLOSE,
|
||||
|
||||
VERB_NONE,
|
||||
VERB_NONE,
|
||||
VERB_LOOK_AT,
|
||||
VERB_MOVE,
|
||||
|
||||
VERB_GIVE,
|
||||
VERB_TALK_TO,
|
||||
VERB_NONE,
|
||||
VERB_NONE,
|
||||
|
||||
VERB_USE,
|
||||
VERB_NONE,
|
||||
VERB_PICK_UP,
|
||||
VERB_NONE
|
||||
};
|
||||
return sdv[(state >> 4) & 0xF];
|
||||
}
|
||||
|
||||
StateUse State::findUse(uint16 state) {
|
||||
return (state & (1 << 10)) ? STATE_USE : STATE_USE_ON;
|
||||
}
|
||||
|
||||
void State::alterOn(uint16 *objState, StateOn state) {
|
||||
switch (state) {
|
||||
case STATE_ON_ON:
|
||||
*objState |= (1 << 8);
|
||||
break;
|
||||
case STATE_ON_OFF:
|
||||
*objState &= ~(1 << 8);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void State::alterDefaultVerb(uint16 *objState, Verb v) {
|
||||
uint16 val;
|
||||
switch (v) {
|
||||
case VERB_OPEN:
|
||||
val = 1;
|
||||
break;
|
||||
case VERB_CLOSE:
|
||||
val = 3;
|
||||
break;
|
||||
case VERB_MOVE:
|
||||
val = 7;
|
||||
break;
|
||||
case VERB_GIVE:
|
||||
val = 8;
|
||||
break;
|
||||
case VERB_USE:
|
||||
val = 12;
|
||||
break;
|
||||
case VERB_PICK_UP:
|
||||
val = 14;
|
||||
break;
|
||||
case VERB_TALK_TO:
|
||||
val = 9;
|
||||
break;
|
||||
case VERB_LOOK_AT:
|
||||
val = 6;
|
||||
break;
|
||||
default:
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
*objState = (*objState & ~0xF0) | (val << 4);
|
||||
}
|
||||
|
||||
} // End of namespace Queen
|
||||
112
engines/queen/state.h
Normal file
112
engines/queen/state.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_STATE_H
|
||||
#define QUEEN_STATE_H
|
||||
|
||||
#include "common/util.h"
|
||||
#include "queen/defs.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
|
||||
enum StateTalk {
|
||||
STATE_TALK_TALK,
|
||||
STATE_TALK_MUTE
|
||||
};
|
||||
|
||||
enum StateGrab {
|
||||
STATE_GRAB_NONE,
|
||||
STATE_GRAB_DOWN,
|
||||
STATE_GRAB_UP,
|
||||
STATE_GRAB_MID
|
||||
};
|
||||
|
||||
enum StateOn {
|
||||
STATE_ON_ON,
|
||||
STATE_ON_OFF
|
||||
};
|
||||
|
||||
enum StateUse {
|
||||
STATE_USE,
|
||||
STATE_USE_ON
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
Each object/item in game has a state field.
|
||||
(refer to ObjectData and ItemData).
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>Bits</td>
|
||||
<td>Description</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>USE</td>
|
||||
<td>10</td>
|
||||
<td>Use</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TALK</td>
|
||||
<td>9</td>
|
||||
<td>Talk</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ON</td>
|
||||
<td>8</td>
|
||||
<td>On/Off</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DEF</td>
|
||||
<td>7,6,5,4</td>
|
||||
<td>Default verb command</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DIR</td>
|
||||
<td>3,2</td>
|
||||
<td>Direction to face for the object</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GRAB</td>
|
||||
<td>1,0</td>
|
||||
<td>Grab Direction</td>
|
||||
</tr>
|
||||
</table>
|
||||
*/
|
||||
struct State {
|
||||
|
||||
static Direction findDirection(uint16 state);
|
||||
static StateTalk findTalk(uint16 state);
|
||||
static StateGrab findGrab(uint16 state);
|
||||
static StateOn findOn(uint16 state);
|
||||
static Verb findDefaultVerb(uint16 state);
|
||||
static StateUse findUse(uint16 state);
|
||||
|
||||
static void alterOn(uint16 *objState, StateOn state);
|
||||
static void alterDefaultVerb(uint16 *objState, Verb v);
|
||||
};
|
||||
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
584
engines/queen/structs.h
Normal file
584
engines/queen/structs.h
Normal file
@@ -0,0 +1,584 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_STRUCTS_H
|
||||
#define QUEEN_STRUCTS_H
|
||||
|
||||
#include "queen/defs.h"
|
||||
#include "common/endian.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
struct Box {
|
||||
int16 x1, y1, x2, y2;
|
||||
|
||||
Box()
|
||||
: x1(0), y1(0), x2(0), y2(0) {
|
||||
}
|
||||
|
||||
Box(int16 xx1, int16 yy1, int16 xx2, int16 yy2)
|
||||
: x1(xx1), y1(yy1), x2(xx2), y2(yy2) {
|
||||
}
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
x1 = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
y1 = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
x2 = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
y2 = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
|
||||
void writeToBE(byte *&ptr) {
|
||||
WRITE_BE_UINT16(ptr, x1); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, y1); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, x2); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, y2); ptr += 2;
|
||||
}
|
||||
|
||||
int16 xDiff() const {
|
||||
return x2 - x1;
|
||||
}
|
||||
|
||||
int16 yDiff() const {
|
||||
return y2 - y1;
|
||||
}
|
||||
|
||||
bool intersects(int16 x, int16 y, uint16 w, uint16 h) const {
|
||||
return (x + w > x1) && (y + h > y1) && (x <= x2) && (y <= y2);
|
||||
}
|
||||
|
||||
bool contains(int16 x, int16 y) const {
|
||||
return (x >= x1) && (x <= x2) && (y >= y1) && (y <= y2);
|
||||
}
|
||||
|
||||
bool operator==(const Box &b) const {
|
||||
return (x1 == b.x1) && (x2 == b.x2) && (y1 == b.y1) && (y2 == b.y2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Area {
|
||||
//! bitmask of connected areas
|
||||
int16 mapNeighbors;
|
||||
//! coordinates defining area limits
|
||||
Box box;
|
||||
//! scaling factors for bobs actors
|
||||
uint16 bottomScaleFactor, topScaleFactor;
|
||||
//! entry in ObjectData, object lying in this area
|
||||
uint16 object;
|
||||
|
||||
Area()
|
||||
: mapNeighbors(0), bottomScaleFactor(0), topScaleFactor(0), object(0) {
|
||||
}
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
mapNeighbors = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
box.readFromBE(ptr);
|
||||
bottomScaleFactor = READ_BE_UINT16(ptr); ptr += 2;
|
||||
topScaleFactor = READ_BE_UINT16(ptr); ptr += 2;
|
||||
object = READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
|
||||
void writeToBE(byte *&ptr) {
|
||||
WRITE_BE_UINT16(ptr, mapNeighbors); ptr += 2;
|
||||
box.writeToBE(ptr);
|
||||
WRITE_BE_UINT16(ptr, bottomScaleFactor); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, topScaleFactor); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, object); ptr += 2;
|
||||
}
|
||||
|
||||
uint16 calcScale(int16 y) const {
|
||||
uint16 dy = box.yDiff();
|
||||
int16 ds = scaleDiff();
|
||||
uint16 scale = 0;
|
||||
|
||||
if (dy) // Prevent division-by-zero
|
||||
scale = ((((y - box.y1) * 100) / dy) * ds) / 100 + bottomScaleFactor;
|
||||
|
||||
if (scale == 0)
|
||||
scale = 100;
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
int16 scaleDiff() const {
|
||||
return (int16)(topScaleFactor - bottomScaleFactor);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct WalkOffData {
|
||||
//! entry in ObjectData
|
||||
int16 entryObj;
|
||||
//! coordinates to reach
|
||||
uint16 x, y;
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
entryObj = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
x = READ_BE_UINT16(ptr); ptr += 2;
|
||||
y = READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
|
||||
void writeToBE(byte *&ptr) {
|
||||
WRITE_BE_UINT16(ptr, entryObj); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, x); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, y); ptr += 2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct GraphicData {
|
||||
//! coordinates of object
|
||||
uint16 x, y;
|
||||
//! bank bobframes
|
||||
/*!
|
||||
<table>
|
||||
<tr>
|
||||
<td>lastFrame == 0</td>
|
||||
<td>non-animated bob (one frame)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>lastFrame < 0</td>
|
||||
<td>rebound animation</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>firstFrame < 0</td>
|
||||
<td>BobSlot::animString (animation is described by a string)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>firstFrame > 0</td>
|
||||
<td>BobSlot::animNormal (animation is a sequence of frames)</td>
|
||||
</tr>
|
||||
</table>
|
||||
*/
|
||||
int16 firstFrame, lastFrame;
|
||||
//! moving speed of object
|
||||
uint16 speed;
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
x = READ_BE_UINT16(ptr); ptr += 2;
|
||||
y = READ_BE_UINT16(ptr); ptr += 2;
|
||||
firstFrame = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
lastFrame = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
speed = READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ObjectData {
|
||||
//! entry in OBJECT_NAME (<0: object is hidden, 0: object has been deleted)
|
||||
int16 name;
|
||||
//! coordinates of object
|
||||
uint16 x, y;
|
||||
//! entry in OBJECT_DESCR
|
||||
uint16 description;
|
||||
//! associated object
|
||||
int16 entryObj;
|
||||
//! room in which this object is available
|
||||
uint16 room;
|
||||
//! state of the object (grab direction, on/off, default command...)
|
||||
uint16 state;
|
||||
//! entry in GraphicData
|
||||
/*!
|
||||
<table>
|
||||
<tr>
|
||||
<td>value</td>
|
||||
<td>description</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>]-4000..-10]</td>
|
||||
<td>graphic image turned off</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-4</td>
|
||||
<td>person object (right facing)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-3</td>
|
||||
<td>person object (left facing)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-2</td>
|
||||
<td>animated bob (off)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-1</td>
|
||||
<td>static bob (off)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>object deleted</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>]0..5000]</td>
|
||||
<td>static or animated bob (on)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>]5000.. [</td>
|
||||
<td>'paste down' bob</td>
|
||||
</tr>
|
||||
</table>
|
||||
*/
|
||||
int16 image;
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
name = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
x = READ_BE_UINT16(ptr); ptr += 2;
|
||||
y = READ_BE_UINT16(ptr); ptr += 2;
|
||||
description = READ_BE_UINT16(ptr); ptr += 2;
|
||||
entryObj = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
room = READ_BE_UINT16(ptr); ptr += 2;
|
||||
state = READ_BE_UINT16(ptr); ptr += 2;
|
||||
image = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
|
||||
void writeToBE(byte *&ptr) {
|
||||
WRITE_BE_UINT16(ptr, name); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, x); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, y); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, description); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, entryObj); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, room); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, state); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, image); ptr += 2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ObjectDescription {
|
||||
//! entry in ObjectData or ItemData
|
||||
uint16 object;
|
||||
//! type of the description
|
||||
/*!
|
||||
refer to select.c l.75-101
|
||||
<table>
|
||||
<tr>
|
||||
<td>value</td>
|
||||
<td>description</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>random but starts at first description</td>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>random</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>sequential with loop</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>sequential and set description to last</td>
|
||||
</tr>
|
||||
</table>
|
||||
*/
|
||||
uint16 type;
|
||||
//! last entry possible in OBJECT_DESCR for this object
|
||||
uint16 lastDescription;
|
||||
//! last description number used (in order to avoid re-using it)
|
||||
uint16 lastSeenNumber;
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
object = READ_BE_UINT16(ptr); ptr += 2;
|
||||
type = READ_BE_UINT16(ptr); ptr += 2;
|
||||
lastDescription = READ_BE_UINT16(ptr); ptr += 2;
|
||||
lastSeenNumber = READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
|
||||
void writeToBE(byte *&ptr) {
|
||||
WRITE_BE_UINT16(ptr, object); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, type); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, lastDescription); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, lastSeenNumber); ptr += 2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ItemData {
|
||||
//! entry in OBJECT_NAME
|
||||
int16 name;
|
||||
//! entry in OBJECT_DESCR
|
||||
uint16 description;
|
||||
//! state of the object
|
||||
uint16 state;
|
||||
//! bank bobframe
|
||||
uint16 frame;
|
||||
//! entry in OBJECT_DESCR (>0 if available)
|
||||
int16 sfxDescription;
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
name = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
description = READ_BE_UINT16(ptr); ptr += 2;
|
||||
state = READ_BE_UINT16(ptr); ptr += 2;
|
||||
frame = READ_BE_UINT16(ptr); ptr += 2;
|
||||
sfxDescription = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
|
||||
void writeToBE(byte *&ptr) {
|
||||
WRITE_BE_UINT16(ptr, name); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, description); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, state); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, frame); ptr += 2;
|
||||
WRITE_BE_UINT16(ptr, sfxDescription); ptr += 2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ActorData {
|
||||
//! room in which the actor is
|
||||
int16 room;
|
||||
//! bob number associated to this actor
|
||||
int16 bobNum;
|
||||
//! entry in ACTOR_NAME
|
||||
uint16 name;
|
||||
//! gamestate entry/value, actor is valid if GAMESTATE[slot] == value
|
||||
int16 gsSlot, gsValue;
|
||||
//! spoken text color
|
||||
uint16 color;
|
||||
//! bank bobframe for standing position of the actor
|
||||
uint16 bobFrameStanding;
|
||||
//! initial coordinates in the room
|
||||
uint16 x, y;
|
||||
//! entry in ACTOR_ANIM
|
||||
uint16 anim;
|
||||
//! bank to use to load the actor file
|
||||
uint16 bankNum;
|
||||
//! entry in ACTOR_FILE
|
||||
uint16 file;
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
room = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
bobNum = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
name = READ_BE_UINT16(ptr); ptr += 2;
|
||||
gsSlot = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
gsValue = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
color = READ_BE_UINT16(ptr); ptr += 2;
|
||||
bobFrameStanding = READ_BE_UINT16(ptr); ptr += 2;
|
||||
x = READ_BE_UINT16(ptr); ptr += 2;
|
||||
y = READ_BE_UINT16(ptr); ptr += 2;
|
||||
anim = READ_BE_UINT16(ptr); ptr += 2;
|
||||
bankNum = READ_BE_UINT16(ptr); ptr += 2;
|
||||
file = READ_BE_UINT16(ptr); ptr += 2;
|
||||
// Fix the actor data (see queen.c - l.1518-1519). When there is no
|
||||
// valid actor file, we must load the data from the objects room bank.
|
||||
// This bank has number 15 (not 10 as in the data files).
|
||||
if (file == 0) {
|
||||
bankNum = 15;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CmdListData {
|
||||
//! action to perform
|
||||
Verb verb;
|
||||
//! first object used in the action
|
||||
int16 nounObj1;
|
||||
//! second object used in the action
|
||||
int16 nounObj2;
|
||||
//! song to play (>0: playbefore, <0: playafter)
|
||||
int16 song;
|
||||
//! if set, P2_SET_AREAS must be called (using CmdArea)
|
||||
bool setAreas;
|
||||
//! if set, P3_SET_OBJECTS must be called (using CmdObject)
|
||||
bool setObjects;
|
||||
//! if set, P4_SET_ITEMS must be called (using CmdInventory)
|
||||
bool setItems;
|
||||
//! if set, P1_SET_CONDITIONS must be called (using CmdGameState)
|
||||
bool setConditions;
|
||||
//! graphic image order
|
||||
int16 imageOrder;
|
||||
//! special section to execute (refer to execute.c l.423-451)
|
||||
int16 specialSection;
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
verb = (Verb)READ_BE_UINT16(ptr); ptr += 2;
|
||||
nounObj1 = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
nounObj2 = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
song = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
setAreas = READ_BE_UINT16(ptr) != 0; ptr += 2;
|
||||
setObjects = READ_BE_UINT16(ptr) != 0; ptr += 2;
|
||||
setItems = READ_BE_UINT16(ptr) != 0; ptr += 2;
|
||||
setConditions = READ_BE_UINT16(ptr) != 0; ptr += 2;
|
||||
imageOrder = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
specialSection = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
|
||||
bool match(const Verb& v, int16 obj1, int16 obj2) const {
|
||||
return verb == v && nounObj1 == obj1 && nounObj2 == obj2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CmdArea {
|
||||
//! CmdListData number
|
||||
int16 id;
|
||||
//! area to turn off/on (<0: off, >0: on)
|
||||
int16 area;
|
||||
//! room in which the area must be changed
|
||||
uint16 room;
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
id = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
area = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
room = READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CmdObject {
|
||||
//! CmdListData number
|
||||
int16 id;
|
||||
//! >0: show, <0: hide
|
||||
int16 dstObj;
|
||||
//! >0: copy from srcObj, 0: nothing, -1: delete dstObj
|
||||
int16 srcObj;
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
id = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
dstObj = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
srcObj = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CmdInventory {
|
||||
//! CmdListData number
|
||||
int16 id;
|
||||
//! <0: delete, >0: add
|
||||
int16 dstItem;
|
||||
//! >0: valid
|
||||
int16 srcItem;
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
id = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
dstItem = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
srcItem = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CmdGameState {
|
||||
//! CmdListData number
|
||||
int16 id;
|
||||
int16 gameStateSlot;
|
||||
int16 gameStateValue;
|
||||
uint16 speakValue;
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
id = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
gameStateSlot = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
gameStateValue = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
speakValue = READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct FurnitureData {
|
||||
//! room in which the furniture are
|
||||
int16 room;
|
||||
//! furniture object number
|
||||
/*!
|
||||
<table>
|
||||
<tr>
|
||||
<td>range</td>
|
||||
<td>type</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>]0..5000]</td>
|
||||
<td>static or animated</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>]5000..[</td>
|
||||
<td>paste down</td>
|
||||
</tr>
|
||||
</table>
|
||||
*/
|
||||
int16 objNum;
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
room = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
objNum = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct GraphicAnim {
|
||||
int16 keyFrame;
|
||||
int16 frame;
|
||||
uint16 speed;
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
keyFrame = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
frame = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
speed = READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct AnimFrame {
|
||||
uint16 frame;
|
||||
uint16 speed;
|
||||
};
|
||||
|
||||
|
||||
struct Person {
|
||||
//! actor settings to use
|
||||
const ActorData *actor;
|
||||
//! actor name
|
||||
const char *name;
|
||||
//! animation string
|
||||
const char *anim;
|
||||
//! current frame
|
||||
uint16 bobFrame;
|
||||
};
|
||||
|
||||
|
||||
struct TalkSelected {
|
||||
bool hasTalkedTo;
|
||||
int16 values[4];
|
||||
|
||||
void readFromBE(byte *&ptr) {
|
||||
hasTalkedTo = READ_BE_UINT16(ptr) != 0; ptr += 2;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
values[i] = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
void writeToBE(byte *&ptr) {
|
||||
WRITE_BE_UINT16(ptr, (uint16)hasTalkedTo); ptr += 2;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
WRITE_BE_UINT16(ptr, values[i]); ptr += 2;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct BobFrame {
|
||||
uint16 width, height;
|
||||
uint16 xhotspot, yhotspot;
|
||||
uint8 *data;
|
||||
};
|
||||
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
1815
engines/queen/talk.cpp
Normal file
1815
engines/queen/talk.cpp
Normal file
File diff suppressed because it is too large
Load Diff
227
engines/queen/talk.h
Normal file
227
engines/queen/talk.h
Normal file
@@ -0,0 +1,227 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_TALK_H
|
||||
#define QUEEN_TALK_H
|
||||
|
||||
#include "common/util.h"
|
||||
#include "queen/structs.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
class QueenEngine;
|
||||
|
||||
class Talk {
|
||||
public:
|
||||
|
||||
//! Public interface to run a talk from a file
|
||||
static void talk(const char *filename, int personInRoom, char *cutawayFilename, QueenEngine *vm);
|
||||
|
||||
//! Public interface to speak a sentence
|
||||
static bool speak(const char *sentence, Person *person, const char *voiceFilePrefix, QueenEngine *vm);
|
||||
|
||||
//! Read a string from ptr and update offset
|
||||
static void getString(const byte *ptr, uint16 &offset, char *str, int maxLength, int align = 2);
|
||||
|
||||
private:
|
||||
|
||||
//! Collection of constants used by Talk
|
||||
enum {
|
||||
LINE_HEIGHT = 10,
|
||||
MAX_STRING_LENGTH = 255,
|
||||
MAX_STRING_SIZE = (MAX_STRING_LENGTH + 1),
|
||||
MAX_TEXT_WIDTH = (320-18),
|
||||
PUSHUP = 4,
|
||||
ARROW_ZONE_UP = 5,
|
||||
ARROW_ZONE_DOWN = 6,
|
||||
DOG_HEADER_SIZE = 20,
|
||||
OPTION_TEXT_MARGIN = 24
|
||||
};
|
||||
|
||||
//! Special commands for speech
|
||||
enum {
|
||||
SPEAK_DEFAULT = 0,
|
||||
SPEAK_FACE_LEFT = -1,
|
||||
SPEAK_FACE_RIGHT = -2,
|
||||
SPEAK_FACE_FRONT = -3,
|
||||
SPEAK_FACE_BACK = -4,
|
||||
SPEAK_ORACLE = -5,
|
||||
SPEAK_UNKNOWN_6 = -6,
|
||||
SPEAK_AMAL_ON = -7,
|
||||
SPEAK_PAUSE = -8,
|
||||
SPEAK_NONE = -9
|
||||
};
|
||||
|
||||
struct DialogueNode {
|
||||
int16 head;
|
||||
int16 dialogueNodeValue1;
|
||||
int16 gameStateIndex;
|
||||
int16 gameStateValue;
|
||||
};
|
||||
|
||||
struct SpeechParameters {
|
||||
const char *name;
|
||||
signed char state,faceDirection;
|
||||
signed char body,bf,rf,af;
|
||||
const char *animation;
|
||||
signed char ff;
|
||||
};
|
||||
|
||||
QueenEngine *_vm;
|
||||
|
||||
//! Raw .dog file data (without 20 byte header)
|
||||
byte *_fileData;
|
||||
|
||||
//! Number of dialogue levels
|
||||
int16 _levelMax;
|
||||
|
||||
//! Unique key for this dialogue
|
||||
int16 _uniqueKey;
|
||||
|
||||
//! Used to select voice files
|
||||
int16 _talkKey;
|
||||
|
||||
int16 _jMax;
|
||||
|
||||
//! Used by findDialogueString
|
||||
int16 _pMax;
|
||||
|
||||
// Update game state efter dialogue
|
||||
int16 _gameState[2];
|
||||
int16 _testValue[2];
|
||||
int16 _itemNumber[2];
|
||||
|
||||
//! String data
|
||||
uint16 _person1PtrOff;
|
||||
|
||||
//! Cutaway data
|
||||
uint16 _cutawayPtrOff;
|
||||
|
||||
//! Data used if we have talked to the person before
|
||||
uint16 _person2PtrOff;
|
||||
|
||||
//! Data used if we haven't talked to the person before
|
||||
uint16 _joePtrOff;
|
||||
|
||||
//! Is a talking head
|
||||
bool _talkHead;
|
||||
|
||||
//! IDs for sentences
|
||||
DialogueNode _dialogueTree[18][6];
|
||||
|
||||
//! Greeting from person Joe has talked to before
|
||||
char _person2String[MAX_STRING_SIZE];
|
||||
|
||||
int _oldSelectedSentenceIndex;
|
||||
int _oldSelectedSentenceValue;
|
||||
|
||||
char _talkString[5][MAX_STRING_SIZE];
|
||||
char _joeVoiceFilePrefix[5][MAX_STRING_SIZE];
|
||||
|
||||
static const SpeechParameters _speechParameters[];
|
||||
|
||||
Talk(QueenEngine *vm);
|
||||
~Talk();
|
||||
|
||||
//! Perform talk in file and return a cutaway filename
|
||||
void talk(const char *filename, int personInRoom, char *cutawayFilename);
|
||||
|
||||
byte *loadDialogFile(const char *filename);
|
||||
|
||||
//! Load talk data from .dog file
|
||||
void load(const char *filename);
|
||||
|
||||
//! First things spoken
|
||||
void initialTalk();
|
||||
|
||||
//! Find a string in the dialogue tree
|
||||
void findDialogueString(uint16 offset, int16 id, int16 max, char *str);
|
||||
|
||||
//! Get TalkSelected struct for this talk
|
||||
TalkSelected *talkSelected();
|
||||
|
||||
//! Interface to the TalkSelected struct
|
||||
bool hasTalkedTo() { return talkSelected()->hasTalkedTo; }
|
||||
|
||||
//! Interface to the TalkSelected struct
|
||||
void setHasTalkedTo() { talkSelected()->hasTalkedTo = true; }
|
||||
|
||||
//! Get a selected value
|
||||
int16 selectedValue(int index) {
|
||||
return talkSelected()->values[index-1];
|
||||
}
|
||||
|
||||
//! Set a selected value
|
||||
void selectedValue(int index, int16 value) {
|
||||
talkSelected()->values[index-1] = value;
|
||||
}
|
||||
|
||||
//! The sentence will not be displayed again
|
||||
void disableSentence(int oldLevel, int selectedSentence);
|
||||
|
||||
//! Select what to say
|
||||
int16 selectSentence();
|
||||
|
||||
//! Speak sentence
|
||||
bool speak(const char *sentence, Person *person, const char *voiceFilePrefix);
|
||||
|
||||
//! Convert command in sentence to command code
|
||||
int getSpeakCommand(const Person *person, const char *sentence, unsigned &index);
|
||||
|
||||
//! Speak a part of a sentence
|
||||
void speakSegment(
|
||||
const char *segmentStart,
|
||||
int length,
|
||||
Person *person,
|
||||
int command,
|
||||
const char *voiceFilePrefix,
|
||||
int index);
|
||||
|
||||
void headStringAnimation(const SpeechParameters *parameters, int bobNum, int bankNum);
|
||||
|
||||
void stringAnimation(const SpeechParameters *parameters, int startFrame, int bankNum);
|
||||
|
||||
void defaultAnimation(
|
||||
const char *segment,
|
||||
bool isJoe,
|
||||
const SpeechParameters *parameters,
|
||||
int startFrame,
|
||||
int bankNum);
|
||||
|
||||
int countSpaces(const char *segment);
|
||||
|
||||
//! Get special parameters for speech
|
||||
const SpeechParameters *findSpeechParameters(
|
||||
const char *name,
|
||||
int state,
|
||||
int faceDirection);
|
||||
|
||||
int splitOption(const char *str, char optionText[5][MAX_STRING_SIZE]);
|
||||
|
||||
int splitOptionHebrew(const char *str, char optionText[5][MAX_STRING_SIZE]);
|
||||
|
||||
int splitOptionDefault(const char *str, char optionText[5][MAX_STRING_SIZE]);
|
||||
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
159
engines/queen/version.cpp
Normal file
159
engines/queen/version.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/* 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 "queen/version.h"
|
||||
#include "queen/defs.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/file.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
//! known FOTAQ versions
|
||||
static const RetailGameVersion gameVersions[] = {
|
||||
{ "PEM10", 1, 0x00000008, 22677657 },
|
||||
{ "CEM10", 1, 0x0000584E, 190787021 },
|
||||
{ "PFM10", 1, 0x0002CD93, 22157304 },
|
||||
{ "CFM10", 1, 0x00032585, 186689095 },
|
||||
{ "PGM10", 1, 0x00059ACA, 22240013 },
|
||||
{ "CGM10", 1, 0x0005F2A7, 217648975 },
|
||||
{ "PIM10", 1, 0x000866B1, 22461366 },
|
||||
{ "CIM10", 1, 0x0008BEE2, 190795582 },
|
||||
{ "CSM10", 1, 0x000B343C, 190730602 },
|
||||
{ "CHM10", 1, 0x000DA981, 190705558 },
|
||||
{ "PE100", 1, 0x00101EC6, 3724538 },
|
||||
{ "PE100", 1, 0x00102B7F, 3732177 },
|
||||
{ "PEint", 1, 0x00103838, 1915913 },
|
||||
{ "aEM10", 2, 0x00103F1E, 351775 },
|
||||
{ "CE101", 2, 0x00107D8D, 563335 },
|
||||
{ "PE100", 2, 0x001086D4, 597032 },
|
||||
{ "aGM10", 3, 0x00108C6A, 344575 }
|
||||
};
|
||||
|
||||
bool detectVersion(DetectedGameVersion *ver, Common::File *f) {
|
||||
memset(ver, 0, sizeof(DetectedGameVersion));
|
||||
|
||||
if (f->readUint32BE() == MKTAG('Q','T','B','L')) {
|
||||
f->read(ver->str, 6);
|
||||
f->skip(2);
|
||||
ver->compression = f->readByte();
|
||||
ver->features = GF_REBUILT;
|
||||
ver->queenTblVersion = 0;
|
||||
ver->queenTblOffset = 0;
|
||||
} else {
|
||||
const RetailGameVersion *gameVersion = detectGameVersionFromSize(f->size());
|
||||
if (gameVersion == nullptr) {
|
||||
warning("Unknown/unsupported FOTAQ version");
|
||||
return false;
|
||||
}
|
||||
Common::strcpy_s(ver->str, gameVersion->str);
|
||||
ver->compression = COMPRESSION_NONE;
|
||||
ver->features = 0;
|
||||
ver->queenTblVersion = gameVersion->queenTblVersion;
|
||||
ver->queenTblOffset = gameVersion->queenTblOffset;
|
||||
|
||||
// Handle game versions for which versionStr information is irrevelant
|
||||
if (gameVersion == &gameVersions[VER_AMI_DEMO]) { // CE101
|
||||
ver->language = Common::EN_ANY;
|
||||
ver->features |= GF_FLOPPY | GF_DEMO;
|
||||
ver->platform = Common::kPlatformAmiga;
|
||||
return true;
|
||||
}
|
||||
if (gameVersion == &gameVersions[VER_AMI_INTERVIEW]) { // PE100
|
||||
ver->language = Common::EN_ANY;
|
||||
ver->features |= GF_FLOPPY | GF_INTERVIEW;
|
||||
ver->platform = Common::kPlatformAmiga;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
switch (ver->str[1]) {
|
||||
case 'E':
|
||||
if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS) {
|
||||
ver->language = Common::RU_RUS;
|
||||
} else if (Common::parseLanguage(ConfMan.get("language")) == Common::EL_GRC) {
|
||||
ver->language = Common::EL_GRC;
|
||||
} else {
|
||||
ver->language = Common::EN_ANY;
|
||||
}
|
||||
break;
|
||||
case 'F':
|
||||
ver->language = Common::FR_FRA;
|
||||
break;
|
||||
case 'G':
|
||||
ver->language = Common::DE_DEU;
|
||||
break;
|
||||
case 'H':
|
||||
ver->language = Common::HE_ISR;
|
||||
break;
|
||||
case 'I':
|
||||
ver->language = Common::IT_ITA;
|
||||
break;
|
||||
case 'S':
|
||||
ver->language = Common::ES_ESP;
|
||||
break;
|
||||
case 'g':
|
||||
ver->language = Common::EL_GRC;
|
||||
break;
|
||||
case 'R':
|
||||
ver->language = Common::RU_RUS;
|
||||
break;
|
||||
default:
|
||||
error("Invalid language id '%c'", ver->str[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ver->str[0]) {
|
||||
case 'P':
|
||||
ver->features |= GF_FLOPPY;
|
||||
ver->platform = Common::kPlatformDOS;
|
||||
break;
|
||||
case 'C':
|
||||
ver->features |= GF_TALKIE;
|
||||
ver->platform = Common::kPlatformDOS;
|
||||
break;
|
||||
case 'a':
|
||||
ver->features |= GF_FLOPPY;
|
||||
ver->platform = Common::kPlatformAmiga;
|
||||
break;
|
||||
default:
|
||||
error("Invalid platform id '%c'", ver->str[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp(ver->str + 2, "100") == 0 || strcmp(ver->str + 2, "101") == 0) {
|
||||
ver->features |= GF_DEMO;
|
||||
} else if (strcmp(ver->str + 2, "int") == 0) {
|
||||
ver->features |= GF_INTERVIEW;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const RetailGameVersion *detectGameVersionFromSize(uint32 size) {
|
||||
for (int i = 0; i < VER_COUNT; ++i) {
|
||||
if (gameVersions[i].dataFileSize == size) {
|
||||
return &gameVersions[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace Queen
|
||||
59
engines/queen/version.h
Normal file
59
engines/queen/version.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_VERSION_H
|
||||
#define QUEEN_VERSION_H
|
||||
|
||||
#include "common/language.h"
|
||||
#include "common/platform.h"
|
||||
|
||||
namespace Common {
|
||||
class File;
|
||||
}
|
||||
|
||||
namespace Queen {
|
||||
|
||||
struct DetectedGameVersion {
|
||||
Common::Platform platform;
|
||||
Common::Language language;
|
||||
uint8 features;
|
||||
uint8 compression;
|
||||
char str[6];
|
||||
uint8 queenTblVersion;
|
||||
uint32 queenTblOffset;
|
||||
};
|
||||
|
||||
struct RetailGameVersion {
|
||||
char str[6];
|
||||
uint8 queenTblVersion;
|
||||
uint32 queenTblOffset;
|
||||
uint32 dataFileSize;
|
||||
};
|
||||
|
||||
//! detect game version
|
||||
bool detectVersion(DetectedGameVersion *ver, Common::File *f);
|
||||
|
||||
//! detect game version based on queen.1 datafile size
|
||||
const RetailGameVersion *detectGameVersionFromSize(uint32 size);
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
563
engines/queen/walk.cpp
Normal file
563
engines/queen/walk.cpp
Normal file
@@ -0,0 +1,563 @@
|
||||
/* 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 "common/textconsole.h"
|
||||
|
||||
#include "queen/walk.h"
|
||||
|
||||
#include "queen/bankman.h"
|
||||
#include "queen/input.h"
|
||||
#include "queen/logic.h"
|
||||
#include "queen/graphics.h"
|
||||
#include "queen/grid.h"
|
||||
#include "queen/queen.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
const MovePersonData Walk::_moveData[] = {
|
||||
{ "COMPY", -1, -6, 1, 6, 0, 0, 0, 0, 12, 12, 1, 14 },
|
||||
{ "DEINO", -1, -8, 1, 8, 0, 0, 0, 0, 11, 11, 1, 10 },
|
||||
{ "FAYE", -1, -6, 1, 6, 13, 18, 7, 12, 19, 22, 2, 5 },
|
||||
{ "GUARDS", -1, -6, 1, 6, 0, 0, 0, 0, 7, 7, 2, 5 },
|
||||
{ "PRINCESS1", -1, -6, 1, 6, 13, 18, 7, 12, 19, 21, 2, 5 },
|
||||
{ "PRINCESS2", -1, -6, 1, 6, 13, 18, 7, 12, 19, 21, 2, 5 },
|
||||
{ "AMGUARD", -1, -6, 1, 6, 13, 18, 7, 12, 19, 21, 2, 5 },
|
||||
{ "SPARKY", -1, -6, 1, 6, 13, 18, 7, 12, 21, 20, 2, 5 },
|
||||
{ "LOLA_SHOWER", -1, -6, 55, 60, 0, 0, 0, 0, 7, 7, 2, 5 },
|
||||
{ "LOLA", -24, -29, 24, 29, 0, 0, 0, 0, 30, 30, 2, 5 },
|
||||
{ "BOB", -15, -20, 15, 20, 21, 26, 0, 0, 27, 29, 2, 5 },
|
||||
{ "CHEF", -1, -4, 1, 4, 0, 0, 0, 0, 1, 5, 2, 4 },
|
||||
{ "HENRY", -1, -6, 1, 6, 0, 0, 0, 0, 7, 7, 2, 6 },
|
||||
{ "ANDERSON", -1, -6, 1, 6, 0, 0, 0, 0, 7, 7, 2, 5 },
|
||||
{ "JASPAR", -4, -9, 4, 9, 16, 21, 10, 15, 1, 3, 1, 10 },
|
||||
{ "PYGMY", -7, -12, 7, 12, 0, 0, 0, 0, 27, 27, 2, 5 },
|
||||
{ "FRANK", 7, 12, 1, 6, 0, 0, 0, 0, 13, 13, 2, 4 },
|
||||
{ "WEDGEWOOD", -20, -25, 20, 25, 0, 0, 0, 0, 1, 1, 1, 5 },
|
||||
{ "TMPD", -1, -6, 1, 6, 13, 18, 7, 12, 19, 21, 2, 5 },
|
||||
{ "IAN", -1, -6, 1, 6, 0, 0, 0, 0, 7, 7, 2, 6 },
|
||||
{ "*", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
Walk::Walk(QueenEngine *vm)
|
||||
: _vm(vm) {
|
||||
}
|
||||
|
||||
void Walk::animateJoePrepare() {
|
||||
// queen.c l.2748-2788
|
||||
uint16 i;
|
||||
for (i = 1; i <= _walkDataCount; ++i) {
|
||||
|
||||
WalkData *pwd = &_walkData[i];
|
||||
|
||||
if (pwd->dx < 0) {
|
||||
pwd->anim.set(11, 18, DIR_LEFT);
|
||||
} else {
|
||||
pwd->anim.set(11, 18, DIR_RIGHT);
|
||||
}
|
||||
|
||||
int16 k = ABS(pwd->dy);
|
||||
int16 ds = pwd->area->scaleDiff();
|
||||
if (ds > 0) {
|
||||
k *= ((k * ds) / pwd->area->box.yDiff()) / 2;
|
||||
}
|
||||
|
||||
if (ABS(pwd->dx) < k) {
|
||||
if (pwd->dy < 0) {
|
||||
if (ds < 0) {
|
||||
pwd->anim.set(19, 24, DIR_FRONT);
|
||||
} else {
|
||||
pwd->anim.set(25, 30, DIR_BACK);
|
||||
}
|
||||
} else if (pwd->dy > 0) {
|
||||
if (ds < 0) {
|
||||
pwd->anim.set(25, 30, DIR_BACK);
|
||||
} else {
|
||||
pwd->anim.set(19, 24, DIR_FRONT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Walk::animateJoe() {
|
||||
// queen.c l.2789-2835
|
||||
uint16 lastDirection = 0;
|
||||
uint16 i;
|
||||
BobSlot *pbs = _vm->graphics()->bob(0);
|
||||
_vm->logic()->joeFacing(_walkData[1].anim.facing);
|
||||
_vm->logic()->joeScale(_walkData[1].area->calcScale(pbs->y));
|
||||
_vm->logic()->joeFace();
|
||||
for (i = 1; i <= _walkDataCount && !_joeInterrupted; ++i) {
|
||||
|
||||
WalkData *pwd = &_walkData[i];
|
||||
|
||||
// area has been turned off, see if we should execute a cutaway
|
||||
if (pwd->area->mapNeighbors < 0) {
|
||||
// queen.c l.2838-2911
|
||||
_vm->logic()->handleSpecialArea(pwd->anim.facing, pwd->areaNum, i);
|
||||
_joeMoveBlock = true;
|
||||
return;
|
||||
}
|
||||
if (lastDirection != pwd->anim.facing) {
|
||||
pbs->animNormal(pwd->anim.firstFrame, pwd->anim.lastFrame, 1, false, false);
|
||||
}
|
||||
|
||||
uint16 moveSpeed = _vm->grid()->findScale(pbs->x, pbs->y) * 6 / 100;
|
||||
pbs->move(pbs->x + pwd->dx, pbs->y + pwd->dy, moveSpeed);
|
||||
pbs->xflip = (pbs->xdir < 0);
|
||||
while (pbs->moving) {
|
||||
// adjust Joe's movespeed according to scale
|
||||
pbs->scale = pwd->area->calcScale(pbs->y);
|
||||
_vm->logic()->joeScale(pbs->scale);
|
||||
pbs->scaleWalkSpeed(6);
|
||||
_vm->update(true);
|
||||
if (_vm->input()->cutawayQuit() || _vm->logic()->joeWalk() == JWM_EXECUTE || _vm->shouldQuit()) {
|
||||
stopJoe();
|
||||
break;
|
||||
}
|
||||
}
|
||||
lastDirection = pwd->anim.facing;
|
||||
}
|
||||
_vm->logic()->joeFacing(lastDirection);
|
||||
}
|
||||
|
||||
void Walk::animatePersonPrepare(const MovePersonData *mpd, int direction) {
|
||||
// queen.c l.2469-2572
|
||||
int i;
|
||||
for (i = 1; i <= _walkDataCount; ++i) {
|
||||
|
||||
WalkData *pwd = &_walkData[i];
|
||||
|
||||
if (pwd->dx < 0) {
|
||||
pwd->anim.set(mpd->walkLeft1, mpd->walkLeft2, DIR_LEFT);
|
||||
} else if (pwd->dx > 0) {
|
||||
pwd->anim.set(mpd->walkRight1, mpd->walkRight2, DIR_RIGHT);
|
||||
} else {
|
||||
if (ABS(mpd->walkLeft1) == ABS(mpd->walkRight1)) {
|
||||
pwd->anim.set(mpd->walkRight1, mpd->walkRight2, DIR_RIGHT);
|
||||
} else {
|
||||
// we have specific moves for this actor, see what direction they were last facing
|
||||
if (direction == -3) {
|
||||
// previously facing right
|
||||
pwd->anim.set(mpd->walkLeft1, mpd->walkLeft2, DIR_LEFT);
|
||||
} else {
|
||||
// previously facing left
|
||||
pwd->anim.set(mpd->walkRight1, mpd->walkRight2, DIR_RIGHT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int16 k = ABS(pwd->dy);
|
||||
int16 ds = pwd->area->scaleDiff();
|
||||
if (ds > 0) {
|
||||
k *= ((k * ds) / pwd->area->box.yDiff()) / 2;
|
||||
}
|
||||
|
||||
if (ABS(pwd->dx) < k) {
|
||||
if (pwd->dy < 0) {
|
||||
if (mpd->walkBack1 > 0) {
|
||||
pwd->anim.set(mpd->walkBack1, mpd->walkBack2, DIR_BACK);
|
||||
} else if (pwd->dx < 0) {
|
||||
pwd->anim.set(mpd->walkLeft1, mpd->walkLeft2, DIR_BACK);
|
||||
} else {
|
||||
pwd->anim.set(mpd->walkRight1, mpd->walkRight2, DIR_BACK);
|
||||
}
|
||||
} else if (pwd->dy > 0) {
|
||||
if (mpd->walkFront1 > 0) {
|
||||
pwd->anim.set(mpd->walkFront1, mpd->walkFront2, DIR_FRONT);
|
||||
} else if (ABS(mpd->walkLeft1) == ABS(mpd->walkRight1)) {
|
||||
if (pwd->dx < 0) {
|
||||
pwd->anim.set(mpd->walkLeft1, mpd->walkLeft2, DIR_FRONT);
|
||||
} else {
|
||||
pwd->anim.set(mpd->walkRight1, mpd->walkRight2, DIR_FRONT);
|
||||
}
|
||||
} else {
|
||||
// we have a special move for left/right, so select that instead!
|
||||
if (direction == -3) {
|
||||
// previously facing right
|
||||
pwd->anim.set(mpd->walkLeft1, mpd->walkLeft2, DIR_FRONT);
|
||||
} else {
|
||||
// previously facing left
|
||||
pwd->anim.set(mpd->walkRight1, mpd->walkRight2, DIR_FRONT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Walk::animatePerson(const MovePersonData *mpd, uint16 image, uint16 bobNum, uint16 bankNum, int direction) {
|
||||
// queen.c l.2572-2651
|
||||
BobSlot *pbs = _vm->graphics()->bob(bobNum);
|
||||
|
||||
// check to see which way person should be facing
|
||||
if (mpd->walkLeft1 == mpd->walkRight1) {
|
||||
pbs->xflip = (direction == -3);
|
||||
} else {
|
||||
// they have special walk for left and right, so don't flip
|
||||
pbs->xflip = false;
|
||||
}
|
||||
|
||||
uint16 i;
|
||||
for (i = 1; i <= _walkDataCount; ++i) {
|
||||
WalkData *pwd = &_walkData[i];
|
||||
|
||||
// unpack necessary frames for bob animation
|
||||
uint16 dstFrame = image;
|
||||
uint16 srcFrame = ABS(pwd->anim.firstFrame);
|
||||
while (srcFrame <= ABS(pwd->anim.lastFrame)) {
|
||||
_vm->bankMan()->unpack(srcFrame, dstFrame, bankNum);
|
||||
++dstFrame;
|
||||
++srcFrame;
|
||||
}
|
||||
// pass across bobs direction ONLY if walk is a mirror flip!
|
||||
if (ABS(mpd->walkLeft1) == ABS(mpd->walkRight1)) {
|
||||
pbs->animNormal(image, dstFrame - 1, mpd->animSpeed, false, pbs->xflip);
|
||||
} else {
|
||||
pbs->animNormal(image, dstFrame - 1, mpd->animSpeed, false, false);
|
||||
}
|
||||
|
||||
// move other actors at correct speed relative to scale
|
||||
uint16 moveSpeed = _vm->grid()->findScale(pbs->x, pbs->y) * mpd->moveSpeed / 100;
|
||||
pbs->move(pbs->x + pwd->dx, pbs->y + pwd->dy, moveSpeed);
|
||||
|
||||
// flip if one set of frames for actor
|
||||
if (mpd->walkLeft1 < 0 || ABS(mpd->walkLeft1) == ABS(mpd->walkRight1)) {
|
||||
pbs->xflip = pwd->dx < 0;
|
||||
}
|
||||
|
||||
while (pbs->moving) {
|
||||
_vm->update();
|
||||
pbs->scale = pwd->area->calcScale(pbs->y);
|
||||
pbs->scaleWalkSpeed(mpd->moveSpeed);
|
||||
if (_vm->input()->cutawayQuit() || _vm->shouldQuit()) {
|
||||
stopPerson(bobNum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int16 Walk::moveJoe(int direction, int16 endx, int16 endy, bool inCutaway) {
|
||||
_joeInterrupted = false;
|
||||
_joeMoveBlock = false;
|
||||
int16 can = 0;
|
||||
initWalkData();
|
||||
|
||||
uint16 oldx = _vm->graphics()->bob(0)->x;
|
||||
uint16 oldy = _vm->graphics()->bob(0)->y;
|
||||
|
||||
_vm->logic()->joeWalk(JWM_MOVE);
|
||||
|
||||
uint16 oldPos = _vm->grid()->findAreaForPos(GS_ROOM, oldx, oldy);
|
||||
uint16 newPos = _vm->grid()->findAreaForPos(GS_ROOM, endx, endy);
|
||||
|
||||
debug(9, "Walk::moveJoe(%d, %d, %d, %d, %d) - old = %d, new = %d", direction, oldx, oldy, endx, endy, oldPos, newPos);
|
||||
|
||||
// if in cutaway, allow Joe to walk anywhere
|
||||
if (newPos == 0 && inCutaway) {
|
||||
incWalkData(oldx, oldy, endx, endy, oldPos);
|
||||
} else {
|
||||
if (calc(oldPos, newPos, oldx, oldy, endx, endy)) {
|
||||
if (_walkDataCount > 0) {
|
||||
animateJoePrepare();
|
||||
animateJoe();
|
||||
if (_joeInterrupted) {
|
||||
can = -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// path has been blocked, make Joe say so
|
||||
_vm->logic()->makeJoeSpeak(4);
|
||||
can = -1;
|
||||
}
|
||||
}
|
||||
|
||||
_vm->graphics()->bob(0)->animating = false;
|
||||
if (_joeMoveBlock) {
|
||||
can = -2;
|
||||
_joeMoveBlock = false;
|
||||
} else if (direction > 0) {
|
||||
_vm->logic()->joeFacing(direction);
|
||||
}
|
||||
_vm->logic()->joePrevFacing(_vm->logic()->joeFacing());
|
||||
_vm->logic()->joeFace();
|
||||
return can;
|
||||
}
|
||||
|
||||
int16 Walk::movePerson(const Person *pp, int16 endx, int16 endy, uint16 curImage, int direction) {
|
||||
if (endx == 0 && endy == 0) {
|
||||
warning("Walk::movePerson() - endx == 0 && endy == 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16 can = 0;
|
||||
initWalkData();
|
||||
|
||||
uint16 bobNum = pp->actor->bobNum;
|
||||
uint16 bankNum = pp->actor->bankNum;
|
||||
|
||||
uint16 oldx = _vm->graphics()->bob(bobNum)->x;
|
||||
uint16 oldy = _vm->graphics()->bob(bobNum)->y;
|
||||
|
||||
uint16 oldPos = _vm->grid()->findAreaForPos(GS_ROOM, oldx, oldy);
|
||||
uint16 newPos = _vm->grid()->findAreaForPos(GS_ROOM, endx, endy);
|
||||
|
||||
debug(9, "Walk::movePerson(%d, %d, %d, %d, %d) - old = %d, new = %d", direction, oldx, oldy, endx, endy, oldPos, newPos);
|
||||
|
||||
// find MovePersonData associated to Person
|
||||
const MovePersonData *mpd = _moveData;
|
||||
while (mpd->name[0] != '*') {
|
||||
if (scumm_stricmp(mpd->name, pp->name) == 0) {
|
||||
break;
|
||||
}
|
||||
++mpd;
|
||||
}
|
||||
|
||||
if (calc(oldPos, newPos, oldx, oldy, endx, endy)) {
|
||||
if (_walkDataCount > 0) {
|
||||
animatePersonPrepare(mpd, direction);
|
||||
animatePerson(mpd, curImage, bobNum, bankNum, direction);
|
||||
}
|
||||
} else {
|
||||
can = -1;
|
||||
}
|
||||
|
||||
uint16 standingFrame = 31 + bobNum;
|
||||
|
||||
// make other person face the right direction
|
||||
BobSlot *pbs = _vm->graphics()->bob(bobNum);
|
||||
pbs->endx = endx;
|
||||
pbs->endy = endy;
|
||||
pbs->animating = false;
|
||||
pbs->scale = _walkData[_walkDataCount].area->calcScale(endy);
|
||||
if (_walkData[_walkDataCount].anim.facing == DIR_BACK) {
|
||||
_vm->bankMan()->unpack(mpd->backStandingFrame, standingFrame, bankNum);
|
||||
} else {
|
||||
_vm->bankMan()->unpack(mpd->frontStandingFrame, standingFrame, bankNum);
|
||||
}
|
||||
uint16 obj = _vm->logic()->objectForPerson(bobNum);
|
||||
if (_walkData[_walkDataCount].dx < 0) {
|
||||
_vm->logic()->objectData(obj)->image = -3;
|
||||
pbs->xflip = true;
|
||||
} else {
|
||||
_vm->logic()->objectData(obj)->image = -4;
|
||||
pbs->xflip = false;
|
||||
}
|
||||
pbs->frameNum = standingFrame;
|
||||
return can;
|
||||
}
|
||||
|
||||
void Walk::stopJoe() {
|
||||
BobSlot *pbs = _vm->graphics()->bob(0);
|
||||
pbs->moving = false;
|
||||
_joeInterrupted = true;
|
||||
}
|
||||
|
||||
void Walk::stopPerson(uint16 bobNum) {
|
||||
BobSlot *pbs = _vm->graphics()->bob(bobNum);
|
||||
pbs->x = pbs->endx;
|
||||
pbs->y = pbs->endy;
|
||||
pbs->moving = false;
|
||||
}
|
||||
|
||||
bool Walk::calc(uint16 oldPos, uint16 newPos, int16 oldx, int16 oldy, int16 x, int16 y) {
|
||||
// if newPos is outside of an AREA then traverse Y axis until an AREA is found
|
||||
if (newPos == 0) {
|
||||
newPos = findAreaPosition(&x, &y, true);
|
||||
}
|
||||
|
||||
// do the same for oldPos in case Joe somehow sits on the border of an AREA
|
||||
// and does not register
|
||||
if (oldPos == 0) {
|
||||
oldPos = findAreaPosition(&oldx, &oldy, false);
|
||||
}
|
||||
|
||||
if (oldPos == newPos) {
|
||||
incWalkData(oldx, oldy, x, y, newPos);
|
||||
return true;
|
||||
} else if (calcPath(oldPos, newPos)) {
|
||||
uint16 i;
|
||||
int16 px = oldx;
|
||||
int16 py = oldy;
|
||||
for (i = 2; i <= _areaListCount; ++i) {
|
||||
uint16 a1 = _areaList[i - 1];
|
||||
uint16 a2 = _areaList[i];
|
||||
const Area *pa1 = &_roomArea[a1];
|
||||
const Area *pa2 = &_roomArea[a2];
|
||||
uint16 x1 = calcC(pa1->box.x1, pa1->box.x2, pa2->box.x1, pa2->box.x2, px);
|
||||
uint16 y1 = calcC(pa1->box.y1, pa1->box.y2, pa2->box.y1, pa2->box.y2, py);
|
||||
incWalkData(px, py, x1, y1, a1);
|
||||
px = x1;
|
||||
py = y1;
|
||||
}
|
||||
incWalkData(px, py, x, y, newPos);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int16 Walk::calcC(int16 c1, int16 c2, int16 c3, int16 c4, int16 lastc) {
|
||||
int16 s1 = MAX(c1, c3);
|
||||
int16 s2 = MIN(c2, c4);
|
||||
int16 c;
|
||||
if ((lastc >= s1 && lastc <= s2) || (lastc >= s2 && lastc <= s1)) {
|
||||
c = lastc;
|
||||
} else {
|
||||
c = (s1 + s2) / 2;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int16 Walk::findAreaPosition(int16 *x, int16 *y, bool recalibrate) {
|
||||
// In order to locate the nearest available area, the original algorithm
|
||||
// computes the horizontal and vertical distances for each available area.
|
||||
// Unlike the original, we also compute the diagonal distance.
|
||||
// To get an example of this in action, in the room D1, make Joe walking
|
||||
// to the wall at the right of the window (just above the radiator). On the
|
||||
// original game, Joe will go to the left door...
|
||||
uint16 i;
|
||||
uint16 pos = 1;
|
||||
uint32 minDist = (uint32)~0;
|
||||
const Box *b = &_roomArea[1].box;
|
||||
for (i = 1; i <= _roomAreaCount; ++i) {
|
||||
|
||||
b = &_roomArea[i].box;
|
||||
|
||||
uint16 dx1 = ABS(b->x1 - *x);
|
||||
uint16 dx2 = ABS(b->x2 - *x);
|
||||
uint16 dy1 = ABS(b->y1 - *y);
|
||||
uint16 dy2 = ABS(b->y2 - *y);
|
||||
uint16 csx = MIN(dx1, dx2);
|
||||
uint16 csy = MIN(dy1, dy2);
|
||||
|
||||
bool inX = (*x >= b->x1) && (*x <= b->x2);
|
||||
bool inY = (*y >= b->y1) && (*y <= b->y2);
|
||||
|
||||
uint32 dist = minDist;
|
||||
if (!inX && !inY) {
|
||||
dist = csx * csx + csy * csy;
|
||||
} else if (inX) {
|
||||
dist = csy * csy;
|
||||
} else if (inY) {
|
||||
dist = csx * csx;
|
||||
}
|
||||
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
pos = i;
|
||||
}
|
||||
}
|
||||
// we now have the closest area near X,Y, so we can recalibrate
|
||||
// the X,Y coord to be in this area
|
||||
if (recalibrate) {
|
||||
b = &_roomArea[pos].box;
|
||||
if (*x < b->x1) *x = b->x1;
|
||||
if (*x > b->x2) *x = b->x2;
|
||||
if (*y < b->y1) *y = b->y1;
|
||||
if (*y > b->y2) *y = b->y2;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
uint16 Walk::findFreeArea(uint16 area) const {
|
||||
uint16 testArea;
|
||||
uint16 freeArea = 0;
|
||||
uint16 map = ABS(_roomArea[area].mapNeighbors);
|
||||
for (testArea = 1; testArea <= _roomAreaCount; ++testArea) {
|
||||
int b = _roomAreaCount - testArea;
|
||||
if (map & (1 << b)) {
|
||||
// connecting area, check if it's been struck off
|
||||
if (!isAreaStruck(testArea)) {
|
||||
// legitimate connecting area, keep it
|
||||
freeArea = testArea;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return freeArea;
|
||||
}
|
||||
|
||||
bool Walk::isAreaStruck(uint16 area) const {
|
||||
uint16 i;
|
||||
bool found = false;
|
||||
for (i = 1; i <= _areaStrikeCount; ++i) {
|
||||
if (_areaStrike[i] == area) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool Walk::calcPath(uint16 oldArea, uint16 newArea) {
|
||||
debug(9, "Walk::calcPath(%d, %d)", oldArea, newArea);
|
||||
_areaList[1] = _areaStrike[1] = oldArea;
|
||||
_areaListCount = _areaStrikeCount = 1;
|
||||
uint16 area = oldArea;
|
||||
while (_areaListCount > 0 && area != newArea) {
|
||||
area = findFreeArea(area);
|
||||
if (!area) {
|
||||
// wrong path, rolling back
|
||||
_areaList[_areaListCount] = 0;
|
||||
--_areaListCount;
|
||||
area = _areaList[_areaListCount];
|
||||
} else {
|
||||
++_areaListCount;
|
||||
assert(_areaListCount < MAX_WALK_DATA);
|
||||
_areaList[_areaListCount] = area;
|
||||
if (!isAreaStruck(area)) {
|
||||
++_areaStrikeCount;
|
||||
assert(_areaStrikeCount < MAX_WALK_DATA);
|
||||
_areaStrike[_areaStrikeCount] = area;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _areaList[1] != 0;
|
||||
}
|
||||
|
||||
void Walk::initWalkData() {
|
||||
uint16 curRoom = _vm->logic()->currentRoom();
|
||||
_roomArea = _vm->grid()->area(curRoom, 0);
|
||||
_roomAreaCount = _vm->grid()->areaMax(curRoom);
|
||||
|
||||
_walkDataCount = 0;
|
||||
memset(_walkData, 0, sizeof(_walkData));
|
||||
_areaStrikeCount = 0;
|
||||
memset(_areaStrike, 0, sizeof(_areaStrike));
|
||||
_areaListCount = 0;
|
||||
memset(_areaList, 0, sizeof(_areaList));
|
||||
}
|
||||
|
||||
void Walk::incWalkData(int16 px, int16 py, int16 x, int16 y, uint16 areaNum) {
|
||||
debug(9, "Walk::incWalkData(%d, %d, %d)", (x - px), (y - py), areaNum);
|
||||
if (px != x || py != y) {
|
||||
++_walkDataCount;
|
||||
assert(_walkDataCount < MAX_WALK_DATA);
|
||||
WalkData *pwd = &_walkData[_walkDataCount];
|
||||
pwd->dx = x - px;
|
||||
pwd->dy = y - py;
|
||||
pwd->area = &_roomArea[areaNum];
|
||||
pwd->areaNum = areaNum;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Queen
|
||||
143
engines/queen/walk.h
Normal file
143
engines/queen/walk.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QUEEN_WALK_H
|
||||
#define QUEEN_WALK_H
|
||||
|
||||
#include "common/util.h"
|
||||
#include "queen/structs.h"
|
||||
|
||||
namespace Queen {
|
||||
|
||||
struct MovePersonAnim {
|
||||
int16 firstFrame;
|
||||
int16 lastFrame;
|
||||
Direction facing;
|
||||
|
||||
void set(int16 ff, int16 lf, Direction dir) {
|
||||
firstFrame = ff;
|
||||
lastFrame = lf;
|
||||
facing = dir;
|
||||
}
|
||||
};
|
||||
|
||||
struct WalkData {
|
||||
int16 dx, dy;
|
||||
const Area *area;
|
||||
uint16 areaNum;
|
||||
MovePersonAnim anim;
|
||||
};
|
||||
|
||||
struct MovePersonData {
|
||||
const char *name;
|
||||
int16 walkLeft1, walkLeft2;
|
||||
int16 walkRight1, walkRight2;
|
||||
int16 walkBack1, walkBack2;
|
||||
int16 walkFront1, walkFront2;
|
||||
uint16 frontStandingFrame;
|
||||
uint16 backStandingFrame;
|
||||
uint16 animSpeed;
|
||||
uint16 moveSpeed;
|
||||
};
|
||||
|
||||
class QueenEngine;
|
||||
|
||||
class Walk {
|
||||
public:
|
||||
|
||||
Walk(QueenEngine *vm);
|
||||
|
||||
int16 moveJoe(int direction, int16 endx, int16 endy, bool inCutaway);
|
||||
int16 movePerson(const Person *pp, int16 endx, int16 endy, uint16 curImage, int direction);
|
||||
|
||||
void stopJoe();
|
||||
void stopPerson(uint16 bobNum);
|
||||
|
||||
enum {
|
||||
MAX_WALK_DATA = 16
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
void animateJoePrepare();
|
||||
void animateJoe();
|
||||
|
||||
void animatePersonPrepare(const MovePersonData *mpd, int direction);
|
||||
void animatePerson(const MovePersonData *mpd, uint16 image, uint16 bobNum, uint16 bankNum, int direction);
|
||||
|
||||
/// compute transition coordinate
|
||||
static int16 calcC(int16 c1, int16 c2, int16 c3, int16 c4, int16 lastc);
|
||||
|
||||
/// find area for position
|
||||
int16 findAreaPosition(int16 *x, int16 *y, bool recalibrate);
|
||||
|
||||
/// find an area not already struck
|
||||
uint16 findFreeArea(uint16 area) const;
|
||||
|
||||
/// return true if the area is already on the walking path
|
||||
bool isAreaStruck(uint16 area) const;
|
||||
|
||||
/// calculates the path list from oldArea to newArea
|
||||
bool calcPath(uint16 oldArea, uint16 newArea);
|
||||
|
||||
/// resets path computed in calcPath()
|
||||
void initWalkData();
|
||||
|
||||
/// add an area to the path
|
||||
void incWalkData(int16 px, int16 py, int16 x, int16 y, uint16 area);
|
||||
|
||||
/// compute path (and populates _walkData) from current position to the new one
|
||||
bool calc(uint16 oldPos, uint16 newPos, int16 oldx, int16 oldy, int16 x, int16 y);
|
||||
|
||||
|
||||
/// areas for current room
|
||||
const Area *_roomArea;
|
||||
|
||||
/// number of areas for current room
|
||||
uint16 _roomAreaCount;
|
||||
|
||||
/// walking steps
|
||||
WalkData _walkData[MAX_WALK_DATA];
|
||||
|
||||
/// number of walking steps
|
||||
uint16 _walkDataCount;
|
||||
|
||||
uint16 _areaStrike[MAX_WALK_DATA];
|
||||
uint16 _areaStrikeCount;
|
||||
|
||||
uint16 _areaList[MAX_WALK_DATA];
|
||||
uint16 _areaListCount;
|
||||
|
||||
/// set if stopJoe() is called
|
||||
bool _joeInterrupted;
|
||||
|
||||
/// set if handleSpecialArea() is called
|
||||
bool _joeMoveBlock;
|
||||
|
||||
QueenEngine *_vm;
|
||||
|
||||
/// persons walking animation data
|
||||
static const MovePersonData _moveData[];
|
||||
};
|
||||
|
||||
} // End of namespace Queen
|
||||
|
||||
#endif
|
||||
496
engines/queen/xref.txt
Normal file
496
engines/queen/xref.txt
Normal file
@@ -0,0 +1,496 @@
|
||||
$Id$
|
||||
|
||||
Cross-reference for functions and variables for the original source code and
|
||||
the ScummVM implementation.
|
||||
|
||||
|
||||
BANKS
|
||||
=====
|
||||
erase() BankManager::close
|
||||
freeallframes() BankManager::eraseFrames(true)
|
||||
freeframes() BankManager::eraseFrames(false)
|
||||
loadbank() BankManager::load
|
||||
overpack() BankManager::overpack
|
||||
unpack() BankManager::unpack
|
||||
|
||||
|
||||
COMMAND
|
||||
=======
|
||||
ALTER_DEFAULT() *not needed* (use State::alterDefaultVerb)
|
||||
CLEAR_COMMAND() Command::clear
|
||||
EXECUTE_ACTION() Command::executeCurrentAction
|
||||
FIND_DEFAULT() *not needed* (use State::findDefaultVerb)
|
||||
LOOK() Command::lookAtSelectedObject
|
||||
LOOK_ICON(),LOOK_ITEM() Command::lookForCurrentIcon
|
||||
LOOK_ROOM() Command::lookForCurrentObject
|
||||
OPEN_CLOSE_OTHER() Command::openOrCloseAssociatedObject
|
||||
P1_SET_CONDITIONS() Command::setConditions
|
||||
P2_SET_AREAS() Command::setAreas
|
||||
P3_SET_OBJECTS() Command::setObjects
|
||||
P4_SET_ITEMS() Command::setItems
|
||||
SELECT() Command::grabCurrentSelection
|
||||
SELECT_ITEM() Command::grabSelectedItem
|
||||
SELECT_NOUN() Command::grabSelectedNoun
|
||||
SELECT_VERB() Command::grabSelectedVerb
|
||||
WALK() Command::makeJoeWalkTo
|
||||
-
|
||||
ACTION Command::_state.action
|
||||
ACTION2 Command::_state.selAction
|
||||
CLEVEL Command::_state.commandLevel
|
||||
COM_A Command::_cmdArea
|
||||
COM_A_MAX Command::_numCmdArea
|
||||
COM_O Command::_cmdObject
|
||||
COM_O_MAX Command::_numCmdObject
|
||||
COM_G Command::_cmdGameState
|
||||
COM_G_MAX Command::_numCmdGameState
|
||||
COM_I Command::_cmdInventory
|
||||
COM_I_MAX Command::_numCmdInventory
|
||||
COM_LIST Command::_cmdList
|
||||
COM_LIST_MAX Command::_numCmdList
|
||||
COMMANDstr Command::_cmdText
|
||||
DEFCOMM Command::_state.defaultVerb
|
||||
MKEY Command::_mouseKey
|
||||
OLDVERB,VERB Command::_state.*verb
|
||||
OLDNOUN,NOUN Command::_state.*noun
|
||||
NOUN2 Command::_state.selNoun
|
||||
PARSE Command::_parse
|
||||
SUBJ1,SUBJ2 Command::_state.subject*
|
||||
|
||||
|
||||
CREDIT SCRIPTING SYSTEM
|
||||
=======================
|
||||
Cinit() Credits::Credits()
|
||||
Ctext() *not needed* (included in Credits::update)
|
||||
Cupdate() Credits::update
|
||||
-
|
||||
Ccol Credits::_color
|
||||
Ccount Credits::_count
|
||||
Cfp
|
||||
Cflag Credits::_running
|
||||
Cfontsize Credits::_fontSize
|
||||
Cjustify Credits::_justify
|
||||
Cpausecount Credits::_pause
|
||||
Czone Credits::_zone
|
||||
|
||||
|
||||
CUTAWAY
|
||||
=======
|
||||
action_special_move() Cutaway::actionSpecialMove
|
||||
CUTAWAY() Cutaway::run
|
||||
MAKE_COMPLEX_ANIM() Cutaway::makeComplexAnimation
|
||||
SCENE_START() Logic::sceneStart
|
||||
SCENE_END() Logic::sceneStop
|
||||
-
|
||||
CUTON Input::_cutawayRunning
|
||||
CUTQUIT Input::_cutawayQuit
|
||||
FINAL_ROOM Cutaway::_finalRoom
|
||||
IROOM Cutaway::_initialRoom
|
||||
OBJ_CUT
|
||||
OBJ_ANIM
|
||||
OLDBANK
|
||||
PERSON_DATA
|
||||
SCENE Logic::_scene
|
||||
TROOM Cutaway::_temporaryRoom
|
||||
|
||||
|
||||
DEBUG
|
||||
=====
|
||||
cd_sample_check()
|
||||
debuginfo() Debugger::Cmd_Info
|
||||
select_new_room() Debugger::Cmd_Room
|
||||
-
|
||||
AREAVAR (boolean, if true display objects/areas boxes)
|
||||
|
||||
|
||||
GAME SETTINGS
|
||||
=============
|
||||
game_load() Logic::gameLoad
|
||||
game_save() Logic::gameSave
|
||||
-
|
||||
config_request
|
||||
MUSICTOGGLE Sound::_musicToggle / ConfMan.("music_mute")
|
||||
SFXTOGGLE Sound::_sfxToggle / ConfMan.("sfx_mute")
|
||||
TALKSPD QueenEngine::_talkSpeed / ConfMan.("talkspeed")
|
||||
TEXTTOGGLE QueenEngine::_subtitles / ConfMan.("subtitles")
|
||||
VersionStr GameVersion::versionString
|
||||
VOICETOGGLE Sound::_speechToggle / ConfMan.("speech_mute")
|
||||
VOLUME ? / ConfMan.("master_volume")
|
||||
|
||||
|
||||
GRAPHICS
|
||||
========
|
||||
bob() Graphics::drawBob
|
||||
CHECK_PARALLAX() Graphics::handleParallax
|
||||
clearallbobs() Graphics::clearBobs
|
||||
clearbob() BobSlot::clear
|
||||
DISP_OBJECTS() Graphics::setupRoomObjects
|
||||
drawbobs() Graphics::drawBobs
|
||||
invbob() Graphics::drawInventoryItem
|
||||
loadbackdrop() *not needed* (included in Display::setupNewRoom)
|
||||
loadpanel() Display::setupPanel
|
||||
MAKE_SPEAK_BOB() Graphics::setBobText
|
||||
makeanim() BobSlot::animNormal
|
||||
movebob() BobSlot::move
|
||||
pastebob() Graphics::pasteBob
|
||||
REDISP_OBJECT() Graphics::refreshObject
|
||||
requestor()
|
||||
shrinkbob() Graphics::shrinkFrame
|
||||
sortbobs() Graphics::sortBobs
|
||||
stringanim() BobSlot::animString
|
||||
-
|
||||
bobs Graphics::_bobs
|
||||
cambob Graphics::_cameraBob
|
||||
sortedbobs Graphics::_sortedBobs
|
||||
|
||||
|
||||
INPUT
|
||||
=====
|
||||
check_keys() Input::checkKeys()
|
||||
get_key() *not needed*
|
||||
-
|
||||
drawmouseflag *not needed* (equivalent to _display->showMouseCursor(bool))
|
||||
key_commands Input::_currentCommandKeys
|
||||
key_language Input::_commandKeys
|
||||
KEYVERB Input::_keyVerb
|
||||
MouseButton Input::_mouseButton
|
||||
mouseflag *not needed*
|
||||
no_check_keys Input::_noCheckKeys
|
||||
|
||||
|
||||
INVENTORY
|
||||
=========
|
||||
DEL_ITEM_NUM() Logic::inventoryDeleteItem
|
||||
INS_ITEM_NUM() Logic::inventoryInsertItem
|
||||
INVDWN() Logic::inventoryScroll
|
||||
INVENTORY() Logic::inventoryRefresh
|
||||
INVUP() Logic::inventoryScroll
|
||||
SETUP_ITEMS() Logic::inventorySetup
|
||||
-
|
||||
INV1,INV2,INV3,INV4 Logic::_inventoryItem
|
||||
|
||||
|
||||
JOE
|
||||
===
|
||||
FACE_JOE() Logic::joeFace
|
||||
GRAB_DIR(),GRAB_JOE() Logic::joeGrab
|
||||
SETUP_HERO() Logic::setupJoeInRoom
|
||||
SETUP_JOE() Logic::setupJoe
|
||||
USE_UNDERWEAR() Logic::joeUseUnderwear
|
||||
USE_CLOTHES() Logic::joeUseClothes
|
||||
USE_DRESS() Logic::joeUseDress
|
||||
-
|
||||
CUTJOEF Logic::_joe.cutFacing
|
||||
JOE_RESPstr Logic::_joeResponse
|
||||
JOEF,JX,JY,JDIR Logic::_joe.*
|
||||
JOEWALK Logic::_joe.walk
|
||||
|
||||
|
||||
JOURNAL
|
||||
=======
|
||||
clearlefttext() Journal::clearPanelTexts
|
||||
drawnames() Journal::drawSaveDescriptions
|
||||
findsaves() Journal::findSaveDescriptions
|
||||
menutext() Journal::drawPanelText
|
||||
predrawbobs() Journal::drawConfigPanel / Journal::drawNormalPanel
|
||||
prompt_do() *not needed*
|
||||
USE_JOURNAL() Logic::useJournal
|
||||
waitmousezone() *not needed*
|
||||
-
|
||||
choice Journal::_currentSaveSlot
|
||||
decbase Journal::_currentSavePage
|
||||
in_journal *not needed* (the hack in puttext() seems useless and CHECK_PARALLAX() is never called)
|
||||
save_descriptions Journal::_saveDescriptions
|
||||
walkgameload *not needed ?*
|
||||
|
||||
|
||||
LOGIC
|
||||
=====
|
||||
CHECK_PLAYER() QueenEngine::update
|
||||
CUTAWAY_SPECIAL() Logic::removeHotelItemsFromInventory
|
||||
DISP_ROOM() Logic::displayRoom
|
||||
FIND_BOB() Logic::findBob
|
||||
FIND_FRAME() Logic::findFrame
|
||||
FIND_GRAPHIC() Logic::graphicData
|
||||
P3_COPY_FROM() Logic::objectCopy
|
||||
R_MAP() Logic::handlePinnacleRoom
|
||||
restart_game()
|
||||
SETUP_BOBS() Graphics::unpackControlBank / Graphics::setupMouseCursor
|
||||
SETUP_FURNITURE() Graphics::setupRoomFurniture
|
||||
SETUP_ROOM() Logic::changeRoom
|
||||
SETUP_SCREENS() *not needed* (only calls Display::setupPanel)
|
||||
SETUP_VARS() *not needed* (equivalent to Command::clear(), SCENE=0, clear(gamestate))
|
||||
update() QueenEngine::update
|
||||
-
|
||||
A_ANIMstr Logic::_aAnim
|
||||
A_ANIM_MAX Logic::_numAAnim
|
||||
A_NAMEstr Logic::_aName
|
||||
A_NAME_MAX Logic::_numAName
|
||||
A_FILEstr Logic::_aFile
|
||||
A_FILE_MAX Logic::_numAFile
|
||||
ACTOR_DATA_MAX Logic::_numActors
|
||||
bamflag BamScene::_flag
|
||||
bamindex BamScene::_index
|
||||
DESCTOT Logic::_numDescriptions
|
||||
ENTRY_OBJ Logic::_entryObj
|
||||
FMAX Logic::_numFurnitureStatic
|
||||
FMAXA Logic::_numFurnitureAnimated
|
||||
FMAXLEN Logic::_numFurnitureAnimatedLen
|
||||
FRAMES Logic::_numFrames
|
||||
FURN_DATA_MAX Logic::_numFurniture
|
||||
GAMESTATE Logic::_gameState
|
||||
GRAPHIC_ANIM_MAX Logic::_numGraphicAnim
|
||||
GRAPHIC_DATA Logic::_graphicData
|
||||
GRAPHIC_MAX Logic::_numGraphics
|
||||
ITEMTOT Logic::_numItems
|
||||
ITEM_DATA Logic::_itemData
|
||||
NAMETOT Logic::_numNames
|
||||
OBJ_DESC_DATA Logic::_objectDescription
|
||||
OBJ_DESC_MAX Logic::_numObjDesc
|
||||
OBJECT_DATA Logic::_objectData
|
||||
OBJECT_DESCRstr Logic::_objDescription
|
||||
OBJECT_NAMEstr Logic::_objName
|
||||
OBJTOT Logic::_numObjects
|
||||
OLDROOM,ROOM,NEW_ROOM Logic::_*oom
|
||||
ROOMTOT Logic::_numRooms
|
||||
ROOM_DATA Logic::_roomData
|
||||
ROOM_NAMEstr Logic::_roomName
|
||||
SFACTOR Logic::_joe.scale
|
||||
VERB_NAMEstr Logic::_verbName
|
||||
WALK_OFF_DATA Logic::_walkOffData
|
||||
WALK_OFF_MAX Logic::_numWalkOffs
|
||||
|
||||
|
||||
PERSONS
|
||||
=======
|
||||
ALLOCATE_PERSON() Logic::allocatePersonFrames
|
||||
CREATE_ANIM() Graphics::setupPersonAnim
|
||||
SET_PERSON_DATA() Logic::initPerson
|
||||
SETUP_PERSON() Logic::setupPersonInRoom
|
||||
OBJ_PERSON() Logic::objectForPerson
|
||||
-
|
||||
NEW_ANIM Graphics::_newAnim
|
||||
PERSON_FACE
|
||||
PERSON_FACE_MAX
|
||||
PERSON_FRAMES Logic::_personFrames
|
||||
P_ANIMstr Person.anim
|
||||
P_NAMEstr Person.name
|
||||
P_STAND,P_BNUM,P_ROOM Person.actor->*
|
||||
P_BANK,P_X,P_Y,P_COLOR Person.actor->*
|
||||
P_VALUE,P_GAMES Person.actor->*
|
||||
SFRAME Person.bobFrame
|
||||
|
||||
|
||||
RESOURCE
|
||||
========
|
||||
tflen() Resource::fileSize
|
||||
topen() Resource::loadFile
|
||||
tseek() *not needed*
|
||||
|
||||
|
||||
SCREEN
|
||||
======
|
||||
Box() Display::drawBox
|
||||
calc_screen_scroll() Display::horizontalScrollUpdate
|
||||
changejoepal() Display::palSetJoe*
|
||||
check_colors() Display::palCustomColors
|
||||
check_pal_scroll Display::palCustomScroll
|
||||
clearpanel() Display::prepareUpdate
|
||||
drawbackdrop() Display::prepareUpdate
|
||||
drawpanel() Display::prepareUpdate
|
||||
drawscreen() Display::update
|
||||
dynalum() Display::dynalumUpdate
|
||||
fade_panel() Display::palGreyPanel
|
||||
fadein() Display::palFadeIn
|
||||
fadeout() Display::palFadeOut
|
||||
flashspecial() Display::palCustomFlash
|
||||
loadfont() Display::initFont
|
||||
palscroll() Display::palScroll
|
||||
putcharacter() Display::drawChar
|
||||
setpal() Display::palSet
|
||||
-
|
||||
BDxres Display::_bdWidth
|
||||
BDyres Display::_bdHeight
|
||||
clothespal Display::_palJoeClothes
|
||||
COMPANEL *not needed* (argument)
|
||||
dresspal Display::_palJoeDress
|
||||
font Display::_font
|
||||
font_sizes Display::_charWidth
|
||||
FULLSCREEN Display::_fullscreen
|
||||
nopalscroll Display::_pal.scrollable
|
||||
palette Display::_pal.room
|
||||
panelflag *not needed* (redundant with fullscreen)
|
||||
scrollx Display::_horizontalScroll
|
||||
tpal Display::_pal.screen
|
||||
|
||||
|
||||
SOUND
|
||||
=====
|
||||
alter_current_volume()
|
||||
playsong() Sound::playSong()
|
||||
sfxbusy() Sound::waitSfxFinished()
|
||||
sfxplay() Sound::playSfx()
|
||||
-
|
||||
song[] Sound::_song[]
|
||||
tunelist[] Sound::_tune[]
|
||||
CURRSONG Music::_currentSong
|
||||
SFXNAME Sound::_sfxName
|
||||
VOLUME
|
||||
|
||||
|
||||
STATE
|
||||
=====
|
||||
ALTER_STATE() State::alterState*
|
||||
FIND_STATE() State::findState*
|
||||
-
|
||||
|
||||
|
||||
TALK
|
||||
====
|
||||
FIND_SACTION() Talk::findSpeechParameters
|
||||
MOVE_SPEAK() *not needed* (included in Talk::getSpeakCommand)
|
||||
SPEAK() Talk::speak
|
||||
SPEAK_SUB() Talk::speakSegment
|
||||
talk() Talk::talk
|
||||
TALK_PROC() Talk::talk
|
||||
-
|
||||
A1,A12
|
||||
actiondata Talk::_speechParameters
|
||||
HEAD
|
||||
JMAX
|
||||
JOEKEYstr
|
||||
LEVEL
|
||||
LEVELMAX
|
||||
OLDLEVEL
|
||||
OLDS
|
||||
OWALK
|
||||
PERstr
|
||||
PKEYstr
|
||||
TALKHEAD
|
||||
TALKQUIT Input::_talkQuit
|
||||
TALKstr
|
||||
TALK_SELECTED Logic::_talkSelected
|
||||
|
||||
|
||||
TEXTS
|
||||
=====
|
||||
blanktexts() Display::clearTexts
|
||||
drawtext() Display::drawTexts
|
||||
Ink() Display::textCurrentColor
|
||||
MIDDLE() Display::textCenterX / Display::textSetCentered
|
||||
text() Display::setText
|
||||
textlen() Display::textWidth
|
||||
-
|
||||
textcol Display::_curTextColor
|
||||
texts Display::_texts
|
||||
|
||||
|
||||
WALK
|
||||
====
|
||||
CALC_PATH() Walk::calcPath
|
||||
CALC_WALK() Walk::incWalkData
|
||||
CALC_X() Walk::calcC
|
||||
CALC_Y() Walk::calcC
|
||||
CALCSCALE() Area::calcScale
|
||||
FIND_FREE_AREA Walk::findFreeArea
|
||||
FIND_NEWP() Walk::findAreaPosition
|
||||
FIND_OLDP() Walk::findAreaPosition
|
||||
MOVE_JOE() Walk::moveJoe
|
||||
MOVE_OTHER() Walk::movePerson
|
||||
-
|
||||
AREALIST Walk::_areaList
|
||||
AREASTRIKE Walk::_areaStrike
|
||||
movdata Walk::_moveData
|
||||
WALK_DATA Walk::_walkData
|
||||
WALKI Walk::_walkDataCount
|
||||
|
||||
|
||||
ZONES
|
||||
=====
|
||||
ClearZones() Grid::clear
|
||||
FIND_SCALE() Grid::findScale
|
||||
FIND_VERB() Grid::findVerbUnderCursor
|
||||
SETUP_PANEL_ZONES() Grid::setupPanel
|
||||
SETUP_ZONES() Grid::setupNewRoom
|
||||
SetZone() Grid::setZone
|
||||
zone() Grid::findZoneForPos / Logic::findAreaForPos
|
||||
-
|
||||
AREA Grid::_area
|
||||
AREAMAX Grid::_areaMax
|
||||
OBJECT_BOX Grid::_objectBox
|
||||
OBJMAX Grid::_objMax
|
||||
zones Grid::_zones
|
||||
|
||||
|
||||
(UNSORTED)
|
||||
==========
|
||||
in() Cutaway::inRange
|
||||
find_cd_cut() findCdCut
|
||||
find_cd_desc() *not needed* (included in Logic::joeSpeak)
|
||||
-
|
||||
Kstr
|
||||
bank9
|
||||
NEWDEF,
|
||||
M,A,
|
||||
FRAME,
|
||||
AM,
|
||||
WX,WY,
|
||||
PX,PY,
|
||||
LD,FD
|
||||
DESC2,DESC
|
||||
PERSON_OBJ
|
||||
FS,FE,FACE,
|
||||
TY,
|
||||
DY,
|
||||
I2,
|
||||
N,V,
|
||||
ds,bs,
|
||||
bx,by,
|
||||
dx,dy,
|
||||
SFAC,FDIR,
|
||||
OBJ,E,T,
|
||||
CH,
|
||||
OLDG,S2,S1,ITEM,TYPE,C,
|
||||
NAME,TL,TI,TS,WC,IMAGE,
|
||||
D,P,LI,R
|
||||
CANTQUIT !Input::_canQuit
|
||||
|
||||
|
||||
(NO NEED TO BE GLOBAL)
|
||||
======================
|
||||
Nstr,F1,F2,F3,F4,F5,F6,F7,F8,SF,BF,AS,MS // MOVE_OTHER (struct movdata *)
|
||||
Nstr,S,F,BODY,BF,RF,AF,SANIMstr,FF // FIND_SACTION (struct action *)
|
||||
CURRBOB // SETUP_FURNITURE, REDISP_OBJECT, DISP_OBJECTS
|
||||
PSY,PSX,CSX,DX1,DX2,DY1,DY2,PCF,CCF,CSY // FIND_NEWP, FIND_OLDP
|
||||
tx,ty,SFRAME,EFRAME,SPEED // FIND_GRAPHIC
|
||||
AREAMAXv
|
||||
CURRY
|
||||
OMAX,OMAXA
|
||||
TEMPA
|
||||
BANK,BNUM
|
||||
DIFF // LOOK local var
|
||||
RET // P1_SET_CONDITIONS local var
|
||||
BS,DS // CALC_SCALE
|
||||
SX,SY,
|
||||
NEWA // FIND_FREE_AREA local
|
||||
IX,IY // Cutaway locals
|
||||
COM // EXECUTE_ACTION local
|
||||
COMMAX // EXECUTE_ACTION local
|
||||
COND // EXECUTE_ACTION local
|
||||
CURRCOM // EXECUTE_ACTION local
|
||||
GSET // P1_SET_CONDITIONS local
|
||||
A2 // EXECUTE_ACTION local
|
||||
TEMPI // P1_SET_CONDITIONS local
|
||||
MAPC // findFreeArea local var
|
||||
NEWP,OLDP // locals in joeMove && personMove
|
||||
OLDX,X,OLDY,Y // passed as arguments
|
||||
X2,X1,XD,YD // incWalkData && findFreeArea locals
|
||||
Gstr // not needed, grab state
|
||||
Pstr // not needed, FIND_STATE result
|
||||
OUTLINE // not needed, textSet() Graphics::parameter
|
||||
FTOT // queen.c/SETUP_FURNITURE local var
|
||||
OBJMAXv // == Logic::_objMax[Logic::_currentRoom]
|
||||
TEMPstr
|
||||
WORDstr
|
||||
JOE2str,PERSON2str // locals in Talk::initialTalk
|
||||
SUBJECT
|
||||
tmpbamflag
|
||||
Reference in New Issue
Block a user