2003-10-07 03:58:44 +00:00
|
|
|
/* ScummVM - Scumm Interpreter
|
|
|
|
* Copyright (C) 2003 The ScummVM project
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
* $Header$
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "talk.h"
|
|
|
|
#include "graphics.h"
|
|
|
|
|
|
|
|
namespace Queen {
|
|
|
|
|
|
|
|
/*
|
|
|
|
Functions needed:
|
|
|
|
|
|
|
|
Data needed:
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2003-10-12 19:16:48 +00:00
|
|
|
void Talk::talk(
|
2003-10-07 03:58:44 +00:00
|
|
|
const char *filename,
|
2003-10-15 09:23:05 +00:00
|
|
|
int personInRoom,
|
2003-10-07 03:58:44 +00:00
|
|
|
char *cutawayFilename,
|
2003-10-07 12:20:31 +00:00
|
|
|
Graphics *graphics,
|
2003-10-07 03:58:44 +00:00
|
|
|
Logic *logic,
|
|
|
|
Resource *resource) {
|
2003-10-07 12:20:31 +00:00
|
|
|
Talk *talk = new Talk(graphics, logic, resource);
|
2003-10-15 09:23:05 +00:00
|
|
|
talk->talk(filename, personInRoom, cutawayFilename);
|
2003-10-07 03:58:44 +00:00
|
|
|
delete talk;
|
|
|
|
}
|
|
|
|
|
2003-10-12 19:16:48 +00:00
|
|
|
bool Talk::speak(
|
|
|
|
const char *sentence,
|
|
|
|
const char *person,
|
|
|
|
const char *voiceFilePrefix,
|
|
|
|
Graphics *graphics,
|
|
|
|
Logic *logic,
|
|
|
|
Resource *resource) {
|
|
|
|
Talk *talk = new Talk(graphics, logic, resource);
|
|
|
|
bool result = talk->speak(sentence, person, voiceFilePrefix);
|
|
|
|
delete talk;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2003-10-07 03:58:44 +00:00
|
|
|
Talk::Talk(
|
2003-10-07 12:20:31 +00:00
|
|
|
Graphics *graphics,
|
2003-10-07 03:58:44 +00:00
|
|
|
Logic *logic,
|
|
|
|
Resource *resource)
|
2003-10-07 12:20:31 +00:00
|
|
|
: _graphics(graphics), _logic(logic), _resource(resource), _fileData(NULL), _quit(false) {
|
2003-10-07 03:58:44 +00:00
|
|
|
|
|
|
|
//! TODO Move this to the Logic class later!
|
|
|
|
memset(_talkSelected, 0, sizeof(_talkSelected));
|
|
|
|
}
|
|
|
|
|
|
|
|
Talk::~Talk() {
|
|
|
|
delete[] _fileData;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-10-15 09:23:05 +00:00
|
|
|
void Talk::talk(const char *filename, int personInRoom, char *cutawayFilename) {
|
2003-10-07 03:58:44 +00:00
|
|
|
_oldSelectedSentenceIndex = 0;
|
|
|
|
_oldSelectedSentenceValue = 0;
|
|
|
|
|
|
|
|
debug(0, "----- talk(\"%s\") -----", filename);
|
|
|
|
|
|
|
|
cutawayFilename[0] = '\0';
|
2003-10-10 09:45:22 +00:00
|
|
|
|
|
|
|
// XXX S=SUBJECT[1];
|
2003-10-15 09:23:05 +00:00
|
|
|
|
|
|
|
int roomStart = _logic->roomData(_logic->currentRoom());
|
|
|
|
ObjectData *data = _logic->objectData(roomStart + personInRoom);
|
|
|
|
|
|
|
|
if (data->name <= 0) // disabled!
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (data->entryObj > 0)
|
|
|
|
return;
|
|
|
|
|
2003-10-10 09:45:22 +00:00
|
|
|
// XXX R=ROOM_DATA[ROOM];
|
|
|
|
// XXX if(OBJECT_DATA[NOUN2+R][0]<=0) return;
|
|
|
|
// XXX if(OBJECT_DATA[NOUN2+R][4]>0) return;
|
|
|
|
// XXX strcpy(Pstr,FIND_STATE(OBJECT_DATA[NOUN2+R][6],"TALK"));
|
|
|
|
|
|
|
|
// I cant talk to that.
|
|
|
|
|
|
|
|
// XXX if(seq(Pstr,"MUTE")) {
|
|
|
|
// XXX k=24+Rnd(2);
|
|
|
|
// XXX SPEAK(JOE_RESPstr[k],"JOE",find_cd_desc(k));
|
|
|
|
// XXX return;
|
|
|
|
// XXX }
|
|
|
|
// XXX panelflag=0;
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-10-07 03:58:44 +00:00
|
|
|
load(filename);
|
|
|
|
|
2003-10-15 09:23:05 +00:00
|
|
|
//Person person;
|
|
|
|
//_logic->personSetData(
|
|
|
|
|
2003-10-07 03:58:44 +00:00
|
|
|
char personName[MAX_STRING_SIZE];
|
|
|
|
// XXX SET_PERSON_DATA(N,NAMEstr,0);
|
2003-10-07 06:56:29 +00:00
|
|
|
int bobNum = 1; // XXX P_BNUM;
|
2003-10-07 03:58:44 +00:00
|
|
|
// XXX strcpy(PERstr,P_NAMEstr);
|
|
|
|
personName[0] = '\0';
|
|
|
|
|
|
|
|
int16 oldLevel = 0;
|
|
|
|
bool personWalking = false; // OWALK in talk.c
|
|
|
|
|
|
|
|
// Lines 828-846 in talk.c
|
|
|
|
for (int i = 1; i <= 4; i++) {
|
|
|
|
if (talkSelected()->values[i-1] > 0) {
|
|
|
|
// This option has been redefined so display new dialogue option
|
|
|
|
_dialogueTree[1][i].head = talkSelected()->values[i-1];
|
|
|
|
}
|
|
|
|
else if (talkSelected()->values[i-1] == -1) {
|
|
|
|
|
|
|
|
// Already selected so don't redisplay
|
|
|
|
if (_dialogueTree[1][i].gameStateIndex >= 0) {
|
|
|
|
_dialogueTree[1][i].head = -1;
|
|
|
|
_dialogueTree[1][i].dialogueNodeValue1 = -1;
|
|
|
|
_dialogueTree[1][i].gameStateIndex = -1;
|
|
|
|
_dialogueTree[1][i].gameStateValue = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
initialTalk();
|
|
|
|
|
|
|
|
// Lines 906-? in talk.c
|
|
|
|
// XXX drawmouseflag=1;
|
2003-10-07 09:34:19 +00:00
|
|
|
int16 level=1, retval=0;
|
2003-10-07 03:58:44 +00:00
|
|
|
int16 head = _dialogueTree[level][0].head;
|
|
|
|
|
2003-10-07 06:56:29 +00:00
|
|
|
// TODO: split this loop in several functions
|
2003-10-07 03:58:44 +00:00
|
|
|
while(retval != -1) {
|
2003-10-07 12:20:31 +00:00
|
|
|
// debug(0, "retval = %i", retval);
|
2003-10-07 03:58:44 +00:00
|
|
|
|
|
|
|
char otherVoiceFilePrefix [MAX_STRING_SIZE];
|
|
|
|
|
2003-10-07 06:56:29 +00:00
|
|
|
_talkString[0][0] = '\0';
|
2003-10-07 03:58:44 +00:00
|
|
|
|
|
|
|
if(talkSelected()->hasTalkedTo == 1 && head == 1)
|
2003-10-07 06:56:29 +00:00
|
|
|
strcpy(_talkString[0], _person2String);
|
2003-10-07 03:58:44 +00:00
|
|
|
else
|
2003-10-07 06:56:29 +00:00
|
|
|
findDialogueString(_person1Ptr, head, _talkString[0]);
|
2003-10-07 03:58:44 +00:00
|
|
|
|
|
|
|
if(talkSelected()->hasTalkedTo == 1 && head == 1)
|
|
|
|
sprintf(otherVoiceFilePrefix, "%2dXXXXP", _talkKey);
|
|
|
|
else
|
|
|
|
sprintf(otherVoiceFilePrefix, "%2d%4xP", _talkKey, head);
|
|
|
|
|
2003-10-07 06:56:29 +00:00
|
|
|
if (_talkString[0][0] == '\0' && retval > 1) {
|
|
|
|
findDialogueString(_person1Ptr, retval, _talkString[0]);
|
2003-10-07 03:58:44 +00:00
|
|
|
sprintf(otherVoiceFilePrefix,"%2d%4xP", _talkKey, retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Joe dialogue
|
|
|
|
|
|
|
|
for (int i = 1; i <= 4; i++) {
|
2003-10-07 06:56:29 +00:00
|
|
|
findDialogueString(_joePtr, _dialogueTree[level][i].head, _talkString[i]);
|
2003-10-07 03:58:44 +00:00
|
|
|
|
|
|
|
int16 index = _dialogueTree[level][i].gameStateIndex;
|
|
|
|
|
|
|
|
if (index < 0 && _logic->gameState(abs(index)) != _dialogueTree[level][i].gameStateValue)
|
2003-10-07 06:56:29 +00:00
|
|
|
_talkString[i][0] = '\0';
|
2003-10-07 03:58:44 +00:00
|
|
|
|
2003-10-10 09:45:22 +00:00
|
|
|
sprintf(_joeVoiceFilePrefix[i], "%2d%4xJ", _talkKey, _dialogueTree[level][i].head);
|
2003-10-07 03:58:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check to see if(all the dialogue options have been selected.
|
|
|
|
// if this is the case, and the last one left is the exit option,
|
|
|
|
// then automatically set S to that and exit.
|
|
|
|
|
|
|
|
int choicesLeft = 0;
|
|
|
|
int selectedSentence = 0;
|
|
|
|
|
|
|
|
for (int i = 1; i <= 4; i++) {
|
2003-10-07 06:56:29 +00:00
|
|
|
if (_talkString[i][0] != '\0') {
|
2003-10-07 03:58:44 +00:00
|
|
|
choicesLeft++;
|
|
|
|
selectedSentence = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-10-07 12:20:31 +00:00
|
|
|
// debug(0, "choicesLeft = %i", choicesLeft);
|
2003-10-07 03:58:44 +00:00
|
|
|
|
|
|
|
if (1 == choicesLeft) {
|
|
|
|
// Automatically run the final dialogue option
|
2003-10-07 06:56:29 +00:00
|
|
|
if (speak(_talkString[0], personName, otherVoiceFilePrefix))
|
2003-10-07 03:58:44 +00:00
|
|
|
personWalking = true;
|
|
|
|
|
|
|
|
if (_quit)
|
|
|
|
break;
|
|
|
|
|
2003-10-10 09:45:22 +00:00
|
|
|
speak(_talkString[selectedSentence], personName, _joeVoiceFilePrefix[selectedSentence]);
|
2003-10-07 03:58:44 +00:00
|
|
|
}
|
|
|
|
else {
|
2003-10-07 06:56:29 +00:00
|
|
|
if (bobNum > 0) {
|
|
|
|
speak(_talkString[0], personName, otherVoiceFilePrefix);
|
|
|
|
selectedSentence = selectSentence();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
warning("bobBum is %i", bobNum);
|
|
|
|
selectedSentence = 0;
|
2003-10-07 03:58:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_quit)
|
|
|
|
break;
|
|
|
|
|
|
|
|
retval = _dialogueTree[level][selectedSentence].dialogueNodeValue1;
|
|
|
|
head = _dialogueTree[level][selectedSentence].head;
|
|
|
|
oldLevel = level;
|
|
|
|
level = 0;
|
|
|
|
|
|
|
|
// Set LEVEL to the selected child in dialogue tree
|
|
|
|
|
|
|
|
for (int i = 1; i <= _levelMax; i++)
|
|
|
|
if (_dialogueTree[i][0].head == head)
|
|
|
|
level = i;
|
|
|
|
|
|
|
|
if (0 == level) {
|
|
|
|
// No new level has been selected, so lets set LEVEL to the
|
|
|
|
// tree path pointed to by the RETVAL
|
|
|
|
|
|
|
|
for (int i = 1; i <= _levelMax; i++)
|
|
|
|
for (int j = 0; j <= 5; j++)
|
|
|
|
if (_dialogueTree[i][j].head == retval)
|
|
|
|
level = i;
|
|
|
|
|
|
|
|
disableSentence(oldLevel, selectedSentence);
|
|
|
|
}
|
|
|
|
else { // 0 != level
|
|
|
|
// Check to see if Person Return value is positive, if it is, then
|
|
|
|
// change the selected dialogue option to the Return value
|
|
|
|
|
|
|
|
if (_dialogueTree[level][0].dialogueNodeValue1 > 0) {
|
|
|
|
if (1 == oldLevel) {
|
|
|
|
_oldSelectedSentenceIndex = selectedSentence;
|
|
|
|
_oldSelectedSentenceValue = talkSelected()->values[selectedSentence-1];
|
|
|
|
talkSelected()->values[selectedSentence-1] = _dialogueTree[level][0].dialogueNodeValue1;
|
|
|
|
}
|
|
|
|
|
|
|
|
_dialogueTree[oldLevel][selectedSentence].head = _dialogueTree[level][0].dialogueNodeValue1;
|
|
|
|
_dialogueTree[level][0].dialogueNodeValue1 = -1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
disableSentence(oldLevel, selectedSentence);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check selected person to see if any Gamestates need setting
|
|
|
|
|
|
|
|
int16 index = _dialogueTree[level][0].gameStateIndex;
|
|
|
|
|
|
|
|
if (index > 0)
|
|
|
|
_logic->gameState(index, _dialogueTree[level][0].gameStateValue);
|
|
|
|
|
|
|
|
// if the selected dialogue line has a POSITIVE game state value
|
|
|
|
// then set gamestate to Value = TALK(OLDLEVEL,S,3)
|
|
|
|
|
|
|
|
index = _dialogueTree[oldLevel][selectedSentence].gameStateIndex;
|
|
|
|
if (index > 0)
|
|
|
|
_logic->gameState(index, _dialogueTree[oldLevel][selectedSentence].gameStateValue);
|
|
|
|
|
|
|
|
|
|
|
|
// if(RETVAL = -1, then before we exit, check to see if(person
|
|
|
|
// has something final to say!
|
|
|
|
|
2003-10-07 06:56:29 +00:00
|
|
|
if (-1 == retval) {
|
|
|
|
findDialogueString(_person1Ptr, head, _talkString[0]);
|
|
|
|
if (_talkString[0][0] != '\0') {
|
|
|
|
sprintf(otherVoiceFilePrefix, "%2d%4xP", _talkKey, head);
|
|
|
|
if (speak(_talkString[0], personName, otherVoiceFilePrefix))
|
|
|
|
personWalking = true;
|
|
|
|
}
|
|
|
|
}
|
2003-10-07 03:58:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Talk::disableSentence(int oldLevel, int selectedSentence) {
|
|
|
|
// Mark off selected option
|
|
|
|
|
|
|
|
if (1 == oldLevel) {
|
|
|
|
if (_dialogueTree[oldLevel][selectedSentence].dialogueNodeValue1 != -1) {
|
|
|
|
// Make sure choice is not exit option
|
|
|
|
_oldSelectedSentenceIndex = selectedSentence;
|
|
|
|
_oldSelectedSentenceValue = talkSelected()->values[selectedSentence-1];
|
|
|
|
talkSelected()->values[selectedSentence-1] = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cancel selected dialogue line, so that its no longer displayed
|
|
|
|
|
|
|
|
_dialogueTree[oldLevel][selectedSentence].head = -1;
|
|
|
|
_dialogueTree[oldLevel][selectedSentence].dialogueNodeValue1 = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Talk::findDialogueString(byte *ptr, int16 id, char *str) {
|
|
|
|
str[0] = '\0';
|
|
|
|
|
|
|
|
for (int i = 1; i <= _pMax; i++) {
|
|
|
|
ptr += 2;
|
|
|
|
int16 currentId = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
if (id == currentId) {
|
|
|
|
ptr = getString(ptr, str, MAX_STRING_LENGTH, 4);
|
2003-10-07 06:56:29 +00:00
|
|
|
//debug(0, "Found string with ID %i: '%s'", id, str);
|
2003-10-07 03:58:44 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ptr = getString(ptr, NULL, MAX_STRING_LENGTH, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (str[0] == '\0')
|
|
|
|
warning("Failed to find string with ID %i", id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Talk::load(const char *filename) {
|
|
|
|
byte *ptr = _fileData = _resource->loadFile(filename, 20);
|
|
|
|
if (!_fileData) {
|
|
|
|
error("Failed to load resource data file '%s'", filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool canQuit;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Load talk header
|
|
|
|
//
|
|
|
|
|
|
|
|
_levelMax = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
|
2003-10-07 06:56:29 +00:00
|
|
|
//debug(0, "levelMax = %i", _levelMax);
|
2003-10-07 03:58:44 +00:00
|
|
|
|
|
|
|
if (_levelMax < 0) {
|
|
|
|
_levelMax = -_levelMax;
|
|
|
|
canQuit = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
canQuit = true;
|
|
|
|
|
|
|
|
_uniqueKey = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
_talkKey = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
2003-10-07 09:34:19 +00:00
|
|
|
/*int16 jMax =*/ (int16)READ_BE_UINT16(ptr); ptr += 2;
|
2003-10-07 03:58:44 +00:00
|
|
|
_pMax = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
2003-10-07 09:34:19 +00:00
|
|
|
/*int16 gameState1 =*/ (int16)READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
/*int16 testValue1 =*/ (int16)READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
/*int16 itemToInsert1 =*/ (int16)READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
/*int16 gameState2 =*/ (int16)READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
/*int16 testValue2 =*/ (int16)READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
/*int16 itemToInsert2 =*/ (int16)READ_BE_UINT16(ptr); ptr += 2;
|
2003-10-07 03:58:44 +00:00
|
|
|
|
2003-10-07 06:56:29 +00:00
|
|
|
//debug(0, "uniqueKey = %i", _uniqueKey);
|
|
|
|
//debug(0, "talkKey = %i", _talkKey);
|
2003-10-07 03:58:44 +00:00
|
|
|
|
|
|
|
_person1Ptr = _fileData + READ_BE_UINT16(ptr); ptr += 2;
|
2003-10-09 16:33:00 +00:00
|
|
|
/*byte *cutawayPtr = _fileData + READ_BE_UINT16(ptr);*/ ptr += 2;
|
2003-10-07 03:58:44 +00:00
|
|
|
_person2Ptr = _fileData + READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
|
|
|
|
if (ptr != (_fileData + 28))
|
|
|
|
error("ptr != (_fileData + 28))");
|
|
|
|
|
|
|
|
byte *dataPtr = _fileData + 32;
|
|
|
|
_joePtr = dataPtr + _levelMax * 96;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Load dialogue tree
|
|
|
|
//
|
|
|
|
|
|
|
|
ptr = dataPtr;
|
|
|
|
|
|
|
|
for (int i = 1; i <= _levelMax; i++)
|
|
|
|
for (int j = 0; j <= 5; j++) {
|
|
|
|
ptr += 2;
|
|
|
|
_dialogueTree[i][j].head = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
ptr += 2;
|
|
|
|
_dialogueTree[i][j].dialogueNodeValue1 = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
ptr += 2;
|
|
|
|
_dialogueTree[i][j].gameStateIndex = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
ptr += 2;
|
|
|
|
_dialogueTree[i][j].gameStateValue = (int16)READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Talk::initialTalk() {
|
|
|
|
// Lines 848-903 in talk.c
|
|
|
|
|
|
|
|
byte *ptr = _joePtr + 2;
|
|
|
|
|
|
|
|
uint16 hasString = READ_BE_UINT16(ptr); ptr += 2;
|
|
|
|
|
|
|
|
char joeString[MAX_STRING_SIZE];
|
|
|
|
if (hasString) {
|
|
|
|
ptr = getString(ptr, joeString, MAX_STRING_LENGTH);
|
2003-10-07 06:56:29 +00:00
|
|
|
//debug(0, "joeString = '%s'", joeString);
|
2003-10-07 03:58:44 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
joeString[0] = '\0';
|
|
|
|
|
|
|
|
ptr = _person2Ptr;
|
|
|
|
ptr = getString(ptr, _person2String, MAX_STRING_LENGTH);
|
2003-10-07 06:56:29 +00:00
|
|
|
//debug(0, "person2String = '%s'", _person2String);
|
2003-10-07 03:58:44 +00:00
|
|
|
|
|
|
|
char joe2String[MAX_STRING_SIZE];
|
|
|
|
ptr = getString(ptr, joe2String, MAX_STRING_LENGTH);
|
2003-10-07 06:56:29 +00:00
|
|
|
//debug(0, "joe2String = '%s'", joe2String);
|
2003-10-07 03:58:44 +00:00
|
|
|
|
|
|
|
if (talkSelected()->hasTalkedTo == 0) {
|
|
|
|
|
|
|
|
// Not yet talked to this person
|
|
|
|
|
|
|
|
if (joeString[0] != '0') {
|
|
|
|
char voiceFilePrefix[MAX_STRING_SIZE];
|
|
|
|
sprintf(voiceFilePrefix, "%2dSSSSJ", _talkKey);
|
|
|
|
speak(joeString, "JOE", voiceFilePrefix);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Already spoken to them, choose second response
|
|
|
|
|
|
|
|
if (joe2String[0] != '0') {
|
|
|
|
char voiceFilePrefix[MAX_STRING_SIZE];
|
|
|
|
sprintf(voiceFilePrefix, "%2dSSSSJ", _talkKey);
|
|
|
|
speak(joe2String, "JOE", voiceFilePrefix);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2003-10-12 19:16:48 +00:00
|
|
|
int Talk::getSpeakCommand(const char *sentence, unsigned &index) {
|
|
|
|
// Lines 1299-1362 in talk.c
|
|
|
|
int commandCode = SPEAK_DEFAULT;
|
|
|
|
|
|
|
|
switch (sentence[index]) {
|
|
|
|
case 'A':
|
|
|
|
if (sentence[index + 1] == 'O')
|
|
|
|
commandCode = SPEAK_AMAL_ON;
|
|
|
|
else
|
|
|
|
warning("Unknown command string: '%2s'", sentence + index);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'F':
|
|
|
|
switch (sentence[index + 1]) {
|
|
|
|
case 'L':
|
|
|
|
commandCode = SPEAK_FACE_LEFT;
|
|
|
|
break;
|
|
|
|
case 'F':
|
|
|
|
commandCode = SPEAK_FACE_FRONT;
|
|
|
|
break;
|
|
|
|
case 'B':
|
|
|
|
commandCode = SPEAK_FACE_BACK;
|
|
|
|
break;
|
|
|
|
case 'R':
|
|
|
|
commandCode = SPEAK_FACE_RIGHT;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
warning("Unknown command string: '%2s'", sentence + index);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'G':
|
|
|
|
switch (sentence[index + 1]) {
|
|
|
|
case 'D':
|
|
|
|
// XXX GRAB_DIR("DOWN",0);
|
|
|
|
break;
|
|
|
|
case 'M':
|
|
|
|
// XXX GRAB_DIR("MID",0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
warning("Unknown command string: '%2s'", sentence + index);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
commandCode = SPEAK_NONE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'X':
|
|
|
|
// For example *XY00(237,112)
|
|
|
|
if (sentence[index + 1] == 'Y') {
|
|
|
|
commandCode = atoi(sentence + index + 2);
|
|
|
|
// XXX int x = atoi(sentence + index + 5);
|
|
|
|
// XXX int y = atoi(sentence + index + 9);
|
|
|
|
// XXX MOVE_SPEAK(person, x, y)
|
|
|
|
index += 11;
|
|
|
|
/// XXX personWalking = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
warning("Unknown command string: '%2s'", sentence + index);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (sentence[index + 0] >= '0' && sentence[index + 0] <= '9' &&
|
|
|
|
sentence[index + 1] >= '0' && sentence[index + 1] <= '9') {
|
|
|
|
commandCode = (sentence[index] - '0') * 10 + (sentence[index + 1] - '0');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
warning("Unknown command string: '%2s'", sentence + index);
|
|
|
|
}
|
|
|
|
|
|
|
|
index += 2;
|
|
|
|
|
|
|
|
return commandCode;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-10-07 03:58:44 +00:00
|
|
|
bool Talk::speak(const char *sentence, const char *person, const char *voiceFilePrefix) {
|
2003-10-12 19:16:48 +00:00
|
|
|
// Function SPEAK, lines 1266-1384 in talk.c
|
|
|
|
bool personWalking = false;
|
|
|
|
bool talkHead;
|
|
|
|
unsigned segmentIndex = 0;
|
|
|
|
unsigned segmentStart = 0;
|
|
|
|
unsigned i;
|
|
|
|
|
2003-10-07 03:58:44 +00:00
|
|
|
debug(0, "Sentence '%s' is said by person '%s' and voice files with prefix '%s' played",
|
|
|
|
sentence, person, voiceFilePrefix);
|
2003-10-12 19:16:48 +00:00
|
|
|
|
|
|
|
if (sentence[0] == '\0') {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0 == strcmp(person, "FAYE-H") ||
|
|
|
|
0 == strcmp(person, "FRANK-H") ||
|
|
|
|
0 == strcmp(person, "AZURA-H") ||
|
|
|
|
0 == strcmp(person, "X3_RITA-H"))
|
|
|
|
talkHead = true;
|
|
|
|
else
|
|
|
|
talkHead = false;
|
|
|
|
|
|
|
|
// XXX CLEAR_COMMAND(false)
|
|
|
|
|
|
|
|
for (i = 0; i < strlen(sentence); i++) {
|
|
|
|
if (sentence[i] == '*') {
|
|
|
|
int segmentLength = i - segmentStart;
|
|
|
|
|
|
|
|
i++;
|
|
|
|
int command = getSpeakCommand(sentence, i);
|
|
|
|
|
|
|
|
if (SPEAK_NONE != command) {
|
|
|
|
speakSegment(
|
|
|
|
sentence + segmentStart,
|
|
|
|
segmentLength,
|
|
|
|
person,
|
|
|
|
command,
|
|
|
|
voiceFilePrefix,
|
|
|
|
segmentIndex);
|
|
|
|
// XXX if (JOEWALK == 2) break
|
|
|
|
}
|
|
|
|
|
|
|
|
segmentIndex++;
|
|
|
|
segmentStart = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (segmentStart != i) {
|
|
|
|
speakSegment(
|
|
|
|
sentence + segmentStart,
|
|
|
|
i - segmentStart,
|
|
|
|
person,
|
|
|
|
0,
|
|
|
|
voiceFilePrefix,
|
|
|
|
segmentIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
exit:
|
|
|
|
return personWalking;
|
|
|
|
}
|
|
|
|
|
2003-10-15 09:23:05 +00:00
|
|
|
int Talk::countSpaces(const char *segment) {
|
|
|
|
int tmp = 0;
|
|
|
|
|
|
|
|
while (*segment++)
|
|
|
|
tmp++;
|
|
|
|
|
|
|
|
if (tmp < 10)
|
|
|
|
tmp = 10;
|
|
|
|
|
|
|
|
return (tmp * 2) / _logic->talkSpeed();
|
|
|
|
}
|
|
|
|
|
2003-10-12 19:16:48 +00:00
|
|
|
void Talk::speakSegment(
|
|
|
|
const char *segment,
|
|
|
|
int length,
|
|
|
|
const char *person,
|
|
|
|
int command,
|
|
|
|
const char *voiceFilePrefix,
|
|
|
|
int index) {
|
|
|
|
// Function SPEAK_SUB, lines 1406-1870 in talk.c
|
|
|
|
char voiceFileName[MAX_STRING_SIZE];
|
|
|
|
snprintf(voiceFileName, sizeof(voiceFileName), "%s%1x", voiceFilePrefix, index);
|
|
|
|
|
|
|
|
//debug(0, "Sentence segment '%*s' is said by person '%s' and voice file '%s' is played",
|
|
|
|
// length, segment, person, voiceFileName);
|
|
|
|
|
|
|
|
debug(0, "Playing voice file '%s'", voiceFileName);
|
|
|
|
|
|
|
|
|
2003-10-15 09:23:05 +00:00
|
|
|
if (SPEAK_PAUSE == command) {
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
|
|
if (_quit)
|
|
|
|
break;
|
|
|
|
_graphics->update();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//int spaces = countSpaces(segment);
|
|
|
|
|
|
|
|
if (scumm_stricmp(person, "JOE")) {
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2003-10-07 03:58:44 +00:00
|
|
|
}
|
|
|
|
|
2003-10-12 19:16:48 +00:00
|
|
|
|
2003-10-07 03:58:44 +00:00
|
|
|
byte *Talk::getString(byte *ptr, char *str, int maxLength, int align) {
|
|
|
|
int length = *ptr;
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
if (length > maxLength) {
|
|
|
|
error("String too long. Length = %i, maxLength = %i, str = '%*s'",
|
|
|
|
length, maxLength, length, (const char*)ptr);
|
|
|
|
}
|
|
|
|
else if (length) {
|
|
|
|
if (str)
|
|
|
|
memcpy(str, (const char*)ptr, length);
|
|
|
|
ptr += length;
|
|
|
|
|
|
|
|
while ((int)ptr % align)
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (str)
|
|
|
|
str[length] = '\0';
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
Talk::TalkSelected *Talk::talkSelected() {
|
|
|
|
return _talkSelected + _uniqueKey;
|
|
|
|
}
|
|
|
|
|
2003-10-07 12:20:31 +00:00
|
|
|
int Talk::splitOption(const char *str, char optionText[5][MAX_STRING_SIZE]) {
|
|
|
|
|
|
|
|
//debug(0, "splitOption(\"%s\")", str);
|
|
|
|
|
|
|
|
// Check to see if option fits on one line, and exit early
|
|
|
|
|
|
|
|
/* XXX if (_logic->language() == ENGLISH || textWidth(str) <= MAX_TEXT_WIDTH)*/ {
|
|
|
|
strcpy(optionText[0], str);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
abort();
|
|
|
|
|
|
|
|
// Split up multiple line option at closest space character
|
|
|
|
// int optionLines = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *removeStar(char *str) {
|
|
|
|
|
|
|
|
// The remove_star function in talk.c uses a static variable, but this
|
|
|
|
// modifies the string instead, so the caller should use a copy of the
|
|
|
|
// string.
|
|
|
|
|
|
|
|
char *p = strchr(str, '*');
|
|
|
|
if (p)
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2003-10-07 06:56:29 +00:00
|
|
|
int16 Talk::selectSentence() {
|
2003-10-07 12:20:31 +00:00
|
|
|
// Function TALK_BOB (lines 577-739) in talk.c
|
2003-10-07 06:56:29 +00:00
|
|
|
int selectedSentence = 0;
|
|
|
|
|
2003-10-07 12:20:31 +00:00
|
|
|
int scrollX = 0; // XXX: global variable
|
|
|
|
int startOption = 1;
|
|
|
|
int optionLines = 0;
|
|
|
|
char optionText[5][MAX_STRING_SIZE];
|
|
|
|
|
2003-10-10 09:45:22 +00:00
|
|
|
// Change NORMAL_INK -> TALK_NORMAL_INK
|
|
|
|
|
|
|
|
_graphics->textCurrentColor(INK_TALK_NORMAL);
|
|
|
|
|
2003-10-07 12:20:31 +00:00
|
|
|
// These bobs are up and down arrows
|
|
|
|
|
|
|
|
BobSlot *bob1 = _graphics->bob(SENTENCE_BOB_1);
|
|
|
|
BobSlot *bob2 = _graphics->bob(SENTENCE_BOB_2);
|
|
|
|
|
|
|
|
bob1->x = 303 + 8 + scrollX;
|
|
|
|
bob1->y = 150 + 1;
|
|
|
|
bob1->frameNum = 3;
|
|
|
|
bob1->box.y2 = 199;
|
|
|
|
bob1->active = false;
|
|
|
|
|
|
|
|
bob2->x = 303 + scrollX;
|
|
|
|
bob2->y = 175;
|
|
|
|
bob2->frameNum = 4;
|
|
|
|
bob2->box.y2 = 199;
|
|
|
|
bob2->active = false;
|
|
|
|
|
|
|
|
bool rezone = true;
|
|
|
|
|
|
|
|
while (rezone) {
|
|
|
|
rezone = false;
|
|
|
|
|
|
|
|
// Set zones for UP/DOWN text arrows when not English version
|
|
|
|
// XXX ClearZones(1);
|
|
|
|
|
|
|
|
if (_logic->language() != ENGLISH) {
|
|
|
|
// XXX SetZone(1,5,MAXTEXTLEN+1, 0,319,24);
|
|
|
|
// XXX SetZone(1,6,MAXTEXTLEN+1,25,319,49);
|
|
|
|
}
|
|
|
|
|
2003-10-10 09:45:22 +00:00
|
|
|
_graphics->textClear(151,199);
|
2003-10-07 06:56:29 +00:00
|
|
|
|
2003-10-07 12:20:31 +00:00
|
|
|
int sentenceCount = 0;
|
|
|
|
int yOffset = 1;
|
|
|
|
|
|
|
|
for (int i = startOption; i <= 4; i++) {
|
|
|
|
// XXX TALK_ZONE[I] = 0;
|
|
|
|
if (_talkString[i][0] != '\0') {
|
|
|
|
sentenceCount++;
|
2003-10-10 09:45:22 +00:00
|
|
|
|
2003-10-07 12:20:31 +00:00
|
|
|
char temp[MAX_STRING_SIZE];
|
|
|
|
strcpy(temp, _talkString[i]);
|
|
|
|
optionLines = splitOption(removeStar(temp), optionText);
|
|
|
|
|
|
|
|
if (yOffset < 5)
|
|
|
|
/* XXX SetZone(
|
2003-10-10 09:45:22 +00:00
|
|
|
1,
|
|
|
|
I,
|
|
|
|
0,
|
|
|
|
(yofs * 10) - PUSHUP,
|
|
|
|
(VersionStr[1] =='E') ? 319 : MAX_TEXT_WIDTH,
|
|
|
|
10 * optionLines + (yOffset * 10) - PUSHUP) */;
|
|
|
|
|
|
|
|
for (int j = 0; j < optionLines; j++) {
|
|
|
|
if (yOffset < 5) {
|
|
|
|
debug(0, "Draw text '%s'", optionText[j]);
|
|
|
|
_graphics->textSet(
|
|
|
|
(j == 0) ? 0 : 24,
|
|
|
|
150 - PUSHUP + yOffset * 10,
|
|
|
|
optionText[j]);
|
|
|
|
}
|
|
|
|
yOffset++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX TALK_ZONE[i] = sentenceCount;
|
2003-10-07 12:20:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
yOffset--;
|
|
|
|
|
|
|
|
// Up and down dialogue arrows
|
|
|
|
|
|
|
|
if (_logic->language() != ENGLISH) {
|
|
|
|
bob1->active = (startOption > 1);
|
|
|
|
bob2->active = (yOffset > 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX KEYVERB=0;
|
|
|
|
if (sentenceCount > 0) {
|
2003-10-10 09:45:22 +00:00
|
|
|
int zone = 0;
|
|
|
|
int oldZone = 0;
|
2003-10-07 12:20:31 +00:00
|
|
|
|
2003-10-10 09:45:22 +00:00
|
|
|
while (0 == selectedSentence) {
|
|
|
|
|
|
|
|
if (_quit)
|
|
|
|
break;
|
2003-10-07 12:20:31 +00:00
|
|
|
|
2003-10-10 09:45:22 +00:00
|
|
|
_graphics->update();
|
2003-10-07 12:20:31 +00:00
|
|
|
|
2003-10-10 09:45:22 +00:00
|
|
|
// XXX zone = zone(1, mouseX, mouseY);
|
|
|
|
|
|
|
|
if (5 == zone || 6 == zone) {
|
|
|
|
// XXX Arrow zones
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (oldZone != zone) {
|
|
|
|
// Changed zone, change text colors
|
|
|
|
|
|
|
|
if (zone > 0) {
|
|
|
|
|
|
|
|
// XXX for (int i = zones[1][zone].y1; i < zones[1][zone].y2; i += 10)
|
|
|
|
// XXX texts[i + 150].col = INK_JOE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldZone > 0) {
|
|
|
|
// XXX for (i = zones[1][oldZone].y1; i < zones[1][oldZone].y2; i += 10)
|
|
|
|
// XXX texts[i + 150].col = INK_TALK_NORMAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
oldZone = zone;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX make the loop exit as we can't get any input yet
|
|
|
|
selectedSentence = 1;
|
|
|
|
} // while()
|
2003-10-07 12:20:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// XXX Begin debug stuff
|
|
|
|
// debug(0, "----- Select a sentence of these -----");
|
2003-10-07 06:56:29 +00:00
|
|
|
for (int i = 1; i <= 4; i++) {
|
|
|
|
if (_talkString[i][0] != '\0') {
|
2003-10-07 12:20:31 +00:00
|
|
|
// XXX debug(0, "%i: %s", i, _talkString[i]);
|
|
|
|
if (!selectedSentence)
|
|
|
|
selectedSentence = i;
|
2003-10-07 06:56:29 +00:00
|
|
|
}
|
|
|
|
}
|
2003-10-07 12:20:31 +00:00
|
|
|
// XXX End debug stuff
|
|
|
|
|
2003-10-10 09:45:22 +00:00
|
|
|
|
|
|
|
debug(0, "Selected sentence %i", selectedSentence);
|
|
|
|
|
2003-10-07 12:20:31 +00:00
|
|
|
bob1->active = false;
|
|
|
|
bob2->active = false;
|
|
|
|
|
2003-10-10 09:45:22 +00:00
|
|
|
if (selectedSentence > 0) {
|
|
|
|
_graphics->textClear(0,198);
|
|
|
|
|
|
|
|
speak(_talkString[selectedSentence], "JOE", _joeVoiceFilePrefix[selectedSentence]);
|
|
|
|
}
|
|
|
|
|
|
|
|
_graphics->textClear(151,151);
|
|
|
|
|
2003-10-07 06:56:29 +00:00
|
|
|
return selectedSentence;
|
|
|
|
}
|
|
|
|
|
2003-10-07 03:58:44 +00:00
|
|
|
} // End of namespace Queen
|