aboutsummaryrefslogtreecommitdiff
path: root/sword2
diff options
context:
space:
mode:
authorTorbjörn Andersson2004-05-05 07:06:18 +0000
committerTorbjörn Andersson2004-05-05 07:06:18 +0000
commit5882ea5819563aa1c381a96e736bc3be85bb2b17 (patch)
treeb7d8e7b5e52d82568580dd4467c9813eafe536a0 /sword2
parent42ba9c983f01cad3378c734e602f5e33c6c01382 (diff)
downloadscummvm-rg350-5882ea5819563aa1c381a96e736bc3be85bb2b17.tar.gz
scummvm-rg350-5882ea5819563aa1c381a96e736bc3be85bb2b17.tar.bz2
scummvm-rg350-5882ea5819563aa1c381a96e736bc3be85bb2b17.zip
Cleanup.
Part of this cleanup involved removing _unpauseZone. It was only used by fnISpeak(), and as far as I could tell it was just because the original code didn't trust amISpeaking() and getSpeechStatus() to return sensible values directly after unpausing the game. svn-id: r13781
Diffstat (limited to 'sword2')
-rw-r--r--sword2/console.cpp5
-rw-r--r--sword2/console.h2
-rw-r--r--sword2/debug.cpp6
-rw-r--r--sword2/logic.h12
-rw-r--r--sword2/speech.cpp1159
-rw-r--r--sword2/sword2.cpp1
6 files changed, 479 insertions, 706 deletions
diff --git a/sword2/console.cpp b/sword2/console.cpp
index 1bd521761b..4d9acfe3fc 100644
--- a/sword2/console.cpp
+++ b/sword2/console.cpp
@@ -57,6 +57,11 @@ Debugger::Debugger(Sword2Engine *vm)
// object resources (except player) in
// fnAddHuman()
+ _speechScriptWaiting = 0; // The id of whoever we're waiting for
+ // in a speech script. See fnTheyDo(),
+ // fnTheyDoWeWait(), fnWeWait(), and
+ // fnTimedWait().
+
_startTime = 0; // "TIMEON" & "TIMEOFF" - system start
// time
diff --git a/sword2/console.h b/sword2/console.h
index ca8879806c..396f7e5de4 100644
--- a/sword2/console.h
+++ b/sword2/console.h
@@ -65,6 +65,8 @@ public:
bool _testingSnR;
+ int32 _speechScriptWaiting;
+
int32 _textNumber;
ObjectGraphic _playerGraphic;
diff --git a/sword2/debug.cpp b/sword2/debug.cpp
index da61b81b43..b16555e5e8 100644
--- a/sword2/debug.cpp
+++ b/sword2/debug.cpp
@@ -265,10 +265,10 @@ void Debugger::buildDebugText(void) {
// "waiting for person" indicator - set form fnTheyDo and
// fnTheyDoWeWait
- if (_vm->_logic->_speechScriptWaiting) {
+ if (_speechScriptWaiting) {
sprintf(buf, "script waiting for %s (%d)",
- _vm->fetchObjectName(_vm->_logic->_speechScriptWaiting, name),
- _vm->_logic->_speechScriptWaiting);
+ _vm->fetchObjectName(_speechScriptWaiting, name),
+ _speechScriptWaiting);
makeDebugTextBlock(buf, 0, 90);
}
diff --git a/sword2/logic.h b/sword2/logic.h
index c1d9f3e41c..df7d7a560d 100644
--- a/sword2/logic.h
+++ b/sword2/logic.h
@@ -170,8 +170,7 @@ public:
_speechAnimType(0), _leftClickDelay(0), _rightClickDelay(0),
_defaultResponseId(0), _totalStartups(0),
_totalScreenManagers(0), _officialTextNumber(0),
- _speechScriptWaiting(0), _speechTextBlocNo(0),
- _choosing(false), _unpauseZone(0) {
+ _speechTextBlocNo(0), _choosing(false) {
_scriptVars = NULL;
memset(_subjectList, 0, sizeof(_subjectList));
memset(_eventList, 0, sizeof(_eventList));
@@ -192,21 +191,12 @@ public:
int16 _officialTextNumber;
- // usually 0; if non-zero then it's the id of whoever we're waiting for
- // in a speech script see fnTheyDo, fnTheyDoWeWait and fnWeWait
-
- int32 _speechScriptWaiting;
-
// so speech text cleared when running a new start-script
-
uint32 _speechTextBlocNo;
// could alternately use logic->looping of course
-
bool _choosing;
- uint32 _unpauseZone;
-
void resetScriptVars(void);
void conPrintStartMenu(void);
diff --git a/sword2/speech.cpp b/sword2/speech.cpp
index 86f28debf2..73e5c060eb 100644
--- a/sword2/speech.cpp
+++ b/sword2/speech.cpp
@@ -32,56 +32,26 @@
namespace Sword2 {
-enum {
- INS_talk = 1,
- INS_anim = 2,
- INS_reverse_anim = 3,
- INS_walk = 4,
- INS_turn = 5,
- INS_face = 6,
- INS_trace = 7,
- INS_no_sprite = 8,
- INS_sort = 9,
- INS_foreground = 10,
- INS_background = 11,
- INS_table_anim = 12,
- INS_reverse_table_anim = 13,
- INS_walk_to_anim = 14,
- INS_set_frame = 15,
- INS_stand_after_anim = 16,
- INS_quit = 42
-};
-
int32 Logic::fnAddSubject(int32 *params) {
// params: 0 id
// 1 daves reference number
if (_scriptVars[IN_SUBJECT] == 0) {
- // This is the start of the new subject list
- // Set the default repsonse id to zero in case we're never
- // passed one
+ // This is the start of the new subject list. Set the default
+ // repsonse id to zero in case we're never passed one.
_defaultResponseId = 0;
}
- // - this just means we'd get the response for the 1st icon in the
- // chooser which is better than crashing
-
- if (params[0] == -1)
- {
- // this isn't an icon at all, it's telling us the id of the
- // default response
+ if (params[0] == -1) {
+ // Id -1 is used for setting the default response, i.e. the
+ // response when someone uses an object on a person and he
+ // doesn't know anything about it. See fnChoose() below.
- // and here it is - this is the ref number we will return if
_defaultResponseId = params[1];
-
- // a luggage icon is clicked on someone when it wouldn't have
- // been in the chooser list (see fnChoose below)
} else {
+ debug(5, "fnAddSubject res %d, uid %d", params[0], params[1]);
_subjectList[_scriptVars[IN_SUBJECT]].res = params[0];
_subjectList[_scriptVars[IN_SUBJECT]].ref = params[1];
-
- debug(5, "fnAddSubject res %d, uid %d", params[0], params[1]);
-
_scriptVars[IN_SUBJECT]++;
}
@@ -91,197 +61,166 @@ int32 Logic::fnAddSubject(int32 *params) {
int32 Logic::fnChoose(int32 *params) {
// params: none
- // the human is switched off so there will be no normal mouse engine
+ // This opcode is used to open the conversation menu. The human is
+ // switched off so there will be no normal mouse engine.
- MouseEvent *me;
- uint32 i;
- int hit;
- byte *icon;
+ // The player's choice is piggy-backed on the standard opcode return
+ // values, to be used with the CP_JUMP_ON_RETURNED opcode. As far as I
+ // can tell, this is the only function that uses that feature.
- _scriptVars[AUTO_SELECTED] = 0; // see below
+ uint i;
- // new thing to intercept objects held at time of clicking on a person
+ _scriptVars[AUTO_SELECTED] = 0;
if (_scriptVars[OBJECT_HELD]) {
- // So that, if there is no match, the speech script uses the
- // default text for objects that are not accounted for
+ // The player used an object on a person. In this case it
+ // triggered a conversation menu. Act as if the user tried to
+ // talk to the person about that object. If the person doesn't
+ // know anything about it, use the default response.
- int response = _defaultResponseId;
-
- // If we are using a luggage icon on the person, scan the
- // subject list to see if this icon would have been available
- // at this time.
- //
- // If it is there, return the relevant 'ref' number (as if it
- // had been selected from within the conversation). If not,
- // just return a special code to get the default text line(s)
- // for unsupported objects.
- //
- // Note that we won't display the subject icons in this case!
-
- // scan the subject list for a match with our 'object_held'
+ uint32 response = _defaultResponseId;
for (i = 0; i < _scriptVars[IN_SUBJECT]; i++) {
if (_subjectList[i].res == _scriptVars[OBJECT_HELD]) {
- // Return special subject chosen code (same
- // as in normal chooser routine below)
response = _subjectList[i].ref;
break;
}
}
- _scriptVars[OBJECT_HELD] = 0; // clear it so it doesn't keep happening!
- _scriptVars[IN_SUBJECT] = 0; // clear the subject list
+ // The user won't be holding the object any more, and the
+ // conversation menu will be closed.
+ _scriptVars[OBJECT_HELD] = 0;
+ _scriptVars[IN_SUBJECT] = 0;
return IR_CONT | (response << 3);
}
- // new thing for skipping chooser with "nothing else to say" text
-
- // If this is the 1st time the chooser is coming up in this
- // conversation, AND there's only 1 subject, AND it's the EXIT icon
-
if (_scriptVars[CHOOSER_COUNT_FLAG] == 0 && _scriptVars[IN_SUBJECT] == 1 && _subjectList[0].res == EXIT_ICON) {
- _scriptVars[AUTO_SELECTED] = 1; // for speech script
- _scriptVars[IN_SUBJECT] = 0; // clear the subject list
+ // This is the first time the chooser is coming up in this
+ // conversation, there is only one subject and that's the
+ // EXIT icon.
+ //
+ // In other words, the player doesn't have anything to talk
+ // about. Skip it.
- // return special subject chosen code (same as in normal
- // chooser routine below)
+ // The conversation menu will be closed. We set AUTO_SELECTED
+ // because the speech script depends on it.
+
+ _scriptVars[AUTO_SELECTED] = 1;
+ _scriptVars[IN_SUBJECT] = 0;
return IR_CONT | (_subjectList[0].ref << 3);
}
+ byte *icon;
+
if (!_choosing) {
- // new choose session
- // build menus from subject_list
+ // This is a new conversation menu.
if (!_scriptVars[IN_SUBJECT])
- error("fnChoose with no subjects :-O");
-
- // init top menu from master list
- // all icons are highlighted / full colour
+ error("fnChoose with no subjects");
- for (i = 0; i < 15; i++) {
- if (i < _scriptVars[IN_SUBJECT]) {
- debug(5, " ICON res %d for %d", _subjectList[i].res, i);
- icon = _vm->_resman->openResource(_subjectList[i].res) + sizeof(StandardHeader) + RDMENU_ICONWIDE * RDMENU_ICONDEEP;
- _vm->_graphics->setMenuIcon(RDMENU_BOTTOM, (uint8) i, icon);
- _vm->_resman->closeResource(_subjectList[i].res);
- } else {
- // no icon here
- debug(5, " NULL for %d", i);
- _vm->_graphics->setMenuIcon(RDMENU_BOTTOM, (uint8) i, NULL);
- }
+ for (i = 0; i < _scriptVars[IN_SUBJECT]; i++) {
+ icon = _vm->_resman->openResource(_subjectList[i].res) + sizeof(StandardHeader) + RDMENU_ICONWIDE * RDMENU_ICONDEEP;
+ _vm->_graphics->setMenuIcon(RDMENU_BOTTOM, i, icon);
+ _vm->_resman->closeResource(_subjectList[i].res);
}
- // start menus appearing
- _vm->_graphics->showMenu(RDMENU_BOTTOM);
+ for (; i < 15; i++)
+ _vm->_graphics->setMenuIcon(RDMENU_BOTTOM, (uint8) i, NULL);
- // lets have the mouse pointer back
+ _vm->_graphics->showMenu(RDMENU_BOTTOM);
_vm->setMouse(NORMAL_MOUSE_ID);
-
_choosing = true;
return IR_REPEAT;
}
- // menu is there - we're just waiting for a click
- debug(5, "choosing");
-
- me = _vm->_input->mouseEvent();
+ // The menu is there - we're just waiting for a click. We only care
+ // about left clicks and ignore mouse releases.
- // we only care about left clicks
- // we ignore mouse releases
+ MouseEvent *me = _vm->_input->mouseEvent();
- if (!me || !(me->buttons & RD_LEFTBUTTONDOWN) || _vm->_input->_mouseY < 400) {
- debug(5, "end choose");
+ if (!me || !(me->buttons & RD_LEFTBUTTONDOWN) || _vm->_input->_mouseY < 400)
return IR_REPEAT;
- }
-
- // Check for click on a menu. If so then end the choose, highlight only
- // the chosen, blank the mouse and return the ref code * 8
- hit = _vm->menuClick(_scriptVars[IN_SUBJECT]);
+ // Check for click on a menu.
- if (hit < 0) {
- debug(5, "end choose");
+ int hit = _vm->menuClick(_scriptVars[IN_SUBJECT]);
+ if (hit < 0)
return IR_REPEAT;
- }
-
- debug(5, "Icons available:");
- byte buf[NAME_LEN];
+ // Hilight the clicked icon by greying the others.
- // change icons
for (i = 0; i < _scriptVars[IN_SUBJECT]; i++) {
- debug(5, "%s", _vm->fetchObjectName(_subjectList[i].res, buf));
-
- // change all others to grey
- if (i != (uint32) hit) {
+ if ((int) i != hit) {
icon = _vm->_resman->openResource(_subjectList[i].res) + sizeof(StandardHeader);
- _vm->_graphics->setMenuIcon(RDMENU_BOTTOM, (uint8) i, icon);
+ _vm->_graphics->setMenuIcon(RDMENU_BOTTOM, i, icon);
_vm->_resman->closeResource(_subjectList[i].res);
}
}
- debug(2, "Selected: %s", _vm->fetchObjectName(_subjectList[hit].res, buf));
+ // For non-speech scripts that manually call the chooser
+ _scriptVars[RESULT] = _subjectList[hit].res;
- // this is our looping flag
- _choosing = false;
+ // The conversation menu will be closed
+ _choosing = false;
_scriptVars[IN_SUBJECT] = 0;
-
- // blank mouse again
_vm->setMouse(0);
- debug(5, "hit %d - ref %d ref*8 %d", hit, _subjectList[hit].ref, _subjectList[hit].ref * 8);
-
- // for non-speech scripts that manually
- // call the chooser
- _scriptVars[RESULT] = _subjectList[hit].res;
-
- // return special subject chosen code
return IR_CONT | (_subjectList[hit].ref << 3);
}
-int32 Logic::fnStartConversation(int32 *params) {
- // Start conversation
-
- // reset 'chooser_count_flag' at the start of each conversation:
-
- // Note that fnStartConversation might accidently be called every time
- // the script loops back for another chooser but we only want to reset
- // the chooser count flag the first time this function is called ie.
- // when talk flag is zero
+/**
+ * Start a conversation.
+ *
+ * Note that fnStartConversation() might accidentally be called every time the
+ * script loops back for another chooser, but we only want to reset the chooser
+ * count flag the first time this function is called, i.e. when the talk flag
+ * is zero.
+ */
+int32 Logic::fnStartConversation(int32 *params) {
// params: none
- if (_scriptVars[TALK_FLAG] == 0)
- _scriptVars[CHOOSER_COUNT_FLAG] = 0; // see fnChooser & speech scripts
+ if (_scriptVars[TALK_FLAG] == 0) {
+ // See fnChooser & speech scripts
+ _scriptVars[CHOOSER_COUNT_FLAG] = 0;
+ }
fnNoHuman(params);
return IR_CONT;
}
-int32 Logic::fnEndConversation(int32 *params) {
- // end conversation
+/**
+ * End a conversation.
+ */
+int32 Logic::fnEndConversation(int32 *params) {
// params: none
_vm->_graphics->hideMenu(RDMENU_BOTTOM);
if (_vm->_input->_mouseY > 399) {
- // will wait for cursor to move off the bottom menu
+ // Will wait for cursor to move off the bottom menu
_vm->_mouseMode = MOUSE_holding;
- debug(5, " holding");
}
- _scriptVars[TALK_FLAG] = 0; // in-case DC forgets
+ // In case DC forgets
+ _scriptVars[TALK_FLAG] = 0;
+
return IR_CONT;
}
-int32 Logic::fnTheyDo(int32 *params) {
- // doesn't send the command until target is waiting - once sent we
- // carry on
+// To request the status of a target, we run its 4th script, get-speech-state.
+// This will cause RESULT to be set to either 1 (target is waiting) or 0
+// (target is busy).
+
+/**
+ * Wait for a target to become waiting, i.e. not busy, then send a command to
+ * it.
+ */
+int32 Logic::fnTheyDo(int32 *params) {
// params: 0 target
// 1 command
// 2 ins1
@@ -290,31 +229,26 @@ int32 Logic::fnTheyDo(int32 *params) {
// 5 ins4
// 6 ins5
- uint32 null_pc = 5; // 4th script - get-speech-state
- char *raw_script_ad;
- StandardHeader *head;
- int32 target = params[0];
+ StandardHeader *head = (StandardHeader *) _vm->_resman->openResource(params[0]);
+ assert (head->fileType == GAME_OBJECT);
- // request status of target
- head = (StandardHeader *) _vm->_resman->openResource(target);
- if (head->fileType != GAME_OBJECT)
- error("fnTheyDo %d not an object", target);
+ // Run the target's get-speech-state script
- raw_script_ad = (char *) head;
+ int32 target = params[0];
+ char *raw_script_ad = (char *) head;
+ uint32 null_pc = 5;
- // call the base script - this is the graphic/mouse service call
runScript(raw_script_ad, raw_script_ad, &null_pc);
_vm->_resman->closeResource(target);
- // result is 1 for waiting, 0 for busy
-
if (_scriptVars[RESULT] == 1 && !_scriptVars[INS_COMMAND]) {
- // its waiting and no other command is queueing
- // reset debug flag now that we're no longer waiting - see
- // debug.cpp
+ // The target is waiting, i.e. not busy, and there is no other
+ // command queued. Send the command.
- _speechScriptWaiting = 0;
+ debug(5, "fnTheyDo: sending command to %d", target);
+
+ _vm->_debugger->_speechScriptWaiting = 0;
_scriptVars[SPEECH_ID] = params[0];
_scriptVars[INS_COMMAND] = params[1];
@@ -327,16 +261,18 @@ int32 Logic::fnTheyDo(int32 *params) {
return IR_CONT;
}
- // debug flag to indicate who we're waiting for - see debug.cpp
- _speechScriptWaiting = target;
+ // The target is busy. Come back again next cycle.
- // target is busy so come back again next cycle
+ _vm->_debugger->_speechScriptWaiting = target;
return IR_REPEAT;
}
-int32 Logic::fnTheyDoWeWait(int32 *params) {
- // give target a command and wait for it to register as finished
+/**
+ * Wait for a target to become waiting, i.e. not busy, send a command to it,
+ * then wait for it to finish.
+ */
+int32 Logic::fnTheyDoWeWait(int32 *params) {
// params: 0 pointer to ob_logic
// 1 target
// 2 command
@@ -346,35 +282,29 @@ int32 Logic::fnTheyDoWeWait(int32 *params) {
// 6 ins4
// 7 ins5
- // 'looping' flag is used as a sent command yes/no
+ StandardHeader *head = (StandardHeader *) _vm->_resman->openResource(params[1]);
+ assert(head->fileType == GAME_OBJECT);
- ObjectLogic *ob_logic;
+ // Run the target's get-speech-state script
- uint32 null_pc = 5; // 4th script - get-speech-state
- char *raw_script_ad;
- StandardHeader *head;
int32 target = params[1];
+ char *raw_script_ad = (char *) head;
+ uint32 null_pc = 5;
- // ok, see if the target is busy - we must request this info from the
- // target object
-
- head = (StandardHeader *) _vm->_resman->openResource(target);
- if (head->fileType != GAME_OBJECT)
- error("fnTheyDoWeWait %d not an object", target);
-
- raw_script_ad = (char *) head;
-
- // call the base script - this is the graphic/mouse service call
runScript(raw_script_ad, raw_script_ad, &null_pc);
_vm->_resman->closeResource(target);
- ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]);
+ ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]);
- if (!_scriptVars[INS_COMMAND] && _scriptVars[RESULT] == 1 && ob_logic->looping == 0) {
- // first time so set up targets command if target is waiting
+ if (_scriptVars[RESULT] == 1 && !_scriptVars[INS_COMMAND] && ob_logic->looping == 0) {
+ // The target is waiting, i.e. not busy, and there is no other
+ // command queued. We haven't sent the command yet, so do it.
- debug(5, "fnTheyDoWeWait sending command to %d", target);
+ debug(5, "fnTheyDoWeWait: sending command to %d", target);
+
+ _vm->_debugger->_speechScriptWaiting = target;
+ ob_logic->looping = 1;
_scriptVars[SPEECH_ID] = params[1];
_scriptVars[INS_COMMAND] = params[2];
@@ -384,190 +314,180 @@ int32 Logic::fnTheyDoWeWait(int32 *params) {
_scriptVars[INS4] = params[6];
_scriptVars[INS5] = params[7];
- ob_logic->looping = 1;
-
- // debug flag to indicate who we're waiting for - see debug.cpp
- _speechScriptWaiting = target;
-
- // finish this cycle - but come back again to check for it
- // being finished
return IR_REPEAT;
- } else if (ob_logic->looping == 0) {
- // did not send the command
- // debug flag to indicate who we're waiting for - see debug.cpp
- _speechScriptWaiting = target;
+ }
- // come back next go and try again to send the instruction
+ if (ob_logic->looping == 0) {
+ // The command has not been sent yet. Keep waiting.
+ _vm->_debugger->_speechScriptWaiting = target;
return IR_REPEAT;
}
- // ok, the command has been sent - has the target actually done it yet?
+ if (_scriptVars[RESULT] == 0) {
+ // The command has been sent, and the target is busy doing it.
+ // Wait for it to finish.
- // result is 1 for waiting, 0 for busy
-
- if (_scriptVars[RESULT] == 1) {
- // its waiting now so we can be finished with all this
- debug(5, "fnTheyDoWeWait finished");
+ debug(5, "fnTheyDoWeWait: Waiting for %d to finish", target);
- // not looping anymore
- ob_logic->looping = 0;
-
- // reset debug flag now that we're no longer waiting - see
- // debug.cpp
- _speechScriptWaiting = 0;
- return IR_CONT;
+ _vm->_debugger->_speechScriptWaiting = target;
+ return IR_REPEAT;
}
- debug(5, "fnTheyDoWeWait just waiting");
+ debug(5, "fnTheyDoWeWait: %d finished", target);
- // debug flag to indicate who we're waiting for - see debug.cpp
- _speechScriptWaiting = target;
- return IR_REPEAT;
+ ob_logic->looping = 0;
+ _vm->_debugger->_speechScriptWaiting = 0;
+ return IR_CONT;
}
-int32 Logic::fnWeWait(int32 *params) {
- // loop until the target is free
+/**
+ * Wait for a target to become waiting, i.e. not busy.
+ */
+int32 Logic::fnWeWait(int32 *params) {
// params: 0 target
- uint32 null_pc = 5; // 4th script - get-speech-state
- char *raw_script_ad;
- StandardHeader *head;
- int32 target = params[0];
+ StandardHeader *head = (StandardHeader *) _vm->_resman->openResource(params[0]);
+ assert(head->fileType == GAME_OBJECT);
- // request status of target
- head = (StandardHeader *) _vm->_resman->openResource(target);
- if (head->fileType != GAME_OBJECT)
- error("fnWeWait: %d not an object", target);
+ // Run the target's get-speech-state script
- raw_script_ad = (char *) head;
+ int32 target = params[0];
+ char *raw_script_ad = (char *) head;
+ uint32 null_pc = 5;
- // call the base script - this is the graphic/mouse service call
runScript(raw_script_ad, raw_script_ad, &null_pc);
_vm->_resman->closeResource(target);
- // result is 1 for waiting, 0 for busy
-
- if (_scriptVars[RESULT] == 1) {
- // reset debug flag now that we're no longer waiting - see
- // debug.cpp
- _speechScriptWaiting = 0;
- return IR_CONT;
+ if (_scriptVars[RESULT] == 0) {
+ // The target is busy. Try again.
+ _vm->_debugger->_speechScriptWaiting = target;
+ return IR_REPEAT;
}
- // debug flag to indicate who we're waiting for - see debug.cpp
- _speechScriptWaiting = target;
+ // The target is waiting, i.e. not busy.
- // target is busy so come back again next cycle
- return IR_REPEAT;
+ _vm->_debugger->_speechScriptWaiting = 0;
+ return IR_CONT;
}
-int32 Logic::fnTimedWait(int32 *params) {
- // loop until the target is free but only while the timer is high
- // useful when clicking on a target to talk to them - if they never
- // reply then this'll fall out avoiding a lock up
+/**
+ * Wait for a target to become waiting, i.e. not busy, or until we time out.
+ * This is useful when clicking on a target to talk to it, and it doesn't
+ * reply. This way, we won't lock up.
+ *
+ * If the target becomes waiting, RESULT is set to 0. If we time out, RESULT is
+ * set to 1.
+ */
+int32 Logic::fnTimedWait(int32 *params) {
// params: 0 ob_logic
// 1 target
// 2 number of cycles before give up
- uint32 null_pc = 5; // 4th script - get-speech-state
- char *raw_script_ad;
- ObjectLogic *ob_logic;
- StandardHeader *head;
- int32 target = params[1];
+ StandardHeader *head = (StandardHeader *) _vm->_resman->openResource(params[1]);
+ assert(head->fileType == GAME_OBJECT);
- ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]);
+ ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[0]);
- if (!ob_logic->looping)
- ob_logic->looping = params[2]; // first time in
+ if (!ob_logic->looping) {
+ // This is the first time, so set up the time-out.
+ ob_logic->looping = params[2];
+ }
- // request status of target
- head = (StandardHeader *) _vm->_resman->openResource(target);
- if (head->fileType != GAME_OBJECT)
- error("fnTimedWait %d not an object", target);
+ // Run the target's get-speech-state script
- raw_script_ad = (char *) head;
+ int32 target = params[1];
+ char *raw_script_ad = (char *) head;
+ uint32 null_pc = 5;
- // call the base script - this is the graphic/mouse service call
runScript(raw_script_ad, raw_script_ad, &null_pc);
_vm->_resman->closeResource(target);
- // result is 1 for waiting, 0 for busy
-
if (_scriptVars[RESULT] == 1) {
- // reset because counter is likely to be still high
- ob_logic->looping = 0;
-
- //means ok
- _scriptVars[RESULT] = 0;
+ // The target is waiting, i.e. not busy
- // reset debug flag now that we're no longer waiting - see
- // debug.cpp
- _speechScriptWaiting = 0;
+ _vm->_debugger->_speechScriptWaiting = 0;
+ ob_logic->looping = 0;
+ _scriptVars[RESULT] = 0;
return IR_CONT;
}
ob_logic->looping--;
- if (!ob_logic->looping) { // time up - caller must check RESULT
- // not ok
- _scriptVars[RESULT] = 1;
-
- // clear the event that hasn't been picked up - in theory,
- // none of this should ever happen
- killAllIdsEvents(target);
+ if (!ob_logic->looping) {
+ // Time's up.
- debug(5, "EVENT timed out");
+ debug(5, "fnTimedWait: Timed out waiting for %d", target);
+ _vm->_debugger->_speechScriptWaiting = 0;
- // reset debug flag now that we're no longer waiting - see
- // debug.cpp
- _speechScriptWaiting = 0;
+ // Clear the event that hasn't been picked up - in theory,
+ // none of this should ever happen.
+ killAllIdsEvents(target);
+ _scriptVars[RESULT] = 1;
return IR_CONT;
}
- // debug flag to indicate who we're waiting for - see debug.cpp
- _speechScriptWaiting = target;
+ // Target is busy. Keep trying.
- // target is busy so come back again next cycle
+ _vm->_debugger->_speechScriptWaiting = target;
return IR_REPEAT;
}
-int32 Logic::fnSpeechProcess(int32 *params) {
- // Receive and sequence the commands sent from the conversation
- // script.
-
- // We have to do this in a slightly tweeky manner as we can no longer
- // have generic scripts.
+enum {
+ INS_talk = 1,
+ INS_anim = 2,
+ INS_reverse_anim = 3,
+ INS_walk = 4,
+ INS_turn = 5,
+ INS_face = 6,
+ INS_trace = 7,
+ INS_no_sprite = 8,
+ INS_sort = 9,
+ INS_foreground = 10,
+ INS_background = 11,
+ INS_table_anim = 12,
+ INS_reverse_table_anim = 13,
+ INS_walk_to_anim = 14,
+ INS_set_frame = 15,
+ INS_stand_after_anim = 16,
+ INS_quit = 42
+};
- // This function comes in with all the structures that will be
- // required.
+/**
+ * Receive and sequence the commands sent from the conversation script. We have
+ * to do this in a slightly tweeky manner as we can no longer have generic
+ * scripts.
+ */
+int32 Logic::fnSpeechProcess(int32 *params) {
// params: 0 pointer to ob_graphic
// 1 pointer to ob_speech
// 2 pointer to ob_logic
// 3 pointer to ob_mega
// 4 pointer to ob_walkdata
- // note - we could save a var and ditch wait_state and check
- // 'command' for non zero means busy
-
- ObjectSpeech *ob_speech;
- int32 pars[9];
+ ObjectSpeech *ob_speech = (ObjectSpeech *) _vm->_memory->decodePtr(params[1]);
- ob_speech = (ObjectSpeech *) _vm->_memory->decodePtr(params[1]);
+ while (1) {
+ int32 pars[9];
- debug(5, " SP");
+ // Check which command we're waiting for, and call the
+ // appropriate function. Once we're done, clear the command
+ // and set wait_state to 1.
+ //
+ // Note: we could save a var and ditch wait_state and check
+ // 'command' for non zero means busy
+ //
+ // Note: I can't see that we ever check the value of wait_state
+ // but perhaps it accesses that memory location directly?
- while (1) {
- //we are currently running a command
switch (ob_speech->command) {
case 0:
- // Do nothing
break;
case INS_talk:
pars[0] = params[0]; // ob_graphic
@@ -580,18 +500,8 @@ int32 Logic::fnSpeechProcess(int32 *params) {
pars[7] = ob_speech->ins4; // anim table res id
pars[8] = ob_speech->ins5; // animation mode - 0 lip synced, 1 just straight animation
- debug(5, "speech-process talk");
-
- // run the function - (it thinks it's been called from
- // script - bloody fool)
-
if (fnISpeak(pars) != IR_REPEAT) {
- debug(5, "speech-process talk finished");
-
- // command finished
ob_speech->command = 0;
-
- // waiting for command
ob_speech->wait_state = 1;
}
@@ -604,10 +514,7 @@ int32 Logic::fnSpeechProcess(int32 *params) {
pars[4] = ob_speech->ins1; // direction to turn to
if (fnTurn(pars) != IR_REPEAT) {
- // command finished
ob_speech->command = 0;
-
- // waiting for command
ob_speech->wait_state = 1;
}
@@ -620,10 +527,7 @@ int32 Logic::fnSpeechProcess(int32 *params) {
pars[4] = ob_speech->ins1; // target
if (fnFaceMega(pars) != IR_REPEAT) {
- // command finished
ob_speech->command = 0;
-
- // waiting for command
ob_speech->wait_state = 1;
}
@@ -634,10 +538,7 @@ int32 Logic::fnSpeechProcess(int32 *params) {
pars[2] = ob_speech->ins1; // anim res
if (fnAnim(pars) != IR_REPEAT) {
- // command finished
ob_speech->command = 0;
-
- // waiting for command
ob_speech->wait_state = 1;
}
@@ -648,10 +549,7 @@ int32 Logic::fnSpeechProcess(int32 *params) {
pars[2] = ob_speech->ins1; // anim res
if (fnReverseAnim(pars) != IR_REPEAT) {
- // command finished
ob_speech->command = 0;
-
- // waiting for command
ob_speech->wait_state = 1;
}
@@ -663,10 +561,7 @@ int32 Logic::fnSpeechProcess(int32 *params) {
pars[3] = ob_speech->ins1; // pointer to anim table
if (fnMegaTableAnim(pars) != IR_REPEAT) {
- // command finished
ob_speech->command = 0;
-
- // waiting for command
ob_speech->wait_state = 1;
}
@@ -678,33 +573,34 @@ int32 Logic::fnSpeechProcess(int32 *params) {
pars[3] = ob_speech->ins1; // pointer to anim table
if (fnReverseMegaTableAnim(pars) != IR_REPEAT) {
- // command finished
ob_speech->command = 0;
-
- // waiting for command
ob_speech->wait_state = 1;
}
return IR_REPEAT;
case INS_no_sprite:
fnNoSprite(params); // ob_graphic
- ob_speech->command = 0; // command finished
- ob_speech->wait_state = 1; // waiting for command
+
+ ob_speech->command = 0;
+ ob_speech->wait_state = 1;
return IR_REPEAT ;
case INS_sort:
fnSortSprite(params); // ob_graphic
- ob_speech->command = 0; // command finished
- ob_speech->wait_state = 1; // waiting for command
+
+ ob_speech->command = 0;
+ ob_speech->wait_state = 1;
return IR_REPEAT;
case INS_foreground:
fnForeSprite(params); // ob_graphic
- ob_speech->command = 0; // command finished
- ob_speech->wait_state = 1; // waiting for command
+
+ ob_speech->command = 0;
+ ob_speech->wait_state = 1;
return IR_REPEAT;
case INS_background:
- fnBackSprite(params); // ob_graphic
- ob_speech->command = 0; // command finished
- ob_speech->wait_state = 1; // waiting for command
+ fnBackSprite(pars); // ob_graphic
+
+ ob_speech->command = 0;
+ ob_speech->wait_state = 1;
return IR_REPEAT;
case INS_walk:
pars[0] = params[2]; // ob_logic
@@ -716,12 +612,7 @@ int32 Logic::fnSpeechProcess(int32 *params) {
pars[6] = ob_speech->ins3; // target direction
if (fnWalk(pars) != IR_REPEAT) {
- debug(5, "speech-process walk finished");
-
- // command finished
ob_speech->command = 0;
-
- //waiting for command
ob_speech->wait_state = 1;
}
@@ -734,12 +625,7 @@ int32 Logic::fnSpeechProcess(int32 *params) {
pars[4] = ob_speech->ins1; // anim resource
if (fnWalkToAnim(pars) != IR_REPEAT) {
- debug(5, "speech-process walk finished");
-
- // command finished
ob_speech->command = 0;
-
- // waiting for command
ob_speech->wait_state = 1;
}
@@ -748,37 +634,42 @@ int32 Logic::fnSpeechProcess(int32 *params) {
pars[0] = params[0]; // ob_graphic
pars[1] = params[3]; // ob_mega
pars[2] = ob_speech->ins1; // anim resource
+
fnStandAfterAnim(pars);
- ob_speech->command = 0; // command finished
- ob_speech->wait_state = 1; // waiting for command
+
+ ob_speech->command = 0;
+ ob_speech->wait_state = 1;
return IR_REPEAT;
case INS_set_frame:
pars[0] = params[0]; // ob_graphic
pars[1] = ob_speech->ins1; // anim_resource
pars[2] = ob_speech->ins2; // FIRST_FRAME or LAST_FRAME
fnSetFrame(pars);
- ob_speech->command = 0; // command finished
- ob_speech->wait_state = 1; // waiting for command
+
+ ob_speech->command = 0;
+ ob_speech->wait_state = 1;
return IR_REPEAT;
case INS_quit:
- debug(5, "speech-process - quit");
-
- ob_speech->command = 0; // finish with all this
- // ob_speech->wait_state = 0; // start with waiting for command next conversation
- return IR_CONT; // thats it, we're finished with this
+ // That's it - we're finished with this
+ ob_speech->command = 0;
+ // ob_speech->wait_state = 0;
+ return IR_CONT;
default:
- ob_speech->command = 0; // not yet implemented - just cancel
- ob_speech->wait_state = 1; // waiting for command
+ // Unimplemented command - just cancel
+ ob_speech->command = 0;
+ ob_speech->wait_state = 1;
break;
}
if (_scriptVars[SPEECH_ID] == _scriptVars[ID]) {
- // new command for us!
- // clear this or it could trigger next go
- _scriptVars[SPEECH_ID] = 0;
+ // There's a new command for us! Grab the command -
+ // potentially we only have this cycle to do this - and
+ // set things up so that the command will be picked up
+ // on the next iteration of the while loop.
+
+ debug(5, "fnSpeechProcess: Received new command %d", _scriptVars[INS_COMMAND]);
- // grab the command - potentially, we only have this
- // cycle to do this
+ _scriptVars[SPEECH_ID] = 0;
ob_speech->command = _scriptVars[INS_COMMAND];
ob_speech->ins1 = _scriptVars[INS1];
@@ -786,24 +677,13 @@ int32 Logic::fnSpeechProcess(int32 *params) {
ob_speech->ins3 = _scriptVars[INS3];
ob_speech->ins4 = _scriptVars[INS4];
ob_speech->ins5 = _scriptVars[INS5];
-
- debug(5, "received new command %d", _scriptVars[INS_COMMAND]);
-
- // the current send has been received - i.e. separate
- // multiple they-do's
-
- _scriptVars[INS_COMMAND] = 0;
-
- // now busy
ob_speech->wait_state = 0;
- // we'll drop off and be caught by the while(1), so
- // kicking in the new command straight away
+ _scriptVars[INS_COMMAND] = 0;
} else {
- // no new command
- // we could run a blink anim (or something) here
+ // No new command. We could run a blink anim (or
+ // something) here.
- // now free
ob_speech->wait_state = 1;
return IR_REPEAT;
}
@@ -823,12 +703,14 @@ enum {
S_ANIM_MODE = 8
};
-int32 Logic::fnISpeak(int32 *params) {
- // its the super versatile fnSpeak
- // text and wavs can be selected in any combination
-
- // we can assume no human - there should be no human at least!
+/**
+ * It's the super versatile fnSpeak. Text and wavs can be selected in any
+ * combination.
+ *
+ * @note We can assume no human - there should be no human, at least!
+ */
+int32 Logic::fnISpeak(int32 *params) {
// params: 0 pointer to ob_graphic
// 1 pointer to ob_speech
// 2 pointer to ob_logic
@@ -840,30 +722,13 @@ int32 Logic::fnISpeak(int32 *params) {
// 8 animation mode 0 lip synced,
// 1 just straight animation
- MouseEvent *me;
- AnimHeader *anim_head;
- ObjectLogic *ob_logic;
- ObjectGraphic *ob_graphic;
- ObjectMega *ob_mega;
- byte *anim_file;
- uint32 local_text;
- uint32 text_res;
- byte *text;
- static bool speechRunning;
- int32 *anim_table;
- bool speechFinished = false;
- int8 speech_pan;
- char speechFile[256];
static bool cycle_skip = false;
- uint32 rv;
-
- // for text/speech testing & checking for correct file type
- StandardHeader *head;
+ static bool speechRunning;
- // set up the pointers which we know we'll always need
+ // Set up the pointers which we know we'll always need
- ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[S_OB_LOGIC]);
- ob_graphic = (ObjectGraphic *) _vm->_memory->decodePtr(params[S_OB_GRAPHIC]);
+ ObjectLogic *ob_logic = (ObjectLogic *) _vm->_memory->decodePtr(params[S_OB_LOGIC]);
+ ObjectGraphic *ob_graphic = (ObjectGraphic *) _vm->_memory->decodePtr(params[S_OB_GRAPHIC]);
// FIRST TIME ONLY: create the text, load the wav, set up the anim,
// etc.
@@ -875,27 +740,34 @@ int32 Logic::fnISpeak(int32 *params) {
if (_vm->_sound->getSpeechStatus() != RDSE_SAMPLEFINISHED)
return IR_REPEAT;
- // New fudge for 'fx' subtitles
- // If subtitles switched off, and we don't want to use a wav
- // for this line either, then just quit back to script right
- // now!
+ // New fudge for 'fx' subtitles: If subtitles switched off, and
+ // we don't want to use a wav for this line either, then just
+ // quit back to script right now!
if (!_vm->_gui->_subtitles && !wantSpeechForLine(params[S_WAV]))
return IR_CONT;
- if (!cycle_skip) {
- // drop out for 1st cycle to allow walks/anims to end
- // & display last frame/ before system locks while
- // speech loaded
+ // Drop out for 1st cycle to allow walks/anims to end and
+ // display last frame before system locks while speech loaded
+ if (!cycle_skip) {
cycle_skip = true;
return IR_REPEAT;
- } else
- cycle_skip = false;
+ }
+
+ cycle_skip = false;
+
+ _vm->_debugger->_textNumber = params[S_TEXT];
- _vm->_debugger->_textNumber = params[S_TEXT]; // for debug info
+ // Pull out the text line to get the official text number
+ // (for wav id). Once the wav id's go into all script text
+ // commands, we'll only need this for debugging.
+
+ uint32 text_res = params[S_TEXT] / SIZE;
+ uint32 local_text = params[S_TEXT] & 0xffff;
// For testing all text & speech!
+ //
// A script loop can send any text number to fnISpeak and it
// will only run the valid ones or return with 'result' equal
// to '1' or '2' to mean 'invalid text resource' and 'text
@@ -905,83 +777,57 @@ int32 Logic::fnISpeak(int32 *params) {
// section of linc
if (_scriptVars[SYSTEM_TESTING_TEXT]) {
- _scriptVars[RESULT] = 0;
-
- text_res = params[S_TEXT] / SIZE;
- local_text = params[S_TEXT] & 0xffff;
-
- // if the resource number is within range & it's not
- // a null resource
-
- if (_vm->_resman->checkValid(text_res)) {
- // open the resource
- head = (StandardHeader *) _vm->_resman->openResource(text_res);
+ if (!_vm->_resman->checkValid(text_res)) {
+ // Not a valid resource number - invalid (null
+ // resource)
+ _scriptVars[RESULT] = 1;
+ return IR_CONT;
+ }
- if (head->fileType == TEXT_FILE) {
- // if it's not an animation file
- // if line number is out of range
- if (!_vm->checkTextLine((byte *) head, local_text)) {
- // line number out of range
- _scriptVars[RESULT] = 2;
- }
- } else {
- // invalid (not a text resource)
- _scriptVars[RESULT] = 1;
- }
+ StandardHeader *head = (StandardHeader *) _vm->_resman->openResource(text_res);
- // close the resource
+ if (head->fileType != TEXT_FILE) {
+ // Invalid - not a text resource
_vm->_resman->closeResource(text_res);
-
- if (_scriptVars[RESULT])
- return IR_CONT;
- } else {
- // not a valid resource number - invalid (null
- // resource)
_scriptVars[RESULT] = 1;
return IR_CONT;
}
- }
- // Pull out the text line to get the official text number
- // (for wav id). Once the wav id's go into all script text
- // commands, we'll only need this for _SWORD2_DEBUG
+ if (!_vm->checkTextLine((byte *) head, local_text)) {
+ // Line number out of range
+ _vm->_resman->closeResource(text_res);
+ _scriptVars[RESULT] = 2;
+ return IR_CONT;
+ }
- text_res = params[S_TEXT] / SIZE;
- local_text = params[S_TEXT] & 0xffff;
+ _vm->_resman->closeResource(text_res);
+ _scriptVars[RESULT] = 0;
+ }
- // open text file & get the line
- text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text);
+ byte *text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text);
_officialTextNumber = READ_LE_UINT16(text);
-
- // now ok to close the text file
_vm->_resman->closeResource(text_res);
- // prevent dud lines from appearing while testing text & speech
+ // Prevent dud lines from appearing while testing text & speech
// since these will not occur in the game anyway
- if (_scriptVars[SYSTEM_TESTING_TEXT]) { // if testing text & speech
- // if actor number is 0 and text line is just a 'dash'
+ if (_scriptVars[SYSTEM_TESTING_TEXT]) {
+ // If actor number is 0 and text line is just a 'dash'
// character
if (_officialTextNumber == 0 && text[2] == '-' && text[3] == 0) {
- // dud line - return & continue script
_scriptVars[RESULT] = 3;
return IR_CONT;
}
}
- // set the 'looping_flag' & the text-click-delay
+ // Set the 'looping_flag' and the text-click-delays. We can
+ // left-click past the text after half a second, and
+ // right-click past it after a quarter of a second.
ob_logic->looping = 1;
-
- // can't left-click past the text for the first half second
_leftClickDelay = 6;
-
- // can't right-click past the text for the first quarter second
_rightClickDelay = 3;
- // Write to walkthrough file (zebug0.txt)
- // if (player_id != george), then player is controlling Nico
-
if (_scriptVars[PLAYER_ID] != CUR_PLAYER_ID)
debug(5, "(%d) Nico: %s", _officialTextNumber, text + 2);
else {
@@ -993,115 +839,93 @@ int32 Logic::fnISpeak(int32 *params) {
// Set up the speech animation
if (params[S_ANIM]) {
- // just a straight anim
- _animId = params[S_ANIM];
-
- // anim type
- _speechAnimType = _scriptVars[SPEECHANIMFLAG];
-
- // set the talker's graphic to this speech anim now
- ob_graphic->anim_resource = _animId;
-
- // set to first frame
- ob_graphic->anim_pc = 0;
+ // Just a straight anim.
+ _animId = params[6];
} else if (params[S_DIR_TABLE]) {
- // use this direction table to derive the anim
+ // Use this direction table to derive the anim
// NB. ASSUMES WE HAVE A MEGA OBJECT!!
- ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[S_OB_MEGA]);
+ ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[S_OB_MEGA]);
+ int32 *anim_table = (int32 *) _vm->_memory->decodePtr(params[S_DIR_TABLE]);
- // pointer to anim table
- anim_table = (int32 *) _vm->_memory->decodePtr(params[S_DIR_TABLE]);
-
- // appropriate anim resource is in 'table[direction]'
_animId = anim_table[ob_mega->current_dir];
+ } else {
+ // No animation choosen
+ _animId = 0;
+ }
- // anim type
- _speechAnimType = _scriptVars[SPEECHANIMFLAG];
+ if (_animId) {
+ // Set the talker's graphic to the first frame of this
+ // speech anim for now.
- // set the talker's graphic to this speech anim now
+ _speechAnimType = _scriptVars[SPEECHANIMFLAG];
ob_graphic->anim_resource = _animId;
-
- // set to first frame
ob_graphic->anim_pc = 0;
- } else {
- // no animation choosen
- _animId = 0;
}
// Default back to looped lip synced anims.
_scriptVars[SPEECHANIMFLAG] = 0;
- // set up '_textX' & '_textY' for speech-pan and/or
- // text-sprite position
+ // Set up _textX and _textY for speech panning and/or text
+ // sprite position.
locateTalker(params);
- // is it to be speech or subtitles or both?
+ // Is it to be speech or subtitles or both?
- // assume not running until know otherwise
+ // Assume not running until know otherwise
speechRunning = false;
- // New fudge for 'fx' subtitles
- // if speech is selected, and this line is allowed speech
- // (not if it's an fx subtitle!)
+ // New fudge for 'fx' subtitles: If speech is selected, and
+ // this line is allowed speech (not if it's an fx subtitle!)
if (!_vm->_sound->isSpeechMute() && wantSpeechForLine(_officialTextNumber)) {
- // if the wavId paramter is zero because not yet
+ // If the wavId parameter is zero because not yet
// compiled into speech command, we can still get it
- // from the 1st 2 chars of the text line
+ // from the 1st 2 chars of the text line.
if (!params[S_WAV])
params[S_WAV] = (int32) _officialTextNumber;
-#define SPEECH_VOLUME 16 // 0..16
-#define SPEECH_PAN 0 // -16..16
-
- speech_pan = ((_textX - 320) * 16) / 320;
-
- // '_textX' 'speech_pan'
- // 0 -16
- // 320 0
- // 640 16
+ // Panning goes from -16 (left) to 16 (right)
+ int8 speech_pan = ((_textX - 320) * 16) / 320;
- // keep within limits of -16..16, just in case
if (speech_pan < -16)
speech_pan = -16;
else if (speech_pan > 16)
speech_pan = 16;
- // set up path to speech cluster
- // first checking if we have speech1.clu or
- // speech2.clu in current directory (for translators
- // to test)
-
- File fp;
+ char speechFile[20];
sprintf(speechFile, "speech%d.clu", _vm->_resman->whichCd());
+ File fp;
+
if (fp.open(speechFile))
fp.close();
else
strcpy(speechFile, "speech.clu");
// Load speech but don't start playing yet
- rv = _vm->_sound->playCompSpeech(speechFile, params[S_WAV], SPEECH_VOLUME, speech_pan);
+ uint32 rv = _vm->_sound->playCompSpeech(speechFile, params[S_WAV], 16, speech_pan);
+
if (rv == RD_OK) {
- // ok, we've got something to play
- speechRunning = true;
+ // Ok, we've got something to play. Set it
+ // playing now. (We might want to do this the
+ // next cycle, don't know yet.)
- // set it playing now (we might want to do
- // this next cycle, don't know yet)
+ speechRunning = true;
_vm->_sound->unpauseSpeech();
} else {
debug(5, "ERROR: PlayCompSpeech(speechFile=\"%s\", wav=%d (res=%d pos=%d)) returned %.8x", speechFile, params[S_WAV], text_res, local_text, rv);
}
}
- // if we want subtitles, or speech failed to load
if (_vm->_gui->_subtitles || !speechRunning) {
- // then we're going to show the text
- // so create the text sprite
+ // We want subtitles, or the speech failed to load.
+ // Either way, we're going to show the text so create
+ // the text sprite.
+
formText(params);
}
}
@@ -1109,41 +933,32 @@ int32 Logic::fnISpeak(int32 *params) {
// EVERY TIME: run a cycle of animation, if there is one
if (_animId) {
- // there is an animation
- // increment the anim frame number
+ // There is an animation - Increment the anim frame number.
ob_graphic->anim_pc++;
- // open the anim file
- anim_file = _vm->_resman->openResource(ob_graphic->anim_resource);
- anim_head = _vm->fetchAnimHeader(anim_file);
+ byte *anim_file = _vm->_resman->openResource(ob_graphic->anim_resource);
+ AnimHeader *anim_head = _vm->fetchAnimHeader(anim_file);
if (!_speechAnimType) {
// ANIM IS TO BE LIP-SYNC'ED & REPEATING
- // if finished the anim
+
if (ob_graphic->anim_pc == (int32) (anim_head->noAnimFrames)) {
- // restart from frame 0
+ // End of animation - restart from frame 0
+ ob_graphic->anim_pc = 0;
+ } else if (speechRunning && _vm->_sound->amISpeaking() == RDSE_QUIET) {
+ // The speech is running, but we're at a quiet
+ // bit. Restart from frame 0 (closed mouth).
ob_graphic->anim_pc = 0;
- } else if (speechRunning) {
- // if playing a sample
- if (!_unpauseZone) {
- // if we're at a quiet bit
- if (_vm->_sound->amISpeaking() == RDSE_QUIET) {
- // restart from frame 0
- // ('closed mouth' frame)
- ob_graphic->anim_pc = 0;
- }
- }
}
} else {
// ANIM IS TO PLAY ONCE ONLY
if (ob_graphic->anim_pc == (int32) (anim_head->noAnimFrames) - 1) {
- // reached the last frame of the anim
- // hold anim on this last frame
+ // Reached the last frame of the anim. Hold
+ // anim on this last frame
_animId = 0;
}
}
- // close the anim file
_vm->_resman->closeResource(ob_graphic->anim_resource);
} else if (_speechAnimType) {
// Placed here so we actually display the last frame of the
@@ -1153,19 +968,18 @@ int32 Logic::fnISpeak(int32 *params) {
// EVERY TIME: FIND OUT IF WE NEED TO STOP THE SPEECH NOW...
- // if there is a wav then we're using that to end the speech naturally
+ // If there is a wav then we're using that to end the speech naturally
- // if playing a sample
+ bool speechFinished = false;
+
+ // If playing a sample
if (speechRunning) {
- if (!_unpauseZone) {
- // has it finished?
- if (_vm->_sound->getSpeechStatus() == RDSE_SAMPLEFINISHED)
- speechFinished = true;
- } else
- _unpauseZone--;
+ // Has it finished?
+ if (_vm->_sound->getSpeechStatus() == RDSE_SAMPLEFINISHED)
+ speechFinished = true;
} else if (!speechRunning && _speechTime) {
- // counting down text time because there is no sample - this
+ // Counting down text time because there is no sample - this
// ends the speech
// if no sample then we're using _speechTime to end speech
@@ -1176,21 +990,21 @@ int32 Logic::fnISpeak(int32 *params) {
speechFinished = true;
}
- // ok, all is running along smoothly - but a click means stop
+ // Ok, all is running along smoothly - but a click means stop
// unnaturally
- // so that we can go to the options panel while text & speech is
+ // So that we can go to the options panel while text & speech is
// being tested
if (_scriptVars[SYSTEM_TESTING_TEXT] == 0 || _vm->_input->_mouseY > 0) {
- me = _vm->_input->mouseEvent();
+ MouseEvent *me = _vm->_input->mouseEvent();
// Note that we now have TWO click-delays - one for LEFT
// button, one for RIGHT BUTTON
if ((!_leftClickDelay && me && (me->buttons & RD_LEFTBUTTONDOWN)) ||
(!_rightClickDelay && me && (me->buttons & RD_RIGHTBUTTONDOWN))) {
- // mouse click, after click_delay has expired -> end
- // the speech we ignore mouse releases
+ // Mouse click, after click_delay has expired -> end
+ // the speech. We ignore mouse releases
// if testing text & speech
if (_scriptVars[SYSTEM_TESTING_TEXT]) {
@@ -1210,30 +1024,26 @@ int32 Logic::fnISpeak(int32 *params) {
speechFinished = true;
- // if speech sample playing
- if (speechRunning) {
- // halt the sample prematurely
+ // if speech sample playing, halt it prematurely
+ if (speechRunning)
_vm->_sound->stopSpeech();
- }
}
}
- // if we are finishing the speech this cycle, do the business
+ // If we are finishing the speech this cycle, do the business
// !speechAnimType, as we want an anim which is playing once to have
// finished.
if (speechFinished && !_speechAnimType) {
- // if there is text
+ // If there is text, kill it
if (_speechTextBlocNo) {
- // kill the text block
_vm->_fontRenderer->killTextBloc(_speechTextBlocNo);
_speechTextBlocNo = 0;
}
- // if there is a speech anim
+ // if there is a speech anim, end it on closed mouth frame
if (_animId) {
- // end it on 1st frame (closed mouth)
_animId = 0;
ob_graphic->anim_pc = 0;
}
@@ -1243,22 +1053,19 @@ int32 Logic::fnISpeak(int32 *params) {
// no longer in a script function loop
ob_logic->looping = 0;
- // reset for debug info
_vm->_debugger->_textNumber = 0;
// reset to zero, in case text line not even extracted (since
// this number comes from the text line)
_officialTextNumber = 0;
- _scriptVars[RESULT] = 0; // ok
+ _scriptVars[RESULT] = 0;
return IR_CONT;
}
- // speech still going, so decrement the click_delay if it's still
+ // Speech still going, so decrement the click_delay if it's still
// active
- // count down to clickability
-
if (_leftClickDelay)
_leftClickDelay--;
@@ -1268,12 +1075,15 @@ int32 Logic::fnISpeak(int32 *params) {
return IR_REPEAT;
}
-#define GAP_ABOVE_HEAD 20 // distance kept above talking sprite
+// Distance kept above talking sprite
+#define GAP_ABOVE_HEAD 20
-void Logic::locateTalker(int32 *params) {
- // sets '_textX' & '_textY' for position of text sprite
- // but '_textX' also used to calculate speech-pan
+/**
+ * Sets _textX and _textY for position of text sprite. Note that _textX is
+ * also used to calculate speech pan.
+ */
+void Logic::locateTalker(int32 *params) {
// params: 0 pointer to ob_graphic
// 1 pointer to ob_speech
// 2 pointer to ob_logic
@@ -1285,91 +1095,76 @@ void Logic::locateTalker(int32 *params) {
// 8 animation mode 0 lip synced,
// 1 just straight animation
- ObjectMega *ob_mega;
-
- byte *file;
- FrameHeader *frame_head;
- AnimHeader *anim_head;
- CdtEntry *cdt_entry;
- uint16 scale;
+ if (!_animId) {
+ // There is no animation. Assume it's voice-over text, and put
+ // it at the bottom of the screen.
- // if there's no anim
- if (_animId == 0) {
- // assume it's Voice-Over text, so it goes at bottom of screen
_textX = 320;
_textY = 400;
- } else {
- // Note: this code has been adapted from Register_frame() in
- // build_display.cpp
+ return;
+ }
- // open animation file & set up the necessary pointers
- file = _vm->_resman->openResource(_animId);
+ byte *file = _vm->_resman->openResource(_animId);
- anim_head = _vm->fetchAnimHeader(file);
+ // '0' means 1st frame
- // '0' means 1st frame
- cdt_entry = _vm->fetchCdtEntry(file, 0);
+ CdtEntry *cdt_entry = _vm->fetchCdtEntry(file, 0);
+ FrameHeader *frame_head = _vm->fetchFrameHeader(file, 0);
- // '0' means 1st frame
- frame_head = _vm->fetchFrameHeader(file, 0);
+ // Note: This part of the code is quite similar to registerFrame().
- // check if this frame has offsets ie. this is a scalable
- // mega frame
+ if (cdt_entry->frameType & FRAME_OFFSET) {
+ // The frame has offsets, i.e. it's a scalable mega frame
+ ObjectMega *ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[S_OB_MEGA]);
- if (cdt_entry->frameType & FRAME_OFFSET) {
- // this may be NULL
- ob_mega = (ObjectMega *) _vm->_memory->decodePtr(params[S_OB_MEGA]);
+ // Calculate scale at which to print the sprite, based on feet
+ // y-coord and scaling constants (NB. 'scale' is actually
+ // 256 * true_scale, to maintain accuracy)
- // calc scale at which to print the sprite, based on
- // feet y-coord & scaling constants (NB. 'scale' is
- // actually 256 * true_scale, to maintain accuracy)
+ // Ay+B gives 256 * scale ie. 256 * 256 * true_scale for even
+ // better accuracy, ie. scale = (Ay + B) / 256
- // Ay+B gives 256 * scale ie. 256 * 256 * true_scale
- // for even better accuracy, ie. scale = (Ay + B) / 256
- scale = (uint16) ((ob_mega->scale_a * ob_mega->feet_y + ob_mega->scale_b) / 256);
+ uint16 scale = (uint16) ((ob_mega->scale_a * ob_mega->feet_y + ob_mega->scale_b) / 256);
- // calc suitable centre point above the head, based on
- // scaled height
+ // Calc suitable centre point above the head, based on scaled
+ // height
- // just use 'feet_x' as centre
- _textX = (int16) (ob_mega->feet_x);
+ // just use 'feet_x' as centre
+ _textX = (int16) ob_mega->feet_x;
- // add scaled y-offset to feet_y coord to get top of
- // sprite
- _textY = (int16) (ob_mega->feet_y + (cdt_entry->y * scale) / 256);
- } else {
- // it's a non-scaling anim - calc suitable centre
- // point above the head, based on scaled width
+ // Add scaled y-offset to feet_y coord to get top of sprite
+ _textY = (int16) (ob_mega->feet_y + (cdt_entry->y * scale) / 256);
+ } else {
+ // It's a non-scaling anim - calc suitable centre point above
+ // the head, based on scaled width
- // x-coord + half of width
- _textX = cdt_entry->x + (frame_head->width) / 2;
- _textY = cdt_entry->y;
- }
+ // x-coord + half of width
+ _textX = cdt_entry->x + (frame_head->width) / 2;
+ _textY = cdt_entry->y;
+ }
- // leave space above their head
- _textY -= GAP_ABOVE_HEAD;
-
- // adjust the text coords for RDSPR_DISPLAYALIGN
+ _vm->_resman->closeResource(_animId);
- _textX -= _vm->_thisScreen.scroll_offset_x;
- _textY -= _vm->_thisScreen.scroll_offset_y;
+ // Leave space above their head
+ _textY -= GAP_ABOVE_HEAD;
+
+ // Adjust the text coords for RDSPR_DISPLAYALIGN
- // release the anim resource
- _vm->_resman->closeResource(_animId);
- }
+ _textX -= _vm->_thisScreen.scroll_offset_x;
+ _textY -= _vm->_thisScreen.scroll_offset_y;
}
-void Logic::formText(int32 *params) {
- // its the first time in so we build the text block if we need one
- // we also bring in the wav if there is one
- // also setup the animation if there is one
-
- // anim is optional - anim can be a repeating lip-sync or a run-once
- // anim
-
- // if there is no wav then the text comes up instead
- // there can be any combination of text/wav playing
+/**
+ * This function is called the first time to build the text, if we need one. If
+ * If necessary it also brings in the wav and sets up the animation.
+ *
+ * If there is an animation it can be repeating lip-sync or run-once.
+ *
+ * If there is no wav, then the text comes up instead. There can be any
+ * combination of text/wav playing.
+ */
+void Logic::formText(int32 *params) {
// params 0 pointer to ob_graphic
// 1 pointer to ob_speech
// 2 pointer to ob_logic
@@ -1381,62 +1176,44 @@ void Logic::formText(int32 *params) {
// 8 animation mode 0 lip synced,
// 1 just straight animation
- uint32 local_text;
- uint32 text_res;
- byte *text;
- uint32 textWidth;
- ObjectSpeech *ob_speech;
+ // There should always be a text line, as all text is derived from it.
+ // If there is none, that's bad...
- // should always be a text line, as all text is derived from line of
- // text
-
- if (params[S_TEXT]) {
- ob_speech = (ObjectSpeech *) _vm->_memory->decodePtr(params[S_OB_SPEECH]);
-
- // establish the max width allowed for this text sprite
-
- // if a specific width has been set up for this character,
- // then override the default
+ if (!params[S_TEXT]) {
+ warning("No text line for speech wav %d", params[S_WAV]);
+ return;
+ }
- if (ob_speech->width)
- textWidth = ob_speech->width;
- else
- textWidth = 400;
+ ObjectSpeech *ob_speech = (ObjectSpeech *) _vm->_memory->decodePtr(params[S_OB_SPEECH]);
- // pull out the text line & make the sprite & text block
+ // Establish the max width allowed for this text sprite.
+ uint32 textWidth = ob_speech->width ? ob_speech->width : 400;
- text_res = params[S_TEXT] / SIZE;
- local_text = params[S_TEXT] & 0xffff;
+ // Pull out the text line, and make the sprite and text block
- // open text file & get the line
- text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text);
+ uint32 text_res = params[S_TEXT] / SIZE;
+ uint32 local_text = params[S_TEXT] & 0xffff;
+ byte *text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text);
- // 'text + 2' to skip the first 2 bytes which form the line
- // reference number
+ // 'text + 2' to skip the first 2 bytes which form the line reference
+ // number
- _speechTextBlocNo = _vm->_fontRenderer->buildNewBloc(
- text + 2, _textX, _textY,
- textWidth, ob_speech->pen,
- RDSPR_TRANS | RDSPR_DISPLAYALIGN,
- _vm->_speechFontId, POSITION_AT_CENTRE_OF_BASE);
+ _speechTextBlocNo = _vm->_fontRenderer->buildNewBloc(
+ text + 2, _textX, _textY,
+ textWidth, ob_speech->pen,
+ RDSPR_TRANS | RDSPR_DISPLAYALIGN,
+ _vm->_speechFontId, POSITION_AT_CENTRE_OF_BASE);
- // now ok to close the text file
- _vm->_resman->closeResource(text_res);
+ _vm->_resman->closeResource(text_res);
- // set speech duration, in case not using wav
- // no. of cycles = (no. of chars) + 30
-
- _speechTime = strlen((char *) text) + 30;
- } else {
- // no text line passed? - this is bad
- debug(5, "no text line for speech wav %d", params[S_WAV]);
- }
+ // Set speech duration, in case not using a wav.
+ _speechTime = strlen((char *) text) + 30;
}
-// For preventing sfx subtitles from trying to load speech samples
-// - since the sfx are implemented as normal sfx, so we don't want them as
-// speech samples too
-// - and we only want the subtitles if selected, not if samples can't be found!
+/**
+ * There are some hard-coded cases where speech is used to illustrate a sound
+ * effect. In this case there is no sound associated with the speech itself.
+ */
bool Logic::wantSpeechForLine(uint32 wavId) {
switch (wavId) {
@@ -1464,13 +1241,13 @@ bool Logic::wantSpeechForLine(uint32 wavId) {
case 528: // PresidentaSpeech
// SFX (528);
// FX <Nearby Crash of Collapsing Masonry>
- case 920: // location 62
- case 923: // location 62
- case 926: // location 62
- // don't want speech for these lines!
+ case 920: // Zombie Island forest maze (bird)
+ case 923: // Zombie Island forest maze (monkey)
+ case 926: // Zombie Island forest maze (zombie)
+ // Don't want speech for these lines!
return false;
default:
- // ok for all other lines
+ // Ok for all other lines
return true;
}
}
diff --git a/sword2/sword2.cpp b/sword2/sword2.cpp
index 22ea9dd6c6..c44697457f 100644
--- a/sword2/sword2.cpp
+++ b/sword2/sword2.cpp
@@ -529,7 +529,6 @@ void Sword2Engine::unpauseGame(void) {
}
_gamePaused = false;
- _logic->_unpauseZone = 2;
// if mouse is about or we're in a chooser menu
if (!_mouseStatus || _logic->_choosing)