mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-16 14:50:17 +00:00
883 lines
23 KiB
C++
883 lines
23 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.
|
|
*
|
|
*/
|
|
|
|
#include "sherlock/tattoo/tattoo_talk.h"
|
|
#include "sherlock/tattoo/tattoo_people.h"
|
|
#include "sherlock/tattoo/tattoo_scene.h"
|
|
#include "sherlock/tattoo/tattoo_user_interface.h"
|
|
#include "sherlock/sherlock.h"
|
|
#include "sherlock/screen.h"
|
|
|
|
namespace Sherlock {
|
|
|
|
namespace Tattoo {
|
|
|
|
static const uint8 DIRECTION_CONVERSION[] = {
|
|
WALK_RIGHT, WALK_DOWN, WALK_LEFT, WALK_UP, STOP_RIGHT, STOP_DOWN, STOP_LEFT, STOP_UP,
|
|
WALK_UPRIGHT, WALK_DOWNRIGHT, WALK_UPLEFT, WALK_DOWNLEFT, STOP_UPRIGHT, STOP_UPLEFT,
|
|
STOP_DOWNRIGHT, STOP_DOWNLEFT
|
|
};
|
|
|
|
const byte TATTOO_OPCODES[] = {
|
|
170, // OP_SWITCH_SPEAKER
|
|
171, // OP_RUN_CANIMATION
|
|
0, // OP_ASSIGN_PORTRAIT_LOCATION
|
|
173, // OP_PAUSE
|
|
0, // OP_REMOVE_PORTRAIT
|
|
0, // OP_CLEAR_WINDOW
|
|
176, // OP_ADJUST_OBJ_SEQUENCE
|
|
177, // OP_WALK_HOlMES_TO_COORDS
|
|
178, // OP_PAUSE_WITHOUT_CONTROL
|
|
179, // OP_BANISH_WINDOW
|
|
0, // OP_SUMMON_WINDOW
|
|
181, // OP_SET_FLAG
|
|
0, // OP_SFX_COMMAND
|
|
183, // OP_TOGGLE_OBJECT
|
|
184, // OP_STEALTH_MODE_ACTIVE
|
|
0, // OP_IF_STATEMENT
|
|
0, // OP_ELSE_STATEMENT
|
|
0, // OP_END_IF_STATEMENT
|
|
188, // OP_STEALTH_MODE_DEACTIVATE
|
|
189, // OP_TURN_HOLMES_OFF
|
|
190, // OP_TURN_HOLMES_ON
|
|
191, // OP_GOTO_SCENE
|
|
0, // OP_PLAY_PROLOGUE
|
|
193, // OP_ADD_ITEM_TO_INVENTORY
|
|
194, // OP_SET_OBJECT
|
|
172, // OP_CALL_TALK_FILE
|
|
0, // OP_MOVE_MOUSE
|
|
0, // OP_DISPLAY_INFO_LINE
|
|
0, // OP_CLEAR_INFO_LINE
|
|
199, // OP_WALK_TO_CANIMATION
|
|
200, // OP_REMOVE_ITEM_FROM_INVENTORY
|
|
201, // OP_ENABLE_END_KEY
|
|
202, // OP_DISABLE_END_KEY
|
|
203, // OP_END_TEXT_WINDOW
|
|
174, // OP_MOUSE_ON_OFF
|
|
175, // OP_SET_WALK_CONTROL
|
|
180, // OP_SET_TALK_SEQUENCE
|
|
182, // OP_PLAY_SONG
|
|
187, // OP_WALK_HOLMES_AND_NPC_TO_CANIM
|
|
192, // OP_SET_NPC_PATH_DEST
|
|
195, // OP_NEXT_SONG
|
|
196, // OP_SET_NPC_PATH_PAUSE
|
|
197, // OP_PASSWORD
|
|
198, // OP_SET_SCENE_ENTRY_FLAG
|
|
185, // OP_WALK_NPC_TO_CANIM
|
|
186, // OP_WALK_NPC_TO_COORDS
|
|
204, // OP_WALK_HOLMES_AND_NPC_TO_COORDS
|
|
205, // OP_SET_NPC_TALK_FILE
|
|
206, // OP_TURN_NPC_OFF
|
|
207, // OP_TURN_NPC_ON
|
|
208, // OP_NPC_DESC_ON_OFF
|
|
209, // OP_NPC_PATH_PAUSE_TAKING_NOTES
|
|
210, // OP_NPC_PATH_PAUSE_LOOKING_HOLMES
|
|
211, // OP_ENABLE_TALK_INTERRUPTS
|
|
212, // OP_DISABLE_TALK_INTERRUPTS
|
|
213, // OP_SET_NPC_INFO_LINE
|
|
214, // OP_SET_NPC_POSITION
|
|
215, // OP_NPC_PATH_LABEL
|
|
216, // OP_PATH_GOTO_LABEL
|
|
217, // OP_PATH_IF_FLAG_GOTO_LABEL
|
|
218, // OP_NPC_WALK_GRAPHICS
|
|
220, // OP_NPC_VERB
|
|
221, // OP_NPC_VERB_CANIM
|
|
222, // OP_NPC_VERB_SCRIPT
|
|
224, // OP_RESTORE_PEOPLE_SEQUENCE
|
|
226, // OP_NPC_VERB_TARGET
|
|
227, // OP_TURN_SOUNDS_OFF
|
|
225 // OP_NULL
|
|
};
|
|
|
|
/*----------------------------------------------------------------*/
|
|
|
|
TattooTalk::TattooTalk(SherlockEngine *vm) : Talk(vm), _talkWidget(vm) {
|
|
static OpcodeMethod OPCODE_METHODS[] = {
|
|
(OpcodeMethod)&TattooTalk::cmdSwitchSpeaker,
|
|
|
|
(OpcodeMethod)&TattooTalk::cmdRunCAnimation,
|
|
(OpcodeMethod)&TattooTalk::cmdCallTalkFile,
|
|
(OpcodeMethod)&TattooTalk::cmdPause,
|
|
(OpcodeMethod)&TattooTalk::cmdMouseOnOff,
|
|
(OpcodeMethod)&TattooTalk::cmdSetWalkControl,
|
|
(OpcodeMethod)&TattooTalk::cmdAdjustObjectSequence,
|
|
(OpcodeMethod)&TattooTalk::cmdWalkHolmesToCoords,
|
|
(OpcodeMethod)&TattooTalk::cmdPauseWithoutControl,
|
|
(OpcodeMethod)&TattooTalk::cmdBanishWindow,
|
|
(OpcodeMethod)&TattooTalk::cmdSetTalkSequence,
|
|
|
|
(OpcodeMethod)&TattooTalk::cmdSetFlag,
|
|
(OpcodeMethod)&TattooTalk::cmdPlaySong,
|
|
(OpcodeMethod)&TattooTalk::cmdToggleObject,
|
|
(OpcodeMethod)&TattooTalk::cmdStealthModeActivate,
|
|
(OpcodeMethod)&TattooTalk::cmdWalkNPCToCAnimation,
|
|
(OpcodeMethod)&TattooTalk::cmdWalkNPCToCoords,
|
|
(OpcodeMethod)&TattooTalk::cmdWalkHomesAndNPCToCoords,
|
|
(OpcodeMethod)&TattooTalk::cmdStealthModeDeactivate,
|
|
(OpcodeMethod)&TattooTalk::cmdHolmesOff,
|
|
(OpcodeMethod)&TattooTalk::cmdHolmesOn,
|
|
|
|
(OpcodeMethod)&TattooTalk::cmdGotoScene,
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCPathDest,
|
|
(OpcodeMethod)&TattooTalk::cmdAddItemToInventory,
|
|
(OpcodeMethod)&TattooTalk::cmdSetObject,
|
|
(OpcodeMethod)&TattooTalk::cmdNextSong,
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCPathPause,
|
|
(OpcodeMethod)&TattooTalk::cmdPassword,
|
|
(OpcodeMethod)&TattooTalk::cmdSetSceneEntryFlag,
|
|
(OpcodeMethod)&TattooTalk::cmdWalkToCAnimation,
|
|
(OpcodeMethod)&TattooTalk::cmdRemoveItemFromInventory,
|
|
|
|
(OpcodeMethod)&TattooTalk::cmdEnableEndKey,
|
|
(OpcodeMethod)&TattooTalk::cmdDisableEndKey,
|
|
(OpcodeMethod)&TattooTalk::cmdEndTextWindow,
|
|
(OpcodeMethod)&TattooTalk::cmdWalkHomesAndNPCToCoords,
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCTalkFile,
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCOff,
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCOn,
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCDescOnOff,
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCPathPauseTakingNotes,
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCPathPauseLookingHolmes,
|
|
|
|
(OpcodeMethod)&TattooTalk::cmdTalkInterruptsEnable,
|
|
(OpcodeMethod)&TattooTalk::cmdTalkInterruptsDisable,
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCInfoLine,
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCPosition,
|
|
(OpcodeMethod)&TattooTalk::cmdNPCLabelSet,
|
|
(OpcodeMethod)&TattooTalk::cmdNPCLabelGoto,
|
|
(OpcodeMethod)&TattooTalk::cmdNPCLabelIfFlagGoto,
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCWalkGraphics,
|
|
nullptr,
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCVerb,
|
|
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCVerbCAnimation,
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCVerbScript,
|
|
nullptr,
|
|
(OpcodeMethod)&TattooTalk::cmdRestorePeopleSequence,
|
|
(OpcodeMethod)&TattooTalk::cmdSetNPCVerbTarget,
|
|
(OpcodeMethod)&TattooTalk::cmdTurnSoundsOff
|
|
};
|
|
|
|
_opcodes = TATTOO_OPCODES;
|
|
_opcodeTable = OPCODE_METHODS;
|
|
}
|
|
|
|
void TattooTalk::talkInterface(const byte *&str) {
|
|
TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
|
|
const byte *s = str;
|
|
|
|
// Move to past the end of the text string
|
|
_charCount = 0;
|
|
while ((*str < TATTOO_OPCODES[0] || *str == TATTOO_OPCODES[OP_NULL]) && *str) {
|
|
++_charCount;
|
|
++str;
|
|
}
|
|
|
|
// Display the text window
|
|
// ui.banishWindow();
|
|
ui._textWidget.load(Common::String((const char *)s, (const char *)str), _speaker);
|
|
ui._textWidget.summonWindow();
|
|
_wait = true;
|
|
}
|
|
|
|
void TattooTalk::showTalk() {
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
|
|
|
|
_sequenceStack.clear();
|
|
people.setListenSequence(_talkTo, 129);
|
|
|
|
_talkWidget.load();
|
|
_talkWidget.summonWindow();
|
|
_talkWidget.refresh();
|
|
|
|
if (ui._menuMode != MESSAGE_MODE)
|
|
ui._menuMode = TALK_MODE;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSwitchSpeaker(const byte *&str) {
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
Screen &screen = *_vm->_screen;
|
|
UserInterface &ui = *_vm->_ui;
|
|
|
|
if (_talkToAbort)
|
|
return RET_EXIT;
|
|
|
|
ui.clearWindow();
|
|
|
|
_yp = screen.fontHeight() + 11;
|
|
_charCount = _line = 0;
|
|
|
|
people.setListenSequence(_speaker, 129);
|
|
_speaker = *++str - 1;
|
|
++str;
|
|
|
|
people.setTalkSequence(_speaker, 1);
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdMouseOnOff(const byte *&str) {
|
|
Events &events = *_vm->_events;
|
|
bool mouseOn = *++str == 2;
|
|
if (mouseOn)
|
|
events.showCursor();
|
|
else
|
|
events.hideCursor();
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdWalkHolmesToCoords(const byte *&str) {
|
|
People &people = *_vm->_people;
|
|
++str;
|
|
|
|
int xp = (str[0] - 1) * 256 + str[1] - 1;
|
|
if (xp > 16384)
|
|
// Negative X
|
|
xp = -1 * (xp - 16384);
|
|
int yp = (str[2] - 1) * 256 + str[3] - 1;
|
|
|
|
people[HOLMES].walkToCoords(Point32(xp * FIXED_INT_MULTIPLIER, yp * FIXED_INT_MULTIPLIER),
|
|
DIRECTION_CONVERSION[str[4] - 1]);
|
|
|
|
if (_talkToAbort)
|
|
return RET_EXIT;
|
|
|
|
str += 4;
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdGotoScene(const byte *&str) {
|
|
Map &map = *_vm->_map;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
Scene &scene = *_vm->_scene;
|
|
scene._goToScene = str[1] - 1;
|
|
|
|
if (scene._goToScene != OVERHEAD_MAP) {
|
|
// Not going to the map overview
|
|
map._oldCharPoint = scene._goToScene;
|
|
|
|
// Run a canimation?
|
|
if (str[2] > 100) {
|
|
people._savedPos = PositionFacing(160, 100, str[2]);
|
|
} else {
|
|
int32 posX = (str[3] - 1) * 256 + str[4] - 1;
|
|
if (posX > 16384)
|
|
posX = -1 * (posX - 16384);
|
|
int32 posY = (str[5] - 1) * 256 + str[6] - 1;
|
|
people._savedPos = PositionFacing(posX, posY, str[2] - 1);
|
|
}
|
|
|
|
_scriptMoreFlag = 1;
|
|
}
|
|
|
|
str += 7;
|
|
if (scene._goToScene != OVERHEAD_MAP)
|
|
_scriptSaveIndex = str - _scriptStart;
|
|
|
|
_endStr = true;
|
|
_wait = 0;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdNextSong(const byte *&str) {
|
|
Music &music = *_vm->_music;
|
|
|
|
// Get the name of the next song to play
|
|
++str;
|
|
music._nextSongName = "";
|
|
for (int idx = 0; idx < 8; ++idx) {
|
|
if (str[idx] != '~')
|
|
music._nextSongName += str[idx];
|
|
else
|
|
break;
|
|
}
|
|
str += 7;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdNPCLabelGoto(const byte *&str) {
|
|
int npcNum = *++str;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
|
|
if (person._resetNPCPath) {
|
|
person._npcIndex = person._npcPause = 0;
|
|
person._resetNPCPath = false;
|
|
memset(person._npcPath, 0, 100);
|
|
}
|
|
|
|
person._npcPath[person._npcIndex] = 8;
|
|
person._npcPath[person._npcIndex + 1] = str[1];
|
|
person._npcIndex += 2;
|
|
str++;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdNPCLabelIfFlagGoto(const byte *&str) {
|
|
int npcNum = *++str;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
|
|
if (person._resetNPCPath) {
|
|
person._npcIndex = person._npcPause = 0;
|
|
person._resetNPCPath = false;
|
|
memset(person._npcPath, 0, 100);
|
|
}
|
|
|
|
person._npcPath[person._npcIndex] = 9;
|
|
for (int i = 1; i <= 3; i++)
|
|
person._npcPath[person._npcIndex + i] = str[i];
|
|
|
|
person._npcIndex += 4;
|
|
str += 3;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdNPCLabelSet(const byte *&str) {
|
|
int npcNum = *++str;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
|
|
if (person._resetNPCPath) {
|
|
person._npcIndex = person._npcPause = 0;
|
|
person._resetNPCPath = false;
|
|
memset(person._npcPath, 0, 100);
|
|
}
|
|
|
|
person._npcPath[person._npcIndex] = 7;
|
|
person._npcPath[person._npcIndex + 1] = str[1];
|
|
person._npcIndex += 2;
|
|
str++;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdPassword(const byte *&str) { error("TODO: script opcode (cmdPassword)"); }
|
|
|
|
OpcodeReturn TattooTalk::cmdPlaySong(const byte *&str) {
|
|
Music &music = *_vm->_music;
|
|
Common::String currentSong = music._currentSongName;
|
|
|
|
// Get the name of the song to play
|
|
music._currentSongName = "";
|
|
str++;
|
|
for (int idx = 0; idx < 8; ++idx) {
|
|
if (str[idx] != '~')
|
|
music._currentSongName += str[idx];
|
|
else
|
|
break;
|
|
}
|
|
str += 7;
|
|
|
|
// Play the song
|
|
music.loadSong(music._currentSongName);
|
|
|
|
// Copy the old song name to _nextSongName so that when the new song is finished, the old song will restart
|
|
music._nextSongName = currentSong;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdRestorePeopleSequence(const byte *&str) {
|
|
int npcNum = *++str - 1;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
person._misc = 0;
|
|
|
|
if (person._seqTo) {
|
|
person._walkSequences[person._sequenceNumber]._sequences[person._frameNumber] = person._seqTo;
|
|
person._seqTo = 0;
|
|
}
|
|
person._sequenceNumber = person._savedNpcSequence;
|
|
person._frameNumber = person._savedNpcFrame;
|
|
person.checkWalkGraphics();
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCDescOnOff(const byte *&str) {
|
|
int npcNum = *++str;
|
|
++str;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
Person &person = people[npcNum];
|
|
|
|
// Copy over the NPC examine text until we reach a stop marker, which is
|
|
// the same as a start marker, or we reach the end of the file
|
|
while (*str && *str != _opcodes[OP_NPC_DESC_ON_OFF])
|
|
person._examine += *str++;
|
|
|
|
// Move past any leftover text till we reach a stop marker
|
|
while (*str && *str != _opcodes[OP_NPC_DESC_ON_OFF])
|
|
str++;
|
|
|
|
if (!*str)
|
|
// Reached end of file, so decrement pointer so outer loop will terminate on NULL
|
|
--str;
|
|
else
|
|
// Move past the ending OP_NPC_DEST_ON_OFF opcode
|
|
++str;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCInfoLine(const byte *&str) {
|
|
int npcNum = *++str;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
|
|
person._description = "";
|
|
int len = *++str;
|
|
for (int idx = 0; idx < len; ++idx)
|
|
person._description += str[idx + 1];
|
|
|
|
str += len;
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCOff(const byte *&str) {
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
int npcNum = *++str;
|
|
people[npcNum]._type = REMOVE;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCOn(const byte *&str) {
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
int npcNum = *++str;
|
|
people[npcNum]._type = CHARACTER;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCPathDest(const byte *&str) {
|
|
int npcNum = *++str;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
|
|
if (person._resetNPCPath) {
|
|
person._npcIndex = person._npcPause = 0;
|
|
person._resetNPCPath = false;
|
|
memset(person._npcPath, 0, 100);
|
|
}
|
|
|
|
person._npcPath[person._npcIndex] = 1;
|
|
for (int i = 1; i <= 4; i++)
|
|
person._npcPath[person._npcIndex + i] = str[i];
|
|
person._npcPath[person._npcIndex + 5] = DIRECTION_CONVERSION[str[5] - 1] + 1;
|
|
|
|
person._npcIndex += 6;
|
|
str += 5;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCPathPause(const byte *&str) {
|
|
int npcNum = *++str;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
|
|
if (person._resetNPCPath) {
|
|
person._npcIndex = person._npcPause = 0;
|
|
person._resetNPCPath = false;
|
|
memset(person._npcPath, 0, 100);
|
|
}
|
|
|
|
person._npcPath[person._npcIndex] = 2;
|
|
for (int i = 1; i <= 2; i++)
|
|
person._npcPath[person._npcIndex + i] = str[i];
|
|
|
|
person._npcIndex += 3;
|
|
str += 2;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCPathPauseTakingNotes(const byte *&str) {
|
|
int npcNum = *++str;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
|
|
if (person._resetNPCPath) {
|
|
person._npcIndex = person._npcPause = 0;
|
|
person._resetNPCPath = false;
|
|
memset(person._npcPath, 0, 100);
|
|
}
|
|
|
|
person._npcPath[person._npcIndex] = 5;
|
|
for (int i = 1; i <= 2; i++)
|
|
person._npcPath[person._npcIndex + i] = str[i];
|
|
|
|
person._npcIndex += 3;
|
|
str += 2;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCPathPauseLookingHolmes(const byte *&str) {
|
|
int npcNum = *++str;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
|
|
if (person._resetNPCPath) {
|
|
person._npcIndex = person._npcPause = 0;
|
|
person._resetNPCPath = false;
|
|
memset(person._npcPath, 0, 100);
|
|
}
|
|
|
|
person._npcPath[person._npcIndex] = 6;
|
|
for (int i = 1; i <= 2; i++)
|
|
person._npcPath[person._npcIndex + i] = str[i];
|
|
|
|
person._npcIndex += 3;
|
|
str += 2;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCPosition(const byte *&str) {
|
|
int npcNum = *++str - 1;
|
|
++str;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
int32 posX = (str[0] - 1) * 256 + str[1] - 1;
|
|
if (posX > 16384)
|
|
posX = -1 * (posX - 16384);
|
|
int32 posY = (str[2] - 1) * 256 + str[3] - 1;
|
|
|
|
people[npcNum]._position = Point32(posX * FIXED_INT_MULTIPLIER, posY * FIXED_INT_MULTIPLIER);
|
|
if (person._seqTo && person._walkLoaded) {
|
|
person._walkSequences[person._sequenceNumber]._sequences[person._frameNumber] = person._seqTo;
|
|
person._seqTo = 0;
|
|
}
|
|
|
|
assert(str[4] - 1 < 16);
|
|
person._sequenceNumber = DIRECTION_CONVERSION[str[4] - 1];
|
|
person._frameNumber = 0;
|
|
|
|
if (person._walkLoaded)
|
|
person.checkWalkGraphics();
|
|
|
|
if (person._walkLoaded && person._type == CHARACTER &&
|
|
person._sequenceNumber >= STOP_UP && person._sequenceNumber <= STOP_UPLEFT) {
|
|
bool done = false;
|
|
do {
|
|
person.checkSprite();
|
|
for (int x = 0; x < person._frameNumber; x++) {
|
|
if (person._walkSequences[person._sequenceNumber]._sequences[x] == 0) {
|
|
done = true;
|
|
break;
|
|
}
|
|
}
|
|
} while(!done);
|
|
}
|
|
|
|
str += 4;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCTalkFile(const byte *&str) {
|
|
int npcNum = *++str;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
|
|
if (person._resetNPCPath) {
|
|
person._npcIndex = person._npcPause = 0;
|
|
person._resetNPCPath = false;
|
|
memset(person._npcPath, 0, 100);
|
|
}
|
|
|
|
person._npcPath[person._npcIndex] = 3;
|
|
for (int i = 1; i <= 8; i++)
|
|
person._npcPath[person._npcIndex + i] = str[i];
|
|
|
|
person._npcIndex += 9;
|
|
str += 8;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCVerb(const byte *&str) {
|
|
int npcNum = *++str;
|
|
int verbNum = *++str - 1;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
Common::String &verb = people[npcNum]._use[verbNum]._verb;
|
|
|
|
for (int x = 0; x < 12; x++) {
|
|
if (str[x + 1] != '~')
|
|
verb.setChar(str[x + 1], x);
|
|
else
|
|
verb.setChar(0, x);
|
|
}
|
|
|
|
verb.setChar(0, 11);
|
|
|
|
uint len = verb.size() - 1;
|
|
while (verb[len] == ' ' && len)
|
|
len--;
|
|
verb.setChar(0, len + 1);
|
|
if (verb != " ")
|
|
verb.clear();
|
|
str += 12;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCVerbCAnimation(const byte *&str) {
|
|
int npcNum = *++str;
|
|
int verbNum = *++str - 1;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
UseType &useType = people[npcNum]._use[verbNum];
|
|
|
|
useType._cAnimNum = (str[1] - 1) & 127;
|
|
useType._cAnimSpeed = 1 + 128 * (str[1] >= 128);
|
|
str++;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCVerbScript(const byte *&str) {
|
|
int npcNum = *++str;
|
|
int verbNum = *++str - 1;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
UseType &useType = people[npcNum]._use[verbNum];
|
|
Common::String &name = useType._names[0];
|
|
name.setChar('*', 0);
|
|
name.setChar('C', 1);
|
|
|
|
for (int x = 0; x < 8; x++) {
|
|
if (str[x + 1] != '~')
|
|
name.setChar(str[x + 1], x + 2);
|
|
else
|
|
name.setChar(0, x + 2);
|
|
}
|
|
|
|
name.setChar(0, 11);
|
|
useType._cAnimNum = 99;
|
|
useType._cAnimSpeed = 1;
|
|
str += 8;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCVerbTarget(const byte *&str) {
|
|
int npcNum = *++str;
|
|
int verbNum = *++str - 1;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
Common::String &target = people[npcNum]._use[verbNum]._target;
|
|
|
|
for (int x = 0; x < 12; x++) {
|
|
if (str[x + 1] != '~')
|
|
target.setChar(str[x + 1], x);
|
|
else
|
|
target.setChar(0, x);
|
|
}
|
|
|
|
target.setChar(0, 11);
|
|
|
|
uint len = target.size() - 1;
|
|
while (target[len] == ' ' && len)
|
|
len--;
|
|
target.setChar(0, len + 1);
|
|
str += 12;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetNPCWalkGraphics(const byte *&str) {
|
|
int npcNum = *++str - 1;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
Person &person = people[npcNum];
|
|
|
|
// Build up walk library name for the given NPC
|
|
person._walkVGSName = "";
|
|
for (int idx = 0; idx < 8; ++idx) {
|
|
if (str[idx + 1] != '~')
|
|
person._walkVGSName += str[idx + 1];
|
|
else
|
|
break;
|
|
}
|
|
person._walkVGSName += ".VGS";
|
|
|
|
people._forceWalkReload = true;
|
|
str += 8;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetSceneEntryFlag(const byte *&str) {
|
|
TattooScene &scene = *(TattooScene *)_vm->_scene;
|
|
++str;
|
|
int flag = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1);
|
|
|
|
int flag1 = flag & 16383;
|
|
if (flag > 16383)
|
|
flag1 *= -1;
|
|
|
|
str += 2;
|
|
|
|
// Make sure that this instance is not already being tracked
|
|
bool found = false;
|
|
for (uint idx = 0; idx < scene._sceneTripCounters.size() && !found; ++idx) {
|
|
SceneTripEntry &entry = scene._sceneTripCounters[idx];
|
|
if (entry._flag == flag1 && entry._sceneNumber == str[0] - 1)
|
|
found = true;
|
|
}
|
|
|
|
// Only add it if it's not being tracked already
|
|
if (!found)
|
|
scene._sceneTripCounters.push_back(SceneTripEntry(flag1, str[0] - 1, str[1] - 1));
|
|
|
|
++str;
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetTalkSequence(const byte *&str) {
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
int speaker = str[1] - 1;
|
|
int sequenceNumber = str[2];
|
|
|
|
if (sequenceNumber < 128)
|
|
people.setTalkSequence(speaker, sequenceNumber);
|
|
else
|
|
people.setListenSequence(speaker, sequenceNumber);
|
|
|
|
str += 2;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdSetWalkControl(const byte *&str) {
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
++str;
|
|
people._walkControl = str[0] - 1;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
// Dummy opcode
|
|
OpcodeReturn TattooTalk::cmdTalkInterruptsDisable(const byte *&str) { error("Dummy opcode cmdTalkInterruptsDisable called"); }
|
|
|
|
// Dummy opcode
|
|
OpcodeReturn TattooTalk::cmdTalkInterruptsEnable(const byte *&str) { error("Dummy opcode cmdTalkInterruptsEnable called"); }
|
|
|
|
OpcodeReturn TattooTalk::cmdTurnSoundsOff(const byte *&str) { error("TODO: script opcode (cmdTurnSoundsOff)"); }
|
|
|
|
OpcodeReturn TattooTalk::cmdWalkHolmesAndNPCToCAnimation(const byte *&str) {
|
|
int npcNum = *++str;
|
|
int cAnimNum = *++str;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
Scene &scene = *_vm->_scene;
|
|
CAnim &anim = scene._cAnim[cAnimNum];
|
|
|
|
if (person._pathStack.empty())
|
|
person.pushNPCPath();
|
|
person._npcMoved = true;
|
|
|
|
person.walkToCoords(anim._goto[1], anim._goto[1]._facing);
|
|
|
|
if (_talkToAbort)
|
|
return RET_EXIT;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdWalkNPCToCAnimation(const byte *&str) {
|
|
int npcNum = *++str;
|
|
int cAnimNum = *++str;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
Scene &scene = *_vm->_scene;
|
|
CAnim &anim = scene._cAnim[cAnimNum];
|
|
|
|
if (person._pathStack.empty())
|
|
person.pushNPCPath();
|
|
person._npcMoved = true;
|
|
|
|
person.walkToCoords(anim._goto[1], anim._goto[1]._facing);
|
|
|
|
if (_talkToAbort)
|
|
return RET_EXIT;
|
|
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdWalkNPCToCoords(const byte *&str) {
|
|
int npcNum = *++str;
|
|
str++;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
|
|
if (person._pathStack.empty())
|
|
person.pushNPCPath();
|
|
person._npcMoved = true;
|
|
|
|
int xp = (str[0] - 1) * 256 + str[1] - 1;
|
|
if (xp > 16384)
|
|
xp = -1 * (xp - 16384);
|
|
int yp = (str[2] - 1) * 256 + str[3] - 1;
|
|
|
|
person.walkToCoords(Point32(xp * FIXED_INT_MULTIPLIER, yp * FIXED_INT_MULTIPLIER),
|
|
DIRECTION_CONVERSION[str[4] - 1]);
|
|
if (_talkToAbort)
|
|
return RET_EXIT;
|
|
|
|
str += 4;
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
OpcodeReturn TattooTalk::cmdWalkHomesAndNPCToCoords(const byte *&str) {
|
|
int npcNum = *++str;
|
|
str++;
|
|
TattooPeople &people = *(TattooPeople *)_vm->_people;
|
|
TattooPerson &person = people[npcNum];
|
|
|
|
if (person._pathStack.empty())
|
|
person.pushNPCPath();
|
|
person._npcMoved = true;
|
|
|
|
int xp = (str[0] - 1) * 256 + str[1] - 1;
|
|
if (xp > 16384)
|
|
xp = -1 * (xp - 16384);
|
|
int yp = (str[2] - 1) * 256 + str[3] - 1;
|
|
|
|
person.walkToCoords(Point32(xp * FIXED_INT_MULTIPLIER, yp * FIXED_INT_MULTIPLIER),
|
|
DIRECTION_CONVERSION[str[4] - 1]);
|
|
|
|
if (_talkToAbort)
|
|
return RET_EXIT;
|
|
|
|
str += 9;
|
|
return RET_SUCCESS;
|
|
}
|
|
|
|
} // End of namespace Tattoo
|
|
|
|
} // End of namespace Sherlock
|