mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-22 18:02:05 +00:00
f158688c33
svn-id: r53807
1014 lines
24 KiB
C++
1014 lines
24 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* $URL$
|
|
* $Id$
|
|
*
|
|
*/
|
|
|
|
|
|
#include "scumm/actor.h"
|
|
#include "scumm/charset.h"
|
|
#include "scumm/object.h"
|
|
#include "scumm/scumm_v0.h"
|
|
#include "scumm/verbs.h"
|
|
|
|
namespace Scumm {
|
|
|
|
#define OPCODE(i, x) _opcodes[i]._OPCODE(ScummEngine_v0, x)
|
|
|
|
void ScummEngine_v0::setupOpcodes() {
|
|
/* 00 */
|
|
OPCODE(0x00, o5_stopObjectCode);
|
|
OPCODE(0x01, o2_putActor);
|
|
OPCODE(0x02, o5_startMusic);
|
|
OPCODE(0x03, o_doSentence);
|
|
/* 04 */
|
|
OPCODE(0x04, o2_isGreaterEqual);
|
|
OPCODE(0x05, o_stopCurrentScript);
|
|
OPCODE(0x06, o5_getDist);
|
|
OPCODE(0x07, o5_getActorRoom);
|
|
/* 08 */
|
|
OPCODE(0x08, o5_isNotEqual);
|
|
OPCODE(0x09, o_stopCurrentScript);
|
|
OPCODE(0x0a, o_stopCurrentScript);
|
|
OPCODE(0x0b, o_setActorBitVar);
|
|
/* 0C */
|
|
OPCODE(0x0c, o_loadSound);
|
|
OPCODE(0x0d, o_printEgo_c64);
|
|
OPCODE(0x0e, o_putActorAtObject);
|
|
OPCODE(0x0f, o2_clearState02);
|
|
/* 10 */
|
|
OPCODE(0x10, o5_breakHere);
|
|
OPCODE(0x11, o_animateActor);
|
|
OPCODE(0x12, o2_panCameraTo);
|
|
OPCODE(0x13, o_lockCostume);
|
|
/* 14 */
|
|
OPCODE(0x14, o_print_c64);
|
|
OPCODE(0x15, o5_walkActorToActor);
|
|
OPCODE(0x16, o5_getRandomNr);
|
|
OPCODE(0x17, o2_clearState08);
|
|
/* 18 */
|
|
OPCODE(0x18, o5_jumpRelative);
|
|
OPCODE(0x19, o_stopCurrentScript);
|
|
OPCODE(0x1a, o5_move);
|
|
OPCODE(0x1b, o_getActorBitVar);
|
|
/* 1C */
|
|
OPCODE(0x1c, o5_startSound);
|
|
OPCODE(0x1d, o_setBitVar);
|
|
OPCODE(0x1e, o2_walkActorTo);
|
|
OPCODE(0x1f, o2_ifState04);
|
|
/* 20 */
|
|
OPCODE(0x20, o5_stopMusic);
|
|
OPCODE(0x21, o2_putActor);
|
|
OPCODE(0x22, o4_saveLoadGame);
|
|
OPCODE(0x23, o_stopCurrentScript);
|
|
/* 24 */
|
|
OPCODE(0x24, o_unknown2);
|
|
OPCODE(0x25, o5_loadRoom);
|
|
OPCODE(0x26, o_getClosestObjActor);
|
|
OPCODE(0x27, o2_getActorY);
|
|
/* 28 */
|
|
OPCODE(0x28, o5_equalZero);
|
|
OPCODE(0x29, o_setOwnerOf);
|
|
OPCODE(0x2a, o2_delay);
|
|
OPCODE(0x2b, o_setActorBitVar);
|
|
/* 2C */
|
|
OPCODE(0x2c, o_stopCurrentScript);
|
|
OPCODE(0x2d, o2_putActorInRoom);
|
|
OPCODE(0x2e, o_print_c64);
|
|
OPCODE(0x2f, o2_ifState08);
|
|
/* 30 */
|
|
OPCODE(0x30, o_loadCostume);
|
|
OPCODE(0x31, o_getBitVar);
|
|
OPCODE(0x32, o2_setCameraAt);
|
|
OPCODE(0x33, o_lockScript);
|
|
/* 34 */
|
|
OPCODE(0x34, o5_getDist);
|
|
OPCODE(0x35, o_stopCurrentScript);
|
|
OPCODE(0x36, o2_walkActorToObject);
|
|
OPCODE(0x37, o2_clearState04);
|
|
/* 38 */
|
|
OPCODE(0x38, o2_isLessEqual);
|
|
OPCODE(0x39, o_stopCurrentScript);
|
|
OPCODE(0x3a, o2_subtract);
|
|
OPCODE(0x3b, o_stopCurrentScript);
|
|
/* 3C */
|
|
OPCODE(0x3c, o5_stopSound);
|
|
OPCODE(0x3d, o_setBitVar);
|
|
OPCODE(0x3e, o2_walkActorTo);
|
|
OPCODE(0x3f, o2_ifState02);
|
|
/* 40 */
|
|
OPCODE(0x40, o_cutscene);
|
|
OPCODE(0x41, o2_putActor);
|
|
OPCODE(0x42, o2_startScript);
|
|
OPCODE(0x43, o_doSentence);
|
|
/* 44 */
|
|
OPCODE(0x44, o2_isLess);
|
|
OPCODE(0x45, o_stopCurrentScript);
|
|
OPCODE(0x46, o5_increment);
|
|
OPCODE(0x47, o2_getActorX);
|
|
/* 48 */
|
|
OPCODE(0x48, o5_isEqual);
|
|
OPCODE(0x49, o_stopCurrentScript);
|
|
OPCODE(0x4a, o_loadRoom);
|
|
OPCODE(0x4b, o_setActorBitVar);
|
|
/* 4C */
|
|
OPCODE(0x4c, o_loadScript);
|
|
OPCODE(0x4d, o_lockRoom);
|
|
OPCODE(0x4e, o_putActorAtObject);
|
|
OPCODE(0x4f, o2_clearState02);
|
|
/* 50 */
|
|
OPCODE(0x50, o_nop);
|
|
OPCODE(0x51, o_animateActor);
|
|
OPCODE(0x52, o5_actorFollowCamera);
|
|
OPCODE(0x53, o_lockSound);
|
|
/* 54 */
|
|
OPCODE(0x54, o_setObjectName);
|
|
OPCODE(0x55, o5_walkActorToActor);
|
|
OPCODE(0x56, o_getActorMoving);
|
|
OPCODE(0x57, o2_clearState08);
|
|
/* 58 */
|
|
OPCODE(0x58, o_beginOverride);
|
|
OPCODE(0x59, o_stopCurrentScript);
|
|
OPCODE(0x5a, o2_add);
|
|
OPCODE(0x5b, o_getActorBitVar);
|
|
/* 5C */
|
|
OPCODE(0x5c, o5_startSound);
|
|
OPCODE(0x5d, o_setBitVar);
|
|
OPCODE(0x5e, o2_walkActorTo);
|
|
OPCODE(0x5f, o2_ifState04);
|
|
/* 60 */
|
|
OPCODE(0x60, o_cursorCommand);
|
|
OPCODE(0x61, o2_putActor);
|
|
OPCODE(0x62, o2_stopScript);
|
|
OPCODE(0x63, o_stopCurrentScript);
|
|
/* 64 */
|
|
OPCODE(0x64, o_ifActiveObject);
|
|
OPCODE(0x65, o_stopCurrentScript);
|
|
OPCODE(0x66, o_getClosestObjActor);
|
|
OPCODE(0x67, o5_getActorFacing);
|
|
/* 68 */
|
|
OPCODE(0x68, o5_isScriptRunning);
|
|
OPCODE(0x69, o_setOwnerOf);
|
|
OPCODE(0x6a, o_stopCurrentScript);
|
|
OPCODE(0x6b, o_setActorBitVar);
|
|
/* 6C */
|
|
OPCODE(0x6c, o_stopCurrentScript);
|
|
OPCODE(0x6d, o2_putActorInRoom);
|
|
OPCODE(0x6e, o2_dummy);
|
|
OPCODE(0x6f, o2_ifState08);
|
|
/* 70 */
|
|
OPCODE(0x70, o_lights);
|
|
OPCODE(0x71, o_getBitVar);
|
|
OPCODE(0x72, o_nop);
|
|
OPCODE(0x73, o5_getObjectOwner);
|
|
/* 74 */
|
|
OPCODE(0x74, o5_getDist);
|
|
OPCODE(0x75, o_printEgo_c64);
|
|
OPCODE(0x76, o2_walkActorToObject);
|
|
OPCODE(0x77, o2_clearState04);
|
|
/* 78 */
|
|
OPCODE(0x78, o2_isGreater);
|
|
OPCODE(0x79, o_stopCurrentScript);
|
|
OPCODE(0x7a, o_stopCurrentScript);
|
|
OPCODE(0x7b, o_stopCurrentScript);
|
|
/* 7C */
|
|
OPCODE(0x7c, o5_isSoundRunning);
|
|
OPCODE(0x7d, o_setBitVar);
|
|
OPCODE(0x7e, o2_walkActorTo);
|
|
OPCODE(0x7f, o2_ifNotState02);
|
|
/* 80 */
|
|
OPCODE(0x80, o_stopCurrentScript);
|
|
OPCODE(0x81, o2_putActor);
|
|
OPCODE(0x82, o_stopCurrentScript);
|
|
OPCODE(0x83, o_doSentence);
|
|
/* 84 */
|
|
OPCODE(0x84, o2_isGreaterEqual);
|
|
OPCODE(0x85, o_stopCurrentScript);
|
|
OPCODE(0x86, o_nop);
|
|
OPCODE(0x87, o5_getActorRoom);
|
|
/* 88 */
|
|
OPCODE(0x88, o5_isNotEqual);
|
|
OPCODE(0x89, o_stopCurrentScript);
|
|
OPCODE(0x8a, o_stopCurrentScript);
|
|
OPCODE(0x8b, o_setActorBitVar);
|
|
/* 8C */
|
|
OPCODE(0x8c, o_loadSound);
|
|
OPCODE(0x8d, o_stopCurrentScript);
|
|
OPCODE(0x8e, o_putActorAtObject);
|
|
OPCODE(0x8f, o2_setState02);
|
|
/* 90 */
|
|
OPCODE(0x90, o_pickupObject);
|
|
OPCODE(0x91, o_animateActor);
|
|
OPCODE(0x92, o2_panCameraTo);
|
|
OPCODE(0x93, o_unlockCostume);
|
|
/* 94 */
|
|
OPCODE(0x94, o5_print);
|
|
OPCODE(0x95, o2_actorFromPos);
|
|
OPCODE(0x96, o_stopCurrentScript);
|
|
OPCODE(0x97, o2_setState08);
|
|
/* 98 */
|
|
OPCODE(0x98, o2_restart);
|
|
OPCODE(0x99, o_stopCurrentScript);
|
|
OPCODE(0x9a, o5_move);
|
|
OPCODE(0x9b, o_getActorBitVar);
|
|
/* 9C */
|
|
OPCODE(0x9c, o5_startSound);
|
|
OPCODE(0x9d, o_setBitVar);
|
|
OPCODE(0x9e, o2_walkActorTo);
|
|
OPCODE(0x9f, o2_ifNotState04);
|
|
/* A0 */
|
|
OPCODE(0xa0, o5_stopObjectCode);
|
|
OPCODE(0xa1, o2_putActor);
|
|
OPCODE(0xa2, o4_saveLoadGame);
|
|
OPCODE(0xa3, o_stopCurrentScript);
|
|
/* A4 */
|
|
OPCODE(0xa4, o_unknown2);
|
|
OPCODE(0xa5, o5_loadRoom);
|
|
OPCODE(0xa6, o_stopCurrentScript);
|
|
OPCODE(0xa7, o2_getActorY);
|
|
/* A8 */
|
|
OPCODE(0xa8, o5_notEqualZero);
|
|
OPCODE(0xa9, o_setOwnerOf);
|
|
OPCODE(0xaa, o_stopCurrentScript);
|
|
OPCODE(0xab, o_setActorBitVar);
|
|
/* AC */
|
|
OPCODE(0xac, o_stopCurrentScript);
|
|
OPCODE(0xad, o2_putActorInRoom);
|
|
OPCODE(0xae, o_print_c64);
|
|
OPCODE(0xaf, o2_ifNotState08);
|
|
/* B0 */
|
|
OPCODE(0xb0, o_loadCostume);
|
|
OPCODE(0xb1, o_getBitVar);
|
|
OPCODE(0xb2, o2_setCameraAt);
|
|
OPCODE(0xb3, o_unlockScript);
|
|
/* B4 */
|
|
OPCODE(0xb4, o5_getDist);
|
|
OPCODE(0xb5, o_stopCurrentScript);
|
|
OPCODE(0xb6, o2_walkActorToObject);
|
|
OPCODE(0xb7, o2_setState04);
|
|
/* B8 */
|
|
OPCODE(0xb8, o2_isLessEqual);
|
|
OPCODE(0xb9, o_stopCurrentScript);
|
|
OPCODE(0xba, o2_subtract);
|
|
OPCODE(0xbb, o_stopCurrentScript);
|
|
/* BC */
|
|
OPCODE(0xbc, o5_stopSound);
|
|
OPCODE(0xbd, o_setBitVar);
|
|
OPCODE(0xbe, o2_walkActorTo);
|
|
OPCODE(0xbf, o2_ifNotState02);
|
|
/* C0 */
|
|
OPCODE(0xc0, o_endCutscene);
|
|
OPCODE(0xc1, o2_putActor);
|
|
OPCODE(0xc2, o2_startScript);
|
|
OPCODE(0xc3, o_doSentence);
|
|
/* C4 */
|
|
OPCODE(0xc4, o2_isLess);
|
|
OPCODE(0xc5, o_stopCurrentScript);
|
|
OPCODE(0xc6, o5_decrement);
|
|
OPCODE(0xc7, o2_getActorX);
|
|
/* C8 */
|
|
OPCODE(0xc8, o5_isEqual);
|
|
OPCODE(0xc9, o_stopCurrentScript);
|
|
OPCODE(0xca, o_loadRoom);
|
|
OPCODE(0xcb, o_setActorBitVar);
|
|
/* CC */
|
|
OPCODE(0xcc, o_loadScript);
|
|
OPCODE(0xcd, o_unlockRoom);
|
|
OPCODE(0xce, o_putActorAtObject);
|
|
OPCODE(0xcf, o2_setState02);
|
|
/* D0 */
|
|
OPCODE(0xd0, o_nop);
|
|
OPCODE(0xd1, o_animateActor);
|
|
OPCODE(0xd2, o5_actorFollowCamera);
|
|
OPCODE(0xd3, o_unlockSound);
|
|
/* D4 */
|
|
OPCODE(0xd4, o_setObjectName);
|
|
OPCODE(0xd5, o2_actorFromPos);
|
|
OPCODE(0xd6, o_getActorMoving);
|
|
OPCODE(0xd7, o2_setState08);
|
|
/* D8 */
|
|
OPCODE(0xd8, o_stopCurrentScript);
|
|
OPCODE(0xd9, o_stopCurrentScript);
|
|
OPCODE(0xda, o2_add);
|
|
OPCODE(0xdb, o_getActorBitVar);
|
|
/* DC */
|
|
OPCODE(0xdc, o5_startSound);
|
|
OPCODE(0xdd, o_setBitVar);
|
|
OPCODE(0xde, o2_walkActorTo);
|
|
OPCODE(0xdf, o2_ifNotState04);
|
|
/* E0 */
|
|
OPCODE(0xe0, o_cursorCommand);
|
|
OPCODE(0xe1, o2_putActor);
|
|
OPCODE(0xe2, o2_stopScript);
|
|
OPCODE(0xe3, o_stopCurrentScript);
|
|
/* E4 */
|
|
OPCODE(0xe4, o_ifActiveObject);
|
|
OPCODE(0xe5, o_loadRoomWithEgo);
|
|
OPCODE(0xe6, o_stopCurrentScript);
|
|
OPCODE(0xe7, o5_getActorFacing);
|
|
/* E8 */
|
|
OPCODE(0xe8, o5_isScriptRunning);
|
|
OPCODE(0xe9, o_setOwnerOf);
|
|
OPCODE(0xea, o_stopCurrentScript);
|
|
OPCODE(0xeb, o_setActorBitVar);
|
|
/* EC */
|
|
OPCODE(0xec, o_stopCurrentScript);
|
|
OPCODE(0xed, o2_putActorInRoom);
|
|
OPCODE(0xee, o2_dummy);
|
|
OPCODE(0xef, o2_ifNotState08);
|
|
/* F0 */
|
|
OPCODE(0xf0, o_lights);
|
|
OPCODE(0xf1, o_getBitVar);
|
|
OPCODE(0xf2, o_nop);
|
|
OPCODE(0xf3, o5_getObjectOwner);
|
|
/* F4 */
|
|
OPCODE(0xf4, o5_getDist);
|
|
OPCODE(0xf5, o_stopCurrentScript);
|
|
OPCODE(0xf6, o2_walkActorToObject);
|
|
OPCODE(0xf7, o2_setState04);
|
|
/* F8 */
|
|
OPCODE(0xf8, o2_isGreater);
|
|
OPCODE(0xf9, o_stopCurrentScript);
|
|
OPCODE(0xfa, o_stopCurrentScript);
|
|
OPCODE(0xfb, o_stopCurrentScript);
|
|
/* FC */
|
|
OPCODE(0xfc, o5_isSoundRunning);
|
|
OPCODE(0xfd, o_setBitVar);
|
|
OPCODE(0xfe, o2_walkActorTo);
|
|
OPCODE(0xff, o2_ifState02);
|
|
}
|
|
|
|
int ScummEngine_v0::getVarOrDirectWord(byte mask) {
|
|
return getVarOrDirectByte(mask);
|
|
}
|
|
|
|
uint ScummEngine_v0::fetchScriptWord() {
|
|
return fetchScriptByte();
|
|
}
|
|
|
|
int ScummEngine_v0::getActiveObject() {
|
|
if (_opcode & PARAM_2)
|
|
return _activeObject;
|
|
|
|
return fetchScriptByte();
|
|
}
|
|
|
|
void ScummEngine_v0::decodeParseString() {
|
|
byte buffer[512];
|
|
byte *ptr = buffer;
|
|
byte c;
|
|
bool insertSpace = false;
|
|
|
|
while ((c = fetchScriptByte())) {
|
|
|
|
insertSpace = (c & 0x80) != 0;
|
|
c &= 0x7f;
|
|
|
|
if (c == '/') {
|
|
*ptr++ = 13;
|
|
} else {
|
|
*ptr++ = c;
|
|
}
|
|
|
|
if (insertSpace)
|
|
*ptr++ = ' ';
|
|
|
|
}
|
|
*ptr = 0;
|
|
|
|
int textSlot = 0;
|
|
_string[textSlot].xpos = 0;
|
|
_string[textSlot].ypos = 0;
|
|
_string[textSlot].right = _screenWidth - 1;
|
|
_string[textSlot].center = false;
|
|
_string[textSlot].overhead = false;
|
|
|
|
if (_actorToPrintStrFor == 0xFF)
|
|
_string[textSlot].color = 14;
|
|
|
|
actorTalk(buffer);
|
|
}
|
|
|
|
void ScummEngine_v0::drawSentenceWord(int object, bool usePrep, bool objInInventory) {
|
|
const byte *temp;
|
|
int sentencePrep = 0;
|
|
|
|
// If object not in inventory, we except an index
|
|
if (!objInInventory)
|
|
_v0ObjectIndex = true;
|
|
else
|
|
_v0ObjectInInventory = true;
|
|
|
|
temp = getObjOrActorName(object);
|
|
|
|
_v0ObjectInInventory = false;
|
|
_v0ObjectIndex = false;
|
|
|
|
// Append the 'object-name'
|
|
if (temp) {
|
|
_sentenceBuf += " ";
|
|
_sentenceBuf += (const char *)temp;
|
|
}
|
|
|
|
// Append the modifier? (With / On / To / In)
|
|
if (!usePrep)
|
|
return;
|
|
|
|
if (_verbs[_activeVerb].prep == 0xFF) {
|
|
_v0ObjectInInventory = objInInventory;
|
|
sentencePrep = verbPrep(object);
|
|
} else {
|
|
sentencePrep = _verbs[_activeVerb].prep;
|
|
}
|
|
|
|
if (sentencePrep > 0 && sentencePrep <= 4) {
|
|
// The prepositions, like the fonts, were hard code in the engine. Thus
|
|
// we have to do that, too, and provde localized versions for all the
|
|
// languages MM/Zak are available in.
|
|
static const char *prepositions[][5] = {
|
|
{ " ", " in", " with", " on", " to" }, // English
|
|
{ " ", " mit", " mit", " mit", " zu" }, // German
|
|
{ " ", " dans", " avec", " sur", " <" }, // French
|
|
{ " ", " in", " con", " su", " a" }, // Italian
|
|
{ " ", " en", " con", " en", " a" }, // Spanish
|
|
};
|
|
int lang;
|
|
switch (_language) {
|
|
case Common::DE_DEU:
|
|
lang = 1;
|
|
break;
|
|
case Common::FR_FRA:
|
|
lang = 2;
|
|
break;
|
|
case Common::IT_ITA:
|
|
lang = 3;
|
|
break;
|
|
case Common::ES_ESP:
|
|
lang = 4;
|
|
break;
|
|
default:
|
|
lang = 0; // Default to english
|
|
}
|
|
|
|
_sentenceBuf += prepositions[lang][sentencePrep];
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v0::drawSentence() {
|
|
Common::Rect sentenceline;
|
|
bool inventoryFirst = false;
|
|
|
|
if (!(_userState & 32))
|
|
return;
|
|
|
|
// Current Verb, Walk/Use
|
|
if (getResourceAddress(rtVerb, _activeVerb)) {
|
|
_sentenceBuf = (char *)getResourceAddress(rtVerb, _activeVerb);
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
// If using inventory first, draw it first
|
|
if (_activeInvExecute && _activeInventory) {
|
|
drawSentenceWord(_activeInventory, true, true);
|
|
} else {
|
|
// Not using inventory, use selected object
|
|
if (_activeObject)
|
|
drawSentenceWord(_activeObjectIndex, true, false);
|
|
else
|
|
inventoryFirst = true;
|
|
}
|
|
|
|
|
|
// Draw the inventory?
|
|
if (_activeInventory > 0 && _activeObject2 == 0) {
|
|
// Only if inventory isnt first (it will already be drawn by now)
|
|
if (!_activeInvExecute) {
|
|
drawSentenceWord(_activeInventory, inventoryFirst, true);
|
|
} else {
|
|
// Draw the active object, which could be inventory based, or room based
|
|
if (_activeObject && !_activeObjectIndex) {
|
|
drawSentenceWord(_activeObject, inventoryFirst, true);
|
|
} else // Room based
|
|
drawSentenceWord(_activeObjectIndex, inventoryFirst, false);
|
|
}
|
|
|
|
// Draw the 2nd active object
|
|
} else if (_activeObject2) {
|
|
|
|
// 2nd Object is in inventory
|
|
if (_activeObject2Inv) {
|
|
_v0ObjectInInventory = true;
|
|
drawSentenceWord(_activeObject2, inventoryFirst, true);
|
|
} else {
|
|
drawSentenceWord(_activeObject2Index, inventoryFirst, false);
|
|
}
|
|
}
|
|
|
|
// Draw the active actor
|
|
if (_activeActor) {
|
|
Actor *a = derefActor(_activeActor, "");
|
|
|
|
_sentenceBuf += " ";
|
|
_sentenceBuf += (const char *)a->getActorName();
|
|
}
|
|
|
|
_string[2].charset = 1;
|
|
_string[2].ypos = _virtscr[kVerbVirtScreen].topline;
|
|
_string[2].xpos = 0;
|
|
_string[2].right = _virtscr[kVerbVirtScreen].w - 1;
|
|
_string[2].color = 16;
|
|
|
|
byte string[80];
|
|
const char *ptr = _sentenceBuf.c_str();
|
|
int i = 0, len = 0;
|
|
|
|
// Maximum length of printable characters
|
|
int maxChars = 40;
|
|
while (*ptr) {
|
|
if (*ptr != '@')
|
|
len++;
|
|
if (len > maxChars) {
|
|
break;
|
|
}
|
|
|
|
string[i++] = *ptr++;
|
|
|
|
}
|
|
string[i] = 0;
|
|
|
|
sentenceline.top = _virtscr[kVerbVirtScreen].topline;
|
|
sentenceline.bottom = _virtscr[kVerbVirtScreen].topline + 8;
|
|
sentenceline.left = 0;
|
|
sentenceline.right = _virtscr[kVerbVirtScreen].w - 1;
|
|
restoreBackground(sentenceline);
|
|
|
|
drawString(2, (byte *)string);
|
|
}
|
|
|
|
void ScummEngine_v0::o_stopCurrentScript() {
|
|
int script;
|
|
|
|
script = vm.slot[_currentScript].number;
|
|
|
|
if (_currentScript != 0 && vm.slot[_currentScript].number == script)
|
|
stopObjectCode();
|
|
else
|
|
stopScript(script);
|
|
}
|
|
|
|
void ScummEngine_v0::o_loadSound() {
|
|
int resid = fetchScriptByte();
|
|
ensureResourceLoaded(rtSound, resid);
|
|
}
|
|
|
|
void ScummEngine_v0::o_lockSound() {
|
|
int resid = fetchScriptByte();
|
|
_res->lock(rtSound, resid);
|
|
}
|
|
|
|
void ScummEngine_v0::o_unlockSound() {
|
|
int resid = fetchScriptByte();
|
|
_res->unlock(rtSound, resid);
|
|
}
|
|
|
|
void ScummEngine_v0::o_loadCostume() {
|
|
int resid = getVarOrDirectByte(PARAM_1);
|
|
ensureResourceLoaded(rtCostume, resid);
|
|
}
|
|
|
|
void ScummEngine_v0::o_lockCostume() {
|
|
int resid = fetchScriptByte();
|
|
_res->lock(rtCostume, resid);
|
|
}
|
|
|
|
void ScummEngine_v0::o_unlockCostume() {
|
|
int resid = fetchScriptByte();
|
|
_res->unlock(rtCostume, resid);
|
|
}
|
|
|
|
void ScummEngine_v0::o_loadScript() {
|
|
int resid = getVarOrDirectByte(PARAM_1);
|
|
ensureResourceLoaded(rtScript, resid);
|
|
}
|
|
|
|
void ScummEngine_v0::o_lockScript() {
|
|
int resid = fetchScriptByte();
|
|
_res->lock(rtScript, resid);
|
|
}
|
|
|
|
void ScummEngine_v0::o_unlockScript() {
|
|
int resid = fetchScriptByte();
|
|
_res->unlock(rtScript, resid);
|
|
}
|
|
|
|
void ScummEngine_v0::o_loadRoom() {
|
|
int resid = getVarOrDirectByte(PARAM_1);
|
|
ensureResourceLoaded(rtRoom, resid);
|
|
}
|
|
|
|
void ScummEngine_v0::o_loadRoomWithEgo() {
|
|
Actor *a;
|
|
int obj, room, x, y, dir;
|
|
|
|
obj = fetchScriptByte();
|
|
room = fetchScriptByte();
|
|
|
|
a = derefActor(VAR(VAR_EGO), "o_loadRoomWithEgo");
|
|
|
|
//0x634F
|
|
if (((ActorC64 *)a)->_miscflags & 0x40) {
|
|
// TODO: Check if this is the correct function
|
|
// to be calling here
|
|
stopObjectCode();
|
|
return;
|
|
}
|
|
|
|
// The original interpreter seems to set the actors new room X/Y to the last rooms X/Y
|
|
// This fixes a problem with MM: script 158 in room 12, the 'Oompf!' script
|
|
// This scripts runs before the actor position is set to the correct location
|
|
a->putActor(a->getPos().x, a->getPos().y, room);
|
|
_egoPositioned = false;
|
|
|
|
startScene(a->_room, a, obj);
|
|
|
|
getObjectXYPos(obj, x, y, dir);
|
|
AdjustBoxResult r = a->adjustXYToBeInBox(x, y);
|
|
x = r.x;
|
|
y = r.y;
|
|
a->putActor(x, y, _currentRoom);
|
|
a->setDirection(dir + 180);
|
|
|
|
camera._dest.x = camera._cur.x = a->getPos().x;
|
|
setCameraAt(a->getPos().x, a->getPos().y);
|
|
setCameraFollows(a);
|
|
|
|
_fullRedraw = true;
|
|
|
|
resetSentence();
|
|
|
|
if (x >= 0 && y >= 0) {
|
|
a->startWalkActor(x, y, -1);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v0::o_lockRoom() {
|
|
int resid = fetchScriptByte();
|
|
_res->lock(rtRoom, resid);
|
|
}
|
|
|
|
void ScummEngine_v0::o_unlockRoom() {
|
|
int resid = fetchScriptByte();
|
|
_res->unlock(rtRoom, resid);
|
|
}
|
|
|
|
void ScummEngine_v0::o_cursorCommand() {
|
|
// TODO
|
|
int state = 0;
|
|
|
|
_currentMode = fetchScriptByte();
|
|
switch (_currentMode) {
|
|
case 0:
|
|
state = 15;
|
|
break;
|
|
case 1:
|
|
state = 31;
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 3:
|
|
state = 247;
|
|
break;
|
|
}
|
|
|
|
setUserState(state);
|
|
debug(0, "o_cursorCommand(%d)", _currentMode);
|
|
}
|
|
|
|
void ScummEngine_v0::o_lights() {
|
|
int a;
|
|
|
|
a = getVarOrDirectByte(PARAM_1);
|
|
// Convert older light mode values into
|
|
// equivalent values.of later games
|
|
// 0 Darkness
|
|
// 1 Flashlight
|
|
// 2 Lighted area
|
|
if (a == 2)
|
|
_currentLights = 11;
|
|
else if (a == 1)
|
|
_currentLights = 4;
|
|
else
|
|
_currentLights = 0;
|
|
|
|
_fullRedraw = true;
|
|
}
|
|
|
|
void ScummEngine_v0::o_animateActor() {
|
|
int act = getVarOrDirectByte(PARAM_1);
|
|
int anim = getVarOrDirectByte(PARAM_2);
|
|
int unk = fetchScriptByte();
|
|
|
|
debug(0,"o_animateActor: unk %d", unk);
|
|
|
|
ActorC64 *a = (ActorC64*) derefActor(act, "o_animateActor");
|
|
|
|
// 0x6993
|
|
if (anim == 0xFE) {
|
|
a->_speaking = 0x80; // Enabled, but not switching
|
|
return;
|
|
}
|
|
// 0x69A3
|
|
if (anim == 0xFD) {
|
|
a->_speaking = 0x00;
|
|
return;
|
|
}
|
|
|
|
a->animateActor(anim);
|
|
}
|
|
|
|
void ScummEngine_v0::o_getActorMoving() {
|
|
getResultPos();
|
|
int act = getVarOrDirectByte(PARAM_1);
|
|
Actor *a = derefActor(act, "o_getActorMoving");
|
|
if (a->_moving)
|
|
setResult(1);
|
|
else
|
|
setResult(2);
|
|
}
|
|
|
|
void ScummEngine_v0::o_putActorAtObject() {
|
|
int obj, x, y;
|
|
Actor *a;
|
|
|
|
a = derefActor(getVarOrDirectByte(PARAM_1), "o_putActorAtObject");
|
|
|
|
obj = fetchScriptByte();
|
|
if (whereIsObject(obj) != WIO_NOT_FOUND) {
|
|
getObjectXYPos(obj, x, y);
|
|
AdjustBoxResult r = a->adjustXYToBeInBox(x, y);
|
|
x = r.x;
|
|
y = r.y;
|
|
} else {
|
|
x = 30;
|
|
y = 60;
|
|
}
|
|
|
|
a->putActor(x, y);
|
|
}
|
|
|
|
void ScummEngine_v0::o_pickupObject() {
|
|
int obj = fetchScriptByte();
|
|
if (obj == 0) {
|
|
obj = _activeObject;
|
|
}
|
|
|
|
if (obj < 1) {
|
|
error("pickupObject received invalid index %d (script %d)", obj, vm.slot[_currentScript].number);
|
|
}
|
|
|
|
if (getObjectIndex(obj) == -1)
|
|
return;
|
|
|
|
if (whereIsObjectInventory(_activeObject2) == WIO_INVENTORY) /* Don't take an */
|
|
return; /* object twice */
|
|
|
|
addObjectToInventory(obj, _roomResource);
|
|
markObjectRectAsDirty(obj);
|
|
putOwner(obj, VAR(VAR_EGO));
|
|
putState(obj, getState(obj) | kObjectState_08 | kObjectStateUntouchable);
|
|
clearDrawObjectQueue();
|
|
|
|
runInventoryScript(1);
|
|
}
|
|
|
|
void ScummEngine_v0::o_setObjectName() {
|
|
int obj = fetchScriptByte();
|
|
setObjectName(obj);
|
|
}
|
|
|
|
void ScummEngine_v0::o_nop() {
|
|
}
|
|
|
|
// TODO: Maybe translate actor flags in future.
|
|
void ScummEngine_v0::o_setActorBitVar() {
|
|
byte act = getVarOrDirectByte(PARAM_1);
|
|
byte mask = getVarOrDirectByte(PARAM_2);
|
|
byte mod = getVarOrDirectByte(PARAM_3);
|
|
|
|
// 0x63ED
|
|
if (act >= _numActors)
|
|
return;
|
|
|
|
ActorC64 *a = (ActorC64 *)derefActor(act, "o_setActorBitVar");
|
|
|
|
if (mod)
|
|
a->_miscflags |= mask;
|
|
else
|
|
a->_miscflags &= ~mask;
|
|
|
|
// This flag causes the actor to stop moving (used by script #158, Green Tentacle 'Oomph!')
|
|
if (a->_miscflags & 0x40)
|
|
a->stopActorMoving();
|
|
if (a->_miscflags & 0x80)
|
|
a->setActorCostume(0);
|
|
|
|
debug(0, "o_setActorBitVar(%d, %d, %d)", act, mask, mod);
|
|
}
|
|
|
|
void ScummEngine_v0::o_getActorBitVar() {
|
|
getResultPos();
|
|
byte act = getVarOrDirectByte(PARAM_1);
|
|
byte mask = getVarOrDirectByte(PARAM_2);
|
|
|
|
ActorC64 *a = (ActorC64 *)derefActor(act, "o_getActorBitVar");
|
|
setResult((a->_miscflags & mask) ? 1 : 0);
|
|
|
|
debug(0, "o_getActorBitVar(%d, %d, %d)", act, mask, (a->_miscflags & mask));
|
|
}
|
|
|
|
void ScummEngine_v0::o_setBitVar() {
|
|
byte flag = getVarOrDirectByte(PARAM_1);
|
|
byte mask = getVarOrDirectByte(PARAM_2);
|
|
byte mod = getVarOrDirectByte(PARAM_3);
|
|
|
|
if (mod)
|
|
_bitVars[flag] |= (1 << mask);
|
|
else
|
|
_bitVars[flag] &= ~(1 << mask);
|
|
|
|
debug(0, "o_setBitVar (%d, %d %d)", flag, mask, mod);
|
|
}
|
|
|
|
void ScummEngine_v0::o_getBitVar() {
|
|
getResultPos();
|
|
byte flag = getVarOrDirectByte(PARAM_1);
|
|
byte mask = getVarOrDirectByte(PARAM_2);
|
|
|
|
setResult((_bitVars[flag] & (1 << mask)) ? 1 : 0);
|
|
|
|
debug(0, "o_getBitVar (%d, %d %d)", flag, mask, _bitVars[flag] & (1 << mask));
|
|
}
|
|
|
|
void ScummEngine_v0::o_print_c64() {
|
|
_actorToPrintStrFor = fetchScriptByte();
|
|
decodeParseString();
|
|
}
|
|
|
|
void ScummEngine_v0::o_printEgo_c64() {
|
|
_actorToPrintStrFor = (byte)VAR(VAR_EGO);
|
|
decodeParseString();
|
|
}
|
|
|
|
void ScummEngine_v0::o_doSentence() {
|
|
byte entry = fetchScriptByte();
|
|
byte obj = fetchScriptByte();
|
|
fetchScriptByte();
|
|
|
|
runObjectScript(obj, entry, false, false, NULL);
|
|
}
|
|
|
|
void ScummEngine_v0::o_unknown2() {
|
|
byte var1 = fetchScriptByte();
|
|
error("STUB: o_unknown2(%d)", var1);
|
|
}
|
|
|
|
void ScummEngine_v0::o_ifActiveObject() {
|
|
byte obj = fetchScriptByte();
|
|
|
|
jumpRelative(obj == _activeInventory);
|
|
}
|
|
|
|
void ScummEngine_v0::o_getClosestObjActor() {
|
|
int obj;
|
|
int act;
|
|
int dist;
|
|
|
|
// This code can't detect any actors farther away than 255 units
|
|
// (pixels in newer games, characters in older ones.) But this is
|
|
// perfectly OK, as it is exactly how the original behaved.
|
|
|
|
int closest_obj = 0xFF, closest_dist = 0xFF;
|
|
|
|
getResultPos();
|
|
|
|
act = getVarOrDirectByte(PARAM_1);
|
|
obj = (_opcode & PARAM_2) ? 25 : 7;
|
|
|
|
do {
|
|
dist = getObjActToObjActDist(act, obj);
|
|
if (dist < closest_dist) {
|
|
closest_dist = dist;
|
|
closest_obj = obj;
|
|
}
|
|
} while (--obj);
|
|
|
|
setResult(closest_obj);
|
|
}
|
|
|
|
void ScummEngine_v0::o_cutscene() {
|
|
vm.cutSceneData[0] = _userState | (_userPut ? 16 : 0);
|
|
vm.cutSceneData[2] = _currentRoom;
|
|
vm.cutSceneData[3] = camera._mode;
|
|
|
|
// Hide inventory, freeze scripts, hide cursor
|
|
setUserState(15);
|
|
|
|
_sentenceNum = 0;
|
|
resetSentence();
|
|
|
|
vm.cutScenePtr[0] = 0;
|
|
}
|
|
|
|
void ScummEngine_v0::o_endCutscene() {
|
|
vm.cutSceneStackPointer = 0;
|
|
|
|
VAR(VAR_OVERRIDE) = 0;
|
|
vm.cutSceneScript[0] = 0;
|
|
vm.cutScenePtr[0] = 0;
|
|
|
|
// Reset user state to values before cutscene
|
|
setUserState(vm.cutSceneData[0] | 7);
|
|
|
|
camera._mode = (byte) vm.cutSceneData[3];
|
|
if (camera._mode == kFollowActorCameraMode) {
|
|
actorFollowCamera(VAR(VAR_EGO));
|
|
} else if (vm.cutSceneData[2] != _currentRoom) {
|
|
startScene(vm.cutSceneData[2], 0, 0);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v0::o_beginOverride() {
|
|
const int idx = vm.cutSceneStackPointer;
|
|
assert(0 <= idx && idx < 5);
|
|
|
|
vm.cutScenePtr[idx] = _scriptPointer - _scriptOrgPointer;
|
|
vm.cutSceneScript[idx] = _currentScript;
|
|
|
|
// Skip the jump instruction following the override instruction
|
|
// (the jump is responsible for "skipping" cutscenes, and the reason
|
|
// why we record the current script position in vm.cutScenePtr).
|
|
fetchScriptByte();
|
|
ScummEngine::fetchScriptWord();
|
|
|
|
// This is based on disassembly
|
|
VAR(VAR_OVERRIDE) = 0;
|
|
}
|
|
|
|
void ScummEngine_v0::o_setOwnerOf() {
|
|
int obj, owner;
|
|
|
|
obj = getVarOrDirectWord(PARAM_1);
|
|
owner = getVarOrDirectByte(PARAM_2);
|
|
|
|
if (obj == 0)
|
|
obj = _activeInventory;
|
|
|
|
setOwnerOf(obj, owner);
|
|
}
|
|
|
|
void ScummEngine_v0::resetSentence(bool walking) {
|
|
_activeVerb = 13;
|
|
|
|
// If the actor is walking, or the screen is a keypad (no sentence verbs/objects are drawn)
|
|
// Then reset all active objects (stops the radio crash, bug #3077966)
|
|
if (!walking || !(_userState & 32)) {
|
|
_v0ObjectFlag = 0;
|
|
_activeInventory = 0;
|
|
_activeObject = 0;
|
|
_activeObject2 = 0;
|
|
_activeObjectIndex = 0;
|
|
_activeObject2Index = 0;
|
|
}
|
|
|
|
_verbExecuting = false;
|
|
_verbPickup = false;
|
|
|
|
_activeActor = 0;
|
|
_activeInvExecute = false;
|
|
_activeObject2Inv = false;
|
|
_activeObjectObtained = false;
|
|
_activeObject2Obtained = false;
|
|
}
|
|
|
|
} // End of namespace Scumm
|