diff options
author | johndoe123 | 2014-04-11 09:40:54 +0200 |
---|---|---|
committer | Eugene Sandulenko | 2018-07-20 06:43:33 +0000 |
commit | 2e149cf651ee9344ee96ea904c5dce5a444aeaff (patch) | |
tree | 5fb2c760d303a4db0856cbc4de7c94609d8b4238 /engines | |
parent | 67366aa04b723fadec300cc6ce1d5c6ee9241af7 (diff) | |
download | scummvm-rg350-2e149cf651ee9344ee96ea904c5dce5a444aeaff.tar.gz scummvm-rg350-2e149cf651ee9344ee96ea904c5dce5a444aeaff.tar.bz2 scummvm-rg350-2e149cf651ee9344ee96ea904c5dce5a444aeaff.zip |
ILLUSIONS: More work on Duckman
- Implement Duckman cursor and interaction handling
- Add more script opcodes
- Add TextDrawer and ScreenText (needs minor refactoring for BBDOU)
Diffstat (limited to 'engines')
32 files changed, 1575 insertions, 166 deletions
diff --git a/engines/illusions/actor.cpp b/engines/illusions/actor.cpp index bfb6fe2da2..f3677e4726 100644 --- a/engines/illusions/actor.cpp +++ b/engines/illusions/actor.cpp @@ -253,32 +253,49 @@ void Control::unpause() { } void Control::appearActor() { - if (_objectId == 0x40004) { - _vm->showCursor(); - } else { - if (_actor->_frameIndex || _actorTypeId == 0x50004) - _actor->_flags |= 1; - else - _actor->_flags |= 0x1000; - for (uint i = 0; i < kSubObjectsCount; ++i) - if (_actor->_subobjects[i]) { - Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]); - subControl->appearActor(); + if (_vm->getGameId() == kGameIdDuckman) { + _flags |= 1; + _actor->_flags |= 1; + if (_objectId == 0x40004) { + if (_actor->_frameIndex) { + _actor->_flags |= 0x2000; + _actor->_flags |= 0x4000; } + _vm->_input->discardButtons(0xFFFF); + } + } else { + if (_objectId == 0x40004) { + _vm->showCursor(); + } else { + if (_actor->_frameIndex || _actorTypeId == 0x50004) + _actor->_flags |= 1; + else + _actor->_flags |= 0x1000; + for (uint i = 0; i < kSubObjectsCount; ++i) + if (_actor->_subobjects[i]) { + Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]); + subControl->appearActor(); + } + } } } void Control::disappearActor() { - if (_objectId == 0x40004) { - _vm->hideCursor(); - } else { + if (_vm->getGameId() == kGameIdDuckman) { + _flags &= ~1; _actor->_flags &= ~1; - _actor->_flags &= ~0x1000; - for (uint i = 0; i < kSubObjectsCount; ++i) - if (_actor->_subobjects[i]) { - Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]); - subControl->disappearActor(); - } + } else { + if (_objectId == 0x40004) { + _vm->hideCursor(); + } else { + _actor->_flags &= ~1; + _actor->_flags &= ~0x1000; + for (uint i = 0; i < kSubObjectsCount; ++i) + if (_actor->_subobjects[i]) { + Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]); + subControl->disappearActor(); + } + } } } @@ -925,7 +942,7 @@ void Control::startSequenceActorIntern(uint32 sequenceId, int value, byte *entry _actor->_seqCodeValue3 = 0; _actor->_seqCodeValue1 = 0; - if (_vm->getGameId() == kGameIdBBDOU) { + if (_vm->getGameId() == kGameIdBBDOU) { _actor->_seqCodeValue2 = value == 1 ? 350 : 600; } else if (_vm->getGameId() == kGameIdDuckman) { _actor->_seqCodeValue2 = value == 1 ? 350 : 750; diff --git a/engines/illusions/backgroundresource.cpp b/engines/illusions/backgroundresource.cpp index a4111c7893..2841971d89 100644 --- a/engines/illusions/backgroundresource.cpp +++ b/engines/illusions/backgroundresource.cpp @@ -69,7 +69,7 @@ void BackgroundResourceLoader::unload(Resource *resource) { // TODO Remove IDs from item48s delete backgroundItem->_bgRes; _vm->_backgroundItems->freeBackgroundItem(backgroundItem); - // TODO _vm->setDefPointDimensions1(); + _vm->setDefaultTextCoords(); debug("BackgroundResourceLoader::unload() Unloading background %08X OK", resource->_resId); } @@ -378,7 +378,7 @@ void BackgroundItem::pause() { for (uint i = 0; i < _bgRes->_item48sCount; ++i) krndictRemoveID(_bgRes->_item48s[i].id); */ - // TODO _vm->setDefPointDimensions1(); + _vm->setDefaultTextCoords(); _vm->_camera->getActiveState(_savedCameraState); _savedPalette = new byte[1024]; _vm->_screen->getPalette(_savedPalette); diff --git a/engines/illusions/camera.cpp b/engines/illusions/camera.cpp index 57d6f6fc51..b9d934284f 100644 --- a/engines/illusions/camera.cpp +++ b/engines/illusions/camera.cpp @@ -279,7 +279,7 @@ void Camera::update(uint32 currTime) { } -void Camera::setBounds(Common::Point &minPt, Common::Point &maxPt) { +void Camera::setBounds(Common::Point minPt, Common::Point maxPt) { _activeState._bounds._topLeft = minPt; _activeState._bounds._bottomRight = maxPt; } diff --git a/engines/illusions/camera.h b/engines/illusions/camera.h index a6f8a7333f..9fa12c4ebc 100644 --- a/engines/illusions/camera.h +++ b/engines/illusions/camera.h @@ -77,7 +77,7 @@ public: void popCameraMode(); void clearCameraModeStack(); void update(uint32 currTime); - void setBounds(Common::Point &minPt, Common::Point &maxPt); + void setBounds(Common::Point minPt, Common::Point maxPt); void setBoundsToDimensions(WidthHeight &dimensions); Common::Point getCurrentPan(); Common::Point getScreenOffset(); diff --git a/engines/illusions/causethread_duckman.cpp b/engines/illusions/causethread_duckman.cpp new file mode 100644 index 0000000000..a10b03f546 --- /dev/null +++ b/engines/illusions/causethread_duckman.cpp @@ -0,0 +1,58 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "illusions/illusions_duckman.h" +#include "illusions/causethread_duckman.h" +#include "illusions/actor.h" +#include "illusions/input.h" + +namespace Illusions { + +// TalkThread + +CauseThread_Duckman::CauseThread_Duckman(IllusionsEngine_Duckman *vm, uint32 threadId, uint32 callingThreadId, uint notifyFlags, + uint32 triggerThreadId) + : Thread(vm, threadId, callingThreadId, notifyFlags), _vm(vm), _triggerThreadId(triggerThreadId), _flag(false) { + _type = kTTCauseThread; + _tag = _vm->getCurrentScene(); +} + +int CauseThread_Duckman::onUpdate() { + if (_flag) { + if (_vm->getCurrentScene() == _tag) { + Control *cursorCursor = _vm->getObjectControl(0x40004); + cursorCursor->appearActor(); + _vm->_input->discardButtons(1); + } + return kTSTerminate; + } else { + _tag = _vm->getCurrentScene(); + Control *cursorCursor = _vm->getObjectControl(0x40004); + cursorCursor->disappearActor(); + _vm->_input->discardButtons(1); + _vm->startScriptThread(_triggerThreadId, _threadId); + _flag = true; + return kTSSuspend; + } +} + +} // End of namespace Illusions diff --git a/engines/illusions/causethread_duckman.h b/engines/illusions/causethread_duckman.h new file mode 100644 index 0000000000..97bf00e7cb --- /dev/null +++ b/engines/illusions/causethread_duckman.h @@ -0,0 +1,45 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ILLUSIONS_CAUSETHREAD_DUCKMAN_H +#define ILLUSIONS_CAUSETHREAD_DUCKMAN_H + +#include "illusions/thread.h" + +namespace Illusions { + +class IllusionsEngine_Duckman; + +class CauseThread_Duckman : public Thread { +public: + CauseThread_Duckman(IllusionsEngine_Duckman *vm, uint32 threadId, uint32 callingThreadId, uint notifyFlags, + uint32 triggerThreadId); + virtual int onUpdate(); +public: + IllusionsEngine_Duckman *_vm; + bool _flag; + uint32 _triggerThreadId; +}; + +} // End of namespace Illusions + +#endif // ILLUSIONS_CAUSETHREAD_DUCKMAN_H diff --git a/engines/illusions/cursor_duckman.cpp b/engines/illusions/cursor_duckman.cpp new file mode 100644 index 0000000000..d23c9ee02c --- /dev/null +++ b/engines/illusions/cursor_duckman.cpp @@ -0,0 +1,82 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "illusions/illusions_duckman.h" +#include "illusions/actor.h" +#include "illusions/cursor_duckman.h" +#include "illusions/input.h" + +namespace Illusions { + +Cursor_Duckman::Cursor_Duckman(IllusionsEngine_Duckman *vm) + : _vm(vm) { + _status = 1; + _control = 0; + _x = 320; + _y = 240; + _cursorNum = 1; + _field_10 = 0; + _sequenceId = 0; +} + +void Cursor_Duckman::place(Control *control, uint32 sequenceId) { + _status = 2; + _control = control; + _cursorNum = 1; + _field_10 = 0; + _sequenceId = sequenceId; + _visibleCtr = 0; + _control->_flags |= 8; + setActorIndex(_cursorNum, 1, 0); + _vm->_input->setCursorPosition(_control->_actor->_position); +} + +void Cursor_Duckman::setActorIndex(int a2, int a3, int a4) { + _control->_actor->_actorIndex = 1;// TODO?!? *((_BYTE *)&stru_42C040[30].y + 2 * ((always0 != 0) + 2 * a2) + a3 + 1); +} + +void Cursor_Duckman::setControl(Control *control) { + _control = control; +} + +void Cursor_Duckman::show() { + ++_visibleCtr; + if (_visibleCtr > 0) { + _control->_flags |= 1; + _control->_actor->_flags |= 1; + if (_control->_actor->_frameIndex) { + _control->_actor->_flags |= 0x2000; + _control->_actor->_flags |= 0x4000; + } + _vm->_input->discardButtons(0xFFFF); + } +} + +void Cursor_Duckman::hide() { + --_visibleCtr; + if (_visibleCtr <= 0) { + _control->_flags &= ~1; + _control->_actor->_flags &= ~1; + } +} + +} // End of namespace Illusions diff --git a/engines/illusions/cursor_duckman.h b/engines/illusions/cursor_duckman.h new file mode 100644 index 0000000000..152585738b --- /dev/null +++ b/engines/illusions/cursor_duckman.h @@ -0,0 +1,30 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ILLUSIONS_CURSOR_H +#define ILLUSIONS_CURSOR_H + +namespace Illusions { + +} // End of namespace Illusions + +#endif // ILLUSIONS_CURSOR_H diff --git a/engines/illusions/dictionary.cpp b/engines/illusions/dictionary.cpp index 2d9d4b4812..5cf4cef652 100644 --- a/engines/illusions/dictionary.cpp +++ b/engines/illusions/dictionary.cpp @@ -24,6 +24,7 @@ #include "illusions/dictionary.h" #include "illusions/actorresource.h" #include "illusions/backgroundresource.h" +#include "illusions/fontresource.h" #include "illusions/talkresource.h" namespace Illusions { @@ -40,6 +41,18 @@ ActorType *Dictionary::findActorType(uint32 id) { return _actorTypes.find(id); } +void Dictionary::addFont(uint32 id, FontResource *fontResource) { + _fontResources.add(id, fontResource); +} + +void Dictionary::removeFont(uint32 id) { + _fontResources.remove(id); +} + +FontResource *Dictionary::findFont(uint32 id) { + return _fontResources.find(id); +} + void Dictionary::addSequence(uint32 id, Sequence *sequence) { _sequences.add(id, sequence); } diff --git a/engines/illusions/dictionary.h b/engines/illusions/dictionary.h index 11b05a6348..63cb9b1750 100644 --- a/engines/illusions/dictionary.h +++ b/engines/illusions/dictionary.h @@ -29,6 +29,7 @@ namespace Illusions { class ActorType; class Control; +class FontResource; class Sequence; class TalkEntry; @@ -86,6 +87,10 @@ public: void removeActorType(uint32 id); ActorType *findActorType(uint32 id); + void addFont(uint32 id, FontResource *fontResource); + void removeFont(uint32 id); + FontResource *findFont(uint32 id); + void addSequence(uint32 id, Sequence *sequence); void removeSequence(uint32 id); Sequence *findSequence(uint32 id); @@ -99,9 +104,10 @@ public: protected: DictionaryHashMap<ActorType> _actorTypes; + DictionaryHashMap<Control> _controls; + DictionaryHashMap<FontResource> _fontResources; DictionaryHashMap<Sequence> _sequences; DictionaryHashMap<TalkEntry> _talkEntries; - DictionaryHashMap<Control> _controls; }; } // End of namespace Illusions diff --git a/engines/illusions/fontresource.cpp b/engines/illusions/fontresource.cpp index e0f48d051c..adfb135da5 100644 --- a/engines/illusions/fontresource.cpp +++ b/engines/illusions/fontresource.cpp @@ -22,6 +22,7 @@ #include "illusions/illusions.h" #include "illusions/fontresource.h" +#include "illusions/dictionary.h" namespace Illusions { @@ -30,11 +31,19 @@ namespace Illusions { void FontResourceLoader::load(Resource *resource) { debug("FontResourceLoader::load() Loading font %08X from %s...", resource->_resId, resource->_filename.c_str()); - // TODO + // TODO + FontResource *fontResource = new FontResource(); + fontResource->load(resource); + resource->_refId = fontResource; + + _vm->_dict->addFont(resource->_resId, fontResource); } void FontResourceLoader::unload(Resource *resource) { + FontResource *fontResource = _vm->_dict->findFont(resource->_resId); + delete fontResource; + _vm->_dict->removeFont(resource->_resId); } void FontResourceLoader::buildFilename(Resource *resource) { @@ -46,4 +55,76 @@ bool FontResourceLoader::isFlag(int flag) { flag == kRlfLoadFile; } +// CharInfo + +void CharInfo::load(byte *dataStart, Common::SeekableReadStream &stream) { + _width = stream.readUint16LE(); + _field_2 = stream.readUint16LE(); + uint32 pixelsOffs = stream.readUint32LE(); + _pixels = dataStart + pixelsOffs; + debug("CharInfo::load() _width: %d; _field_2: %d; pixelsOffs: %08X", + _width, _field_2, pixelsOffs); +} + +// CharRange + +void CharRange::load(byte *dataStart, Common::SeekableReadStream &stream) { + _firstChar = stream.readUint16LE(); + _lastChar = stream.readUint16LE(); + uint count = _lastChar - _firstChar + 1; + uint32 charInfosOffs = stream.readUint32LE(); + _charInfos = new CharInfo[count]; + for (uint i = 0; i < count; ++i) { + stream.seek(charInfosOffs + i * 8); + _charInfos[i].load(dataStart, stream); + } + debug("CharRange::load() _firstChar: %d; _lastChar: %d; charInfosOffs: %08X", + _firstChar, _lastChar, charInfosOffs); +} + +CharInfo *CharRange::getCharInfo(uint16 c) { + return &_charInfos[c - _firstChar]; +} + +bool CharRange::containsChar(uint16 c) { + return c >= _firstChar && c <= _lastChar; +} + +// FontResource + +FontResource::FontResource() { +} + +FontResource::~FontResource() { +} + +void FontResource::load(Resource *resource) { + byte *data = resource->_data; + uint32 dataSize = resource->_dataSize; + Common::MemoryReadStream stream(data, dataSize, DisposeAfterUse::NO); + + _totalSize = stream.readUint32LE(); + _charHeight = stream.readUint16LE(); + _field_6 = stream.readUint16LE(); + _colorIndex = stream.readUint16LE(); + _lineIncr = stream.readUint16LE(); + _widthC = stream.readUint16LE(); + _charRangesCount = stream.readUint16LE(); + uint32 charRangesOffs = stream.pos(); + _charRanges = new CharRange[_charRangesCount]; + for (uint i = 0; i < _charRangesCount; ++i) { + stream.seek(charRangesOffs + i * 8); + _charRanges[i].load(data, stream); + } + debug("FontResource::load() _charHeight: %d; _field_6: %d; _colorIndex: %d; _lineIncr: %d; _widthC: %d; _charRangesCount: %d", + _charHeight, _field_6, _colorIndex, _lineIncr, _widthC, _charRangesCount); +} + +CharInfo *FontResource::getCharInfo(uint16 c) { + for (uint i = 0; i < _charRangesCount; ++i) + if (_charRanges[i].containsChar(c)) + return _charRanges[i].getCharInfo(c); + return 0; +} + } // End of namespace Illusions diff --git a/engines/illusions/fontresource.h b/engines/illusions/fontresource.h index 66860bb14b..33360d7968 100644 --- a/engines/illusions/fontresource.h +++ b/engines/illusions/fontresource.h @@ -42,6 +42,43 @@ protected: IllusionsEngine *_vm; }; +// TODO + +struct CharInfo { + int16 _width; + int16 _field_2; + byte *_pixels; + void load(byte *dataStart, Common::SeekableReadStream &stream); +}; + +struct CharRange { + uint16 _firstChar; + uint16 _lastChar; + CharInfo *_charInfos; + void load(byte *dataStart, Common::SeekableReadStream &stream); + CharInfo *getCharInfo(uint16 c); + bool containsChar(uint16 c); +}; + +class FontResource { +public: + FontResource(); + ~FontResource(); + void load(Resource *resource); + CharInfo *getCharInfo(uint16 c); + int16 getColorIndex() const { return _colorIndex; } +public: + uint32 _totalSize; + int16 _charHeight; + int16 _field_6; + int16 _colorIndex; + int16 _lineIncr; + int16 _widthC; + uint _charRangesCount; + CharRange *_charRanges; + CharRange *getCharRange(uint16 c); +}; + } // End of namespace Illusions #endif // ILLUSIONS_FONTRESOURCE_H diff --git a/engines/illusions/illusions.cpp b/engines/illusions/illusions.cpp index 4d9f4a0702..f4ba0cd131 100644 --- a/engines/illusions/illusions.cpp +++ b/engines/illusions/illusions.cpp @@ -32,6 +32,7 @@ #include "illusions/input.h" #include "illusions/resourcesystem.h" #include "illusions/screen.h" +#include "illusions/screentext.h" #include "illusions/scriptresource.h" #include "illusions/scriptman.h" #include "illusions/soundresource.h" @@ -159,7 +160,6 @@ int IllusionsEngine::updateGraphics() { for (Controls::ItemsIterator it = _controls->_controls.begin(); it != _controls->_controls.end(); ++it) { Control *control = *it; Actor *actor = control->_actor; - if (control->_pauseCtr == 0 && actor && (actor->_flags & 1) && !(actor->_flags & 0x0200)) { Common::Point drawPosition = control->calcPosition(panPoint); if (actor->_flags & 0x2000) { @@ -184,13 +184,11 @@ int IllusionsEngine::updateGraphics() { } } -#if 0 // TODO - if (_textInfo._surface) { + if (_screenText->_surface) { int16 priority = getPriorityFromBase(99); - _screen->_drawQueue->insertTextSurface(_textInfo._surface, _textInfo._dimensions, - _textInfo._position, priority); + _screen->_drawQueue->insertTextSurface(_screenText->_surface, _screenText->_dimensions, + _screenText->_position, priority); } -#endif return 1; } @@ -294,4 +292,20 @@ uint32 IllusionsEngine::clipTextDuration(uint32 duration) { return duration; } +void IllusionsEngine::getDefaultTextDimensions(WidthHeight &dimensions) { + dimensions = _defaultTextDimensions; +} + +void IllusionsEngine::setDefaultTextDimensions(WidthHeight &dimensions) { + _defaultTextDimensions = dimensions; +} + +void IllusionsEngine::getDefaultTextPosition(Common::Point &position) { + position = _defaultTextPosition; +} + +void IllusionsEngine::setDefaultTextPosition(Common::Point &position) { + _defaultTextPosition = position; +} + } // End of namespace Illusions diff --git a/engines/illusions/illusions.h b/engines/illusions/illusions.h index ff7d2194af..3bfa8765cd 100644 --- a/engines/illusions/illusions.h +++ b/engines/illusions/illusions.h @@ -23,6 +23,7 @@ #ifndef ILLUSIONS_ILLUSIONS_H #define ILLUSIONS_ILLUSIONS_H +#include "illusions/graphics.h" #include "audio/mixer.h" #include "audio/decoders/aiff.h" #include "common/array.h" @@ -63,6 +64,7 @@ class Dictionary; class FramesList; class Input; class Screen; +class ScreenText; class ScriptOpcodes; class ScriptResource; class Sequence; @@ -97,6 +99,7 @@ public: void updateEvents(); Screen *_screen; + ScreenText *_screenText; Input *_input; ActorItems *_actorItems; BackgroundItems *_backgroundItems; @@ -118,6 +121,9 @@ public: int _field8; uint32 _fieldA, _fieldE; + WidthHeight _defaultTextDimensions; + Common::Point _defaultTextPosition; + int16 _menuChoiceOfs; int getGameId() const { @@ -143,7 +149,12 @@ public: void setCurrFontId(uint32 fontId); bool checkActiveTalkThreads(); uint32 clipTextDuration(uint32 duration); + void getDefaultTextDimensions(WidthHeight &dimensions); + void setDefaultTextDimensions(WidthHeight &dimensions); + void getDefaultTextPosition(Common::Point &position); + void setDefaultTextPosition(Common::Point &position); + virtual void setDefaultTextCoords() = 0; virtual void loadSpecialCode(uint32 resId) = 0; virtual void unloadSpecialCode(uint32 resId) = 0; virtual void notifyThreadId(uint32 &threadId) = 0; @@ -152,14 +163,12 @@ public: virtual uint32 getPriorityFromBase(int16 priority) = 0; virtual uint32 getPrevScene() = 0; virtual uint32 getCurrentScene() = 0; - virtual bool isCursorObject(uint32 actorTypeId, uint32 objectId) = 0; virtual void setCursorControlRoutine(Control *control) = 0; virtual void placeCursorControl(Control *control, uint32 sequenceId) = 0; virtual void setCursorControl(Control *control) = 0; virtual void showCursor() = 0; virtual void hideCursor() = 0; - virtual void startScriptThreadSimple(uint32 threadId, uint32 callingThreadId) = 0; virtual uint32 startTempScriptThread(byte *scriptCodeIp, uint32 callingThreadId, uint32 value8, uint32 valueC, uint32 value10) = 0; diff --git a/engines/illusions/illusions_bbdou.cpp b/engines/illusions/illusions_bbdou.cpp index 84b3876e6c..d5e9713817 100644 --- a/engines/illusions/illusions_bbdou.cpp +++ b/engines/illusions/illusions_bbdou.cpp @@ -228,8 +228,9 @@ Common::Error IllusionsEngine_BBDOU::run() { _globalSceneId = 0x00010003; + setDefaultTextCoords(); + _resSys->loadResource(0x000D0001, 0, 0); - startScriptThread(0x00020004, 0, 0, 0, 0); _doScriptThreadInit = true; @@ -301,6 +302,15 @@ uint32 IllusionsEngine_BBDOU::causeTrigger(uint32 sceneId, uint32 verbId, uint32 return causeThreadId; } +void IllusionsEngine_BBDOU::setDefaultTextCoords() { + WidthHeight dimensions; + dimensions._width = 480; + dimensions._height = 48; + Common::Point pt(320, 448); + setDefaultTextDimensions(dimensions); + setDefaultTextPosition(pt); +} + void IllusionsEngine_BBDOU::loadSpecialCode(uint32 resId) { _specialCode = new BbdouSpecialCode(this); _specialCode->init(); diff --git a/engines/illusions/illusions_bbdou.h b/engines/illusions/illusions_bbdou.h index d50fe4ce1a..05aea8a863 100644 --- a/engines/illusions/illusions_bbdou.h +++ b/engines/illusions/illusions_bbdou.h @@ -108,6 +108,8 @@ public: void causeDeclare(uint32 verbId, uint32 objectId2, uint32 objectId, TriggerFunctionCallback *callback); uint32 causeTrigger(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId, uint32 callingThreadId); + void setDefaultTextCoords(); + void loadSpecialCode(uint32 resId); void unloadSpecialCode(uint32 resId); void notifyThreadId(uint32 &threadId); diff --git a/engines/illusions/illusions_duckman.cpp b/engines/illusions/illusions_duckman.cpp index 74c27889e4..0cd27e8a29 100644 --- a/engines/illusions/illusions_duckman.cpp +++ b/engines/illusions/illusions_duckman.cpp @@ -33,6 +33,7 @@ #include "illusions/midiresource.h" #include "illusions/resourcesystem.h" #include "illusions/screen.h" +#include "illusions/screentext.h" #include "illusions/scriptopcodes_duckman.h" #include "illusions/scriptresource.h" #include "illusions/scriptman.h" @@ -40,11 +41,13 @@ #include "illusions/specialcode.h" //TODO#include "illusions/bbdou/bbdou_specialcode.h" #include "illusions/talkresource.h" +#include "illusions/textdrawer.h" #include "illusions/thread.h" #include "illusions/time.h" #include "illusions/updatefunctions.h" #include "illusions/abortablethread.h" +#include "illusions/causethread_duckman.h" #include "illusions/scriptthread.h" #include "illusions/talkthread_duckman.h" #include "illusions/timerthread.h" @@ -93,6 +96,7 @@ Common::Error IllusionsEngine_Duckman::run() { _resSys->addResourceLoader(0x00120000, new FontResourceLoader(this)); _screen = new Screen(this, 320, 200, 8); + _screenText = new ScreenText(this); _input = new Input(); _actorItems = new ActorItems(this); _backgroundItems = new BackgroundItems(this); @@ -115,11 +119,18 @@ Common::Error IllusionsEngine_Duckman::run() { _fieldA = 0; _fieldE = 240; - _globalSceneId = 0x00010003; - - _resSys->loadResource(0x000D0001, 0x00010001, 0); + _globalSceneId = 0x00010003; + initSpecialCode(); + setDefaultTextCoords(); + initCursor(); initActiveScenes(); + + _resSys->loadResource(0x120001, 0x00010001, 0); + _resSys->loadResource(0x120002, 0x00010001, 0); + _resSys->loadResource(0x120003, 0x00010001, 0); + + _resSys->loadResource(0x000D0001, 0x00010001, 0); startScriptThread(0x00020004, 0); _doScriptThreadInit = true; @@ -145,6 +156,7 @@ Common::Error IllusionsEngine_Duckman::run() { delete _backgroundItems; delete _actorItems; delete _input; + delete _screenText; delete _screen; delete _resSys; delete _dict; @@ -164,6 +176,15 @@ bool IllusionsEngine_Duckman::hasFeature(EngineFeature f) const { */ } +void IllusionsEngine_Duckman::setDefaultTextCoords() { + WidthHeight dimensions; + dimensions._width = 300; + dimensions._height = 32; + Common::Point pt(160, 176); + setDefaultTextDimensions(dimensions); + setDefaultTextPosition(pt); +} + void IllusionsEngine_Duckman::loadSpecialCode(uint32 resId) { //TODO _specialCode = new BbdouSpecialCode(this); //TODO _specialCode->init(); @@ -229,13 +250,40 @@ void IllusionsEngine_Duckman::setCursorControlRoutine(Control *control) { } void IllusionsEngine_Duckman::placeCursorControl(Control *control, uint32 sequenceId) { + _cursor._gameState = 2; + _cursor._control = control; + _cursor._actorIndex = 1; + _cursor._savedActorIndex = 1; + _cursor._currOverlappedControl = 0; + _cursor._sequenceId1 = sequenceId; + _cursor._field14[0] = true; + _cursor._field14[1] = true; + _cursor._field14[2] = false; + _cursor._field14[3] = false; + _cursor._field14[4] = false; + _cursor._field14[5] = false; + _cursor._field14[9] = false; + _cursor._field14[10] = false; + _cursor._field14[11] = false; + _cursor._field14[12] = false; + _cursor._field14[6] = _cursor._sequenceId2 != 0 && _cursor._objectId != 0; + _cursor._field14[7] = false; + _cursor._field14[8] = false; + _cursor._op113_choiceOfsPtr = 0; + _cursor._notifyThreadId30 = 0; + _cursor._op113_objectNumCtr = 0; + _cursor._overlappedObjectNum = 0; + _cursor._field40 = 0; + control->_flags |= 8; + setCursorActorIndex(_cursor._actorIndex, 1, 0); + // TODO Input_setMousePos(cursorControl->actor->position); // TODO - control->_actor->_actorIndex = 2; + //control->_actor->_actorIndex = 2; // TODO _cursor->place(control, sequenceId); } void IllusionsEngine_Duckman::setCursorControl(Control *control) { - // TODO + _cursor._control = control; } void IllusionsEngine_Duckman::showCursor() { @@ -246,9 +294,108 @@ void IllusionsEngine_Duckman::hideCursor() { // TODO } +void IllusionsEngine_Duckman::initCursor() { + _cursor._gameState = 1; + _cursor._control = 0; + _cursor._position.x = 160; + _cursor._position.y = 100; + _cursor._objectId = 0; + _cursor._actorIndex = 1; + _cursor._savedActorIndex = 1; + _cursor._currOverlappedControl = 0; + _cursor._sequenceId1 = 0; + _cursor._sequenceId2 = 0; + _cursor._field14[0] = true; + _cursor._field14[1] = true; + _cursor._field14[2] = false; + _cursor._field14[3] = false; + _cursor._field14[4] = false; + _cursor._field14[5] = false; + _cursor._field14[6] = false; + _cursor._field14[7] = false; + _cursor._field14[8] = false; + _cursor._field14[9] = false; + _cursor._field14[10] = false; + _cursor._field14[11] = false; + _cursor._field14[12] = false; + _cursor._op113_choiceOfsPtr = 0; + _cursor._notifyThreadId30 = 0; + _cursor._op113_objectNumCtr = 0; + _cursor._overlappedObjectNum = 0; + _cursor._field40 = 0; +} + +void IllusionsEngine_Duckman::setCursorActorIndex(int actorIndex, int a, int b) { + static int kCursorMap[13][2][2] = { + {{ 1, 2}, { 0, 0}}, + {{ 3, 4}, { 0, 0}}, + {{ 5, 6}, {13, 14}}, + {{ 7, 8}, { 0, 0}}, + {{ 9, 10}, { 0, 0}}, + {{11, 12}, { 0, 0}}, + {{ 1, 2}, { 0, 0}}, + {{ 0, 0}, { 0, 0}}, + {{ 0, 0}, { 0, 0}}, + {{15, 16}, { 0, 0}}, + {{17, 18}, { 0, 0}}, + {{19, 20}, { 0, 0}}, + {{21, 22}, { 0, 0}} + }; + _cursor._control->_actor->_actorIndex = kCursorMap[actorIndex - 1][b][a - 1]; + debug("_cursor._control->_actor->_actorIndex: %d", _cursor._control->_actor->_actorIndex); +} + +void IllusionsEngine_Duckman::enableCursorVerb(int verbNum) { + if (verbNum != 7 || _cursor._sequenceId2) + _cursor._field14[verbNum - 1] = true; +} + +void IllusionsEngine_Duckman::disableCursorVerb(int verbNum) { + _cursor._field14[verbNum - 1] = false; + if (_cursor._actorIndex == verbNum) { + _cursor._actorIndex = getCursorActorIndex(); + setCursorActorIndex(_cursor._actorIndex, 1, 0); + startCursorSequence(); + _cursor._currOverlappedControl = 0; + } +} + +void IllusionsEngine_Duckman::setCursorHandMode(int mode) { + if (mode == 1) { + enableCursorVerb(4); + disableCursorVerb(1); + disableCursorVerb(2); + disableCursorVerb(7); + _cursor._actorIndex = 4; + } else { + enableCursorVerb(1); + enableCursorVerb(2); + enableCursorVerb(7); + disableCursorVerb(4); + _cursor._actorIndex = 1; + } + _cursor._control->startSequenceActor(_cursor._sequenceId1, 2, 0); + if (_cursor._currOverlappedControl) + setCursorActorIndex(_cursor._actorIndex, 2, 0); + else + setCursorActorIndex(_cursor._actorIndex, 1, 0); +} + void IllusionsEngine_Duckman::cursorControlRoutine(Control *control, uint32 deltaTime) { control->_actor->_seqCodeValue1 = 100 * deltaTime; - // TODO + if (control->_actor->_flags & 1) { + switch (_cursor._gameState) { + case 2: + updateGameState2(); + break; + case 3: + // TODO updateGameState3(cursorControl); + break; + case 4: + // TODO ShellMgr_update(cursorControl); + break; + } + } } void IllusionsEngine_Duckman::startScriptThreadSimple(uint32 threadId, uint32 callingThreadId) { @@ -437,4 +584,225 @@ uint32 IllusionsEngine_Duckman::getObjectActorTypeId(uint32 objectId) { return _scriptResource->getObjectActorTypeId(objectId); } +Common::Point IllusionsEngine_Duckman::convertMousePos(Common::Point mousePos) { + Common::Point screenOffsPt = _camera->getScreenOffset(); + mousePos.x += screenOffsPt.x; + mousePos.y += screenOffsPt.y; + return mousePos; +} + +void IllusionsEngine_Duckman::startCursorSequence() { + // NOTE Calls to startCursorSequence were put after calls to setCursorActorIndex + // to make the cursor switch more immediate. In the original these calls are swapped. + if (_cursor._actorIndex == 7) + _cursor._control->startSequenceActor(_cursor._sequenceId2, 2, 0); + else + _cursor._control->startSequenceActor(_cursor._sequenceId1, 2, 0); +} + +int IllusionsEngine_Duckman::getCursorActorIndex() { + int result = _cursor._actorIndex; + do { + ++result; + if (result > 13) + result = 1; + } while (!_cursor._field14[result - 1]); + return result; +} + +void IllusionsEngine_Duckman::updateGameState2() { + Common::Point cursorPos = _input->getCursorPosition(); + Common::Point convMousePos = convertMousePos(cursorPos); + int trackCursorIndex = -1; + bool foundOverlapped; + Control *overlappedControl; + + _cursor._control->_actor->_position = cursorPos; + + foundOverlapped = _controls->getOverlappedObject(_cursor._control, convMousePos, &overlappedControl, 0); + + if (cursorPos.y < 8 && !_camera->isAtPanLimit(1)) { + trackCursorIndex = 10; + } else if (cursorPos.y >= 192 && !_camera->isAtPanLimit(2)) { + trackCursorIndex = 11; + } else if (cursorPos.x < 8 && !_camera->isAtPanLimit(3)) { + trackCursorIndex = 12; + } else if (cursorPos.x >= 312 && !_camera->isAtPanLimit(4)) { + trackCursorIndex = 13; + } else if (_cursor._actorIndex == 10 || _cursor._actorIndex == 11 || _cursor._actorIndex == 12 || _cursor._actorIndex == 13) { + _cursor._actorIndex = _cursor._savedActorIndex; + if (_cursor._currOverlappedControl) + setCursorActorIndex(_cursor._actorIndex, 2, 0); + else + setCursorActorIndex(_cursor._actorIndex, 1, 0); + startCursorSequence(); + } + + if (trackCursorIndex >= 0) { + if (_cursor._actorIndex != 10 && _cursor._actorIndex != 11 && _cursor._actorIndex != 12 && _cursor._actorIndex != 13 && _cursor._actorIndex != 3) + _cursor._savedActorIndex = _cursor._actorIndex; + if (_cursor._actorIndex != trackCursorIndex) { + _cursor._actorIndex = trackCursorIndex; + setCursorActorIndex(_cursor._actorIndex, 1, 0); + startCursorSequence(); + } + _cursor._currOverlappedControl = 0; + foundOverlapped = false; + } + + if (foundOverlapped) { + if (_cursor._currOverlappedControl != overlappedControl) { + int cursorValue2 = 0; + if (overlappedControl->_flags & 2) { + if (_cursor._actorIndex != 3) { + _cursor._savedActorIndex = _cursor._actorIndex; + _cursor._actorIndex = 3; + } + if (overlappedControl->_flags & 0x40) + cursorValue2 = 1; + } else if (_cursor._actorIndex == 3) { + _cursor._actorIndex = _cursor._savedActorIndex; + } + setCursorActorIndex(_cursor._actorIndex, 2, cursorValue2); + startCursorSequence(); + _cursor._currOverlappedControl = overlappedControl; + } + } else if (_cursor._currOverlappedControl) { + if (_cursor._actorIndex == 3) + _cursor._actorIndex = _cursor._savedActorIndex; + setCursorActorIndex(_cursor._actorIndex, 1, 0); + startCursorSequence(); + _cursor._currOverlappedControl = 0; + } + + if (_input->pollButton(1)) { + if (_cursor._currOverlappedControl) { + runTriggerCause(_cursor._actorIndex, _cursor._objectId, _cursor._currOverlappedControl->_objectId); + } else { + _cursor._position = convertMousePos(_cursor._control->_actor->_position); + // TODO clipMousePos(&_cursor._position); + if (_cursor._actorIndex == 10 || _cursor._actorIndex == 11 || _cursor._actorIndex == 12 || _cursor._actorIndex == 13) + runTriggerCause(1, _cursor._objectId, 0x40003); + else + runTriggerCause(_cursor._actorIndex, _cursor._objectId, 0x40003); + } + } else if (_input->pollButton(2)) { + if (_cursor._actorIndex != 3 && _cursor._actorIndex != 10 && _cursor._actorIndex != 11 && _cursor._actorIndex != 12 && _cursor._actorIndex != 13) { + int newActorIndex = getCursorActorIndex(); + debug("newActorIndex = %d", newActorIndex); + if (newActorIndex != _cursor._actorIndex) { + _cursor._actorIndex = newActorIndex; + if (_cursor._currOverlappedControl) + setCursorActorIndex(_cursor._actorIndex, 2, 0); + else + setCursorActorIndex(_cursor._actorIndex, 1, 0); + startCursorSequence(); + } + } + } else if (_input->pollButton(8)) { + if (_cursor._field14[0] == 1) { + runTriggerCause(1, 0, _scriptResource->getField6C()); + } else if (_cursor._field14[1] == 1) { + runTriggerCause(2, 0, _scriptResource->getField6C()); + } + } + +} + +void IllusionsEngine_Duckman::playSoundEffect(int index) { + // TODO +} + +bool IllusionsEngine_Duckman::getTriggerCause(uint32 verbId, uint32 objectId2, uint32 objectId, uint32 &outThreadId) { + ProgInfo *progInfo = _scriptResource->getProgInfo(getCurrentScene() & 0xFFFF); + bool found = + progInfo->findTriggerCause(verbId, objectId2, objectId, outThreadId) || + progInfo->findTriggerCause(verbId, objectId2, 0x40001, outThreadId); + if (!found) { + progInfo = _scriptResource->getProgInfo(3); + found = + progInfo->findTriggerCause(verbId, objectId2, objectId, outThreadId) || + progInfo->findTriggerCause(verbId, objectId2, 0x40001, outThreadId); + } + return found; +} + +uint32 IllusionsEngine_Duckman::runTriggerCause(uint32 verbId, uint32 objectId2, uint32 objectId) { + // TODO + debug("runTriggerCause(%08X, %08X, %08X)", verbId, objectId2, objectId); + uint32 triggerThreadId; + + if (!getTriggerCause(verbId, objectId2, objectId, triggerThreadId)) + return 0; + + bool flag = false; + if (_scriptResource->_properties.get(0x000E003C)) { + if (verbId == 7 && objectId == 0x40003 ) { + playSoundEffect(7); + flag = true; + } else if (objectId == 0x40003 ) { + playSoundEffect(14); + flag = true; + } else if (verbId == 3 ) { + playSoundEffect(16); + flag = true; + } else if (verbId == 2 ) { + flag = true; + } + } + + if (!flag) { + if (objectId == 0x40003) { + playSoundEffect(14); + } else if ((verbId == 1 || verbId == 2) && _scriptResource->getField6C() == objectId) { + playSoundEffect(15); + } else if (verbId == 7 && _scriptResource->getField6C() == objectId) { + playSoundEffect(15); + } else if (verbId == 1) { + playSoundEffect(1); + } else if (verbId == 2) { + playSoundEffect(2); + } else if (verbId == 3) { + playSoundEffect(3); + } else if (verbId == 4 || verbId == 7) { + playSoundEffect(4); + } else if (verbId == 9) { + playSoundEffect(5); + } + } + + uint32 tempThreadId = newTempThreadId(); + debug(2, "Starting cause thread %08X", tempThreadId); + CauseThread_Duckman *causeThread = new CauseThread_Duckman(this, tempThreadId, 0, 0, + triggerThreadId); + _threads->startThread(causeThread); + + return tempThreadId; +} + +// Special code + +typedef Common::Functor1Mem<OpCall&, void, IllusionsEngine_Duckman> SpecialCodeFunctionDM; +#define SPECIAL(id, func) _specialCodeMap[id] = new SpecialCodeFunctionDM(this, &IllusionsEngine_Duckman::func); + +void IllusionsEngine_Duckman::initSpecialCode() { + SPECIAL(0x00160002, spcSetCursorHandMode); +} + +void IllusionsEngine_Duckman::runSpecialCode(uint32 specialCodeId, OpCall &opCall) { + SpecialCodeMapIterator it = _specialCodeMap.find(specialCodeId); + if (it != _specialCodeMap.end()) { + (*(*it)._value)(opCall); + } else { + debug("IllusionsEngine_Duckman::runSpecialCode() Unimplemented special code %08X", specialCodeId); + notifyThreadId(opCall._threadId); + } +} + +void IllusionsEngine_Duckman::spcSetCursorHandMode(OpCall &opCall) { + ARG_BYTE(mode); + setCursorHandMode(mode); + notifyThreadId(opCall._threadId); +} + } // End of namespace Illusions diff --git a/engines/illusions/illusions_duckman.h b/engines/illusions/illusions_duckman.h index f70156af88..375407fe09 100644 --- a/engines/illusions/illusions_duckman.h +++ b/engines/illusions/illusions_duckman.h @@ -32,6 +32,31 @@ namespace Illusions { class Dictionary; class ScriptStack; +struct Cursor_Duckman { + int _gameState; + Control *_control; + Common::Point _position; + uint32 _objectId; + int _actorIndex; + int _savedActorIndex; + bool _field14[14]; + Control *_currOverlappedControl; + uint32 _sequenceId1; + uint32 _sequenceId2; + uint32 _notifyThreadId30; + int16 *_op113_choiceOfsPtr; + int _op113_objectNumCtr; + uint _overlappedObjectNum; + uint32 _field3C; + uint32 _field40; +}; + +struct OpCall; + +typedef Common::Functor1<OpCall&, void> SpecialCodeFunction; +typedef Common::HashMap<uint32, SpecialCodeFunction*> SpecialCodeMap; +typedef SpecialCodeMap::iterator SpecialCodeMapIterator; + class IllusionsEngine_Duckman : public IllusionsEngine { public: IllusionsEngine_Duckman(OSystem *syst, const IllusionsGameDescription *gd); @@ -55,6 +80,12 @@ public: uint _activeScenesCount; uint32 _activeScenes[6]; + Cursor_Duckman _cursor; + + SpecialCodeMap _specialCodeMap; + + void setDefaultTextCoords(); + void loadSpecialCode(uint32 resId); void unloadSpecialCode(uint32 resId); void notifyThreadId(uint32 &threadId); @@ -70,6 +101,11 @@ public: void setCursorControl(Control *control); void showCursor(); void hideCursor(); + void initCursor(); + void setCursorActorIndex(int actorIndex, int a, int b); + void enableCursorVerb(int verbNum); + void disableCursorVerb(int verbNum); + void setCursorHandMode(int mode); void cursorControlRoutine(Control *control, uint32 deltaTime); void startScriptThreadSimple(uint32 threadId, uint32 callingThreadId); @@ -104,6 +140,19 @@ public: uint32 getObjectActorTypeId(uint32 objectId); + Common::Point convertMousePos(Common::Point mousePos); + void startCursorSequence(); + int getCursorActorIndex(); + void updateGameState2(); + void playSoundEffect(int index); + bool getTriggerCause(uint32 verbId, uint32 objectId2, uint32 objectId, uint32 &outThreadId); + uint32 runTriggerCause(uint32 verbId, uint32 objectId2, uint32 objectId); + + // Special code + void initSpecialCode(); + void runSpecialCode(uint32 specialCodeId, OpCall &opCall); + void spcSetCursorHandMode(OpCall &opCall); + }; } // End of namespace Illusions diff --git a/engines/illusions/module.mk b/engines/illusions/module.mk index 4341732657..f0688d35ad 100644 --- a/engines/illusions/module.mk +++ b/engines/illusions/module.mk @@ -10,6 +10,7 @@ MODULE_OBJS := \ bbdou/bbdou_inventory.o \ bbdou/bbdou_specialcode.o \ camera.o \ + causethread_duckman.o \ cursor.o \ detection.o \ dictionary.o \ @@ -23,6 +24,7 @@ MODULE_OBJS := \ midiresource.o \ resourcesystem.o \ screen.o \ + screentext.o \ scriptman.o \ scriptopcodes.o \ scriptopcodes_bbdou.o \ @@ -35,6 +37,7 @@ MODULE_OBJS := \ talkresource.o \ talkthread.o \ talkthread_duckman.o \ + textdrawer.o \ thread.o \ time.o \ timerthread.o \ diff --git a/engines/illusions/screen.cpp b/engines/illusions/screen.cpp index 0eb78321a9..f4b6982ab8 100644 --- a/engines/illusions/screen.cpp +++ b/engines/illusions/screen.cpp @@ -22,6 +22,7 @@ #include "illusions/illusions.h" #include "illusions/screen.h" +#include "illusions/fontresource.h" #include "engines/util.h" #include "graphics/palette.h" @@ -315,6 +316,14 @@ void Screen::setPalette(byte *colors, uint start, uint count) { _needRefreshPalette = true; } +void Screen::setPaletteEntry(int16 index, byte r, byte g, byte b) { + byte colors[4]; + colors[0] = r; + colors[1] = g; + colors[2] = b; + setPalette(colors, index, 1); +} + void Screen::getPalette(byte *colors) { byte *srcPal = _mainPalette; for (uint i = 0; i < 256; ++i) { @@ -333,6 +342,26 @@ void Screen::updatePalette() { } } +void Screen::drawText(FontResource *font, Graphics::Surface *surface, int16 x, int16 y, uint16 *text, uint count) { + for (uint i = 0; i < count; ++i) + x += font->_widthC + drawChar(font, surface, x, y, *text++); +} + +int16 Screen::drawChar(FontResource *font, Graphics::Surface *surface, int16 x, int16 y, uint16 c) { + const CharInfo *charInfo = font->getCharInfo(c); + const int16 charWidth = charInfo->_width; + byte *dst = (byte*)surface->getBasePtr(x, y); + byte *pixels = charInfo->_pixels; + for (int16 yc = 0; yc < font->_charHeight; ++yc) { + for (int16 xc = 0; xc < charWidth; ++xc) + if (pixels[xc]) + dst[xc] = pixels[xc]; + dst += surface->pitch; + pixels += charWidth; + } + return charWidth; +} + void Screen::setSystemPalette(byte *palette) { g_system->getPaletteManager()->setPalette(palette, 0, 256); } diff --git a/engines/illusions/screen.h b/engines/illusions/screen.h index 5bd5eb79ce..91750cfba5 100644 --- a/engines/illusions/screen.h +++ b/engines/illusions/screen.h @@ -31,7 +31,7 @@ namespace Illusions { class IllusionsEngine; -class Screen; +class FontResource; struct SpriteDecompressQueueItem { byte *_drawFlags; @@ -112,8 +112,11 @@ public: void decompressSprite(SpriteDecompressQueueItem *item); void drawSurface(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect, int16 scale, uint32 flags); void setPalette(byte *colors, uint start, uint count); + void setPaletteEntry(int16 index, byte r, byte g, byte b); void getPalette(byte *colors); void updatePalette(); + void drawText(FontResource *font, Graphics::Surface *surface, int16 x, int16 y, uint16 *text, uint count); + int16 drawChar(FontResource *font, Graphics::Surface *surface, int16 x, int16 y, uint16 c); int16 getScreenWidth() const { return _backSurface->w; } int16 getScreenHeight() const { return _backSurface->h; } public: diff --git a/engines/illusions/screentext.cpp b/engines/illusions/screentext.cpp new file mode 100644 index 0000000000..684ab5a426 --- /dev/null +++ b/engines/illusions/screentext.cpp @@ -0,0 +1,171 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "illusions/illusions.h" +#include "illusions/screentext.h" +#include "illusions/dictionary.h" +#include "illusions/fontresource.h" +#include "illusions/screen.h" +#include "illusions/textdrawer.h" +#include "engines/util.h" +#include "graphics/palette.h" + +namespace Illusions { + +ScreenText::ScreenText(IllusionsEngine *vm) + : _vm(vm), _surface(0) { +} + +ScreenText::~ScreenText() { +} + +void ScreenText::getTextInfoDimensions(WidthHeight &textInfoDimensions) { + textInfoDimensions = _dimensions; +} + +void ScreenText::setTextInfoPosition(Common::Point position) { + _position = position; + clipTextInfoPosition(_position); +} + +void ScreenText::updateTextInfoPosition(Common::Point position) { + WidthHeight dimensions; + getTextInfoDimensions(dimensions); + position.x = position.x - dimensions._width / 2; + position.y = position.y - dimensions._height / 2; + setTextInfoPosition(position); +} + +void ScreenText::clipTextInfoPosition(Common::Point &position) { + // TODO Set min/max for BBDOU + if (position.x < 2) + position.x = 2; + else if (position.x + _dimensions._width > 318) + position.x = 318 - _dimensions._width; + if (position.y < 2) + position.y = 2; + else if (position.y + _dimensions._height > 198) + position.y = 198 - _dimensions._height; +} + +bool ScreenText::refreshScreenText(FontResource *font, WidthHeight dimensions, Common::Point offsPt, + uint16 *text, uint textFlags, uint16 color2, uint16 color1, uint16 *&outTextPtr) { + TextDrawer textDrawer; + bool done = textDrawer.wrapText(font, text, &dimensions, offsPt, textFlags, outTextPtr); + _surface = _vm->_screen->allocSurface(dimensions._width, dimensions._height); + _dimensions = dimensions; + textDrawer.drawText(_vm->_screen, _surface, color2, color1); + return done; +} + +bool ScreenText::insertText(uint16 *text, uint32 fontId, WidthHeight dimensions, Common::Point offsPt, uint flags, + uint16 color2, uint16 color1, byte colorR, byte colorG, byte colorB, uint16 *&outTextPtr) { + + if (!_screenTexts.empty()) { + ScreenTextEntry *screenText = _screenTexts.back(); + screenText->_info._position = _position; + freeTextSurface(); + } + + ScreenTextEntry *screenText = new ScreenTextEntry(); + screenText->_info._fontId = fontId; + screenText->_info._dimensions = dimensions; + screenText->_info._offsPt = offsPt; + screenText->_info._flags = 0; + if (flags & 8) + screenText->_info._flags |= 8; + if (flags & 0x10) + screenText->_info._flags |= 0x10; + if (flags & 1) + screenText->_info._flags |= 1; + else + screenText->_info._flags |= 2; + screenText->_info._color2 = color2; + screenText->_info._color1 = color1; + screenText->_info._colorR = colorR; + screenText->_info._colorG = colorG; + screenText->_info._colorB = colorB; + _screenTexts.push_back(screenText); + + FontResource *font = _vm->_dict->findFont(screenText->_info._fontId); + bool done = refreshScreenText(font, screenText->_info._dimensions, screenText->_info._offsPt, + text, screenText->_info._flags, screenText->_info._color2, screenText->_info._color1, + outTextPtr); + _vm->_screen->setPaletteEntry(font->getColorIndex(), screenText->_info._colorR, screenText->_info._colorG, screenText->_info._colorB); + + uint16 *textPart = screenText->_text; + while (text != outTextPtr) + *textPart++ = *text++; + *textPart = 0; + + updateTextInfoPosition(Common::Point(160, 100)); + + return done; +} + +void ScreenText::removeText() { + freeTextSurface(); + + if (!_screenTexts.empty()) { + ScreenTextEntry *screenText = _screenTexts.back(); + delete screenText; + _screenTexts.pop_back(); + } + + if (!_screenTexts.empty()) { + ScreenTextEntry *screenText = _screenTexts.back(); + if (screenText->_info._fontId) { + uint16 *outTextPtr; + FontResource *font = _vm->_dict->findFont(screenText->_info._fontId); + refreshScreenText(font, screenText->_info._dimensions, screenText->_info._offsPt, + screenText->_text, screenText->_info._flags, screenText->_info._color2, screenText->_info._color1, + outTextPtr); + _vm->_screen->setPaletteEntry(font->getColorIndex(), screenText->_info._colorR, screenText->_info._colorG, screenText->_info._colorB); + setTextInfoPosition(screenText->_info._position); + } + } + +} + +void ScreenText::clearText() { + + if (!_screenTexts.empty()) { + ScreenTextEntry *screenText = _screenTexts.back(); + screenText->_info._position = _position; + freeTextSurface(); + } + + ScreenTextEntry *screenText = new ScreenTextEntry(); + screenText->_info._fontId = 0; + _screenTexts.push_back(screenText); + +} + +void ScreenText::freeTextSurface() { + if (_surface) { + _surface->free(); + delete _surface; + _surface = 0; + } +} + +} // End of namespace Illusions diff --git a/engines/illusions/screentext.h b/engines/illusions/screentext.h new file mode 100644 index 0000000000..4340224bdb --- /dev/null +++ b/engines/illusions/screentext.h @@ -0,0 +1,77 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ILLUSIONS_SCREENTEXT_H +#define ILLUSIONS_SCREENTEXT_H + +#include "illusions/graphics.h" +#include "common/list.h" +#include "common/rect.h" +#include "graphics/surface.h" + +namespace Illusions { + +class IllusionsEngine; +class FontResource; + +struct ScreenTextInfo { + Common::Point _position; + WidthHeight _dimensions; + Common::Point _offsPt; + uint32 _fontId; + uint16 _color2; + uint16 _color1; + byte _colorR, _colorG, _colorB; + uint _flags; +}; + +struct ScreenTextEntry { + ScreenTextInfo _info; + uint16 _text[1024]; +}; + +class ScreenText { +public: + ScreenText(IllusionsEngine *vm); + ~ScreenText(); + void getTextInfoDimensions(WidthHeight &textInfoDimensions); + void setTextInfoPosition(Common::Point position); + void updateTextInfoPosition(Common::Point position); + void clipTextInfoPosition(Common::Point &position); + bool refreshScreenText(FontResource *font, WidthHeight dimensions, Common::Point offsPt, + uint16 *text, uint textFlags, uint16 color2, uint16 color1, uint16 *&outTextPtr); + bool insertText(uint16 *text, uint32 fontId, WidthHeight dimensions, Common::Point offsPt, uint flags, + uint16 color2, uint16 color1, byte colorR, byte colorG, byte colorB, uint16 *&outTextPtr); + void removeText(); + void clearText(); +public: + IllusionsEngine *_vm; + Common::Point _position; + WidthHeight _dimensions; + Graphics::Surface *_surface; + Common::List<ScreenTextEntry*> _screenTexts; + void freeTextSurface(); +}; + +} // End of namespace Illusions + +#endif // ILLUSIONS_SCREENTEXT_H diff --git a/engines/illusions/scriptopcodes.h b/engines/illusions/scriptopcodes.h index 1020e618a2..cf20380008 100644 --- a/engines/illusions/scriptopcodes.h +++ b/engines/illusions/scriptopcodes.h @@ -61,6 +61,7 @@ protected: // Convenience macros #define ARG_SKIP(x) opCall.skip(x); +#define ARG_BYTE(name) byte name = opCall.readByte(); debug(0, "ARG_BYTE(" #name " = %d)", name); #define ARG_INT16(name) int16 name = opCall.readSint16(); debug(0, "ARG_INT16(" #name " = %d)", name); #define ARG_UINT32(name) uint32 name = opCall.readUint32(); debug(0, "ARG_UINT32(" #name " = %08X)", name); diff --git a/engines/illusions/scriptopcodes_duckman.cpp b/engines/illusions/scriptopcodes_duckman.cpp index ffe4ac0689..f7e96765be 100644 --- a/engines/illusions/scriptopcodes_duckman.cpp +++ b/engines/illusions/scriptopcodes_duckman.cpp @@ -63,14 +63,25 @@ void ScriptOpcodes_Duckman::initOpcodes() { OPCODE(7, opStartTimerThread); OPCODE(9, opNotifyThread); OPCODE(10, opSuspendThread); + OPCODE(16, opLoadResource); + OPCODE(17, opUnloadResource); OPCODE(18, opEnterScene18); OPCODE(20, opChangeScene); + OPCODE(22, opStartModalScene); + OPCODE(23, opExitModalScene); OPCODE(24, opEnterScene24); OPCODE(25, opLeaveScene24); + OPCODE(34, opPanToObject); OPCODE(38, opStartFade); OPCODE(39, opSetDisplay); + OPCODE(40, opSetCameraBounds); + OPCODE(48, opSetProperty); OPCODE(49, opPlaceActor); + OPCODE(50, opFaceActor); + OPCODE(51, opFaceActorToObject); OPCODE(52, opStartSequenceActor); + OPCODE(54, opStartMoveActor); + OPCODE(55, opStartMoveActorToObject); OPCODE(56, opStartTalkThread); OPCODE(57, opAppearActor); OPCODE(58, opDisappearActor); @@ -102,22 +113,14 @@ void ScriptOpcodes_Duckman::initOpcodes() { OPCODE(8, opStartTempScriptThread); OPCODE(14, opSetThreadSceneId); OPCODE(15, opEndTalkThreads); - OPCODE(17, opUnloadResource); OPCODE(20, opEnterScene); - OPCODE(26, opStartModalScene); - OPCODE(27, opExitModalScene); OPCODE(30, opEnterCloseUpScene); OPCODE(31, opExitCloseUpScene); OPCODE(32, opPanCenterObject); - OPCODE(34, opPanToObject); OPCODE(35, opPanToNamedPoint); OPCODE(36, opPanToPoint); OPCODE(37, opPanStop); OPCODE(43, opClearBlockCounter); - OPCODE(45, opSetProperty); - OPCODE(47, opFaceActor); - OPCODE(48, opFaceActorToObject); - OPCODE(51, opStartMoveActor); OPCODE(53, opSetActorToNamedPoint); OPCODE(63, opSetSelectSfx); OPCODE(64, opSetMoveSfx); @@ -206,13 +209,32 @@ void ScriptOpcodes_Duckman::opSuspendThread(ScriptThread *scriptThread, OpCall & _vm->_threads->suspendTimerThreads(threadId); } +void ScriptOpcodes_Duckman::opLoadResource(ScriptThread *scriptThread, OpCall &opCall) { + ARG_SKIP(2); + ARG_UINT32(resourceId); + // NOTE Skipped checking for stalled resources + uint32 sceneId = _vm->getCurrentScene(); + _vm->_resSys->loadResource(resourceId, sceneId, opCall._threadId); + _vm->notifyThreadId(opCall._threadId); +} + +void ScriptOpcodes_Duckman::opUnloadResource(ScriptThread *scriptThread, OpCall &opCall) { + ARG_SKIP(2); + ARG_UINT32(resourceId); + // NOTE Skipped checking for stalled resources + _vm->_resSys->unloadResourceById(resourceId); +} + void ScriptOpcodes_Duckman::opEnterScene18(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(sceneId); _vm->enterScene(sceneId, 0); } -static uint dsceneId = 0x00010008, dthreadId = 0x00020029; +//static uint dsceneId = 0, dthreadId = 0; +static uint dsceneId = 0x00010008, dthreadId = 0x00020029;//Beginning in Jac +//static uint dsceneId = 0x00010012, dthreadId = 0x0002009D;//Paramount +//static uint dsceneId = 0x00010039, dthreadId = 0x00020089;//Map void ScriptOpcodes_Duckman::opChangeScene(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); @@ -234,6 +256,30 @@ void ScriptOpcodes_Duckman::opChangeScene(ScriptThread *scriptThread, OpCall &op } } +void ScriptOpcodes_Duckman::opStartModalScene(ScriptThread *scriptThread, OpCall &opCall) { + ARG_SKIP(2); + ARG_UINT32(sceneId); + ARG_UINT32(threadId); + _vm->_input->discardButtons(0xFFFF); + _vm->enterPause(_vm->getCurrentScene(), opCall._callerThreadId); + _vm->_talkItems->pauseByTag(_vm->getCurrentScene()); + _vm->enterScene(sceneId, threadId); + opCall._result = kTSSuspend; +} + +void ScriptOpcodes_Duckman::opExitModalScene(ScriptThread *scriptThread, OpCall &opCall) { + _vm->_input->discardButtons(0xFFFF); + if (_vm->_scriptResource->_properties.get(0x000E0027)) { + // TODO _vm->startScriptThread2(0x10002, 0x20001, 0); + opCall._result = kTSTerminate; + } else { + _vm->dumpCurrSceneFiles(_vm->getCurrentScene(), opCall._callerThreadId); + _vm->exitScene(); + _vm->leavePause(_vm->getCurrentScene(), opCall._callerThreadId); + _vm->_talkItems->unpauseByTag(_vm->getCurrentScene()); + } +} + void ScriptOpcodes_Duckman::opEnterScene24(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(sceneId); @@ -249,6 +295,14 @@ void ScriptOpcodes_Duckman::opLeaveScene24(ScriptThread *scriptThread, OpCall &o _vm->leavePause(_vm->getCurrentScene(), opCall._callerThreadId); } +void ScriptOpcodes_Duckman::opPanToObject(ScriptThread *scriptThread, OpCall &opCall) { + ARG_INT16(speed); + ARG_UINT32(objectId); + Control *control = _vm->_dict->getObjectControl(objectId); + Common::Point pos = control->getActorPosition(); + _vm->_camera->panToPoint(pos, speed, opCall._threadId); +} + void ScriptOpcodes_Duckman::opStartFade(ScriptThread *scriptThread, OpCall &opCall) { ARG_INT16(arg1); ARG_INT16(arg2); @@ -266,6 +320,20 @@ void ScriptOpcodes_Duckman::opSetDisplay(ScriptThread *scriptThread, OpCall &opC _vm->_screen->setDisplayOn(flag != 0); } +void ScriptOpcodes_Duckman::opSetCameraBounds(ScriptThread *scriptThread, OpCall &opCall) { + ARG_INT16(x1); + ARG_INT16(y1); + ARG_INT16(x2); + ARG_INT16(y2); + _vm->_camera->setBounds(Common::Point(x1, y1), Common::Point(x2, y2)); +} + +void ScriptOpcodes_Duckman::opSetProperty(ScriptThread *scriptThread, OpCall &opCall) { + ARG_INT16(value); + ARG_UINT32(propertyId); + _vm->_scriptResource->_properties.set(propertyId, value != 0); +} + void ScriptOpcodes_Duckman::opPlaceActor(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(objectId); @@ -276,6 +344,26 @@ void ScriptOpcodes_Duckman::opPlaceActor(ScriptThread *scriptThread, OpCall &opC _vm->_controls->placeActor(actorTypeId, pos, sequenceId, objectId, opCall._threadId); } +void ScriptOpcodes_Duckman::opFaceActor(ScriptThread *scriptThread, OpCall &opCall) { + ARG_INT16(facing); + ARG_UINT32(objectId); + Control *control = _vm->_dict->getObjectControl(objectId); + control->faceActor(facing); +} + +void ScriptOpcodes_Duckman::opFaceActorToObject(ScriptThread *scriptThread, OpCall &opCall) { + ARG_SKIP(2); + ARG_UINT32(objectId1); + ARG_UINT32(objectId2); + Control *control1 = _vm->_dict->getObjectControl(objectId1); + Control *control2 = _vm->_dict->getObjectControl(objectId2); + Common::Point pos1 = control1->getActorPosition(); + Common::Point pos2 = control2->getActorPosition(); + uint facing; + if (_vm->calcPointDirection(pos1, pos2, facing)) + control1->faceActor(facing); +} + void ScriptOpcodes_Duckman::opStartSequenceActor(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(objectId); @@ -285,6 +373,37 @@ void ScriptOpcodes_Duckman::opStartSequenceActor(ScriptThread *scriptThread, OpC control->startSequenceActor(sequenceId, 2, opCall._threadId); } +void ScriptOpcodes_Duckman::opStartMoveActor(ScriptThread *scriptThread, OpCall &opCall) { + ARG_SKIP(2); + ARG_UINT32(objectId); + ARG_UINT32(sequenceId); + ARG_UINT32(namedPointId); + // NOTE Skipped checking for stalled sequence, not sure if needed + Control *control = _vm->_dict->getObjectControl(objectId); + Common::Point pos = _vm->getNamedPointPosition(namedPointId); + control->startMoveActor(sequenceId, pos, opCall._callerThreadId, opCall._threadId); +} + +void ScriptOpcodes_Duckman::opStartMoveActorToObject(ScriptThread *scriptThread, OpCall &opCall) { + ARG_SKIP(2); + ARG_UINT32(objectId1); + ARG_UINT32(objectId2); + ARG_UINT32(sequenceId); + Control *control1 = _vm->_dict->getObjectControl(objectId1); + Common::Point pos; + if (objectId2 == 0x40003) { + pos = _vm->_cursor._position; + } else { + Control *control2 = _vm->_dict->getObjectControl(objectId2); + pos = control2->_feetPt; + if (control2->_actor) { + pos.x += control2->_actor->_position.x; + pos.y += control2->_actor->_position.y; + } + } + control1->startMoveActor(sequenceId, pos, opCall._callerThreadId, opCall._threadId); +} + void ScriptOpcodes_Duckman::opStartTalkThread(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(objectId); @@ -351,7 +470,7 @@ void ScriptOpcodes_Duckman::opPlayVideo(ScriptThread *scriptThread, OpCall &opCa void ScriptOpcodes_Duckman::opRunSpecialCode(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(specialCodeId); -//TODO _vm->_specialCode->run(specialCodeId, opCall); + _vm->runSpecialCode(specialCodeId, opCall); //DEBUG Resume calling thread, later done by the special code _vm->notifyThreadId(opCall._threadId); } @@ -514,21 +633,6 @@ void ScriptOpcodes_Duckman::opEndTalkThreads(ScriptThread *scriptThread, OpCall _vm->_threads->endTalkThreads(); } -void ScriptOpcodes_Duckman::opLoadResource(ScriptThread *scriptThread, OpCall &opCall) { - ARG_SKIP(2); - ARG_UINT32(resourceId); - // NOTE Skipped checking for stalled resources - uint32 sceneId = _vm->getCurrentScene(); - _vm->_resSys->loadResource(resourceId, sceneId, opCall._threadId); -} - -void ScriptOpcodes_Duckman::opUnloadResource(ScriptThread *scriptThread, OpCall &opCall) { - ARG_SKIP(2); - ARG_UINT32(resourceId); - // NOTE Skipped checking for stalled resources - _vm->_resSys->unloadResourceById(resourceId); -} - void ScriptOpcodes_Duckman::opEnterScene(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(sceneId); @@ -542,28 +646,6 @@ void ScriptOpcodes_Duckman::opEnterScene(ScriptThread *scriptThread, OpCall &opC opCall._result = kTSTerminate; } -void ScriptOpcodes_Duckman::opStartModalScene(ScriptThread *scriptThread, OpCall &opCall) { - ARG_SKIP(2); - ARG_UINT32(sceneId); - ARG_UINT32(threadId); - // NOTE Skipped checking for stalled resources - _vm->_input->discardButtons(0xFFFF); - _vm->enterPause(opCall._callerThreadId); - _vm->_talkItems->pauseByTag(_vm->getCurrentScene()); - _vm->enterScene(sceneId, opCall._callerThreadId); - _vm->startScriptThread(threadId, 0, - scriptThread->_value8, scriptThread->_valueC, scriptThread->_value10); - opCall._result = kTSSuspend; -} - -void ScriptOpcodes_Duckman::opExitModalScene(ScriptThread *scriptThread, OpCall &opCall) { - // NOTE Skipped checking for stalled resources - _vm->_input->discardButtons(0xFFFF); - _vm->exitScene(opCall._callerThreadId); - _vm->leavePause(opCall._callerThreadId); - _vm->_talkItems->unpauseByTag(_vm->getCurrentScene()); -} - void ScriptOpcodes_Duckman::opEnterCloseUpScene(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(sceneId); @@ -585,14 +667,6 @@ void ScriptOpcodes_Duckman::opPanCenterObject(ScriptThread *scriptThread, OpCall _vm->_camera->panCenterObject(objectId, speed); } -void ScriptOpcodes_Duckman::opPanToObject(ScriptThread *scriptThread, OpCall &opCall) { - ARG_INT16(speed); - ARG_UINT32(objectId); - Control *control = _vm->_dict->getObjectControl(objectId); - Common::Point pos = control->getActorPosition(); - _vm->_camera->panToPoint(pos, speed, opCall._threadId); -} - void ScriptOpcodes_Duckman::opPanToNamedPoint(ScriptThread *scriptThread, OpCall &opCall) { ARG_INT16(speed); ARG_UINT32(namedPointId); @@ -616,43 +690,6 @@ void ScriptOpcodes_Duckman::opClearBlockCounter(ScriptThread *scriptThread, OpCa _vm->_scriptResource->_blockCounters.set(index, 0); } -void ScriptOpcodes_Duckman::opSetProperty(ScriptThread *scriptThread, OpCall &opCall) { - ARG_INT16(value); - ARG_UINT32(propertyId); - _vm->_scriptResource->_properties.set(propertyId, value != 0); -} - -void ScriptOpcodes_Duckman::opFaceActor(ScriptThread *scriptThread, OpCall &opCall) { - ARG_INT16(facing); - ARG_UINT32(objectId); - Control *control = _vm->_dict->getObjectControl(objectId); - control->faceActor(facing); -} - -void ScriptOpcodes_Duckman::opFaceActorToObject(ScriptThread *scriptThread, OpCall &opCall) { - ARG_SKIP(2); - ARG_UINT32(objectId1); - ARG_UINT32(objectId2); - Control *control1 = _vm->_dict->getObjectControl(objectId1); - Control *control2 = _vm->_dict->getObjectControl(objectId2); - Common::Point pos1 = control1->getActorPosition(); - Common::Point pos2 = control2->getActorPosition(); - uint facing; - if (_vm->calcPointDirection(pos1, pos2, facing)) - control1->faceActor(facing); -} - -void ScriptOpcodes_Duckman::opStartMoveActor(ScriptThread *scriptThread, OpCall &opCall) { - ARG_SKIP(2); - ARG_UINT32(objectId); - ARG_UINT32(sequenceId); - ARG_UINT32(namedPointId); - // NOTE Skipped checking for stalled sequence, not sure if needed - Control *control = _vm->_dict->getObjectControl(objectId); - Common::Point pos = _vm->getNamedPointPosition(namedPointId); - control->startMoveActor(sequenceId, pos, opCall._callerThreadId, opCall._threadId); -} - void ScriptOpcodes_Duckman::opSetActorToNamedPoint(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(objectId); diff --git a/engines/illusions/scriptopcodes_duckman.h b/engines/illusions/scriptopcodes_duckman.h index a533d7dfbc..2a30c584f3 100644 --- a/engines/illusions/scriptopcodes_duckman.h +++ b/engines/illusions/scriptopcodes_duckman.h @@ -49,15 +49,26 @@ protected: void opStartScriptThread(ScriptThread *scriptThread, OpCall &opCall); void opNotifyThread(ScriptThread *scriptThread, OpCall &opCall); void opSuspendThread(ScriptThread *scriptThread, OpCall &opCall); + void opLoadResource(ScriptThread *scriptThread, OpCall &opCall); + void opUnloadResource(ScriptThread *scriptThread, OpCall &opCall); void opStartTimerThread(ScriptThread *scriptThread, OpCall &opCall); void opEnterScene18(ScriptThread *scriptThread, OpCall &opCall); void opChangeScene(ScriptThread *scriptThread, OpCall &opCall); + void opStartModalScene(ScriptThread *scriptThread, OpCall &opCall); + void opExitModalScene(ScriptThread *scriptThread, OpCall &opCall); void opEnterScene24(ScriptThread *scriptThread, OpCall &opCall); void opLeaveScene24(ScriptThread *scriptThread, OpCall &opCall); + void opPanToObject(ScriptThread *scriptThread, OpCall &opCall); void opStartFade(ScriptThread *scriptThread, OpCall &opCall); - void opSetDisplay(ScriptThread *scriptThread, OpCall &opCall); + void opSetDisplay(ScriptThread *scriptThread, OpCall &opCall); + void opSetCameraBounds(ScriptThread *scriptThread, OpCall &opCall); + void opSetProperty(ScriptThread *scriptThread, OpCall &opCall); void opPlaceActor(ScriptThread *scriptThread, OpCall &opCall); + void opFaceActor(ScriptThread *scriptThread, OpCall &opCall); + void opFaceActorToObject(ScriptThread *scriptThread, OpCall &opCall); void opStartSequenceActor(ScriptThread *scriptThread, OpCall &opCall); + void opStartMoveActor(ScriptThread *scriptThread, OpCall &opCall); + void opStartMoveActorToObject(ScriptThread *scriptThread, OpCall &opCall); void opStartTalkThread(ScriptThread *scriptThread, OpCall &opCall); void opAppearActor(ScriptThread *scriptThread, OpCall &opCall); void opDisappearActor(ScriptThread *scriptThread, OpCall &opCall); @@ -89,23 +100,14 @@ protected: void opStartTempScriptThread(ScriptThread *scriptThread, OpCall &opCall); void opSetThreadSceneId(ScriptThread *scriptThread, OpCall &opCall); void opEndTalkThreads(ScriptThread *scriptThread, OpCall &opCall); - void opLoadResource(ScriptThread *scriptThread, OpCall &opCall); - void opUnloadResource(ScriptThread *scriptThread, OpCall &opCall); void opEnterScene(ScriptThread *scriptThread, OpCall &opCall); - void opStartModalScene(ScriptThread *scriptThread, OpCall &opCall); - void opExitModalScene(ScriptThread *scriptThread, OpCall &opCall); void opEnterCloseUpScene(ScriptThread *scriptThread, OpCall &opCall); void opExitCloseUpScene(ScriptThread *scriptThread, OpCall &opCall); void opPanCenterObject(ScriptThread *scriptThread, OpCall &opCall); - void opPanToObject(ScriptThread *scriptThread, OpCall &opCall); void opPanToNamedPoint(ScriptThread *scriptThread, OpCall &opCall); void opPanToPoint(ScriptThread *scriptThread, OpCall &opCall); void opPanStop(ScriptThread *scriptThread, OpCall &opCall); void opClearBlockCounter(ScriptThread *scriptThread, OpCall &opCall); - void opSetProperty(ScriptThread *scriptThread, OpCall &opCall); - void opFaceActor(ScriptThread *scriptThread, OpCall &opCall); - void opFaceActorToObject(ScriptThread *scriptThread, OpCall &opCall); - void opStartMoveActor(ScriptThread *scriptThread, OpCall &opCall); void opSetActorToNamedPoint(ScriptThread *scriptThread, OpCall &opCall); void opSetSelectSfx(ScriptThread *scriptThread, OpCall &opCall); void opSetMoveSfx(ScriptThread *scriptThread, OpCall &opCall); diff --git a/engines/illusions/scriptresource.cpp b/engines/illusions/scriptresource.cpp index fb8260f4f2..90658ca165 100644 --- a/engines/illusions/scriptresource.cpp +++ b/engines/illusions/scriptresource.cpp @@ -33,7 +33,7 @@ void ScriptResourceLoader::load(Resource *resource) { ScriptResource *scriptResource = new ScriptResource(); scriptResource->load(resource); - + _vm->_scriptResource = scriptResource; } @@ -311,6 +311,9 @@ void ScriptResource::load(Resource *resource) { } } + stream.seek(0x6C); + _field6C = stream.readUint32LE(); + if (resource->_gameId == kGameIdDuckman) fixupProgInfosDuckman(); diff --git a/engines/illusions/scriptresource.h b/engines/illusions/scriptresource.h index f33ac10a41..6452c7c4c5 100644 --- a/engines/illusions/scriptresource.h +++ b/engines/illusions/scriptresource.h @@ -114,6 +114,7 @@ public: byte *getCode(uint32 codeOffs); ProgInfo *getProgInfo(uint32 index); uint32 getObjectActorTypeId(uint32 objectId); + uint32 getField6C() const { return _field6C; } public: byte *_data; uint32 _dataSize; @@ -127,6 +128,7 @@ public: uint32 _soundIds[27]; uint _objectMapCount; uint32 *_objectMap; + uint32 _field6C; void fixupProgInfosDuckman(); }; diff --git a/engines/illusions/talkthread_duckman.cpp b/engines/illusions/talkthread_duckman.cpp index 46c11c88b6..fe666a3a29 100644 --- a/engines/illusions/talkthread_duckman.cpp +++ b/engines/illusions/talkthread_duckman.cpp @@ -25,6 +25,7 @@ #include "illusions/actor.h" #include "illusions/dictionary.h" #include "illusions/input.h" +#include "illusions/screentext.h" #include "illusions/scriptman.h" #include "illusions/talkresource.h" #include "illusions/time.h" @@ -109,7 +110,7 @@ int TalkThread_Duckman::onUpdate() { _status = 4; // Fallthrough to status 4 - case 4: + case 4: if (!(_flags & 8) ) { uint32 actorTypeId = _vm->getObjectActorTypeId(_objectId); // TODO getActorTypeColor(actorTypeId, &_colorR, &_colorG, &_colorB); @@ -141,7 +142,7 @@ int TalkThread_Duckman::onUpdate() { if (!(_flags & 4) && !_vm->isVoicePlaying()) _flags |= 4; if (!(_flags & 8) && isTimerExpired(_textStartTime, _textEndTime)) { - // TODO _vm->removeText(); + _vm->_screenText->removeText(); if (_entryText && *_entryText) { refreshText(); _vm->_input->discardButtons(0x20); @@ -159,7 +160,7 @@ int TalkThread_Duckman::onUpdate() { } if (_objectId && _vm->_input->pollButton(0x20)) { if (!(_flags & 8)) { - // TODO largeObj_removeText(); + _vm->_screenText->removeText(); if (_entryText && *_entryText) refreshText(); else @@ -178,13 +179,7 @@ int TalkThread_Duckman::onUpdate() { } } } - /* - debug("8: %d", (_flags & 8) != 0); - debug("4: %d", (_flags & 4) != 0); - debug("2: %d", (_flags & 2) != 0); - */ if ((_flags & 8) && (_flags & 2) && (_flags & 4)) { -debug("TALK DONE"); _vm->_input->discardButtons(0x20); return kTSTerminate; } @@ -226,7 +221,7 @@ void TalkThread_Duckman::onTerminated() { if (!(_flags & 4)) _vm->stopVoice(); if (!(_flags & 8)) { - // TODO largeObj_removeText(); + _vm->_screenText->removeText(); } if (!(_flags & 2)) { Control *control = _vm->_dict->getObjectControl(_objectId); @@ -291,16 +286,17 @@ static char *debugW2I(byte *wstr) { } int TalkThread_Duckman::insertText() { - int charCount = 100; debug("%08X %08X [%s]", _threadId, _talkId, debugW2I(_currEntryText)); - _entryText = 0; - // TODO _vm->getDimensions1(&dimensions); - // TODO _vm->insertText(_currEntryText, 0x00120001, dimensions, 0, 2, 0, 0, _colorR, _colorG, _colorB, 0, &outTextPtr); - // TODO _vm->charCount = (char *)outTextPtr - (char *)text; - // TODO _entryText = outTextPtr; - // TODO _vm->getPoint1(&pt); - // TODO _vm->updateTextInfoPosition(pt); - return charCount >> 1; + WidthHeight dimensions; + _vm->getDefaultTextDimensions(dimensions); + uint16 *outTextPtr; + _vm->_screenText->insertText((uint16*)_currEntryText, 0x120001, dimensions, Common::Point(0, 0), 2, 0, 0, _colorR, _colorG, _colorB, outTextPtr); + _entryText = (byte*)outTextPtr; + Common::Point pt; + _vm->getDefaultTextPosition(pt); + _vm->_screenText->updateTextInfoPosition(pt); + int charCount = (_entryText - _currEntryText) / 2; + return charCount; } TalkEntry *TalkThread_Duckman::getTalkResourceEntry(uint32 talkId) { diff --git a/engines/illusions/textdrawer.cpp b/engines/illusions/textdrawer.cpp new file mode 100644 index 0000000000..d3f9379aa9 --- /dev/null +++ b/engines/illusions/textdrawer.cpp @@ -0,0 +1,195 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "illusions/illusions.h" +#include "illusions/textdrawer.h" +#include "illusions/screen.h" + +namespace Illusions { + +bool TextDrawer::wrapText(FontResource *font, uint16 *text, WidthHeight *dimensions, Common::Point offsPt, + uint textFlags, uint16 *&outTextPtr) { + _font = font; + _text = text; + _dimensions = dimensions; + _offsPt = offsPt; + _textFlags = textFlags; + // TODO Calc max width/height using textFlags (border, shadow) + _textLines.clear(); + bool done = wrapTextIntern(0, 0, dimensions->_width, dimensions->_height, outTextPtr); + // TODO Adjust text dimensions + return done; +} + +void TextDrawer::drawText(Screen *screen, Graphics::Surface *surface, uint16 color2, uint16 color1) { + // TODO Fill box, draw borders and shadow if flags are set + for (Common::Array<TextLine>::iterator it = _textLines.begin(); it != _textLines.end(); ++it) { + const TextLine &textLine = *it; + if (textLine._text) + screen->drawText(_font, surface, textLine._x, textLine._y, textLine._text, textLine._length); +#if 0 + for (int16 linePos = 0; linePos < textLine._length; ++linePos) { + const uint16 c = textLine._text[linePos]; + debugN("%c", c); + } + debug(" "); +#endif + } +} + +bool TextDrawer::wrapTextIntern(int16 x, int16 y, int16 maxWidth, int16 maxHeight, uint16 *&outTextPtr) { + + bool lineBreak = false; + bool done = false; + bool hasChar13 = textHasChar(13); + + uint16 *lineStartText = _text; + uint16 *currText = _text; + outTextPtr = _text; + + int16 textPosY = y; + int16 currLineWidth = 0, currLineLen = 0; + int16 currWordWidth = 0, currWordLen = 0; + int16 maxLineWidth = 0; + int16 spaceWidth = getSpaceWidth(); + + while (*currText && !done) { + + currWordWidth = 0; + currWordLen = 0; + do { + currWordWidth += getCharWidth(*currText); + ++currText; + ++currWordLen; + } while (*currText != 32 && *(currText - 1) != 32 && !hasChar13 && *currText != 13 && *currText); + + if (currWordWidth - _font->_widthC > maxWidth) { + while (currWordWidth + currLineWidth - _font->_widthC > maxWidth) { + --currText; + --currWordLen; + currWordWidth -= getCharWidth(*currText); + } + lineBreak = true; + } + + if (!lineBreak && currWordWidth + currLineWidth - _font->_widthC > maxWidth) { + lineBreak = true; + } else { + currLineWidth += currWordWidth; + currLineLen += currWordLen; + if (*currText == 0 || *currText == 13) + lineBreak = true; + if (lineBreak) { + currWordLen = 0; + currWordWidth = 0; + } + } + + while (lineBreak) { + + currLineWidth -= _font->_widthC; + + if (textPosY + _font->_charHeight <= maxHeight) { + int16 textPosX; + + if (_textFlags & 2) { + textPosX = (_dimensions->_width - currLineWidth) / 2; + maxLineWidth = _dimensions->_width; + } else { + textPosX = x; + } + + _textLines.push_back(TextLine(lineStartText, currLineLen, textPosX, textPosY)); + + if (*currText == 13) { + ++currText; + if (*currText == 10) + ++currText; + while (*currText == 13) { + ++currText; + if (*currText == 10) + ++currText; + _textLines.push_back(TextLine()); + textPosY += _font->_lineIncr + _font->_charHeight; + } + lineStartText = currText; + } else { + lineStartText = currText - currWordLen; + if (*lineStartText == 32) { + ++lineStartText; + --currWordLen; + currWordWidth -= spaceWidth; + } + } + + outTextPtr = lineStartText; + + if (maxLineWidth < currLineWidth) + maxLineWidth = currLineWidth; + + currLineWidth = currWordWidth; + currLineLen = currWordLen; + currWordWidth = 0; + currWordLen = 0; + textPosY += _font->_charHeight + _font->_lineIncr; + if (*currText || !currLineLen) + lineBreak = false; + + } else { + lineBreak = false; + done = true; + } + } + + } + + _dimensions->_width = maxLineWidth; + _dimensions->_height = textPosY - _font->_lineIncr; + + return !done; +} + +bool TextDrawer::textHasChar(uint16 c) { + // TODO + return false; +} + +int16 TextDrawer::getSpaceWidth() { + return getCharWidth(32); +} + +int16 TextDrawer::getCharWidth(uint16 c) { + return _font->getCharInfo(c)->_width + _font->_widthC; +} + +// TODO +/* +int16 offsX = (int16)(offsPt.x * 0.75); +int16 offsY = (int16)(offsPt.y * 1.5); +*/ +/* +if (_surface) + drawChar(textPosX, textPosY, c); +textPosX += getCharWidth(c); +*/ + +} // End of namespace Illusions diff --git a/engines/illusions/textdrawer.h b/engines/illusions/textdrawer.h new file mode 100644 index 0000000000..a5f6102d28 --- /dev/null +++ b/engines/illusions/textdrawer.h @@ -0,0 +1,68 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ILLUSIONS_TEXTDRAWER_H +#define ILLUSIONS_TEXTDRAWER_H + +#include "illusions/graphics.h" +#include "illusions/fontresource.h" +#include "common/array.h" +#include "common/rect.h" +#include "graphics/surface.h" + +namespace Illusions { + +class IllusionsEngine; + +struct TextLine { + uint16 *_text; + int16 _length; + int16 _x, _y; + TextLine() : _text(0) {} + TextLine(uint16 *text, int16 length, int16 x, int16 y) + : _text(text), _length(length), _x(x), _y(y) {} +}; + +class TextDrawer { +public: + bool wrapText(FontResource *font, uint16 *text, WidthHeight *dimensions, Common::Point offsPt, + uint textFlags, uint16 *&outTextPtr); + void drawText(Screen *screen, Graphics::Surface *surface, uint16 color2, uint16 color1); +protected: + FontResource *_font; + uint16 *_text; + WidthHeight *_dimensions; + Common::Point _offsPt; + uint _textFlags; + Graphics::Surface *_surface; + + Common::Array<TextLine> _textLines; + + bool textHasChar(uint16 c); + int16 getSpaceWidth(); + int16 getCharWidth(uint16 c); + bool wrapTextIntern(int16 x, int16 y, int16 maxWidth, int16 maxHeight, uint16 *&outTextPtr); +}; + +} // End of namespace Illusions + +#endif // ILLUSIONS_TALKRESOURCE_H diff --git a/engines/illusions/thread.h b/engines/illusions/thread.h index e9a9ec3f3f..3a335a27bf 100644 --- a/engines/illusions/thread.h +++ b/engines/illusions/thread.h @@ -34,7 +34,8 @@ enum ThreadType { kTTTimerThread = 2, kTTTalkThread = 3, kTTAbortableThread = 4, - kTTSpecialThread = 5 + kTTSpecialThread = 5, + kTTCauseThread = 6 }; enum ThreadStatus { |