aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--queen/cutaway.cpp50
-rw-r--r--queen/cutaway.h6
-rw-r--r--queen/module.mk1
-rw-r--r--queen/talk.cpp428
-rw-r--r--queen/talk.h148
5 files changed, 594 insertions, 39 deletions
diff --git a/queen/cutaway.cpp b/queen/cutaway.cpp
index 72d0847403..275d18ba46 100644
--- a/queen/cutaway.cpp
+++ b/queen/cutaway.cpp
@@ -22,6 +22,7 @@
#include "stdafx.h"
#include "cutaway.h"
#include "graphics.h"
+#include "talk.h"
namespace Queen {
@@ -46,7 +47,6 @@ namespace Queen {
Data needed:
CURRSONG
- GAMESTATE
JOEF (Joe's face direction)
JX,JY (Joe's coordintes)
PERSON_FACE
@@ -68,11 +68,11 @@ Cutaway::Cutaway(
const char *filename,
Logic *logic,
Resource *resource)
-: _logic(logic), _quit(false), _lastSong(0), _songBeforeComic(0) {
+: _logic(logic), _resource(resource), _quit(false), _lastSong(0), _songBeforeComic(0) {
// XXX should not create this object ourselves
_graphics = new Graphics(resource);
memset(&_bankNames, 0, sizeof(_bankNames));
- load(filename, resource);
+ load(filename);
}
Cutaway::~Cutaway() {
@@ -81,14 +81,12 @@ Cutaway::~Cutaway() {
delete[] _fileData;
}
-void Cutaway::load(const char *filename, Resource *resource) {
+void Cutaway::load(const char *filename) {
byte *ptr;
- ptr = _fileData = resource->loadFile(filename, 20);
+ ptr = _fileData = _resource->loadFile(filename, 20);
if (!_fileData) {
error("Failed to load resource data file '%s'", filename);
- _quit = true;
- return;
}
if (0 == scumm_stricmp(filename, "comic.cut"))
@@ -149,7 +147,7 @@ void Cutaway::load(const char *filename, Resource *resource) {
}
char entryString[MAX_STRING_SIZE];
- _nextSentence = getString(_nextSentence, entryString, MAX_STRING_LENGTH);
+ _nextSentence = Talk::getString(_nextSentence, entryString, MAX_STRING_LENGTH);
debug(0, "Entry string = '%s'", entryString);
if (entryString[0] == '*' &&
@@ -173,27 +171,6 @@ void Cutaway::load(const char *filename, Resource *resource) {
}
-byte *Cutaway::getString(byte *ptr, char *str, int maxLength) {
- 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) {
- memcpy(str, (const char*)ptr, length);
- ptr += length;
-
- while ((int)ptr % 2)
- ptr++;
- }
-
- str[length] = '\0';
-
- return ptr;
-}
-
void Cutaway::loadStrings(byte *ptr) {
int i,j;
@@ -208,7 +185,7 @@ void Cutaway::loadStrings(byte *ptr) {
*/
for (i = 0, j = 0; i < bankNameCount; i++) {
- ptr = getString(ptr, _bankNames[j], MAX_FILENAME_LENGTH);
+ ptr = Talk::getString(ptr, _bankNames[j], MAX_FILENAME_LENGTH);
if (_bankNames[j][0]) {
debug(0, "Bank name %i = '%s'", _bankNames[j]);
@@ -217,7 +194,7 @@ void Cutaway::loadStrings(byte *ptr) {
}
debug(0, "Getting talk file");
- ptr = getString(ptr, _talkFile, MAX_FILENAME_LENGTH);
+ ptr = Talk::getString(ptr, _talkFile, MAX_FILENAME_LENGTH);
debug(0, "Talk file = '%s'", _talkFile);
int TALKTO = READ_BE_UINT16(ptr);
@@ -268,6 +245,7 @@ void Cutaway::dumpCutawayObject(int index, CutawayObject &object)
switch (object.objectNumber) {
case -1: objectNumberStr = "MESSAGE"; break;
case 0: objectNumberStr = "Joe"; break;
+ case 196: objectNumberStr = "Chef"; break;
case 548: objectNumberStr = "Anderson"; break;
default: objectNumberStr = "unknown"; break;
}
@@ -731,7 +709,7 @@ void Cutaway::run(char *nextFilename) {
limitBob(object);
char sentence[MAX_STRING_SIZE];
- _nextSentence = getString(_nextSentence, sentence, MAX_STRING_LENGTH);
+ _nextSentence = Talk::getString(_nextSentence, sentence, MAX_STRING_LENGTH);
debug(0, "Sentence = '%s'", sentence);
if (OBJECT_ROOMFADE == object.objectNumber) {
@@ -1006,11 +984,11 @@ void Cutaway::updateGameState() {
// Turn area on or off
if (areaSubIndex > 0) {
- int16* area = _logic->area(areaIndex, areaSubIndex);
+ int16 *area = _logic->area(areaIndex, areaSubIndex);
area[0] = abs(area[0]);
}
else {
- int16* area = _logic->area(areaIndex, abs(areaSubIndex));
+ int16 *area = _logic->area(areaIndex, abs(areaSubIndex));
area[0] = -abs(area[0]);
}
}
@@ -1033,8 +1011,10 @@ void Cutaway::talk(char *nextFilename) {
// Lines 2119-2131 in cutaway.c
if (0 == scumm_stricmp(right(_talkFile, 4), ".dog")) {
- warning("Cutaway::talk() needed but not yet implemented");
+ warning("Cutaway::talk() used but not fully implemented");
nextFilename[0] = '\0';
+
+ Talk::run(_talkFile, nextFilename, _logic, _resource);
}
}
diff --git a/queen/cutaway.h b/queen/cutaway.h
index 94e3dd4c5e..2718cd773a 100644
--- a/queen/cutaway.h
+++ b/queen/cutaway.h
@@ -121,6 +121,7 @@ class Cutaway {
};
Logic *_logic;
+ Resource *_resource;
Graphics *_graphics;
//! Raw .cut file data (without 20 byte header)
@@ -188,7 +189,7 @@ class Cutaway {
void run(char *nextFilename);
//! Load cutaway data from file
- void load(const char *filename, Resource *resource);
+ void load(const char *filename);
//! Used by load to read string data
void loadStrings(byte *ptr);
@@ -235,9 +236,6 @@ class Cutaway {
//! Get CutawayAnim data from ptr and return new ptr
byte *getCutawayAnim(byte *ptr, int header, CutawayAnim &anim);
- //! Read a string from ptr and return new ptr
- static byte *getString(byte *ptr, char *str, int maxLength);
-
//! Read a CutawayObject from ptr and return new ptr
static byte *getCutawayObject(byte *ptr, CutawayObject &object);
diff --git a/queen/module.mk b/queen/module.mk
index 8290094d50..9835ec84eb 100644
--- a/queen/module.mk
+++ b/queen/module.mk
@@ -7,6 +7,7 @@ MODULE_OBJS = \
queen/queen.o \
queen/resource.o \
queen/restables.o \
+ queen/talk.o
# This module can be built as a plugin
ifdef BUILD_PLUGINS
diff --git a/queen/talk.cpp b/queen/talk.cpp
new file mode 100644
index 0000000000..95ebbc3ccd
--- /dev/null
+++ b/queen/talk.cpp
@@ -0,0 +1,428 @@
+/* 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:
+
+ */
+
+void Talk::run(
+ const char *filename,
+ char *cutawayFilename,
+ Logic *logic,
+ Resource *resource) {
+ Talk *talk = new Talk(logic, resource);
+ talk->talk(filename, cutawayFilename);
+ delete talk;
+}
+
+Talk::Talk(
+ Logic *logic,
+ Resource *resource)
+: _logic(logic), _resource(resource), _fileData(NULL), _quit(false) {
+
+ //! TODO Move this to the Logic class later!
+ memset(_talkSelected, 0, sizeof(_talkSelected));
+}
+
+Talk::~Talk() {
+ delete[] _fileData;
+}
+
+
+
+void Talk::talk(const char *filename, char *cutawayFilename) {
+ _oldSelectedSentenceIndex = 0;
+ _oldSelectedSentenceValue = 0;
+
+ debug(0, "----- talk(\"%s\") -----", filename);
+
+ cutawayFilename[0] = '\0';
+ load(filename);
+
+ char personName[MAX_STRING_SIZE];
+ // XXX SET_PERSON_DATA(N,NAMEstr,0);
+ int bobNum = 0; // XXX P_BNUM;
+ // 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;
+ int16 level=1, retval=0, type=1;
+ int16 head = _dialogueTree[level][0].head;
+
+ while(retval != -1) {
+ debug(0, "retval = %i", retval);
+
+ char otherVoiceFilePrefix [MAX_STRING_SIZE];
+ char joeVoiceFilePrefix [5][MAX_STRING_SIZE];
+ char talkString [5][MAX_STRING_SIZE];
+
+ talkString[0][0] = '\0';
+
+ if(talkSelected()->hasTalkedTo == 1 && head == 1)
+ strcpy(talkString[0], _person2String);
+ else
+ findDialogueString(_person1Ptr, head, talkString[0]);
+
+ if(talkSelected()->hasTalkedTo == 1 && head == 1)
+ sprintf(otherVoiceFilePrefix, "%2dXXXXP", _talkKey);
+ else
+ sprintf(otherVoiceFilePrefix, "%2d%4xP", _talkKey, head);
+
+ if (talkString[0][0] == '\0' && retval > 1) {
+ findDialogueString(_person1Ptr, retval, talkString[0]);
+ sprintf(otherVoiceFilePrefix,"%2d%4xP", _talkKey, retval);
+ }
+
+ // Joe dialogue
+
+ for (int i = 1; i <= 4; i++) {
+ findDialogueString(_joePtr, _dialogueTree[level][i].head, talkString[i]);
+
+ int16 index = _dialogueTree[level][i].gameStateIndex;
+
+ if (index < 0 && _logic->gameState(abs(index)) != _dialogueTree[level][i].gameStateValue)
+ talkString[i][0] = '\0';
+
+ sprintf(joeVoiceFilePrefix[i], "%2d%4xJ", _talkKey, _dialogueTree[level][i].head);
+ }
+
+ // 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++) {
+ if (talkString[i][0] != '\0') {
+ choicesLeft++;
+ selectedSentence = i;
+ }
+ }
+
+ debug(0, "choicesLeft = %i", choicesLeft);
+
+ if (1 == choicesLeft) {
+ // Automatically run the final dialogue option
+ if (speak(talkString[0], personName, otherVoiceFilePrefix))
+ personWalking = true;
+
+ if (_quit)
+ break;
+
+ speak(talkString[selectedSentence], personName, joeVoiceFilePrefix[selectedSentence]);
+
+ }
+ else {
+ // XXX if (bobNum > 0)
+ // XXX selectedSentence = bobTalk(personName);
+ for (int i = 1; i <= 4; i++) {
+ if (talkString[i][0] != '\0') {
+ selectedSentence = i;
+ break;
+ }
+ }
+ }
+
+ 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!
+
+
+ // XXX debug
+ //break;
+ }
+}
+
+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);
+ debug(0, "Found string with ID %i: '%s'", id, str);
+ 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;
+
+ debug(0, "levelMax = %i", _levelMax);
+
+ 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;
+ int16 jMax = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ _pMax = (int16)READ_BE_UINT16(ptr); ptr += 2;
+ 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;
+
+ debug(0, "uniqueKey = %i", _uniqueKey);
+ debug(0, "talkKey = %i", _talkKey);
+
+ _person1Ptr = _fileData + READ_BE_UINT16(ptr); ptr += 2;
+ byte *cutawayPtr = _fileData + READ_BE_UINT16(ptr); ptr += 2;
+ _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);
+ debug(0, "joeString = '%s'", joeString);
+ }
+ else
+ joeString[0] = '\0';
+
+ ptr = _person2Ptr;
+ ptr = getString(ptr, _person2String, MAX_STRING_LENGTH);
+ debug(0, "person2String = '%s'", _person2String);
+
+ char joe2String[MAX_STRING_SIZE];
+ ptr = getString(ptr, joe2String, MAX_STRING_LENGTH);
+ debug(0, "joe2String = '%s'", joe2String);
+
+ 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);
+ }
+
+ }
+
+}
+
+bool Talk::speak(const char *sentence, const char *person, const char *voiceFilePrefix) {
+ debug(0, "Sentence '%s' is said by person '%s' and voice files with prefix '%s' played",
+ sentence, person, voiceFilePrefix);
+ return false; // XXX
+}
+
+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;
+}
+
+} // End of namespace Queen
diff --git a/queen/talk.h b/queen/talk.h
new file mode 100644
index 0000000000..42fdeebf73
--- /dev/null
+++ b/queen/talk.h
@@ -0,0 +1,148 @@
+/* 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$
+ *
+ */
+
+#ifndef QUEEN_TALK_H
+#define QUEEN_TALK_H
+
+#include "queen/queen.h"
+
+namespace Queen {
+
+class Resource;
+class Logic;
+
+class Talk {
+ public:
+
+ //! Public interface to run a talk from a file
+ static void run(
+ const char *filename,
+ char *cutawayFilename,
+ Logic *logic,
+ Resource *resource);
+
+ //! Public interface to speak a sentence
+#if 0
+ static void run(
+ const char *sentence,
+ const char *person,
+ int noun,
+ Logic *logic,
+ Resource *resource);
+#endif
+
+ //! Read a string from ptr and return new ptr
+ static byte *getString(byte *ptr, char *str, int maxLength, int align = 2);
+
+ private:
+ //! Collection of constants used by Talk
+ enum {
+ MAX_STRING_LENGTH = 255,
+ MAX_STRING_SIZE = (MAX_STRING_LENGTH + 1),
+ TALK_SELECTED_COUNT = 86
+ };
+
+ //! TODO Move this to struct.h later!
+ struct TalkSelected {
+ int16 hasTalkedTo;
+ int16 values[4];
+ };
+
+ struct DialogueNode {
+ int16 head;
+ int16 dialogueNodeValue1;
+ int16 gameStateIndex;
+ int16 gameStateValue;
+ };
+
+ Logic *_logic;
+ Resource *_resource;
+
+ //! 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;
+
+ //! Used by findDialogueString
+ int16 _pMax;
+
+ //! String data
+ byte *_person1Ptr;
+
+ //! Data used if we have talked to the person before
+ byte *_person2Ptr;
+
+ //! Data used if we haven't talked to the person before
+ byte *_joePtr;
+
+ //! Set to true to quit talking
+ bool _quit;
+
+ //! IDs for sentences
+ DialogueNode _dialogueTree[18][6];
+
+ //! TODO Move this to the Logic class later!
+ TalkSelected _talkSelected[TALK_SELECTED_COUNT];
+
+ //! Greeting from person Joe has talked to before
+ char _person2String[MAX_STRING_SIZE];
+
+ int _oldSelectedSentenceIndex;
+ int _oldSelectedSentenceValue;
+
+
+ Talk(Logic *logic, Resource *resource);
+ ~Talk();
+
+ //! Perform talk in file and return a cutaway filename
+ void talk(const char *filename, char *cutawayFilename);
+
+ //! 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(byte *ptr, int16 id, char *str);
+
+ //! Speak sentence
+ bool speak(const char *sentence, const char *person, const char *voiceFilePrefix);
+
+ //! Get TalkSelected struct for this talk
+ TalkSelected *talkSelected();
+
+ //! The sentence will not be displayed again
+ void disableSentence(int oldLevel, int selectedSentence);
+
+
+};
+
+} // End of namespace Queen
+
+#endif