From 5553ef53f191ae190fcd6c35c430e61d665bae44 Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Sun, 24 Apr 2005 12:13:03 +0000 Subject: Moved conversation stuff from Logic to Mouse. svn-id: r17787 --- sword2/function.cpp | 126 +++------------------------------------------------- sword2/icons.cpp | 21 +++++++++ sword2/logic.cpp | 4 +- sword2/logic.h | 20 --------- sword2/mouse.cpp | 121 +++++++++++++++++++++++++++++++++++++++++++++++-- sword2/mouse.h | 25 +++++++++++ sword2/speech.h | 29 ------------ sword2/sword2.cpp | 4 +- 8 files changed, 172 insertions(+), 178 deletions(-) delete mode 100644 sword2/speech.h (limited to 'sword2') diff --git a/sword2/function.cpp b/sword2/function.cpp index a80ffa7f0b..37affd9923 100644 --- a/sword2/function.cpp +++ b/sword2/function.cpp @@ -146,26 +146,7 @@ int32 Logic::fnPreLoad(int32 *params) { 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. - _defaultResponseId = 0; - } - - 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. - - _defaultResponseId = params[1]; - } 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]; - _scriptVars[IN_SUBJECT]++; - } - + _vm->_mouse->addSubject(params[0], params[1]); return IR_CONT; } @@ -194,109 +175,12 @@ int32 Logic::fnChoose(int32 *params) { // 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. - uint i; - - _scriptVars[AUTO_SELECTED] = 0; - - if (_scriptVars[OBJECT_HELD]) { - // 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. - - uint32 response = _defaultResponseId; - - for (i = 0; i < _scriptVars[IN_SUBJECT]; i++) { - if (_subjectList[i].res == _scriptVars[OBJECT_HELD]) { - response = _subjectList[i].ref; - break; - } - } - - // 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); - } - - if (_scriptVars[CHOOSER_COUNT_FLAG] == 0 && _scriptVars[IN_SUBJECT] == 1 && _subjectList[0].res == EXIT_ICON) { - // 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. - - // 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) { - // This is a new conversation menu. + uint32 response = _vm->_mouse->chooseMouse(); - if (!_scriptVars[IN_SUBJECT]) - error("fnChoose with no subjects"); - - for (i = 0; i < _scriptVars[IN_SUBJECT]; i++) { - icon = _vm->_resman->openResource(_subjectList[i].res) + sizeof(StandardHeader) + RDMENU_ICONWIDE * RDMENU_ICONDEEP; - _vm->_mouse->setMenuIcon(RDMENU_BOTTOM, i, icon); - _vm->_resman->closeResource(_subjectList[i].res); - } - - for (; i < 15; i++) - _vm->_mouse->setMenuIcon(RDMENU_BOTTOM, (uint8) i, NULL); - - _vm->_mouse->showMenu(RDMENU_BOTTOM); - _vm->_mouse->setMouse(NORMAL_MOUSE_ID); - _choosing = true; - return IR_REPEAT; - } - - // The menu is there - we're just waiting for a click. We only care - // about left clicks. - - MouseEvent *me = _vm->mouseEvent(); - int mouseX, mouseY; - - _vm->_mouse->getPos(mouseX, mouseY); - - if (!me || !(me->buttons & RD_LEFTBUTTONDOWN) || mouseY < 400) - return IR_REPEAT; - - // Check for click on a menu. - - int hit = _vm->_mouse->menuClick(_scriptVars[IN_SUBJECT]); - if (hit < 0) + if (response == (uint32) -1) return IR_REPEAT; - // Hilight the clicked icon by greying the others. - - for (i = 0; i < _scriptVars[IN_SUBJECT]; i++) { - if ((int) i != hit) { - icon = _vm->_resman->openResource(_subjectList[i].res) + sizeof(StandardHeader); - _vm->_mouse->setMenuIcon(RDMENU_BOTTOM, i, icon); - _vm->_resman->closeResource(_subjectList[i].res); - } - } - - // For non-speech scripts that manually call the chooser - _scriptVars[RESULT] = _subjectList[hit].res; - - // The conversation menu will be closed - - _choosing = false; - _scriptVars[IN_SUBJECT] = 0; - _vm->_mouse->setMouse(0); - - return IR_CONT | (_subjectList[hit].ref << 3); + return IR_CONT | (response << 3); } /** @@ -3255,7 +3139,7 @@ int32 Logic::fnPlayCredits(int32 *params) { screenInfo->new_palette = 99; - if (!_vm->_mouse->getMouseStatus() || _choosing) + if (!_vm->_mouse->getMouseStatus() || _vm->_mouse->isChoosing()) _vm->_mouse->setMouse(NORMAL_MOUSE_ID); if (_scriptVars[DEAD]) diff --git a/sword2/icons.cpp b/sword2/icons.cpp index ab28e94efd..399d40c903 100644 --- a/sword2/icons.cpp +++ b/sword2/icons.cpp @@ -33,6 +33,27 @@ void Mouse::addMenuObject(MenuObject *obj) { _totalTemp++; } +void Mouse::addSubject(int32 id, int32 ref) { + if (Logic::_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. + _defaultResponseId = 0; + } + + if (id == -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(). + + _defaultResponseId = ref; + } else { + debug(5, "fnAddSubject res %d, uid %d", id, ref); + _subjectList[Logic::_scriptVars[IN_SUBJECT]].res = id; + _subjectList[Logic::_scriptVars[IN_SUBJECT]].ref = ref; + Logic::_scriptVars[IN_SUBJECT]++; + } +} + /** * Create and start the inventory (bottom) menu */ diff --git a/sword2/logic.cpp b/sword2/logic.cpp index 5922d92830..c286b2f9b7 100644 --- a/sword2/logic.cpp +++ b/sword2/logic.cpp @@ -34,11 +34,9 @@ Logic::Logic(Sword2Engine *vm) : _vm(vm), _kills(0), _currentRunList(0), _smackerLeadIn(0), _smackerLeadOut(0), _sequenceTextLines(0), _speechTime(0), _animId(0), _speechAnimType(0), _leftClickDelay(0), _rightClickDelay(0), - _defaultResponseId(0), _officialTextNumber(0), _speechTextBlocNo(0), - _choosing(false) { + _officialTextNumber(0), _speechTextBlocNo(0) { _scriptVars = NULL; - memset(_subjectList, 0, sizeof(_subjectList)); memset(_eventList, 0, sizeof(_eventList)); memset(_syncList, 0, sizeof(_syncList)); _router = new Router(_vm); diff --git a/sword2/logic.h b/sword2/logic.h index a23aa10a9e..426c2a2745 100644 --- a/sword2/logic.h +++ b/sword2/logic.h @@ -23,8 +23,6 @@ #ifndef _LOGIC #define _LOGIC -#include "sword2/speech.h" - namespace Sword2 { struct MovieTextObject; @@ -98,15 +96,6 @@ private: void createSequenceSpeech(MovieTextObject *sequenceText[]); void clearSequenceSpeech(MovieTextObject *sequenceText[]); - // array of these for subject menu build up - - struct SubjectUnit { - uint32 res; - uint32 ref; - }; - - SubjectUnit _subjectList[MAX_SUBJECT_LIST]; - // when not playing a wav we calculate the speech time based upon // length of ascii @@ -120,12 +109,6 @@ private: uint32 _leftClickDelay; // click-delay for LEFT mouse button uint32 _rightClickDelay; // click-delay for RIGHT mouse button - // ref number for default response when luggage icon is used on a - // person & it doesn't match any of the icons which would have been in - // the chooser - - uint32 _defaultResponseId; - // calculated by locateTalker() for use in speech-panning & text-sprite // positioning @@ -161,9 +144,6 @@ public: // so speech text cleared when running a new start-script uint32 _speechTextBlocNo; - // could alternately use logic->looping of course - bool _choosing; - int runScript(char *scriptData, char *objectData, uint32 *offset); void sendEvent(uint32 id, uint32 interact_id); diff --git a/sword2/mouse.cpp b/sword2/mouse.cpp index 98d09635cb..176ae7579a 100644 --- a/sword2/mouse.cpp +++ b/sword2/mouse.cpp @@ -85,6 +85,10 @@ Mouse::Mouse(Sword2Engine *vm) { _totalMasters = 0; memset(_masterMenuList, 0, sizeof(_masterMenuList)); memset(_mouseList, 0, sizeof(_mouseList)); + memset(_subjectList, 0, sizeof(_subjectList)); + + _defaultResponseId = 0; + _choosing = false; _iconCount = 0; @@ -253,7 +257,7 @@ int Mouse::menuClick(int menu_items) { return (_pos.x - RDMENU_ICONSTART) / (RDMENU_ICONWIDE + RDMENU_ICONSPACING); } -void Mouse::systemMenuMouse(void) { +void Mouse::systemMenuMouse() { uint32 safe_looping_music_id; MouseEvent *me; int hit; @@ -400,7 +404,7 @@ void Mouse::systemMenuMouse(void) { _vm->_logic->fnStopMusic(NULL); } -void Mouse::dragMouse(void) { +void Mouse::dragMouse() { byte buf1[NAME_LEN], buf2[NAME_LEN]; MouseEvent *me; int hit; @@ -602,7 +606,7 @@ void Mouse::menuMouse() { } } -void Mouse::normalMouse(void) { +void Mouse::normalMouse() { // The gane is playing and none of the menus are activated - but, we // need to check if a menu is to start. Note, won't have luggage @@ -821,6 +825,117 @@ void Mouse::normalMouse(void) { } } +uint32 Mouse::chooseMouse() { + // Unlike the other mouse "engines", this one is called directly by the + // fnChoose() opcode. + + uint i; + + Logic::_scriptVars[AUTO_SELECTED] = 0; + + if (Logic::_scriptVars[OBJECT_HELD]) { + // 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. + + uint32 response = _defaultResponseId; + + for (i = 0; i < Logic::_scriptVars[IN_SUBJECT]; i++) { + if (_subjectList[i].res == Logic::_scriptVars[OBJECT_HELD]) { + response = _subjectList[i].ref; + break; + } + } + + // The user won't be holding the object any more, and the + // conversation menu will be closed. + + Logic::_scriptVars[OBJECT_HELD] = 0; + Logic::_scriptVars[IN_SUBJECT] = 0; + return response; + } + + if (Logic::_scriptVars[CHOOSER_COUNT_FLAG] == 0 && Logic::_scriptVars[IN_SUBJECT] == 1 && _subjectList[0].res == EXIT_ICON) { + // 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. + + // The conversation menu will be closed. We set AUTO_SELECTED + // because the speech script depends on it. + + Logic::_scriptVars[AUTO_SELECTED] = 1; + Logic::_scriptVars[IN_SUBJECT] = 0; + return _subjectList[0].ref; + } + + byte *icon; + + if (!_choosing) { + // This is a new conversation menu. + + if (!Logic::_scriptVars[IN_SUBJECT]) + error("fnChoose with no subjects"); + + for (i = 0; i < Logic::_scriptVars[IN_SUBJECT]; i++) { + icon = _vm->_resman->openResource(_subjectList[i].res) + sizeof(StandardHeader) + RDMENU_ICONWIDE * RDMENU_ICONDEEP; + setMenuIcon(RDMENU_BOTTOM, i, icon); + _vm->_resman->closeResource(_subjectList[i].res); + } + + for (; i < 15; i++) + setMenuIcon(RDMENU_BOTTOM, (uint8) i, NULL); + + showMenu(RDMENU_BOTTOM); + setMouse(NORMAL_MOUSE_ID); + _choosing = true; + return (uint32) -1; + } + + // The menu is there - we're just waiting for a click. We only care + // about left clicks. + + MouseEvent *me = _vm->mouseEvent(); + int mouseX, mouseY; + + getPos(mouseX, mouseY); + + if (!me || !(me->buttons & RD_LEFTBUTTONDOWN) || mouseY < 400) + return (uint32) -1; + + // Check for click on a menu. + + int hit = _vm->_mouse->menuClick(Logic::_scriptVars[IN_SUBJECT]); + if (hit < 0) + return (uint32) -1; + + // Hilight the clicked icon by greying the others. This can look a bit + // odd when you click on the exit icon, but there are also cases when + // it looks strange if you don't do it. + + for (i = 0; i < Logic::_scriptVars[IN_SUBJECT]; i++) { + if ((int) i != hit) { + icon = _vm->_resman->openResource(_subjectList[i].res) + sizeof(StandardHeader); + _vm->_mouse->setMenuIcon(RDMENU_BOTTOM, i, icon); + _vm->_resman->closeResource(_subjectList[i].res); + } + } + + // For non-speech scripts that manually call the chooser + Logic::_scriptVars[RESULT] = _subjectList[hit].res; + + // The conversation menu will be closed + + _choosing = false; + Logic::_scriptVars[IN_SUBJECT] = 0; + setMouse(0); + + return _subjectList[hit].ref; +} + void Mouse::mouseOnOff() { // this handles the cursor graphic when moving on and off mouse areas // it also handles the luggage thingy diff --git a/sword2/mouse.h b/sword2/mouse.h index 54ead36198..d2fc2bdb03 100644 --- a/sword2/mouse.h +++ b/sword2/mouse.h @@ -21,6 +21,8 @@ #ifndef MOUSE_H #define MOUSE_H +#define MAX_SUBJECT_LIST 30 // is that enough? + #define TOTAL_mouse_list 50 namespace Sword2 { @@ -99,6 +101,13 @@ struct MouseUnit { int32 pointer_text; }; +// Array of these for subject menu build up + + struct SubjectUnit { + uint32 res; + uint32 ref; +}; + class Mouse { private: Sword2Engine *_vm; @@ -114,6 +123,17 @@ private: MenuObject _masterMenuList[TOTAL_engine_pockets]; uint32 _totalMasters; + SubjectUnit _subjectList[MAX_SUBJECT_LIST]; + + // ref number for default response when luggage icon is used on a + // person & it doesn't match any of the icons which would have been in + // the chooser + + uint32 _defaultResponseId; + + // could alternately use logic->looping of course + bool _choosing; + uint8 _menuStatus[2]; byte *_icons[2][RDMENU_MAXPOCKETS]; uint8 _pocketStatus[2][RDMENU_MAXPOCKETS]; @@ -200,6 +220,8 @@ public: void processMenu(); void addMenuObject(MenuObject *obj); + void addSubject(int32 id, int32 ref); + void buildMenu(); void buildSystemMenu(); @@ -231,6 +253,9 @@ public: void dragMouse(); void systemMenuMouse(); + bool isChoosing() { return _choosing; } + uint32 chooseMouse(); + int menuClick(int menu_items); }; diff --git a/sword2/speech.h b/sword2/speech.h deleted file mode 100644 index 49ae49f3f9..0000000000 --- a/sword2/speech.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2005 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 _SPEECH -#define _SPEECH - -#define MAX_SUBJECT_LIST 30 // is that enough? - -namespace Sword2 { -} // End of namespace Sword2 - -#endif diff --git a/sword2/sword2.cpp b/sword2/sword2.cpp index 2603f09bfb..20b75998a8 100644 --- a/sword2/sword2.cpp +++ b/sword2/sword2.cpp @@ -331,7 +331,7 @@ int Sword2Engine::go() { pauseGame(); break; case 'c': - if (!Logic::_scriptVars[DEMO] && !_logic->_choosing) + if (!Logic::_scriptVars[DEMO] && !_mouse->isChoosing()) _logic->fnPlayCredits(NULL); break; #ifdef SWORD2_DEBUG @@ -658,7 +658,7 @@ void Sword2Engine::unpauseGame() { _gamePaused = false; // If mouse is about or we're in a chooser menu - if (!_mouse->getMouseStatus() || _logic->_choosing) + if (!_mouse->getMouseStatus() || _mouse->isChoosing()) _mouse->setMouse(NORMAL_MOUSE_ID); } -- cgit v1.2.3