diff options
author | Max Horn | 2006-02-11 22:45:04 +0000 |
---|---|---|
committer | Max Horn | 2006-02-11 22:45:04 +0000 |
commit | 26ee630756ebdd7c96bccede0881a8c8b98e8f2b (patch) | |
tree | 26e378d5cf990a2b81c2c96e9e683a7f333b62e8 /sword2 | |
parent | 2a9a0d4211b1ea5723f1409d91cb95de8984429e (diff) | |
download | scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.gz scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.bz2 scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.zip |
Moved engines to the new engines/ directory
svn-id: r20582
Diffstat (limited to 'sword2')
55 files changed, 0 insertions, 23606 deletions
diff --git a/sword2/_mouse.cpp b/sword2/_mouse.cpp deleted file mode 100644 index db0cf00f73..0000000000 --- a/sword2/_mouse.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "common/system.h" -#include "common/stream.h" - -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/mouse.h" - -namespace Sword2 { - -// This is the maximum mouse cursor size in the SDL backend -#define MAX_MOUSE_W 80 -#define MAX_MOUSE_H 80 - -#define MOUSEFLASHFRAME 6 - -void Mouse::decompressMouse(byte *decomp, byte *comp, uint8 frame, int width, int height, int pitch, int xOff, int yOff) { - int32 size = width * height; - int32 i = 0; - int x = 0; - int y = 0; - - comp = comp + READ_LE_UINT32(comp + frame * 4) - MOUSE_ANIM_HEADER_SIZE; - - while (i < size) { - if (*comp > 183) { - decomp[(y + yOff) * pitch + x + xOff] = *comp++; - if (++x >= width) { - x = 0; - y++; - } - i++; - } else { - x += *comp; - while (x >= width) { - y++; - x -= width; - } - i += *comp++; - } - } -} - -void Mouse::drawMouse() { - byte mouseData[MAX_MOUSE_W * MAX_MOUSE_H]; - - if (!_mouseAnim.data && !_luggageAnim.data) - return; - - // When an object is used in the game, the mouse cursor should be a - // combination of a standard mouse cursor and a luggage cursor. - // - // However, judging by the original code luggage cursors can also - // appear on their own. I have no idea which cases though. - - uint16 mouse_width = 0; - uint16 mouse_height = 0; - uint16 hotspot_x = 0; - uint16 hotspot_y = 0; - int deltaX = 0; - int deltaY = 0; - - if (_mouseAnim.data) { - hotspot_x = _mouseAnim.xHotSpot; - hotspot_y = _mouseAnim.yHotSpot; - mouse_width = _mouseAnim.mousew; - mouse_height = _mouseAnim.mouseh; - } - - if (_luggageAnim.data) { - if (!_mouseAnim.data) { - hotspot_x = _luggageAnim.xHotSpot; - hotspot_y = _luggageAnim.yHotSpot; - } - if (_luggageAnim.mousew > mouse_width) - mouse_width = _luggageAnim.mousew; - if (_luggageAnim.mouseh > mouse_height) - mouse_height = _luggageAnim.mouseh; - } - - if (_mouseAnim.data && _luggageAnim.data) { - deltaX = _mouseAnim.xHotSpot - _luggageAnim.xHotSpot; - deltaY = _mouseAnim.yHotSpot - _luggageAnim.yHotSpot; - } - - assert(deltaX >= 0); - assert(deltaY >= 0); - - // HACK for maximum cursor size. (The SDL backend imposes this - // restriction) - - if (mouse_width + deltaX > MAX_MOUSE_W) - deltaX = 80 - mouse_width; - if (mouse_height + deltaY > MAX_MOUSE_H) - deltaY = 80 - mouse_height; - - mouse_width += deltaX; - mouse_height += deltaY; - - if ((uint32)(mouse_width * mouse_height) > sizeof(mouseData)) { - warning("Mouse cursor too large"); - return; - } - - memset(mouseData, 0, mouse_width * mouse_height); - - if (_luggageAnim.data) - decompressMouse(mouseData, _luggageAnim.data, 0, - _luggageAnim.mousew, _luggageAnim.mouseh, - mouse_width, deltaX, deltaY); - - if (_mouseAnim.data) - decompressMouse(mouseData, _mouseAnim.data, _mouseFrame, - _mouseAnim.mousew, _mouseAnim.mouseh, mouse_width); - - _vm->_system->setMouseCursor(mouseData, mouse_width, mouse_height, hotspot_x, hotspot_y, 0); -} - -/** - * Animates the current mouse pointer - */ - -int32 Mouse::animateMouse() { - uint8 prevMouseFrame = _mouseFrame; - - if (!_mouseAnim.data) - return RDERR_UNKNOWN; - - if (++_mouseFrame == _mouseAnim.noAnimFrames) - _mouseFrame = MOUSEFLASHFRAME; - - if (_mouseFrame != prevMouseFrame) - drawMouse(); - - return RD_OK; -} - -/** - * Sets the mouse cursor animation. - * @param ma a pointer to the animation data, or NULL to clear the current one - * @param size the size of the mouse animation data - * @param mouseFlash RDMOUSE_FLASH or RDMOUSE_NOFLASH, depending on whether - * or not there is a lead-in animation - */ - -int32 Mouse::setMouseAnim(byte *ma, int32 size, int32 mouseFlash) { - free(_mouseAnim.data); - _mouseAnim.data = NULL; - - if (ma) { - if (mouseFlash == RDMOUSE_FLASH) - _mouseFrame = 0; - else - _mouseFrame = MOUSEFLASHFRAME; - - Common::MemoryReadStream readS(ma, size); - - _mouseAnim.runTimeComp = readS.readByte(); - _mouseAnim.noAnimFrames = readS.readByte(); - _mouseAnim.xHotSpot = readS.readSByte(); - _mouseAnim.yHotSpot = readS.readSByte(); - _mouseAnim.mousew = readS.readByte(); - _mouseAnim.mouseh = readS.readByte(); - - _mouseAnim.data = (byte *)malloc(size - MOUSE_ANIM_HEADER_SIZE); - if (!_mouseAnim.data) - return RDERR_OUTOFMEMORY; - - readS.read(_mouseAnim.data, size - MOUSE_ANIM_HEADER_SIZE); - - animateMouse(); - drawMouse(); - - _vm->_system->showMouse(true); - } else { - if (_luggageAnim.data) - drawMouse(); - else - _vm->_system->showMouse(false); - } - - return RD_OK; -} - -/** - * Sets the "luggage" animation to accompany the mouse animation. Luggage - * sprites are of the same format as mouse sprites. - * @param ma a pointer to the animation data, or NULL to clear the current one - * @param size the size of the animation data - */ - -int32 Mouse::setLuggageAnim(byte *ma, int32 size) { - free(_luggageAnim.data); - _luggageAnim.data = NULL; - - if (ma) { - Common::MemoryReadStream readS(ma, size); - - _luggageAnim.runTimeComp = readS.readByte(); - _luggageAnim.noAnimFrames = readS.readByte(); - _luggageAnim.xHotSpot = readS.readSByte(); - _luggageAnim.yHotSpot = readS.readSByte(); - _luggageAnim.mousew = readS.readByte(); - _luggageAnim.mouseh = readS.readByte(); - - _luggageAnim.data = (byte *)malloc(size - MOUSE_ANIM_HEADER_SIZE); - if (!_luggageAnim.data) - return RDERR_OUTOFMEMORY; - - readS.read(_luggageAnim.data, size - MOUSE_ANIM_HEADER_SIZE); - - animateMouse(); - drawMouse(); - - _vm->_system->showMouse(true); - } else { - if (_mouseAnim.data) - drawMouse(); - else - _vm->_system->showMouse(false); - } - - return RD_OK; -} - -} // End of namespace Sword2 diff --git a/sword2/animation.cpp b/sword2/animation.cpp deleted file mode 100644 index 2ba5df6792..0000000000 --- a/sword2/animation.cpp +++ /dev/null @@ -1,535 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "common/file.h" -#include "common/config-manager.h" -#include "common/system.h" -#include "sound/vorbis.h" -#include "sound/mp3.h" - -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/maketext.h" -#include "sword2/resman.h" -#include "sword2/sound.h" -#include "sword2/animation.h" - -namespace Sword2 { - -AnimationState::AnimationState(Sword2Engine *vm) - : BaseAnimationState(vm->_mixer, vm->_system, 640, 480), _vm(vm) { -} - -AnimationState::~AnimationState() { -} - -#ifdef BACKEND_8BIT - -void AnimationState::setPalette(byte *pal) { - _vm->_screen->setPalette(0, 256, pal, RDPAL_INSTANT); -} - -#else - -void AnimationState::drawTextObject(SpriteInfo *s, byte *src) { - OverlayColor *dst = _overlay + RENDERWIDE * s->y + s->x; - - // FIXME: These aren't the "right" colours, but look good to me. - - OverlayColor pen = _sys->RGBToColor(255, 255, 255); - OverlayColor border = _sys->RGBToColor(0, 0, 0); - - for (int y = 0; y < s->h; y++) { - for (int x = 0; x < s->w; x++) { - switch (src[x]) { - case 1: - dst[x] = border; - break; - case 255: - dst[x] = pen; - break; - default: - break; - } - } - dst += RENDERWIDE; - src += s->w; - } -} - -#endif - -void AnimationState::clearScreen() { -#ifdef BACKEND_8BIT - memset(_vm->_screen->getScreen(), 0, _movieWidth * _movieHeight); -#else - OverlayColor black = _sys->RGBToColor(0, 0, 0); - - for (int i = 0; i < _movieWidth * _movieHeight; i++) - _overlay[i] = black; -#endif -} - -void AnimationState::updateScreen() { -#ifdef BACKEND_8BIT - byte *buf = _vm->_screen->getScreen() + ((480 - _movieHeight) / 2) * RENDERWIDE + (640 - _movieWidth) / 2; - - _vm->_system->copyRectToScreen(buf, _movieWidth, (640 - _movieWidth) / 2, (480 - _movieHeight) / 2, _movieWidth, _movieHeight); -#else - _sys->copyRectToOverlay(_overlay, _movieWidth, 0, 0, _movieWidth, _movieHeight); -#endif - _vm->_system->updateScreen(); -} - -void AnimationState::drawYUV(int width, int height, byte *const *dat) { -#ifdef BACKEND_8BIT - _vm->_screen->plotYUV(_lut, width, height, dat); -#else - plotYUV(width, height, dat); -#endif -} - -MovieInfo MoviePlayer::_movies[] = { - { "carib", 222, false }, - { "escape", 187, false }, - { "eye", 248, false }, - { "finale", 1485, false }, - { "guard", 75, false }, - { "intro", 1800, false }, - { "jungle", 186, false }, - { "museum", 167, false }, - { "pablo", 75, false }, - { "pyramid", 60, false }, - { "quaram", 184, false }, - { "river", 656, false }, - { "sailing", 138, false }, - { "shaman", 788, true }, - { "stone1", 34, false }, - { "stone2", 282, false }, - { "stone3", 65, false }, - { "demo", 60, false }, - { "enddemo", 110, false } -}; - -MoviePlayer::MoviePlayer(Sword2Engine *vm) - : _vm(vm), _snd(_vm->_mixer), _sys(_vm->_system), _textSurface(NULL) { -} - -void MoviePlayer::openTextObject(MovieTextObject *obj) { - if (obj->textSprite) - _vm->_screen->createSurface(obj->textSprite, &_textSurface); -} - -void MoviePlayer::closeTextObject(MovieTextObject *obj) { - if (_textSurface) { - _vm->_screen->deleteSurface(_textSurface); - _textSurface = NULL; - } -} - -void MoviePlayer::drawTextObject(AnimationState *anim, MovieTextObject *obj) { - if (obj->textSprite && _textSurface) { -#ifdef BACKEND_8BIT - _vm->_screen->drawSurface(obj->textSprite, _textSurface); -#else - if (anim) - anim->drawTextObject(obj->textSprite, _textSurface); - else - _vm->_screen->drawSurface(obj->textSprite, _textSurface); -#endif - } -} - -/** - * Plays an animated cutscene. - * @param filename the file name of the cutscene file - * @param text the subtitles and voiceovers for the cutscene - * @param leadInRes lead-in music resource id - * @param leadOutRes lead-out music resource id - */ - -int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], int32 leadInRes, int32 leadOutRes) { - Audio::SoundHandle leadInHandle; - - // This happens if the user quits during the "eye" smacker - if (_vm->_quit) - return RD_OK; - - if (leadInRes) { - byte *leadIn = _vm->_resman->openResource(leadInRes); - uint32 leadInLen = _vm->_resman->fetchLen(leadInRes) - ResHeader::size(); - - assert(_vm->_resman->fetchType(leadIn) == WAV_FILE); - - leadIn += ResHeader::size(); - - _vm->_sound->playFx(&leadInHandle, leadIn, leadInLen, Audio::Mixer::kMaxChannelVolume, 0, false, Audio::Mixer::kMusicSoundType); - } - - byte *leadOut = NULL; - uint32 leadOutLen = 0; - - if (leadOutRes) { - leadOut = _vm->_resman->openResource(leadOutRes); - leadOutLen = _vm->_resman->fetchLen(leadOutRes) - ResHeader::size(); - - assert(_vm->_resman->fetchType(leadOut) == WAV_FILE); - - leadOut += ResHeader::size(); - } - - _leadOutFrame = (uint)-1; - - int i; - - for (i = 0; i < ARRAYSIZE(_movies); i++) { - if (scumm_stricmp(filename, _movies[i].name) == 0) { - _seamless = _movies[i].seamless; - if (_movies[i].frames > 60) - _leadOutFrame = _movies[i].frames - 60; - break; - } - } - - if (i == ARRAYSIZE(_movies)) - warning("Unknown movie, '%s'", filename); - -#ifdef USE_MPEG2 - playMPEG(filename, text, leadOut, leadOutLen); -#else - // No MPEG2? Use the old 'Narration Only' hack - playDummy(filename, text, leadOut, leadOutLen); -#endif - - _snd->stopHandle(leadInHandle); - - // Wait for the lead-out to stop, if there is any. Though don't do it - // for seamless movies, since they are meant to blend into the rest of - // the game. - - if (!_seamless) { - while (_vm->_mixer->isSoundHandleActive(_leadOutHandle)) { - _vm->_screen->updateDisplay(); - _vm->_system->delayMillis(30); - } - } - - if (leadInRes) - _vm->_resman->closeResource(leadInRes); - - if (leadOutRes) - _vm->_resman->closeResource(leadOutRes); - - return RD_OK; -} - -void MoviePlayer::playMPEG(const char *filename, MovieTextObject *text[], byte *leadOut, uint32 leadOutLen) { - uint frameCounter = 0, textCounter = 0; - Audio::SoundHandle handle; - bool skipCutscene = false, textVisible = false; - uint32 flags = Audio::Mixer::FLAG_16BITS; - bool startNextText = false; - - byte oldPal[256 * 4]; - memcpy(oldPal, _vm->_screen->getPalette(), sizeof(oldPal)); - - AnimationState *anim = new AnimationState(_vm); - - if (!anim->init(filename)) { - delete anim; - // Missing Files? Use the old 'Narration Only' hack - playDummy(filename, text, leadOut, leadOutLen); - return; - } - - // Clear the screen, because whatever is on it will be visible when the - // overlay is removed. And if there isn't an overlay, we don't want it - // to be visible during the cutscene. (Not all cutscenes cover the - // entire screen.) - _vm->_screen->clearScene(); - _vm->_screen->updateDisplay(); - -#ifndef SCUMM_BIG_ENDIAN - flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN; -#endif - - while (!skipCutscene && anim->decodeFrame()) { - // The frame has been drawn. Now draw the subtitles, if any, - // before updating the screen. - - if (text && text[textCounter]) { - if (frameCounter == text[textCounter]->startFrame) { - openTextObject(text[textCounter]); - textVisible = true; - - if (text[textCounter]->speech) { - startNextText = true; - } - } - - if (startNextText && !_snd->isSoundHandleActive(handle)) { - _snd->playRaw(&handle, text[textCounter]->speech, text[textCounter]->speechBufferSize, 22050, flags); - startNextText = false; - } - - if (frameCounter == text[textCounter]->endFrame) { - closeTextObject(text[textCounter]); - textCounter++; - textVisible = false; - } - - if (textVisible) - drawTextObject(anim, text[textCounter]); - } - - anim->updateScreen(); - frameCounter++; - - if (frameCounter == _leadOutFrame && leadOut) - _vm->_sound->playFx(&_leadOutHandle, leadOut, leadOutLen, Audio::Mixer::kMaxChannelVolume, 0, false, Audio::Mixer::kMusicSoundType); - - OSystem::Event event; - while (_sys->pollEvent(event)) { - switch (event.type) { -#ifndef BACKEND_8BIT - case OSystem::EVENT_SCREEN_CHANGED: - anim->buildLookup(); - break; -#endif - case OSystem::EVENT_KEYDOWN: - if (event.kbd.keycode == 27) - skipCutscene = true; - break; - case OSystem::EVENT_QUIT: - _vm->closeGame(); - skipCutscene = true; - break; - default: - break; - } - } - } - - if (!skipCutscene) { - // Sleep for one frame so that the last frame is displayed. - _sys->delayMillis(1000 / 12); - } - - if (!_seamless) { - // Most movies fade to black on their own, but not all of them. - // Since we may be hanging around in the cutscene player for a - // while longer, waiting for the lead-out sound to finish, - // paint the overlay black. - - anim->clearScreen(); - } - - // If the speech is still playing, redraw the subtitles. At least in - // the English version this is most noticeable in the "carib" cutscene. - - if (textVisible && _snd->isSoundHandleActive(handle)) - drawTextObject(anim, text[textCounter]); - - if (text) - closeTextObject(text[textCounter]); - - anim->updateScreen(); - - // Wait for the voice to stop playing. This is to make sure that we - // don't cut off the speech in mid-sentence, and - even more - // importantly - that we don't free the sound buffer while it's in use. - - if (skipCutscene) - _snd->stopHandle(handle); - - while (_snd->isSoundHandleActive(handle)) { - _vm->_screen->updateDisplay(false); - _sys->delayMillis(100); - } - - if (!_seamless) { - // Clear the screen again - anim->clearScreen(); - anim->updateScreen(); - } - - _vm->_screen->setPalette(0, 256, oldPal, RDPAL_INSTANT); - - delete anim; -} - -/** - * This just plays the cutscene with voiceovers / subtitles, in case the files - * are missing. - */ - -void MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], byte *leadOut, uint32 leadOutLen) { - if (!text) - return; - - int frameCounter = 0, textCounter = 0; - - byte oldPal[256 * 4]; - byte tmpPal[256 * 4]; - - _vm->_screen->clearScene(); - - // HACK: Draw instructions - // - // I'm using the the menu area, because that's unlikely to be touched - // by anything else during the cutscene. - - memset(_vm->_screen->getScreen(), 0, _vm->_screen->getScreenWide() * MENUDEEP); - - byte *data; - - // Russian version substituted latin characters with cyrillic. That's - // why it renders completely unreadable with default message - if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS) { - byte msg[] = "Po\344uk - to\344\345ko pev\345: hagmute k\344abuwy Ucke\343n, u\344u nocetute ca\343t npoekta u ckava\343te budeo po\344uku"; - data = _vm->_fontRenderer->makeTextSprite(msg, RENDERWIDE, 255, _vm->_speechFontId); - } else { - // TODO: Translate message to other languages? -#ifdef USE_MPEG2 - byte msg[] = "Cutscene - Narration Only: Press ESC to exit, or visit www.scummvm.org to download cutscene videos"; -#else - byte msg[] = "Cutscene - Narration Only: Press ESC to exit, or recompile ScummVM with MPEG2 support"; -#endif - - data = _vm->_fontRenderer->makeTextSprite(msg, RENDERWIDE, 255, _vm->_speechFontId); - } - - FrameHeader frame_head; - SpriteInfo msgSprite; - byte *msgSurface; - - frame_head.read(data); - - msgSprite.x = _vm->_screen->getScreenWide() / 2 - frame_head.width / 2; - msgSprite.y = MENUDEEP / 2 - frame_head.height / 2; - msgSprite.w = frame_head.width; - msgSprite.h = frame_head.height; - msgSprite.type = RDSPR_NOCOMPRESSION; - msgSprite.data = data + FrameHeader::size(); - - _vm->_screen->createSurface(&msgSprite, &msgSurface); - _vm->_screen->drawSurface(&msgSprite, msgSurface); - _vm->_screen->deleteSurface(msgSurface); - - free(data); - - // In case the cutscene has a long lead-in, start just before the first - // line of text. - - frameCounter = text[0]->startFrame - 12; - - // Fake a palette that will hopefully make the text visible. In the - // opening cutscene it seems to use colours 1 (black) and 255 (white). - - memcpy(oldPal, _vm->_screen->getPalette(), sizeof(oldPal)); - memset(tmpPal, 0, sizeof(tmpPal)); - tmpPal[255 * 4 + 0] = 255; - tmpPal[255 * 4 + 1] = 255; - tmpPal[255 * 4 + 2] = 255; - _vm->_screen->setPalette(0, 256, tmpPal, RDPAL_INSTANT); - - Audio::SoundHandle handle; - - bool skipCutscene = false; - - uint32 flags = Audio::Mixer::FLAG_16BITS; - -#ifndef SCUMM_BIG_ENDIAN - flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN; -#endif - - while (1) { - if (!text[textCounter]) - break; - - if (frameCounter == text[textCounter]->startFrame) { - _vm->_screen->clearScene(); - openTextObject(text[textCounter]); - drawTextObject(NULL, text[textCounter]); - if (text[textCounter]->speech) { - _snd->playRaw(&handle, text[textCounter]->speech, text[textCounter]->speechBufferSize, 22050, flags); - } - } - - if (frameCounter == text[textCounter]->endFrame) { - closeTextObject(text[textCounter]); - _vm->_screen->clearScene(); - _vm->_screen->setNeedFullRedraw(); - textCounter++; - } - - frameCounter++; - _vm->_screen->updateDisplay(); - - KeyboardEvent *ke = _vm->keyboardEvent(); - - if ((ke && ke->keycode == 27) || _vm->_quit) { - _snd->stopHandle(handle); - skipCutscene = true; - break; - } - - // Simulate ~12 frames per second. I don't know what frame rate - // the original movies had, or even if it was constant, but - // this seems to work reasonably. - - _sys->delayMillis(90); - } - - // Wait for the voice to stop playing. This is to make sure that we - // don't cut off the speech in mid-sentence, and - even more - // importantly - that we don't free the sound buffer while it's in use. - - while (_snd->isSoundHandleActive(handle)) { - _vm->_screen->updateDisplay(false); - _sys->delayMillis(100); - } - - closeTextObject(text[textCounter]); - - _vm->_screen->clearScene(); - _vm->_screen->setNeedFullRedraw(); - - // HACK: Remove the instructions created above - Common::Rect r; - - memset(_vm->_screen->getScreen(), 0, _vm->_screen->getScreenWide() * MENUDEEP); - r.left = r.top = 0; - r.right = _vm->_screen->getScreenWide(); - r.bottom = MENUDEEP; - _vm->_screen->updateRect(&r); - - // FIXME: For now, only play the lead-out music for cutscenes that have - // subtitles. - - if (!skipCutscene && leadOut) - _vm->_sound->playFx(&_leadOutHandle, leadOut, leadOutLen, Audio::Mixer::kMaxChannelVolume, 0, false, Audio::Mixer::kMusicSoundType); - - _vm->_screen->setPalette(0, 256, oldPal, RDPAL_INSTANT); -} - -} // End of namespace Sword2 diff --git a/sword2/animation.h b/sword2/animation.h deleted file mode 100644 index e3a554ccd7..0000000000 --- a/sword2/animation.h +++ /dev/null @@ -1,103 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#ifndef ANIMATION_H -#define ANIMATION_H - -#include "graphics/animation.h" -#include "sound/mixer.h" - -namespace Sword2 { - -struct SpriteInfo; - -// This is the structure which is passed to the sequence player. It includes -// the smack to play, and any text lines which are to be displayed over the top -// of the sequence. - -struct MovieTextObject { - uint16 startFrame; - uint16 endFrame; - SpriteInfo *textSprite; - uint32 speechBufferSize; - uint16 *speech; -}; - -class AnimationState : public ::Graphics::BaseAnimationState { -private: - Sword2Engine *_vm; - -public: - AnimationState(Sword2Engine *vm); - ~AnimationState(); - -#ifndef BACKEND_8BIT - void drawTextObject(SpriteInfo *s, byte *src); -#endif - - void clearScreen(); - void updateScreen(); - -private: - void drawYUV(int width, int height, byte *const *dat); - -#ifdef BACKEND_8BIT - void setPalette(byte *pal); -#endif -}; - -struct MovieInfo { - char name[9]; - uint frames; - bool seamless; -}; - -class MoviePlayer { -private: - Sword2Engine *_vm; - Audio::Mixer *_snd; - OSystem *_sys; - - byte *_textSurface; - - Audio::SoundHandle _leadOutHandle; - - uint _leadOutFrame; - bool _seamless; - - static struct MovieInfo _movies[]; - - void openTextObject(MovieTextObject *obj); - void closeTextObject(MovieTextObject *obj); - void drawTextObject(AnimationState *anim, MovieTextObject *obj); - - void playMPEG(const char *filename, MovieTextObject *text[], byte *leadOut, uint32 leadOutLen); - void playDummy(const char *filename, MovieTextObject *text[], byte *leadOut, uint32 leadOutLen); - -public: - MoviePlayer(Sword2Engine *vm); - int32 play(const char *filename, MovieTextObject *text[], int32 leadInRes, int32 leadOutRes); -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/anims.cpp b/sword2/anims.cpp deleted file mode 100644 index e64903a61f..0000000000 --- a/sword2/anims.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -// --------------------------------------------------------------------------- -// A more intelligent version of the old ANIMS.C -// All this stuff by James -// DON'T TOUCH! -// --------------------------------------------------------------------------- - -#include "common/stdafx.h" -#include "common/file.h" - -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/build_display.h" -#include "sword2/interpreter.h" -#include "sword2/logic.h" -#include "sword2/maketext.h" -#include "sword2/resman.h" -#include "sword2/router.h" -#include "sword2/sound.h" -#include "sword2/animation.h" - -namespace Sword2 { - -int Router::doAnimate(byte *ob_logic, byte *ob_graph, int32 animRes, bool reverse) { - AnimHeader anim_head; - byte *anim_file; - - ObjectLogic obLogic(ob_logic); - ObjectGraphic obGraph(ob_graph); - - if (obLogic.getLooping() == 0) { - byte *ptr; - - // This is the start of the anim - set up the first frame - - // For testing all anims! - // A script loop can send every resource number to the anim - // function & it will only run the valid ones. See - // 'testing_routines' object in George's Player Character - // section of linc - - if (_vm->_logic->readVar(SYSTEM_TESTING_ANIMS)) { - if (!_vm->_resman->checkValid(animRes)) { - // Not a valid resource number. Switch off - // the sprite. Don't animate - just continue - // script next cycle. - setSpriteStatus(ob_graph, NO_SPRITE); - return IR_STOP; - } - - ptr = _vm->_resman->openResource(animRes); - - // if it's not an animation file - if (_vm->_resman->fetchType(animRes) != ANIMATION_FILE) { - _vm->_resman->closeResource(animRes); - - // switch off the sprite - // don't animate - just continue - // script next cycle - setSpriteStatus(ob_graph, NO_SPRITE); - return IR_STOP; - } - - _vm->_resman->closeResource(animRes); - - // switch on the sprite - setSpriteStatus(ob_graph, SORT_SPRITE); - } - - assert(animRes); - - // open anim file - anim_file = _vm->_resman->openResource(animRes); - - assert(_vm->_resman->fetchType(animRes) == ANIMATION_FILE); - - // point to anim header - anim_head.read(_vm->fetchAnimHeader(anim_file)); - - // now running an anim, looping back to this call again - obLogic.setLooping(1); - obGraph.setAnimResource(animRes); - - if (reverse) - obGraph.setAnimPc(anim_head.noAnimFrames - 1); - else - obGraph.setAnimPc(0); - } else if (_vm->_logic->getSync() != -1) { - // We've received a sync - return to script immediately - debug(5, "**sync stopped %d**", _vm->_logic->readVar(ID)); - - // If sync received, anim finishes right now (remaining on - // last frame). Quit animation, but continue script. - obLogic.setLooping(0); - return IR_CONT; - } else { - // Not first frame, and no sync received - set up the next - // frame of the anim. - - // open anim file and point to anim header - anim_file = _vm->_resman->openResource(obGraph.getAnimResource()); - anim_head.read(_vm->fetchAnimHeader(anim_file)); - - if (reverse) - obGraph.setAnimPc(obGraph.getAnimPc() - 1); - else - obGraph.setAnimPc(obGraph.getAnimPc() + 1); - } - - // check for end of anim - - if (reverse) { - if (obGraph.getAnimPc() == 0) - obLogic.setLooping(0); - } else { - if (obGraph.getAnimPc() == anim_head.noAnimFrames - 1) - obLogic.setLooping(0); - } - - // close the anim file - _vm->_resman->closeResource(obGraph.getAnimResource()); - - // check if we want the script to loop back & call this function again - return obLogic.getLooping() ? IR_REPEAT : IR_STOP; -} - -int Router::megaTableAnimate(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *animTable, bool reverse) { - int32 animRes = 0; - - // If this is the start of the anim, read the anim table to get the - // appropriate anim resource - - ObjectLogic obLogic(ob_logic); - - if (obLogic.getLooping() == 0) { - ObjectMega obMega(ob_mega); - - // Appropriate anim resource is in 'table[direction]' - animRes = READ_LE_UINT32(animTable + 4 * obMega.getCurDir()); - } - - return doAnimate(ob_logic, ob_graph, animRes, reverse); -} - -void Router::setSpriteStatus(byte *ob_graph, uint32 type) { - ObjectGraphic obGraph(ob_graph); - - // Remove the previous status, but don't affect the shading upper-word - obGraph.setType((obGraph.getType() & 0xffff0000) | type); -} - -void Router::setSpriteShading(byte *ob_graph, uint32 type) { - ObjectGraphic obGraph(ob_graph); - - // Remove the previous shading, but don't affect the status lower-word. - // Note that mega frames may still be shaded automatically, even when - // not sent 'RDSPR_SHADOW'. - obGraph.setType((obGraph.getType() & 0x0000ffff) | type); -} - -void Logic::createSequenceSpeech(MovieTextObject *sequenceText[]) { - uint32 line; - uint32 local_text; - uint32 text_res; - byte *text; - uint32 wavId; // ie. offical text number (actor text number) - bool speechRunning; - - // for each sequence text line that's been logged - for (line = 0; line < _sequenceTextLines; line++) { - // allocate this structure - sequenceText[line] = new MovieTextObject; - - sequenceText[line]->startFrame = _sequenceTextList[line].startFrame; - sequenceText[line]->endFrame = _sequenceTextList[line].endFrame; - - // pull out the text line to get the official text number - // (for wav id) - - text_res = _sequenceTextList[line].textNumber / SIZE; - local_text = _sequenceTextList[line].textNumber & 0xffff; - - // open text resource & get the line - text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text); - wavId = (int32)READ_LE_UINT16(text); - - // now ok to close the text file - _vm->_resman->closeResource(text_res); - - // 1st word of text line is the official line number - debug(5,"(%d) SEQUENCE TEXT: %s", READ_LE_UINT16(text), text + 2); - - // is it to be speech or subtitles or both? - // assume speech is not running until know otherwise - - speechRunning = false; - _sequenceTextList[line].speech_mem = NULL; - sequenceText[line]->speech = NULL; - - if (!_vm->_sound->isSpeechMute()) { - _sequenceTextList[line].speechBufferSize = _vm->_sound->preFetchCompSpeech(wavId, &_sequenceTextList[line].speech_mem); - if (_sequenceTextList[line].speechBufferSize) { - // ok, we've got speech! - speechRunning = true; - } - } - - // if we want subtitles, or speech failed to load - - if (_vm->getSubtitles() || !speechRunning) { - // open text resource & get the line - text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text); - // make the sprite - // 'text+2' to skip the first 2 bytes which form the - // line reference number - - // NB. The mem block containing the text sprite is - // currently FLOATING! - - // When rendering text over a sequence we need a - // different colour for the border. - - _sequenceTextList[line].text_mem = _vm->_fontRenderer->makeTextSprite(text + 2, 600, 255, _vm->_speechFontId, 1); - - // ok to close the text resource now - _vm->_resman->closeResource(text_res); - } else { - _sequenceTextList[line].text_mem = NULL; - sequenceText[line]->textSprite = NULL; - } - } - - // for drivers: NULL-terminate the array of pointers to - // MovieTextObject's - sequenceText[_sequenceTextLines] = NULL; - - for (line = 0; line < _sequenceTextLines; line++) { - // if we've made a text sprite for this line... - - if (_sequenceTextList[line].text_mem) { - // now fill out the SpriteInfo structure in the - // MovieTextObjectStructure - FrameHeader frame; - - frame.read(_sequenceTextList[line].text_mem); - - sequenceText[line]->textSprite = new SpriteInfo; - - // center text at bottom of screen - sequenceText[line]->textSprite->x = 320 - frame.width / 2; - sequenceText[line]->textSprite->y = 440 - frame.height; - sequenceText[line]->textSprite->w = frame.width; - sequenceText[line]->textSprite->h = frame.height; - sequenceText[line]->textSprite->type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION; - sequenceText[line]->textSprite->data = _sequenceTextList[line].text_mem + FrameHeader::size(); - } - - // if we've loaded a speech sample for this line... - - if (_sequenceTextList[line].speech_mem) { - // for drivers: set up pointer to decompressed wav in - // memory - - sequenceText[line]->speechBufferSize = _sequenceTextList[line].speechBufferSize; - sequenceText[line]->speech = _sequenceTextList[line].speech_mem; - } - } -} - -void Logic::clearSequenceSpeech(MovieTextObject *sequenceText[]) { - for (uint i = 0; i < _sequenceTextLines; i++) { - // free up the memory used by this MovieTextObject - delete sequenceText[i]; - - // free up the mem block containing this text sprite - if (_sequenceTextList[i].text_mem) - free(_sequenceTextList[i].text_mem); - - // free up the mem block containing this speech sample - if (_sequenceTextList[i].speech_mem) - free(_sequenceTextList[i].speech_mem); - } - - // IMPORTANT! Reset the line count ready for the next sequence! - _sequenceTextLines = 0; -} - -} // End of namespace Sword2 diff --git a/sword2/build_display.cpp b/sword2/build_display.cpp deleted file mode 100644 index bc5a31a1f9..0000000000 --- a/sword2/build_display.cpp +++ /dev/null @@ -1,1070 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -// --------------------------------------------------------------------------- -// BUILD_DISPLAY.CPP like the old spr_engi but slightly more aptly named -// --------------------------------------------------------------------------- - -#include "common/stdafx.h" -#include "common/system.h" - -#include "sword2/sword2.h" -#include "sword2/console.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/maketext.h" -#include "sword2/mouse.h" -#include "sword2/resman.h" -#include "sword2/sound.h" - -namespace Sword2 { - -Screen::Screen(Sword2Engine *vm, int16 width, int16 height) { - _vm = vm; - - _dirtyGrid = _buffer = NULL; - - _vm->_system->initSize(width, height); - - _screenWide = width; - _screenDeep = height; - - _gridWide = width / CELLWIDE; - _gridDeep = height / CELLDEEP; - - if ((width % CELLWIDE) || (height % CELLDEEP)) - error("Bad cell size"); - - _dirtyGrid = (byte *)calloc(_gridWide, _gridDeep); - if (!_dirtyGrid) - error("Could not initialise dirty grid"); - - _buffer = (byte *)malloc(width * height); - if (!_buffer) - error("Could not initialise display"); - - for (int i = 0; i < ARRAYSIZE(_blockSurfaces); i++) - _blockSurfaces[i] = NULL; - - _lightMask = NULL; - _needFullRedraw = false; - - memset(&_thisScreen, 0, sizeof(_thisScreen)); - - _fps = 0; - _frameCount = 0; - _cycleTime = 0; - - _lastPaletteRes = 0; - - _scrollFraction = 16; - - _largestLayerArea = 0; - _largestSpriteArea = 0; - - strcpy(_largestLayerInfo, "largest layer: none registered"); - strcpy(_largestSpriteInfo, "largest sprite: none registered"); - - _fadeStatus = RDFADE_NONE; - _renderAverageTime = 60; - - _layer = 0; -} - -Screen::~Screen() { - free(_buffer); - free(_dirtyGrid); - closeBackgroundLayer(); - free(_lightMask); -} - -void Screen::buildDisplay() { - if (_thisScreen.new_palette) { - // start the layer palette fading up - startNewPalette(); - - // should be reset to zero at start of each screen change - _largestLayerArea = 0; - _largestSpriteArea = 0; - } - - // Does this ever happen? - if (!_thisScreen.background_layer_id) - return; - - // there is a valid screen to run - - setScrollTarget(_thisScreen.scroll_offset_x, _thisScreen.scroll_offset_y); - _vm->_mouse->animateMouse(); - startRenderCycle(); - - byte *file = _vm->_resman->openResource(_thisScreen.background_layer_id); - - MultiScreenHeader screenLayerTable; - - screenLayerTable.read(file + ResHeader::size()); - - // Render at least one frame, but if the screen is scrolling, and if - // there is time left, we will render extra frames to smooth out the - // scrolling. - - do { - // first background parallax + related anims - if (screenLayerTable.bg_parallax[0]) { - renderParallax(_vm->fetchBackgroundParallaxLayer(file, 0), 0); - drawBackPar0Frames(); - } - - // second background parallax + related anims - if (screenLayerTable.bg_parallax[1]) { - renderParallax(_vm->fetchBackgroundParallaxLayer(file, 1), 1); - drawBackPar1Frames(); - } - - // normal backround layer (just the one!) - renderParallax(_vm->fetchBackgroundLayer(file), 2); - - // sprites & layers - drawBackFrames(); // background sprites - drawSortFrames(file); // sorted sprites & layers - drawForeFrames(); // foreground sprites - - // first foreground parallax + related anims - - if (screenLayerTable.fg_parallax[0]) { - renderParallax(_vm->fetchForegroundParallaxLayer(file, 0), 3); - drawForePar0Frames(); - } - - // second foreground parallax + related anims - - if (screenLayerTable.fg_parallax[1]) { - renderParallax(_vm->fetchForegroundParallaxLayer(file, 1), 4); - drawForePar1Frames(); - } - - _vm->_debugger->drawDebugGraphics(); - _vm->_fontRenderer->printTextBlocs(); - _vm->_mouse->processMenu(); - - updateDisplay(); - - _frameCount++; - if (_vm->getMillis() > _cycleTime) { - _fps = _frameCount; - _frameCount = 0; - _cycleTime = _vm->getMillis() + 1000; - } - } while (!endRenderCycle()); - - _vm->_resman->closeResource(_thisScreen.background_layer_id); -} - -/** - * Fades down and displays a message on the screen. - * @param text The message - * @param time The number of seconds to display the message, or 0 to display it - * until the user clicks the mouse or presses a key. - */ - -void Screen::displayMsg(byte *text, int time) { - byte pal[256 * 4]; - byte oldPal[256 * 4]; - - debug(2, "DisplayMsg: %s", text); - - if (getFadeStatus() != RDFADE_BLACK) { - fadeDown(); - waitForFade(); - } - - _vm->_mouse->setMouse(0); - _vm->_mouse->setLuggage(0); - _vm->_mouse->closeMenuImmediately(); - - clearScene(); - - byte *text_spr = _vm->_fontRenderer->makeTextSprite(text, 640, 187, _vm->_speechFontId); - - FrameHeader frame; - - frame.read(text_spr); - - SpriteInfo spriteInfo; - - spriteInfo.x = _screenWide / 2 - frame.width / 2; - if (!time) - spriteInfo.y = _screenDeep / 2 - frame.height / 2 - MENUDEEP; - else - spriteInfo.y = 400 - frame.height; - spriteInfo.w = frame.width; - spriteInfo.h = frame.height; - spriteInfo.scale = 0; - spriteInfo.scaledWidth = 0; - spriteInfo.scaledHeight = 0; - spriteInfo.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION | RDSPR_TRANS; - spriteInfo.blend = 0; - spriteInfo.data = text_spr + FrameHeader::size(); - spriteInfo.colourTable = 0; - - uint32 rv = drawSprite(&spriteInfo); - if (rv) - error("Driver Error %.8x (in DisplayMsg)", rv); - - memcpy(oldPal, _palette, sizeof(oldPal)); - memset(pal, 0, sizeof(pal)); - - pal[187 * 4 + 0] = 255; - pal[187 * 4 + 1] = 255; - pal[187 * 4 + 2] = 255; - - setPalette(0, 256, pal, RDPAL_FADE); - fadeUp(); - free(text_spr); - waitForFade(); - - if (time > 0) { - uint32 targetTime = _vm->getMillis() + (time * 1000); - _vm->sleepUntil(targetTime); - } else { - while (!_vm->_quit) { - MouseEvent *me = _vm->mouseEvent(); - if (me && (me->buttons & (RD_LEFTBUTTONDOWN | RD_RIGHTBUTTONDOWN))) - break; - - if (_vm->keyboardEvent()) - break; - - updateDisplay(); - _vm->_system->delayMillis(50); - } - } - - fadeDown(); - waitForFade(); - clearScene(); - setPalette(0, 256, oldPal, RDPAL_FADE); - fadeUp(); -} - -void Screen::drawBackPar0Frames() { - // frame attached to 1st background parallax - for (uint i = 0; i < _curBgp0; i++) - processImage(&_bgp0List[i]); -} - -void Screen::drawBackPar1Frames() { - // frame attached to 2nd background parallax - for (uint i = 0; i < _curBgp1; i++) - processImage(&_bgp1List[i]); -} - -void Screen::drawBackFrames() { - // background sprite, fixed to main background - for (uint i = 0; i < _curBack; i++) - processImage(&_backList[i]); -} - -void Screen::drawSortFrames(byte *file) { - uint i, j; - - // Sort the sort list. Used to be a separate function, but it was only - // called once, right before calling drawSortFrames(). - - if (_curSort > 1) { - for (i = 0; i < _curSort - 1; i++) { - for (j = 0; j < _curSort - 1; j++) { - if (_sortList[_sortOrder[j]].sort_y > _sortList[_sortOrder[j + 1]].sort_y) { - SWAP(_sortOrder[j], _sortOrder[j + 1]); - } - } - } - } - - // Draw the sorted frames - layers, shrinkers & normal flat sprites - - for (i = 0; i < _curSort; i++) { - if (_sortList[_sortOrder[i]].layer_number) { - // it's a layer - minus 1 for true layer number - // we need to know from the BuildUnit because the - // layers will have been sorted in random order - processLayer(file, _sortList[_sortOrder[i]].layer_number - 1); - } else { - // it's a sprite - processImage(&_sortList[_sortOrder[i]]); - } - } -} - -void Screen::drawForeFrames() { - // foreground sprite, fixed to main background - for (uint i = 0; i < _curFore; i++) - processImage(&_foreList[i]); -} - -void Screen::drawForePar0Frames() { - // frame attached to 1st foreground parallax - for (uint i = 0; i < _curFgp0; i++) - processImage(&_fgp0List[i]); -} - -void Screen::drawForePar1Frames() { - // frame attached to 2nd foreground parallax - for (uint i = 0; i < _curFgp1; i++) - processImage(&_fgp1List[i]); -} - -void Screen::processLayer(byte *file, uint32 layer_number) { - LayerHeader layer_head; - - layer_head.read(_vm->fetchLayerHeader(file, layer_number)); - - SpriteInfo spriteInfo; - - spriteInfo.x = layer_head.x; - spriteInfo.y = layer_head.y; - spriteInfo.w = layer_head.width; - spriteInfo.scale = 0; - spriteInfo.scaledWidth = 0; - spriteInfo.scaledHeight = 0; - spriteInfo.h = layer_head.height; - spriteInfo.type = RDSPR_TRANS | RDSPR_RLE256FAST; - spriteInfo.blend = 0; - spriteInfo.data = file + ResHeader::size() + layer_head.offset; - spriteInfo.colourTable = 0; - - // check for largest layer for debug info - - uint32 current_layer_area = layer_head.width * layer_head.height; - - if (current_layer_area > _largestLayerArea) { - byte buf[NAME_LEN]; - - _largestLayerArea = current_layer_area; - sprintf(_largestLayerInfo, - "largest layer: %s layer(%d) is %dx%d", - _vm->_resman->fetchName(_thisScreen.background_layer_id, buf), - layer_number, layer_head.width, layer_head.height); - } - - uint32 rv = drawSprite(&spriteInfo); - if (rv) - error("Driver Error %.8x in processLayer(%d)", rv, layer_number); -} - -void Screen::processImage(BuildUnit *build_unit) { - byte *file = _vm->_resman->openResource(build_unit->anim_resource); - byte *colTablePtr = NULL; - - byte *frame = _vm->fetchFrameHeader(file, build_unit->anim_pc); - - AnimHeader anim_head; - CdtEntry cdt_entry; - FrameHeader frame_head; - - anim_head.read(_vm->fetchAnimHeader(file)); - cdt_entry.read(_vm->fetchCdtEntry(file, build_unit->anim_pc)); - frame_head.read(frame); - - // so that 0-colour is transparent - uint32 spriteType = RDSPR_TRANS; - - if (anim_head.blend) - spriteType |= RDSPR_BLEND; - - // if the frame is to be flipped (only really applicable to frames - // using offsets) - if (cdt_entry.frameType & FRAME_FLIPPED) - spriteType |= RDSPR_FLIP; - - if (cdt_entry.frameType & FRAME_256_FAST) { - // scaling, shading & blending don't work with RLE256FAST - // but the same compression can be decompressed using the - // RLE256 routines! - - // NOTE: If this restriction refers to drawSprite(), I don't - // think we have it any more. But I'm not sure. - - if (build_unit->scale || anim_head.blend || build_unit->shadingFlag) - spriteType |= RDSPR_RLE256; - else - spriteType |= RDSPR_RLE256FAST; - } else { - switch (anim_head.runTimeComp) { - case NONE: - spriteType |= RDSPR_NOCOMPRESSION; - break; - case RLE256: - spriteType |= RDSPR_RLE256; - break; - case RLE16: - spriteType |= RDSPR_RLE16; - // points to just after last cdt_entry, ie. - // start of colour table - colTablePtr = _vm->fetchAnimHeader(file) + AnimHeader::size() + anim_head.noAnimFrames * CdtEntry::size(); - break; - } - } - - // if we want this frame to be affected by the shading mask, - // add the status bit - if (build_unit->shadingFlag) - spriteType |= RDSPR_SHADOW; - - SpriteInfo spriteInfo; - - spriteInfo.x = build_unit->x; - spriteInfo.y = build_unit->y; - spriteInfo.w = frame_head.width; - spriteInfo.h = frame_head.height; - spriteInfo.scale = build_unit->scale; - spriteInfo.scaledWidth = build_unit->scaled_width; - spriteInfo.scaledHeight = build_unit->scaled_height; - spriteInfo.type = spriteType; - spriteInfo.blend = anim_head.blend; - // points to just after frame header, ie. start of sprite data - spriteInfo.data = frame + FrameHeader::size(); - spriteInfo.colourTable = colTablePtr; - - // check for largest layer for debug info - uint32 current_sprite_area = frame_head.width * frame_head.height; - - if (current_sprite_area > _largestSpriteArea) { - byte buf[NAME_LEN]; - - _largestSpriteArea = current_sprite_area; - sprintf(_largestSpriteInfo, - "largest sprite: %s frame(%d) is %dx%d", - _vm->_resman->fetchName(build_unit->anim_resource, buf), - build_unit->anim_pc, - frame_head.width, - frame_head.height); - } - - if (_vm->_logic->readVar(SYSTEM_TESTING_ANIMS)) { // see anims.cpp - // bring the anim into the visible screen - // but leave extra pixel at edge for box - if (spriteInfo.x + spriteInfo.scaledWidth >= 639) - spriteInfo.x = 639 - spriteInfo.scaledWidth; - - if (spriteInfo.y + spriteInfo.scaledHeight >= 399) - spriteInfo.y = 399 - spriteInfo.scaledHeight; - - if (spriteInfo.x < 1) - spriteInfo.x = 1; - - if (spriteInfo.y < 1) - spriteInfo.y = 1; - - // create box to surround sprite - just outside sprite box - _vm->_debugger->_rectX1 = spriteInfo.x - 1; - _vm->_debugger->_rectY1 = spriteInfo.y - 1; - _vm->_debugger->_rectX2 = spriteInfo.x + spriteInfo.scaledWidth; - _vm->_debugger->_rectY2 = spriteInfo.y + spriteInfo.scaledHeight; - } - - uint32 rv = drawSprite(&spriteInfo); - if (rv) { - byte buf[NAME_LEN]; - - error("Driver Error %.8x with sprite %s (%d) in processImage", - rv, - _vm->_resman->fetchName(build_unit->anim_resource, buf), - build_unit->anim_resource); - } - - // release the anim resource - _vm->_resman->closeResource(build_unit->anim_resource); -} - -void Screen::resetRenderLists() { - // reset the sort lists - do this before a logic loop - // takes into account the fact that the start of the list is pre-built - // with the special sortable layers - - _curBgp0 = 0; - _curBgp1 = 0; - _curBack = 0; - // beginning of sort list is setup with the special sort layers - _curSort = _thisScreen.number_of_layers; - _curFore = 0; - _curFgp0 = 0; - _curFgp1 = 0; - - if (_curSort) { - // there are some layers - so rebuild the sort order list - for (uint i = 0; i < _curSort; i++) - _sortOrder[i] = i; - } -} - -void Screen::registerFrame(byte *ob_mouse, byte *ob_graph, byte *ob_mega, BuildUnit *build_unit) { - ObjectGraphic obGraph(ob_graph); - ObjectMega obMega(ob_mega); - - assert(obGraph.getAnimResource()); - - byte *file = _vm->_resman->openResource(obGraph.getAnimResource()); - - AnimHeader anim_head; - CdtEntry cdt_entry; - FrameHeader frame_head; - - anim_head.read(_vm->fetchAnimHeader(file)); - cdt_entry.read(_vm->fetchCdtEntry(file, obGraph.getAnimPc())); - frame_head.read(_vm->fetchFrameHeader(file, obGraph.getAnimPc())); - - // update player graphic details for on-screen debug info - if (_vm->_logic->readVar(ID) == CUR_PLAYER_ID) { - _vm->_debugger->_graphType = obGraph.getType(); - _vm->_debugger->_graphAnimRes = obGraph.getAnimResource(); - // counting 1st frame as 'frame 1' - _vm->_debugger->_graphAnimPc = obGraph.getAnimPc() + 1; - _vm->_debugger->_graphNoFrames = anim_head.noAnimFrames; - } - - // fill in the BuildUnit structure for this frame - - build_unit->anim_resource = obGraph.getAnimResource(); - build_unit->anim_pc = obGraph.getAnimPc(); - build_unit->layer_number = 0; - - // Affected by shading mask? - if (obGraph.getType() & SHADED_SPRITE) - build_unit->shadingFlag = true; - else - build_unit->shadingFlag = false; - - // Check if this frame has offsets ie. this is a scalable mega frame - - int scale = 0; - - if (cdt_entry.frameType & FRAME_OFFSET) { - scale = obMega.calcScale(); - - // calc final render coordinates (top-left of sprite), based - // on feet coords & scaled offsets - - // add scaled offsets to feet coords - build_unit->x = obMega.getFeetX() + (cdt_entry.x * scale) / 256; - build_unit->y = obMega.getFeetY() + (cdt_entry.y * scale) / 256; - - // Work out new width and height. Always divide by 256 after - // everything else, to maintain accurary - build_unit->scaled_width = ((scale * frame_head.width) / 256); - build_unit->scaled_height = ((scale * frame_head.height) / 256); - } else { - // It's a non-scaling anim. Get render coords for sprite, from cdt - build_unit->x = cdt_entry.x; - build_unit->y = cdt_entry.y; - - // Get width and height - build_unit->scaled_width = frame_head.width; - build_unit->scaled_height = frame_head.height; - } - - // either 0 or required scale, depending on whether 'scale' computed - build_unit->scale = scale; - - // calc the bottom y-coord for sorting purposes - build_unit->sort_y = build_unit->y + build_unit->scaled_height - 1; - - if (ob_mouse) { - // passed a mouse structure, so add to the _mouseList - _vm->_mouse->registerMouse(ob_mouse, build_unit); - - } - - _vm->_resman->closeResource(obGraph.getAnimResource()); -} - -void Screen::registerFrame(byte *ob_mouse, byte *ob_graph, byte *ob_mega) { - ObjectGraphic obGraph(ob_graph); - - // check low word for sprite type - switch (obGraph.getType() & 0x0000ffff) { - case BGP0_SPRITE: - assert(_curBgp0 < MAX_bgp0_sprites); - registerFrame(ob_mouse, ob_graph, ob_mega, &_bgp0List[_curBgp0]); - _curBgp0++; - break; - case BGP1_SPRITE: - assert(_curBgp1 < MAX_bgp1_sprites); - registerFrame(ob_mouse, ob_graph, ob_mega, &_bgp1List[_curBgp1]); - _curBgp1++; - break; - case BACK_SPRITE: - assert(_curBack < MAX_back_sprites); - registerFrame(ob_mouse, ob_graph, ob_mega, &_backList[_curBack]); - _curBack++; - break; - case SORT_SPRITE: - assert(_curSort < MAX_sort_sprites); - _sortOrder[_curSort] = _curSort; - registerFrame(ob_mouse, ob_graph, ob_mega, &_sortList[_curSort]); - _curSort++; - break; - case FORE_SPRITE: - assert(_curFore < MAX_fore_sprites); - registerFrame(ob_mouse, ob_graph, ob_mega, &_foreList[_curFore]); - _curFore++; - break; - case FGP0_SPRITE: - assert(_curFgp0 < MAX_fgp0_sprites); - registerFrame(ob_mouse, ob_graph, ob_mega, &_fgp0List[_curFgp0]); - _curFgp0++; - break; - case FGP1_SPRITE: - assert(_curFgp1 < MAX_fgp1_sprites); - registerFrame(ob_mouse, ob_graph, ob_mega, &_fgp1List[_curFgp1]); - _curFgp1++; - break; - default: - // NO_SPRITE no registering! - break; - } -} - -// FIXME: -// -// The original credits used a different font. I think it's stored in the -// font.clu file, but I don't know how to interpret it. -// -// The original used the entire screen. This version cuts off the top and -// bottom of the screen, because that's where the menus would usually be. -// -// The original had some sort of smoke effect at the bottom of the screen. - -enum { - LINE_LEFT, - LINE_CENTER, - LINE_RIGHT -}; - -struct CreditsLine { - char *str; - byte type; - int top; - int height; - byte *sprite; - - CreditsLine() { - str = NULL; - sprite = NULL; - }; - - ~CreditsLine() { - free(str); - free(sprite); - str = NULL; - sprite = NULL; - } -}; - -#define CREDITS_FONT_HEIGHT 25 -#define CREDITS_LINE_SPACING 20 - -void Screen::rollCredits() { - uint32 loopingMusicId = _vm->_sound->getLoopingMusicId(); - - // Prepare for the credits by fading down, stoping the music, etc. - - _vm->_mouse->setMouse(0); - - _vm->_sound->muteFx(true); - _vm->_sound->muteSpeech(true); - - waitForFade(); - fadeDown(); - waitForFade(); - - _vm->_mouse->closeMenuImmediately(); - - // There are three files which I believe are involved in showing the - // credits: - // - // credits.bmp - The "Smacker" logo, stored as follows: - // - // width 2 bytes, little endian - // height 2 bytes, little endian - // palette 3 * 256 bytes - // data width * height bytes - // - // Note that the maximum colour component in the palette is 0x3F. - // This is the same resolution as the _paletteMatch table. I doubt - // that this is a coincidence, but let's use the image palette - // directly anyway, just to be safe. - // - // credits.clu - The credits text - // - // This is simply a text file with CRLF line endings. - // '^' is not shown, but used to mark the center of the line. - // '@' is used as a placeholder for the "Smacker" logo. At least - // when it appears alone. - // Remaining lines are centered. - // The German version also contains character code 9 for no - // apparent reason. We ignore them. - // - // fonts.clu - The credits font? - // - // FIXME: At this time I don't know how to interpret fonts.clu. For - // now, let's just the standard speech font instead. - - SpriteInfo spriteInfo; - Common::File f; - int i; - - // Read the "Smacker" logo - - uint16 logoWidth = 0; - uint16 logoHeight = 0; - byte *logoData = NULL; - byte palette[256 * 4]; - - if (f.open("credits.bmp")) { - logoWidth = f.readUint16LE(); - logoHeight = f.readUint16LE(); - - for (i = 0; i < 256; i++) { - palette[i * 4 + 0] = f.readByte() << 2; - palette[i * 4 + 1] = f.readByte() << 2; - palette[i * 4 + 2] = f.readByte() << 2; - palette[i * 4 + 3] = 0; - } - - logoData = (byte *)malloc(logoWidth * logoHeight); - - f.read(logoData, logoWidth * logoHeight); - f.close(); - } else { - warning("Can't find credits.bmp"); - memset(palette, 0, sizeof(palette)); - palette[14 * 4 + 0] = 252; - palette[14 * 4 + 1] = 252; - palette[14 * 4 + 2] = 252; - palette[14 * 4 + 3] = 0; - } - - setPalette(0, 256, palette, RDPAL_INSTANT); - - // Read the credits text - - Common::Array<CreditsLine *> creditsLines; - - int lineCount = 0; - int lineTop = 400; - int paragraphStart = 0; - bool hasCenterMark = false; - - if (!f.open("credits.clu")) { - warning("Can't find credits.clu"); - return; - } - - while (1) { - char buffer[80]; - char *line = f.readLine(buffer, sizeof(buffer)); - - if (!line || *line == 0) { - if (!hasCenterMark) { - for (i = paragraphStart; i < lineCount; i++) - creditsLines[i]->type = LINE_CENTER; - } - paragraphStart = lineCount; - hasCenterMark = false; - if (paragraphStart == lineCount) - lineTop += CREDITS_LINE_SPACING; - - if (!line) - break; - - continue; - } - - // The German credits contains character code 9. We don't want - // the credits to show the 'dud' symbol, so we replace them - // with spaces. - - for (char *ptr = line; *ptr; ptr++) { - if (*ptr < 32) - *ptr = 32; - } - - char *center_mark = strchr(line, '^'); - - if (center_mark) { - // The current paragraph has at least one center mark. - hasCenterMark = true; - - if (center_mark != line) { - creditsLines.push_back(new CreditsLine); - - // The center mark is somewhere inside the - // line. Split it into left and right side. - *center_mark = 0; - - creditsLines[lineCount]->top = lineTop; - creditsLines[lineCount]->height = CREDITS_FONT_HEIGHT; - creditsLines[lineCount]->type = LINE_LEFT; - creditsLines[lineCount]->str = strdup(line); - - lineCount++; - *center_mark = '^'; - } - - line = center_mark; - } - - creditsLines.push_back(new CreditsLine); - - creditsLines[lineCount]->top = lineTop; - - if (*line == '^') { - creditsLines[lineCount]->type = LINE_RIGHT; - line++; - } else - creditsLines[lineCount]->type = LINE_LEFT; - - if (strcmp(line, "@") == 0) { - creditsLines[lineCount]->height = logoHeight; - lineTop += logoHeight; - } else { - creditsLines[lineCount]->height = CREDITS_FONT_HEIGHT; - lineTop += CREDITS_LINE_SPACING; - } - - creditsLines[lineCount]->str = strdup(line); - lineCount++; - } - - f.close(); - - // We could easily add some ScummVM stuff to the credits, if we wanted - // to. On the other hand, anyone with the attention span to actually - // read all the credits probably already knows. :-) - - // Start the music and roll the credits - - // The credits music (which can also be heard briefly in the "carib" - // cutscene) is played once. - - _vm->_sound->streamCompMusic(309, false); - - clearScene(); - fadeUp(0); - - spriteInfo.scale = 0; - spriteInfo.scaledWidth = 0; - spriteInfo.scaledHeight = 0; - spriteInfo.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION | RDSPR_TRANS; - spriteInfo.blend = 0; - - int startLine = 0; - int scrollPos = 0; - - bool abortCredits = false; - - int scrollSteps = lineTop + CREDITS_FONT_HEIGHT; - uint32 musicStart = _vm->getMillis(); - - // Ideally the music should last just a tiny bit longer than the - // credits. Note that musicTimeRemaining() will return 0 if the music - // is muted, so we need a sensible fallback for that case. - - uint32 musicLength = MAX((int32)(1000 * (_vm->_sound->musicTimeRemaining() - 3)), 25 * (int32)scrollSteps); - - while (scrollPos < scrollSteps && !_vm->_quit) { - clearScene(); - - for (i = startLine; i < lineCount; i++) { - if (!creditsLines[i]) - continue; - - // Free any sprites that have scrolled off the screen - - if (creditsLines[i]->top + creditsLines[i]->height < scrollPos) { - debug(2, "Freeing line %d: '%s'", i, creditsLines[i]->str); - - delete creditsLines[i]; - creditsLines[i] = NULL; - - startLine = i + 1; - } else if (creditsLines[i]->top < scrollPos + 400) { - if (!creditsLines[i]->sprite) { - debug(2, "Creating line %d: '%s'", i, creditsLines[i]->str); - creditsLines[i]->sprite = _vm->_fontRenderer->makeTextSprite((byte *)creditsLines[i]->str, 600, 14, _vm->_speechFontId, 0); - } - - FrameHeader frame; - - frame.read(creditsLines[i]->sprite); - - spriteInfo.y = creditsLines[i]->top - scrollPos; - spriteInfo.w = frame.width; - spriteInfo.h = frame.height; - spriteInfo.data = creditsLines[i]->sprite + FrameHeader::size(); - - switch (creditsLines[i]->type) { - case LINE_LEFT: - spriteInfo.x = RENDERWIDE / 2 - 5 - frame.width; - break; - case LINE_RIGHT: - spriteInfo.x = RENDERWIDE / 2 + 5; - break; - case LINE_CENTER: - if (strcmp(creditsLines[i]->str, "@") == 0) { - spriteInfo.data = logoData; - spriteInfo.x = (RENDERWIDE - logoWidth) / 2; - spriteInfo.w = logoWidth; - spriteInfo.h = logoHeight; - } else - spriteInfo.x = (RENDERWIDE - frame.width) / 2; - break; - } - - if (spriteInfo.data) - drawSprite(&spriteInfo); - } else - break; - } - - updateDisplay(); - - KeyboardEvent *ke = _vm->keyboardEvent(); - - if (ke && ke->keycode == 27) { - if (!abortCredits) { - abortCredits = true; - fadeDown(); - } - } - - if (abortCredits && getFadeStatus() == RDFADE_BLACK) - break; - - _vm->sleepUntil(musicStart + (musicLength * scrollPos) / scrollSteps); - scrollPos++; - } - - // We're done. Clean up and try to put everything back where it was - // before the credits. - - for (i = 0; i < lineCount; i++) { - delete creditsLines[i]; - } - - free(logoData); - - if (!abortCredits) { - fadeDown(); - - // The music should either have stopped or be about to stop, so - // wait for it to really happen. - - while (_vm->_sound->musicTimeRemaining() && !_vm->_quit) { - updateDisplay(false); - _vm->_system->delayMillis(100); - } - } - - if (_vm->_quit) - return; - - waitForFade(); - - _vm->_sound->muteFx(false); - _vm->_sound->muteSpeech(false); - - if (loopingMusicId) - _vm->_sound->streamCompMusic(loopingMusicId, true); - else - _vm->_sound->stopMusic(false); - - if (!_vm->_mouse->getMouseStatus() || _vm->_mouse->isChoosing()) - _vm->_mouse->setMouse(NORMAL_MOUSE_ID); - - if (_vm->_logic->readVar(DEAD)) - _vm->_mouse->buildSystemMenu(); -} - -// This image used to be shown by CacheNewCluster() while copying a data file -// from the CD to the hard disk. ScummVM doesn't do that, so the image is never -// shown. It'd be nice if we could do something useful with it some day... - -void Screen::splashScreen() { - byte *bgfile = _vm->_resman->openResource(2950); - - initialiseBackgroundLayer(NULL); - initialiseBackgroundLayer(NULL); - initialiseBackgroundLayer(_vm->fetchBackgroundLayer(bgfile)); - initialiseBackgroundLayer(NULL); - initialiseBackgroundLayer(NULL); - - setPalette(0, 256, _vm->fetchPalette(bgfile), RDPAL_FADE); - renderParallax(_vm->fetchBackgroundLayer(bgfile), 2); - - closeBackgroundLayer(); - - byte *loadingBar = _vm->_resman->openResource(2951); - byte *frame = _vm->fetchFrameHeader(loadingBar, 0); - - AnimHeader animHead; - CdtEntry cdt; - FrameHeader frame_head; - - animHead.read(_vm->fetchAnimHeader(loadingBar)); - cdt.read(_vm->fetchCdtEntry(loadingBar, 0)); - frame_head.read(_vm->fetchFrameHeader(loadingBar, 0)); - - SpriteInfo barSprite; - - barSprite.x = cdt.x; - barSprite.y = cdt.y; - barSprite.w = frame_head.width; - barSprite.h = frame_head.height; - barSprite.scale = 0; - barSprite.scaledWidth = 0; - barSprite.scaledHeight = 0; - barSprite.type = RDSPR_RLE256FAST | RDSPR_TRANS; - barSprite.blend = 0; - barSprite.colourTable = 0; - barSprite.data = frame + FrameHeader::size(); - - drawSprite(&barSprite); - - fadeUp(); - waitForFade(); - - for (int i = 0; i < animHead.noAnimFrames; i++) { - frame = _vm->fetchFrameHeader(loadingBar, i); - barSprite.data = frame + FrameHeader::size(); - drawSprite(&barSprite); - updateDisplay(); - _vm->_system->delayMillis(30); - } - - _vm->_resman->closeResource(2951); - - fadeDown(); - waitForFade(); -} - -} // End of namespace Sword2 diff --git a/sword2/build_display.h b/sword2/build_display.h deleted file mode 100644 index 1a362da137..0000000000 --- a/sword2/build_display.h +++ /dev/null @@ -1,441 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef _BUILD_DISPLAY -#define _BUILD_DISPLAY - -#include "common/rect.h" -#include "common/stream.h" - -#define MAX_bgp0_sprites 6 -#define MAX_bgp1_sprites 6 -#define MAX_back_sprites 30 -#define MAX_sort_sprites 30 -#define MAX_fore_sprites 30 -#define MAX_fgp0_sprites 6 -#define MAX_fgp1_sprites 6 - -#define PALTABLESIZE (64 * 64 * 64) - -#define BLOCKWIDTH 64 -#define BLOCKHEIGHT 64 -#define MAXLAYERS 5 - -#define MENUDEEP 40 -#define RENDERWIDE 640 -#define RENDERDEEP (480 - (MENUDEEP * 2)) - -// Maximum scaled size of a sprite -#define SCALE_MAXWIDTH 512 -#define SCALE_MAXHEIGHT 512 - -// Dirty grid cell size -#define CELLWIDE 10 -#define CELLDEEP 20 - -namespace Sword2 { - -class Sword2Engine; - -// Sprite defines - -enum { - // This is the low byte part of the sprite type. - - RDSPR_TRANS = 0x0001, - RDSPR_BLEND = 0x0004, - RDSPR_FLIP = 0x0008, - RDSPR_SHADOW = 0x0010, - RDSPR_DISPLAYALIGN = 0x0020, - RDSPR_NOCOMPRESSION = 0x0040, - RDSPR_EDGEBLEND = 0x0080, // Unused - - // This is the high byte part of the sprite type, which defines what - // type of compression is used. Unless RDSPR_NOCOMPRESSION is set. - - RDSPR_RLE16 = 0x0000, - RDSPR_RLE256 = 0x0100, - RDSPR_RLE256FAST = 0x0200 -}; - -// Fading defines - -enum { - RDFADE_NONE, - RDFADE_UP, - RDFADE_DOWN, - RDFADE_BLACK -}; - -// Palette defines - -enum { - RDPAL_FADE, - RDPAL_INSTANT -}; - -// Blitting FX defines - -enum { - RDBLTFX_SPRITEBLEND = 0x01, - RDBLTFX_SHADOWBLEND = 0x02, - RDBLTFX_EDGEBLEND = 0x04 -}; - -// Structure filled out by each object to register its graphic printing -// requrements - -struct BuildUnit { - int16 x; - int16 y; - uint16 scaled_width; - uint16 scaled_height; - int16 sort_y; - uint32 anim_resource; - uint16 anim_pc; - - // Denotes a scaling sprite at print time - and holds the scaling value - // for the shrink routine - - uint16 scale; - - // Non-zero means this item is a layer - retrieve from background layer - // and send to special renderer - - uint16 layer_number; - - // True means we want this frame to be affected by the shading mask - - bool shadingFlag; -}; - -struct ScreenInfo { - uint16 scroll_offset_x; // Position x - uint16 scroll_offset_y; // Position y - uint16 max_scroll_offset_x; // Calc'ed in fnInitBackground - uint16 max_scroll_offset_y; - int16 player_feet_x; // Feet coordinates to use - cant just - int16 player_feet_y; // fetch the player compact anymore - int16 feet_x; // Special offset-to-player position - - int16 feet_y; // tweek as desired - always set in - // screen manager object startup - uint16 screen_wide; // Size of background layer - hence - uint16 screen_deep; // size of back buffer itself (Paul - // actually malloc's it) - uint32 background_layer_id; // Id of the normal background layer - // from the header of the main - // background layer - uint16 number_of_layers; - uint8 new_palette; // Set to non zero to start the - // palette held within layer file - // fading up after a build_display - uint8 scroll_flag; // Scroll mode 0 off 1 on - bool mask_flag; // Using shading mask -}; - -// The SpriteInfo structure is used to tell the driver96 code what attributes -// are linked to a sprite for drawing. These include position, scaling and -// compression. - -struct SpriteInfo { - int16 x; // coords for top-left of sprite - int16 y; - uint16 w; // dimensions of sprite (before scaling) - uint16 h; - uint16 scale; // scale at which to draw, given in 256ths ['0' or '256' MEANS DON'T SCALE] - uint16 scaledWidth; // new dimensions (we calc these for the mouse area, so may as well pass to you to save time) - uint16 scaledHeight; // - uint16 type; // mask containing 'RDSPR_' bits specifying compression type, flip, transparency, etc - uint16 blend; // holds the blending values. - byte *data; // pointer to the sprite data - byte *colourTable; // pointer to 16-byte colour table, only applicable to 16-col compression type -}; - -struct BlockSurface { - byte data[BLOCKWIDTH * BLOCKHEIGHT]; - bool transparent; -}; - -struct Parallax { - uint16 w; - uint16 h; - - // The dimensions are followed by an offset table, but we don't know in - // advance how big it is. See initializeBackgroundLayer(). - - static const int size() { - return 4; - } - - void read(byte *addr) { - Common::MemoryReadStream readS(addr, size()); - - w = readS.readUint16LE(); - h = readS.readUint16LE(); - } - - void write(byte *addr) { - Common::MemoryWriteStream writeS(addr, size()); - - writeS.writeUint16LE(w); - writeS.writeUint16LE(h); - } -}; - -class Screen { -private: - Sword2Engine *_vm; - - // _thisScreen describes the current back buffer and its in-game scroll - // positions, etc. - - ScreenInfo _thisScreen; - - int32 _renderCaps; - int8 _renderLevel; - - byte *_buffer; - byte *_lightMask; - - // Game screen metrics - int16 _screenWide; - int16 _screenDeep; - - bool _needFullRedraw; - - // Scroll variables. _scrollX and _scrollY hold the current scroll - // position, and _scrollXTarget and _scrollYTarget are the target - // position for the end of the game cycle. - - int16 _scrollX; - int16 _scrollY; - - int16 _scrollXTarget; - int16 _scrollYTarget; - int16 _scrollXOld; - int16 _scrollYOld; - - int16 _parallaxScrollX; // current x offset to link a sprite to the - // parallax layer - int16 _parallaxScrollY; // current y offset to link a sprite to the - // parallax layer - int16 _locationWide; - int16 _locationDeep; - - // Dirty grid handling - byte *_dirtyGrid; - - uint16 _gridWide; - uint16 _gridDeep; - - byte _palette[256 * 4]; - byte _paletteMatch[PALTABLESIZE]; - - uint8 _fadeStatus; - int32 _fadeStartTime; - int32 _fadeTotalTime; - - // 'frames per second' counting stuff - uint32 _fps; - uint32 _cycleTime; - uint32 _frameCount; - - int32 _initialTime; - int32 _startTime; - int32 _totalTime; - int32 _renderAverageTime; - int32 _framesPerGameCycle; - bool _renderTooSlow; - - void startNewPalette(); - - void resetRenderEngine(); - - void startRenderCycle(); - bool endRenderCycle(); - - // Holds the order of the sort list, i.e. the list stays static and we - // sort this array. - - uint16 _sortOrder[MAX_sort_sprites]; - - BuildUnit _bgp0List[MAX_bgp0_sprites]; - BuildUnit _bgp1List[MAX_bgp1_sprites]; - BuildUnit _backList[MAX_back_sprites]; - BuildUnit _sortList[MAX_sort_sprites]; - BuildUnit _foreList[MAX_fore_sprites]; - BuildUnit _fgp0List[MAX_fgp0_sprites]; - BuildUnit _fgp1List[MAX_fgp1_sprites]; - - uint32 _curBgp0; - uint32 _curBgp1; - uint32 _curBack; - uint32 _curSort; - uint32 _curFore; - uint32 _curFgp0; - uint32 _curFgp1; - - void drawBackPar0Frames(); - void drawBackPar1Frames(); - void drawBackFrames(); - void drawSortFrames(byte *file); - void drawForeFrames(); - void drawForePar0Frames(); - void drawForePar1Frames(); - - void processLayer(byte *file, uint32 layer_number); - void processImage(BuildUnit *build_unit); - - uint8 _scrollFraction; - - // Last palette used - so that we can restore the correct one after a - // pause (which dims the screen) and it's not always the main screen - // palette that we want, eg. during the eclipse - - // This flag gets set in startNewPalette() and setFullPalette() - - uint32 _lastPaletteRes; - - // Debugging stuff - uint32 _largestLayerArea; - uint32 _largestSpriteArea; - char _largestLayerInfo[128]; - char _largestSpriteInfo[128]; - - void registerFrame(byte *ob_mouse, byte *ob_graph, byte *ob_mega, BuildUnit *build_unit); - - void mirrorSprite(byte *dst, byte *src, int16 w, int16 h); - int32 decompressRLE256(byte *dst, byte *src, int32 decompSize); - void unwindRaw16(byte *dst, byte *src, uint8 blockSize, byte *colTable); - int32 decompressRLE16(byte *dst, byte *src, int32 decompSize, byte *colTable); - void renderParallax(byte *ptr, int16 layer); - - void markAsDirty(int16 x0, int16 y0, int16 x1, int16 y1); - - uint8 _xBlocks[MAXLAYERS]; - uint8 _yBlocks[MAXLAYERS]; - - // An array of sub-blocks, one for each of the parallax layers. - - BlockSurface **_blockSurfaces[MAXLAYERS]; - - uint16 _xScale[SCALE_MAXWIDTH]; - uint16 _yScale[SCALE_MAXHEIGHT]; - - void blitBlockSurface(BlockSurface *s, Common::Rect *r, Common::Rect *clipRect); - - uint16 _layer; - -public: - Screen(Sword2Engine *vm, int16 width, int16 height); - ~Screen(); - - int8 getRenderLevel(); - void setRenderLevel(int8 level); - - byte *getScreen() { return _buffer; } - byte *getPalette() { return _palette; } - ScreenInfo *getScreenInfo() { return &_thisScreen; } - - int16 getScreenWide() { return _screenWide; } - int16 getScreenDeep() { return _screenDeep; } - - uint32 getCurBgp0() { return _curBgp0; } - uint32 getCurBgp1() { return _curBgp1; } - uint32 getCurBack() { return _curBack; } - uint32 getCurSort() { return _curSort; } - uint32 getCurFore() { return _curFore; } - uint32 getCurFgp0() { return _curFgp0; } - uint32 getCurFgp1() { return _curFgp1; } - - uint32 getFps() { return _fps; } - - uint32 getLargestLayerArea() { return _largestLayerArea; } - uint32 getLargestSpriteArea() { return _largestSpriteArea; } - char *getLargestLayerInfo() { return _largestLayerInfo; } - char *getLargestSpriteInfo() { return _largestSpriteInfo; } - - void setNeedFullRedraw(); - - void clearScene(); - - void resetRenderLists(); - - void setLocationMetrics(uint16 w, uint16 h); - int32 initialiseBackgroundLayer(byte *parallax); - void closeBackgroundLayer(); - - void initialiseRenderCycle(); - - void initBackground(int32 res, int32 new_palette); - void registerFrame(byte *ob_mouse, byte *ob_graph, byte *ob_mega); - - void setScrollFraction(uint8 f) { _scrollFraction = f; } - void setScrollTarget(int16 x, int16 y); - void setScrolling(); - - void setFullPalette(int32 palRes); - void setPalette(int16 startEntry, int16 noEntries, byte *palette, uint8 setNow); - uint8 quickMatch(uint8 r, uint8 g, uint8 b); - int32 fadeUp(float time = 0.75); - int32 fadeDown(float time = 0.75); - uint8 getFadeStatus(); - void dimPalette(); - void waitForFade(); - void fadeServer(); - - void updateDisplay(bool redrawScene = true); - - void displayMsg(byte *text, int time); - - int32 createSurface(SpriteInfo *s, byte **surface); - void drawSurface(SpriteInfo *s, byte *surface, Common::Rect *clipRect = NULL); - void deleteSurface(byte *surface); - int32 drawSprite(SpriteInfo *s); - - void scaleImageFast(byte *dst, uint16 dstPitch, uint16 dstWidth, - uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, - uint16 srcHeight); - void scaleImageGood(byte *dst, uint16 dstPitch, uint16 dstWidth, - uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, - uint16 srcHeight, byte *backbuf); - - void updateRect(Common::Rect *r); - - int32 openLightMask(SpriteInfo *s); - int32 closeLightMask(); - - void buildDisplay(); - - void plotPoint(int x, int y, uint8 colour); - void drawLine(int x0, int y0, int x1, int y1, uint8 colour); - -#ifdef BACKEND_8BIT - void plotYUV(byte *lut, int width, int height, byte *const *dat); -#endif - - void rollCredits(); - void splashScreen(); -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/console.cpp b/sword2/console.cpp deleted file mode 100644 index b465dc369f..0000000000 --- a/sword2/console.cpp +++ /dev/null @@ -1,826 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/console.h" -#include "sword2/logic.h" -#include "sword2/maketext.h" -#include "sword2/memory.h" -#include "sword2/mouse.h" -#include "sword2/resman.h" -#include "sword2/sound.h" - -#include "common/debugger.cpp" - -namespace Sword2 { - -Debugger::Debugger(Sword2Engine *vm) - : Common::Debugger<Debugger>() { - _vm = vm; - - memset(_debugTextBlocks, 0, sizeof(_debugTextBlocks)); - memset(_showVar, 0, sizeof(_showVar)); - - _displayDebugText = false; // "INFO" - _displayWalkGrid = false; // "WALKGRID" - _displayMouseMarker = false; // "MOUSE" - _displayTime = false; // "TIME" - _displayPlayerMarker = false; // "PLAYER" - _displayTextNumbers = false; // "TEXT" - - _definingRectangles = false; // "RECT" - _draggingRectangle = 0; // 0 = waiting to start new rect - // 1 = currently dragging a rectangle - - _rectX1 = _rectY1 = 0; - _rectX2 = _rectY2 = 0; - _rectFlicker = false; - - _testingSnR = false; // "SAVEREST" - for system to kill all - // object resources (except player) in - // fnAddHuman() - - _speechScriptWaiting = 0; // The id of whoever we're waiting for - // in a speech script. See fnTheyDo(), - // fnTheyDoWeWait(), fnWeWait(), and - // fnTimedWait(). - - _startTime = 0; // "TIMEON" & "TIMEOFF" - system start - // time - - _textNumber = 0; // Current system text line number - - _graphNoFrames = 0; // No. of frames in currently displayed - // anim - - // Register commands - - DCmd_Register("continue", &Debugger::Cmd_Exit); - DCmd_Register("exit", &Debugger::Cmd_Exit); - DCmd_Register("quit", &Debugger::Cmd_Exit); - DCmd_Register("q", &Debugger::Cmd_Exit); - DCmd_Register("help", &Debugger::Cmd_Help); - DCmd_Register("mem", &Debugger::Cmd_Mem); - DCmd_Register("tony", &Debugger::Cmd_Tony); - DCmd_Register("res", &Debugger::Cmd_Res); - DCmd_Register("reslist", &Debugger::Cmd_ResList); - DCmd_Register("starts", &Debugger::Cmd_Starts); - DCmd_Register("start", &Debugger::Cmd_Start); - DCmd_Register("s", &Debugger::Cmd_Start); - DCmd_Register("info", &Debugger::Cmd_Info); - DCmd_Register("walkgrid", &Debugger::Cmd_WalkGrid); - DCmd_Register("mouse", &Debugger::Cmd_Mouse); - DCmd_Register("player", &Debugger::Cmd_Player); - DCmd_Register("reslook", &Debugger::Cmd_ResLook); - DCmd_Register("cur", &Debugger::Cmd_CurrentInfo); - DCmd_Register("runlist", &Debugger::Cmd_RunList); - DCmd_Register("kill", &Debugger::Cmd_Kill); - DCmd_Register("nuke", &Debugger::Cmd_Nuke); - DCmd_Register("var", &Debugger::Cmd_Var); - DCmd_Register("rect", &Debugger::Cmd_Rect); - DCmd_Register("clear", &Debugger::Cmd_Clear); - DCmd_Register("debugon", &Debugger::Cmd_DebugOn); - DCmd_Register("debugoff", &Debugger::Cmd_DebugOff); - DCmd_Register("saverest", &Debugger::Cmd_SaveRest); - DCmd_Register("timeon", &Debugger::Cmd_TimeOn); - DCmd_Register("timeoff", &Debugger::Cmd_TimeOff); - DCmd_Register("text", &Debugger::Cmd_Text); - DCmd_Register("showvar", &Debugger::Cmd_ShowVar); - DCmd_Register("hidevar", &Debugger::Cmd_HideVar); - DCmd_Register("version", &Debugger::Cmd_Version); - DCmd_Register("animtest", &Debugger::Cmd_AnimTest); - DCmd_Register("texttest", &Debugger::Cmd_TextTest); - DCmd_Register("linetest", &Debugger::Cmd_LineTest); - DCmd_Register("events", &Debugger::Cmd_Events); - DCmd_Register("sfx", &Debugger::Cmd_Sfx); - DCmd_Register("english", &Debugger::Cmd_English); - DCmd_Register("finnish", &Debugger::Cmd_Finnish); - DCmd_Register("polish", &Debugger::Cmd_Polish); -} - -void Debugger::varGet(int var) { - DebugPrintf("%d\n", _vm->_logic->readVar(var)); -} - -void Debugger::varSet(int var, int val) { - DebugPrintf("was %d, ", _vm->_logic->readVar(var)); - _vm->_logic->writeVar(var, val); - DebugPrintf("now %d\n", _vm->_logic->readVar(var)); -} - -void Debugger::preEnter() { - // Pause sound output - if (_vm->_sound) { - _vm->_sound->pauseFx(); - _vm->_sound->pauseSpeech(); - _vm->_sound->pauseMusic(); - } -} - -void Debugger::postEnter() { - if (_vm->_sound) { - // Resume previous sound state - _vm->_sound->unpauseFx(); - _vm->_sound->unpauseSpeech(); - _vm->_sound->unpauseMusic(); - } - - if (_vm->_mouse) { - // Restore old mouse cursor - _vm->_mouse->drawMouse(); - } -} - -// Now the fun stuff: Commands - -bool Debugger::Cmd_Exit(int argc, const char **argv) { - _detach_now = true; - _vm->clearInputEvents(); - return false; -} - -bool Debugger::Cmd_Help(int argc, const char **argv) { - // console normally has 78 line width - // wrap around nicely - int width = 0; - - DebugPrintf("Commands are:\n"); - for (int i = 0 ; i < _dcmd_count ; i++) { - int size = strlen(_dcmds[i].name) + 1; - - if (width + size >= 75) { - DebugPrintf("\n"); - width = size; - } else - width += size; - - DebugPrintf("%s ", _dcmds[i].name); - } - - DebugPrintf("\n"); - return true; -} - -static int compare_blocks(const void *p1, const void *p2) { - const MemBlock *m1 = *(const MemBlock * const *)p1; - const MemBlock *m2 = *(const MemBlock * const *)p2; - - if (m1->size < m2->size) - return 1; - if (m1->size > m2->size) - return -1; - return 0; -} - -bool Debugger::Cmd_Mem(int argc, const char **argv) { - int16 numBlocks = _vm->_memory->getNumBlocks(); - MemBlock *memBlocks = _vm->_memory->getMemBlocks(); - - MemBlock **blocks = (MemBlock **)malloc(numBlocks * sizeof(MemBlock)); - - int i, j; - - for (i = 0, j = 0; i < MAX_MEMORY_BLOCKS; i++) { - if (memBlocks[i].ptr) - blocks[j++] = &memBlocks[i]; - } - - qsort(blocks, numBlocks, sizeof(MemBlock *), compare_blocks); - - DebugPrintf(" size id res type name\n"); - DebugPrintf("---------------------------------------------------------------------------\n"); - - for (i = 0; i < numBlocks; i++) { - const char *type; - - switch (_vm->_resman->fetchType(blocks[i]->ptr)) { - case ANIMATION_FILE: - type = "ANIMATION_FILE"; - break; - case SCREEN_FILE: - type = "SCREEN_FILE"; - break; - case GAME_OBJECT: - type = "GAME_OBJECT"; - break; - case WALK_GRID_FILE: - type = "WALK_GRID_FILE"; - break; - case GLOBAL_VAR_FILE: - type = "GLOBAL_VAR_FILE"; - break; - case PARALLAX_FILE_null: - type = "PARALLAX_FILE_null"; - break; - case RUN_LIST: - type = "RUN_LIST"; - break; - case TEXT_FILE: - type = "TEXT_FILE"; - break; - case SCREEN_MANAGER: - type = "SCREEN_MANAGER"; - break; - case MOUSE_FILE: - type = "MOUSE_FILE"; - break; - case WAV_FILE: - type = "WAV_FILE"; - break; - case ICON_FILE: - type = "ICON_FILE"; - break; - case PALETTE_FILE: - type = "PALETTE_FILE"; - break; - default: - type = "<unknown>"; - break; - } - - DebugPrintf("%9ld %-3d %-4d %-20s %s\n", blocks[i]->size, blocks[i]->id, blocks[i]->uid, type, _vm->_resman->fetchName(blocks[i]->ptr)); - } - - free(blocks); - - DebugPrintf("---------------------------------------------------------------------------\n"); - DebugPrintf("%9ld\n", _vm->_memory->getTotAlloc()); - - return true; -} - -bool Debugger::Cmd_Tony(int argc, const char **argv) { - DebugPrintf("What about him?\n"); - return true; -} - -bool Debugger::Cmd_Res(int argc, const char **argv) { - uint32 numClusters = _vm->_resman->getNumClusters(); - - if (!numClusters) { - DebugPrintf("Argh! No resources!\n"); - return true; - } - - ResourceFile *resFiles = _vm->_resman->getResFiles(); - - for (uint i = 0; i < numClusters; i++) { - const char *locStr[3] = { "HDD", "CD1", "CD2" }; - - DebugPrintf("%-20s %d\n", resFiles[i].fileName, locStr[resFiles[i].cd]); - } - - DebugPrintf("%d resources\n", _vm->_resman->getNumResFiles()); - return true; -} - -bool Debugger::Cmd_ResList(int argc, const char **argv) { - // By default, list only resources that are being held open. - uint minCount = 1; - - if (argc > 1) - minCount = atoi(argv[1]); - - uint32 numResFiles = _vm->_resman->getNumResFiles(); - Resource *resList = _vm->_resman->getResList(); - - for (uint i = 0; i < numResFiles; i++) { - if (resList[i].ptr && resList[i].refCount >= minCount) { - DebugPrintf("%-4d: %-35s refCount: %-3d\n", i, _vm->_resman->fetchName(resList[i].ptr), resList[i].refCount); - } - } - - return true; -} - -bool Debugger::Cmd_Starts(int argc, const char **argv) { - uint32 numStarts = _vm->getNumStarts(); - - if (!numStarts) { - DebugPrintf("Sorry - no startup positions registered?\n"); - - uint32 numScreenManagers = _vm->getNumScreenManagers(); - - if (!numScreenManagers) - DebugPrintf("There is a problem with startup.inf\n"); - else - DebugPrintf(" (%d screen managers found in startup.inf)\n", numScreenManagers); - return true; - } - - StartUp *startList = _vm->getStartList(); - - for (uint i = 0; i < numStarts; i++) - DebugPrintf("%d (%s)\n", i, startList[i].description); - - return true; -} - -bool Debugger::Cmd_Start(int argc, const char **argv) { - uint8 pal[4] = { 255, 255, 255, 0 }; - - if (argc != 2) { - DebugPrintf("Usage: %s number\n", argv[0]); - return true; - } - - uint32 numStarts = _vm->getNumStarts(); - - if (!numStarts) { - DebugPrintf("Sorry - there are no startups!\n"); - return true; - } - - int start = atoi(argv[1]); - - if (start < 0 || start >= (int)numStarts) { - DebugPrintf("Not a legal start position\n"); - return true; - } - - DebugPrintf("Running start %d\n", start); - - _vm->runStart(start); - _vm->_screen->setPalette(187, 1, pal, RDPAL_INSTANT); - return true; -} - -bool Debugger::Cmd_Info(int argc, const char **argv) { - _displayDebugText = !_displayDebugText; - - if (_displayDebugText) - DebugPrintf("Info text on\n"); - else - DebugPrintf("Info Text off\n"); - - return true; -} - -bool Debugger::Cmd_WalkGrid(int argc, const char **argv) { - _displayWalkGrid = !_displayWalkGrid; - - if (_displayWalkGrid) - DebugPrintf("Walk-grid display on\n"); - else - DebugPrintf("Walk-grid display off\n"); - - return true; -} - -bool Debugger::Cmd_Mouse(int argc, const char **argv) { - _displayMouseMarker = !_displayMouseMarker; - - if (_displayMouseMarker) - DebugPrintf("Mouse marker on\n"); - else - DebugPrintf("Mouse marker off\n"); - - return true; -} - -bool Debugger::Cmd_Player(int argc, const char **argv) { - _displayPlayerMarker = !_displayPlayerMarker; - - if (_displayPlayerMarker) - DebugPrintf("Player feet marker on\n"); - else - DebugPrintf("Player feet marker off\n"); - - return true; -} - -bool Debugger::Cmd_ResLook(int argc, const char **argv) { - if (argc != 2) { - DebugPrintf("Usage: %s number\n", argv[0]); - return true; - } - - int res = atoi(argv[1]); - uint32 numResFiles = _vm->_resman->getNumResFiles(); - - if (res < 0 || res >= (int)numResFiles) { - DebugPrintf("Illegal resource %d. There are %d resources, 0-%d.\n", - res, numResFiles, numResFiles - 1); - return true; - } - - if (!_vm->_resman->checkValid(res)) { - DebugPrintf("%d is a null & void resource number\n", res); - return true; - } - - // Open up the resource and take a look inside! - uint8 type = _vm->_resman->fetchType(res);; - byte name[NAME_LEN]; - - _vm->_resman->fetchName(res, name); - - switch (type) { - case ANIMATION_FILE: - DebugPrintf("<anim> %s\n", name); - break; - case SCREEN_FILE: - DebugPrintf("<layer> %s\n", name); - break; - case GAME_OBJECT: - DebugPrintf("<game object> %s\n", name); - break; - case WALK_GRID_FILE: - DebugPrintf("<walk grid> %s\n", name); - break; - case GLOBAL_VAR_FILE: - DebugPrintf("<global variables> %s\n", name); - break; - case PARALLAX_FILE_null: - DebugPrintf("<parallax file NOT USED!> %s\n", name); - break; - case RUN_LIST: - DebugPrintf("<run list> %s\n", name); - break; - case TEXT_FILE: - DebugPrintf("<text file> %s\n", name); - break; - case SCREEN_MANAGER: - DebugPrintf("<screen manager> %s\n", name); - break; - case MOUSE_FILE: - DebugPrintf("<mouse pointer> %s\n", name); - break; - case ICON_FILE: - DebugPrintf("<menu icon> %s\n", name); - break; - default: - DebugPrintf("unrecognised fileType %d\n", type); - break; - } - - return true; -} - -bool Debugger::Cmd_CurrentInfo(int argc, const char **argv) { - // prints general stuff about the screen, etc. - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - if (screenInfo->background_layer_id) { - DebugPrintf("background layer id %d\n", screenInfo->background_layer_id); - DebugPrintf("%d wide, %d high\n", screenInfo->screen_wide, screenInfo->screen_deep); - DebugPrintf("%d normal layers\n", screenInfo->number_of_layers); - - Cmd_RunList(argc, argv); - } else - DebugPrintf("No screen\n"); - return true; -} - -bool Debugger::Cmd_RunList(int argc, const char **argv) { - uint32 runList = _vm->_logic->getRunList(); - - if (runList) { - Common::MemoryReadStream readS(_vm->_resman->openResource(runList), _vm->_resman->fetchLen(runList)); - - readS.seek(ResHeader::size()); - - DebugPrintf("Runlist number %d\n", runList); - - while (1) { - uint32 res = readS.readUint32LE(); - if (!res) - break; - - byte name[NAME_LEN]; - - DebugPrintf("%d %s\n", res, _vm->_resman->fetchName(res, name)); - } - - _vm->_resman->closeResource(runList); - } else - DebugPrintf("No run list set\n"); - - return true; -} - -bool Debugger::Cmd_Kill(int argc, const char **argv) { - if (argc != 2) { - DebugPrintf("Usage: %s number\n", argv[0]); - return true; - } - - int res = atoi(argv[1]); - uint32 numResFiles = _vm->_resman->getNumResFiles(); - - if (res < 0 || res >= (int)numResFiles) { - DebugPrintf("Illegal resource %d. There are %d resources, 0-%d.\n", - res, numResFiles, numResFiles - 1); - return true; - } - - Resource *resList = _vm->_resman->getResList(); - - if (!resList[res].ptr) { - DebugPrintf("Resource %d is not in memory\n", res); - return true; - } - - if (resList[res].refCount) { - DebugPrintf("Resource %d is open - cannot remove\n", res); - return true; - } - - _vm->_resman->remove(res); - DebugPrintf("Trashed %d\n", res); - return true; -} - -bool Debugger::Cmd_Nuke(int argc, const char **argv) { - DebugPrintf("Killing all resources except variable file and player object\n"); - _vm->_resman->killAll(true); - return true; -} - -bool Debugger::Cmd_Var(int argc, const char **argv) { - switch (argc) { - case 2: - varGet(atoi(argv[1])); - break; - case 3: - varSet(atoi(argv[1]), atoi(argv[2])); - break; - default: - DebugPrintf("Usage: %s number value\n", argv[0]); - break; - } - - return true; -} - -bool Debugger::Cmd_Rect(int argc, const char **argv) { - uint32 filter = _vm->setInputEventFilter(0); - - _definingRectangles = !_definingRectangles; - - if (_definingRectangles) { - _vm->setInputEventFilter(filter & ~(RD_LEFTBUTTONUP | RD_RIGHTBUTTONUP)); - DebugPrintf("Mouse rectangles enabled\n"); - } else { - _vm->setInputEventFilter(filter | RD_LEFTBUTTONUP | RD_RIGHTBUTTONUP); - DebugPrintf("Mouse rectangles disabled\n"); - } - - _draggingRectangle = 0; - return true; -} - -bool Debugger::Cmd_Clear(int argc, const char **argv) { - _vm->_resman->killAllObjects(true); - return true; -} - -bool Debugger::Cmd_DebugOn(int argc, const char **argv) { - _displayDebugText = true; - _displayWalkGrid = true; - _displayMouseMarker = true; - _displayPlayerMarker = true; - _displayTextNumbers = true; - DebugPrintf("Enabled all on-screen debug info\n"); - return true; -} - -bool Debugger::Cmd_DebugOff(int argc, const char **argv) { - _displayDebugText = false; - _displayWalkGrid = false; - _displayMouseMarker = false; - _displayPlayerMarker = false; - _displayTextNumbers = false; - DebugPrintf("Disabled all on-screen debug info\n"); - return true; -} - -bool Debugger::Cmd_SaveRest(int argc, const char **argv) { - _testingSnR = !_testingSnR; - - if (_testingSnR) - DebugPrintf("Enabled S&R logic_script stability checking\n"); - else - DebugPrintf("Disabled S&R logic_script stability checking\n"); - - return true; -} - -bool Debugger::Cmd_TimeOn(int argc, const char **argv) { - if (argc == 2) - _startTime = _vm->_system->getMillis() - atoi(argv[1]) * 1000; - else if (_startTime == 0) - _startTime = _vm->_system->getMillis(); - _displayTime = true; - DebugPrintf("Timer display on\n"); - return true; -} - -bool Debugger::Cmd_TimeOff(int argc, const char **argv) { - _displayTime = false; - DebugPrintf("Timer display off\n"); - return true; -} - -bool Debugger::Cmd_Text(int argc, const char **argv) { - _displayTextNumbers = !_displayTextNumbers; - - if (_displayTextNumbers) - DebugPrintf("Text numbers on\n"); - else - DebugPrintf("Text numbers off\n"); - - return true; -} - -bool Debugger::Cmd_ShowVar(int argc, const char **argv) { - int32 showVarNo = 0; - int32 varNo; - - if (argc != 2) { - DebugPrintf("Usage: %s number\n", argv[0]); - return true; - } - - varNo = atoi(argv[1]); - - // search for a spare slot in the watch-list, but also watch out for - // this variable already being in the list - - while (showVarNo < MAX_SHOWVARS && _showVar[showVarNo] != 0 && _showVar[showVarNo] != varNo) - showVarNo++; - - // if we've found a spare slot or the variable's already there - if (showVarNo < MAX_SHOWVARS) { - if (_showVar[showVarNo] == 0) { - // empty slot - add it to the list at this slot - _showVar[showVarNo] = varNo; - DebugPrintf("var(%d) added to the watch-list\n", varNo); - } else - DebugPrintf("var(%d) already in the watch-list!\n", varNo); - } else - DebugPrintf("Sorry - no more allowed - hide one or extend the system watch-list\n"); - - return true; -} - -bool Debugger::Cmd_HideVar(int argc, const char **argv) { - int32 showVarNo = 0; - int32 varNo; - - if (argc != 2) { - DebugPrintf("Usage: %s number\n", argv[0]); - return true; - } - - varNo = atoi(argv[1]); - - // search for 'varNo' in the watch-list - while (showVarNo < MAX_SHOWVARS && _showVar[showVarNo] != varNo) - showVarNo++; - - if (showVarNo < MAX_SHOWVARS) { - // We've found 'varNo' in the list - clear this slot - _showVar[showVarNo] = 0; - DebugPrintf("var(%d) removed from watch-list\n", varNo); - } else - DebugPrintf("Sorry - can't find var(%d) in the list\n", varNo); - - return true; -} - -bool Debugger::Cmd_Version(int argc, const char **argv) { - // This function used to print more information, but nothing we - // particularly care about. - - DebugPrintf("\"Broken Sword II\" (c) Revolution Software 1997.\n"); - return true; -} - -bool Debugger::Cmd_AnimTest(int argc, const char **argv) { - if (argc != 2) { - DebugPrintf("Usage: %s value\n", argv[0]); - return true; - } - - // Automatically do "s 32" to run the animation testing start script - _vm->runStart(32); - - // Same as typing "VAR 912 <value>" at the console - varSet(912, atoi(argv[1])); - - DebugPrintf("Setting flag 'system_testing_anims'\n"); - return true; -} - -bool Debugger::Cmd_TextTest(int argc, const char **argv) { - if (argc != 2) { - DebugPrintf("Usage: %s value\n", argv[0]); - return true; - } - - // Automatically do "s 33" to run the text/speech testing start script - _vm->runStart(33); - - // Same as typing "VAR 1230 <value>" at the console - varSet(1230, atoi(argv[1])); - - _displayTextNumbers = true; - - DebugPrintf("Setting flag 'system_testing_text'\n"); - DebugPrintf("Text numbers on\n"); - return true; -} - -bool Debugger::Cmd_LineTest(int argc, const char **argv) { - if (argc != 3) { - DebugPrintf("Usage: %s value1 value2\n", argv[0]); - return true; - } - - // Automatically do "s 33" to run the text/speech testing start script - _vm->runStart(33); - - // Same as typing "VAR 1230 <value>" at the console - varSet(1230, atoi(argv[1])); - - // Same as typing "VAR 1264 <value>" at the console - varSet(1264, atoi(argv[2])); - - _displayTextNumbers = true; - - DebugPrintf("Setting flag 'system_testing_text'\n"); - DebugPrintf("Setting flag 'system_test_line_no'\n"); - DebugPrintf("Text numbers on\n"); - return true; -} - -bool Debugger::Cmd_Events(int argc, const char **argv) { - EventUnit *eventList = _vm->_logic->getEventList(); - - DebugPrintf("EVENT LIST:\n"); - - for (uint32 i = 0; i < MAX_events; i++) { - if (eventList[i].id) { - byte buf[NAME_LEN]; - uint32 target = eventList[i].id; - uint32 script = eventList[i].interact_id; - - DebugPrintf("slot %2d: id = %s (%d)\n", i, _vm->_resman->fetchName(target, buf), target); - DebugPrintf(" script = %s (%d) pos %d\n", _vm->_resman->fetchName(script / 65536, buf), script / 65536, script % 65536); - } - } - - return true; -} - -bool Debugger::Cmd_Sfx(int argc, const char **argv) { - _vm->_wantSfxDebug = !_vm->_wantSfxDebug; - - if (_vm->_wantSfxDebug) - DebugPrintf("SFX logging activated\n"); - else - DebugPrintf("SFX logging deactivated\n"); - - return true; -} - -bool Debugger::Cmd_English(int argc, const char **argv) { - _vm->initialiseFontResourceFlags(DEFAULT_TEXT); - DebugPrintf("Default fonts selected\n"); - return true; -} - -bool Debugger::Cmd_Finnish(int argc, const char **argv) { - _vm->initialiseFontResourceFlags(FINNISH_TEXT); - DebugPrintf("Finnish fonts selected\n"); - return true; -} - -bool Debugger::Cmd_Polish(int argc, const char **argv) { - _vm->initialiseFontResourceFlags(POLISH_TEXT); - DebugPrintf("Polish fonts selected\n"); - return true; -} - -} // End of namespace Sword2 diff --git a/sword2/console.h b/sword2/console.h deleted file mode 100644 index 95bfbe946d..0000000000 --- a/sword2/console.h +++ /dev/null @@ -1,127 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef C_ONSOLE_H -#define C_ONSOLE_H - -#include "common/debugger.h" -#include "sword2/debug.h" - -namespace Sword2 { - -class Debugger : public Common::Debugger<Debugger> { -private: - void varGet(int var); - void varSet(int var, int val); - - bool _displayDebugText; - bool _displayWalkGrid; - bool _displayMouseMarker; - bool _displayTime; - bool _displayPlayerMarker; - bool _displayTextNumbers; - - bool _rectFlicker; - - int32 _startTime; - - int32 _showVar[MAX_SHOWVARS]; - - byte _debugTextBlocks[MAX_DEBUG_TEXTS]; - - void clearDebugTextBlocks(); - void makeDebugTextBlock(char *text, int16 x, int16 y); - - void plotCrossHair(int16 x, int16 y, uint8 pen); - void drawRect(int16 x, int16 y, int16 x2, int16 y2, uint8 pen); - -public: - Debugger(Sword2Engine *vm); - - int16 _rectX1, _rectY1; - int16 _rectX2, _rectY2; - - uint8 _draggingRectangle; - bool _definingRectangles; - - bool _testingSnR; - - int32 _speechScriptWaiting; - - int32 _textNumber; - - int32 _graphType; - int32 _graphAnimRes; - int32 _graphAnimPc; - uint32 _graphNoFrames; - - void buildDebugText(); - void drawDebugGraphics(); - -protected: - Sword2Engine *_vm; - - virtual void preEnter(); - virtual void postEnter(); - - // Commands - bool Cmd_Exit(int argc, const char **argv); - bool Cmd_Help(int argc, const char **argv); - bool Cmd_Mem(int argc, const char **argv); - bool Cmd_Tony(int argc, const char **argv); - bool Cmd_Res(int argc, const char **argv); - bool Cmd_ResList(int argc, const char **argv); - bool Cmd_Starts(int argc, const char **argv); - bool Cmd_Start(int argc, const char **argv); - bool Cmd_Info(int argc, const char **argv); - bool Cmd_WalkGrid(int argc, const char **argv); - bool Cmd_Mouse(int argc, const char **argv); - bool Cmd_Player(int argc, const char **argv); - bool Cmd_ResLook(int argc, const char **argv); - bool Cmd_CurrentInfo(int argc, const char **argv); - bool Cmd_RunList(int argc, const char **argv); - bool Cmd_Kill(int argc, const char **argv); - bool Cmd_Nuke(int argc, const char **argv); - bool Cmd_Var(int argc, const char **argv); - bool Cmd_Rect(int argc, const char **argv); - bool Cmd_Clear(int argc, const char **argv); - bool Cmd_DebugOn(int argc, const char **argv); - bool Cmd_DebugOff(int argc, const char **argv); - bool Cmd_SaveRest(int argc, const char **argv); - bool Cmd_TimeOn(int argc, const char **argv); - bool Cmd_TimeOff(int argc, const char **argv); - bool Cmd_Text(int argc, const char **argv); - bool Cmd_ShowVar(int argc, const char **argv); - bool Cmd_HideVar(int argc, const char **argv); - bool Cmd_Version(int argc, const char **argv); - bool Cmd_AnimTest(int argc, const char **argv); - bool Cmd_TextTest(int argc, const char **argv); - bool Cmd_LineTest(int argc, const char **argv); - bool Cmd_Events(int argc, const char **argv); - bool Cmd_Sfx(int argc, const char **argv); - bool Cmd_English(int argc, const char **argv); - bool Cmd_Finnish(int argc, const char **argv); - bool Cmd_Polish(int argc, const char **argv); -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/controls.cpp b/sword2/controls.cpp deleted file mode 100644 index df1b38c83e..0000000000 --- a/sword2/controls.cpp +++ /dev/null @@ -1,1416 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "common/rect.h" -#include "common/config-manager.h" -#include "common/system.h" - -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/controls.h" -#include "sword2/mouse.h" -#include "sword2/resman.h" -#include "sword2/sound.h" - -#define MAX_STRING_LEN 64 // 20 was too low; better to be safe ;) -#define CHARACTER_OVERLAP 2 // overlap characters by 3 pixels - -// our fonts start on SPACE character (32) -#define SIZE_OF_CHAR_SET (256 - 32) - -namespace Sword2 { - -static int baseSlot = 0; - -class Widget; - -/** - * Base class for all widgets. - */ - -class Widget { -protected: - Sword2Engine *_vm; - Dialog *_parent; - - SpriteInfo *_sprites; - - struct WidgetSurface { - byte *_surface; - bool _original; - }; - - WidgetSurface *_surfaces; - int _numStates; - int _state; - - Common::Rect _hitRect; - -public: - Widget(Dialog *parent, int states); - - virtual ~Widget(); - - void createSurfaceImage(int state, uint32 res, int x, int y, uint32 pc); - void linkSurfaceImage(Widget *from, int state, int x, int y); - - void createSurfaceImages(uint32 res, int x, int y); - void linkSurfaceImages(Widget *from, int x, int y); - - void setHitRect(int x, int y, int width, int height); - bool isHit(int16 x, int16 y); - - void setState(int state); - int getState(); - - virtual void paint(Common::Rect *clipRect = NULL); - - virtual void onMouseEnter() {} - virtual void onMouseExit() {} - virtual void onMouseMove(int x, int y) {} - virtual void onMouseDown(int x, int y) {} - virtual void onMouseUp(int x, int y) {} - virtual void onWheelUp(int x, int y) {} - virtual void onWheelDown(int x, int y) {} - virtual void onKey(KeyboardEvent *ke) {} - virtual void onTick() {} - - virtual void releaseMouse(int x, int y) {} -}; - -/** - * This class is used to draw text in dialogs, buttons, etc. - */ - -class FontRendererGui { -private: - Sword2Engine *_vm; - - struct Glyph { - byte *_data; - int _width; - int _height; - }; - - Glyph _glyph[SIZE_OF_CHAR_SET]; - - int _fontId; - -public: - enum { - kAlignLeft, - kAlignRight, - kAlignCenter - }; - - FontRendererGui(Sword2Engine *vm, int fontId); - ~FontRendererGui(); - - void fetchText(uint32 textId, byte *buf); - - int getCharWidth(byte c); - int getCharHeight(byte c); - - int getTextWidth(byte *text); - int getTextWidth(uint32 textId); - - void drawText(byte *text, int x, int y, int alignment = kAlignLeft); - void drawText(uint32 textId, int x, int y, int alignment = kAlignLeft); -}; - -FontRendererGui::FontRendererGui(Sword2Engine *vm, int fontId) - : _vm(vm), _fontId(fontId) { - byte *font = _vm->_resman->openResource(fontId); - SpriteInfo sprite; - - sprite.type = RDSPR_NOCOMPRESSION | RDSPR_TRANS; - - for (int i = 0; i < SIZE_OF_CHAR_SET; i++) { - byte *frame = _vm->fetchFrameHeader(font, i); - - FrameHeader frame_head; - - frame_head.read(frame); - - sprite.data = frame + FrameHeader::size(); - sprite.w = frame_head.width; - sprite.h = frame_head.height; - _vm->_screen->createSurface(&sprite, &_glyph[i]._data); - _glyph[i]._width = frame_head.width; - _glyph[i]._height = frame_head.height; - } - - _vm->_resman->closeResource(fontId); -} - -FontRendererGui::~FontRendererGui() { - for (int i = 0; i < SIZE_OF_CHAR_SET; i++) - _vm->_screen->deleteSurface(_glyph[i]._data); -} - -void FontRendererGui::fetchText(uint32 textId, byte *buf) { - byte *data = _vm->fetchTextLine(_vm->_resman->openResource(textId / SIZE), textId & 0xffff); - int i; - - for (i = 0; data[i + 2]; i++) { - if (buf) - buf[i] = data[i + 2]; - } - - buf[i] = 0; - _vm->_resman->closeResource(textId / SIZE); -} - -int FontRendererGui::getCharWidth(byte c) { - if (c < 32) - return 0; - return _glyph[c - 32]._width; -} - -int FontRendererGui::getCharHeight(byte c) { - if (c < 32) - return 0; - return _glyph[c - 32]._height; -} - -int FontRendererGui::getTextWidth(byte *text) { - int textWidth = 0; - - for (int i = 0; text[i]; i++) - if (text[i] >= ' ') - textWidth += (getCharWidth(text[i]) - CHARACTER_OVERLAP); - return textWidth; -} - -int FontRendererGui::getTextWidth(uint32 textId) { - byte text[MAX_STRING_LEN]; - - fetchText(textId, text); - return getTextWidth(text); -} - -void FontRendererGui::drawText(byte *text, int x, int y, int alignment) { - SpriteInfo sprite; - int i; - - if (alignment != kAlignLeft) { - int textWidth = getTextWidth(text); - - switch (alignment) { - case kAlignRight: - x -= textWidth; - break; - case kAlignCenter: - x -= (textWidth / 2); - break; - } - } - - sprite.x = x; - sprite.y = y; - - for (i = 0; text[i]; i++) { - if (text[i] >= ' ') { - sprite.w = getCharWidth(text[i]); - sprite.h = getCharHeight(text[i]); - - _vm->_screen->drawSurface(&sprite, _glyph[text[i] - 32]._data); - - sprite.x += (getCharWidth(text[i]) - CHARACTER_OVERLAP); - } - } -} - -void FontRendererGui::drawText(uint32 textId, int x, int y, int alignment) { - byte text[MAX_STRING_LEN]; - - fetchText(textId, text); - drawText(text, x, y, alignment); -} - -// -// Dialog class functions -// - -Dialog::Dialog(Sword2Engine *vm) - : _numWidgets(0), _finish(false), _result(0), _vm(vm) { - _vm->_screen->setFullPalette(CONTROL_PANEL_PALETTE); - _vm->_screen->clearScene(); - _vm->_screen->updateDisplay(); - - // Usually the mouse pointer will already be "normal", but not always. - _vm->_mouse->setMouse(NORMAL_MOUSE_ID); -} - -Dialog::~Dialog() { - for (int i = 0; i < _numWidgets; i++) - delete _widgets[i]; - _vm->_screen->clearScene(); - _vm->_screen->updateDisplay(); -} - -void Dialog::registerWidget(Widget *widget) { - if (_numWidgets < MAX_WIDGETS) - _widgets[_numWidgets++] = widget; -} - -void Dialog::paint() { - _vm->_screen->clearScene(); - for (int i = 0; i < _numWidgets; i++) - _widgets[i]->paint(); -} - -void Dialog::setResult(int result) { - _result = result; - _finish = true; -} - -int Dialog::runModal() { - uint32 oldFilter = _vm->setInputEventFilter(0); - - int i; - - paint(); - - int oldMouseX = -1; - int oldMouseY = -1; - - while (!_finish) { - // So that the menu icons will reach their full size - _vm->_mouse->processMenu(); - _vm->_screen->updateDisplay(false); - - int newMouseX, newMouseY; - - _vm->_mouse->getPos(newMouseX, newMouseY); - - newMouseY += 40; - - MouseEvent *me = _vm->mouseEvent(); - KeyboardEvent *ke = _vm->keyboardEvent(); - - if (ke) { - if (ke->keycode == 27) - setResult(0); - else if (ke->keycode == '\n' || ke->keycode == '\r') - setResult(1); - } - - int oldHit = -1; - int newHit = -1; - - // Find out which widget the mouse was over the last time, and - // which it is currently over. This assumes the widgets do not - // overlap. - - for (i = 0; i < _numWidgets; i++) { - if (_widgets[i]->isHit(oldMouseX, oldMouseY)) - oldHit = i; - if (_widgets[i]->isHit(newMouseX, newMouseY)) - newHit = i; - } - - // Was the mouse inside a widget the last time? - - if (oldHit >= 0) { - if (newHit != oldHit) - _widgets[oldHit]->onMouseExit(); - } - - // Is the mouse currently in a widget? - - if (newHit >= 0) { - if (newHit != oldHit) - _widgets[newHit]->onMouseEnter(); - - if (me) { - switch (me->buttons) { - case RD_LEFTBUTTONDOWN: - _widgets[newHit]->onMouseDown(newMouseX, newMouseY); - break; - case RD_LEFTBUTTONUP: - _widgets[newHit]->onMouseUp(newMouseX, newMouseY); - break; - case RD_WHEELUP: - _widgets[newHit]->onWheelUp(newMouseX, newMouseY); - break; - case RD_WHEELDOWN: - _widgets[newHit]->onWheelDown(newMouseX, newMouseY); - break; - } - } - } - - // Some events are passed to the widgets regardless of where - // the mouse cursor is. - - for (i = 0; i < _numWidgets; i++) { - if (me && me->buttons == RD_LEFTBUTTONUP) { - // So that slider widgets will know when the - // user releases the mouse button, even if the - // cursor is outside of the slider's hit area. - _widgets[i]->releaseMouse(newMouseX, newMouseY); - } - - // This is to make it easier to drag the slider widget - - if (newMouseX != oldMouseX || newMouseY != oldMouseY) - _widgets[i]->onMouseMove(newMouseX, newMouseY); - - if (ke) - _widgets[i]->onKey(ke); - - _widgets[i]->onTick(); - } - - oldMouseX = newMouseX; - oldMouseY = newMouseY; - - _vm->_system->delayMillis(20); - - if (_vm->_quit) - setResult(0); - } - - _vm->setInputEventFilter(oldFilter); - return _result; -} - -// -// Widget functions -// - -Widget::Widget(Dialog *parent, int states) - : _vm(parent->_vm), _parent(parent), _numStates(states), _state(0) { - _sprites = (SpriteInfo *)calloc(states, sizeof(SpriteInfo)); - _surfaces = (WidgetSurface *)calloc(states, sizeof(WidgetSurface)); - - _hitRect.left = _hitRect.right = _hitRect.top = _hitRect.bottom = -1; -} - -Widget::~Widget() { - for (int i = 0; i < _numStates; i++) { - if (_surfaces[i]._original) - _vm->_screen->deleteSurface(_surfaces[i]._surface); - } - free(_sprites); - free(_surfaces); -} - -void Widget::createSurfaceImage(int state, uint32 res, int x, int y, uint32 pc) { - byte *file, *colTablePtr = NULL; - AnimHeader anim_head; - FrameHeader frame_head; - CdtEntry cdt_entry; - uint32 spriteType = RDSPR_TRANS; - - // open anim resource file, point to base - file = _vm->_resman->openResource(res); - - byte *frame = _vm->fetchFrameHeader(file, pc); - - anim_head.read(_vm->fetchAnimHeader(file)); - cdt_entry.read(_vm->fetchCdtEntry(file, pc)); - frame_head.read(frame); - - // If the frame is flipped. (Only really applicable to frames using - // offsets.) - - if (cdt_entry.frameType & FRAME_FLIPPED) - spriteType |= RDSPR_FLIP; - - // Which compression was used? - - switch (anim_head.runTimeComp) { - case NONE: - spriteType |= RDSPR_NOCOMPRESSION; - break; - case RLE256: - spriteType |= RDSPR_RLE256; - break; - case RLE16: - spriteType |= RDSPR_RLE256; - // Points to just after last cdt_entry, i.e. start of colour - // table - colTablePtr = _vm->fetchAnimHeader(file) + AnimHeader::size() - + anim_head.noAnimFrames * CdtEntry::size(); - break; - } - - _sprites[state].x = x; - _sprites[state].y = y; - _sprites[state].w = frame_head.width; - _sprites[state].h = frame_head.height; - _sprites[state].scale = 0; - _sprites[state].type = spriteType; - _sprites[state].blend = anim_head.blend; - - // Points to just after frame header, ie. start of sprite data - _sprites[state].data = frame + FrameHeader::size(); - - _vm->_screen->createSurface(&_sprites[state], &_surfaces[state]._surface); - _surfaces[state]._original = true; - - // Release the anim resource - _vm->_resman->closeResource(res); -} - -void Widget::linkSurfaceImage(Widget *from, int state, int x, int y) { - _sprites[state].x = x; - _sprites[state].y = y; - _sprites[state].w = from->_sprites[state].w; - _sprites[state].h = from->_sprites[state].h; - _sprites[state].scale = from->_sprites[state].scale; - _sprites[state].type = from->_sprites[state].type; - _sprites[state].blend = from->_sprites[state].blend; - - _surfaces[state]._surface = from->_surfaces[state]._surface; - _surfaces[state]._original = false; -} - -void Widget::createSurfaceImages(uint32 res, int x, int y) { - for (int i = 0; i < _numStates; i++) - createSurfaceImage(i, res, x, y, i); -} - -void Widget::linkSurfaceImages(Widget *from, int x, int y) { - for (int i = 0; i < from->_numStates; i++) - linkSurfaceImage(from, i, x, y); -} - -void Widget::setHitRect(int x, int y, int width, int height) { - _hitRect.left = x; - _hitRect.right = x + width; - _hitRect.top = y; - _hitRect.bottom = y + height; -} - -bool Widget::isHit(int16 x, int16 y) { - return _hitRect.left >= 0 && _hitRect.contains(x, y); -} - -void Widget::setState(int state) { - if (state != _state) { - _state = state; - paint(); - } -} - -int Widget::getState() { - return _state; -} - -void Widget::paint(Common::Rect *clipRect) { - _vm->_screen->drawSurface(&_sprites[_state], _surfaces[_state]._surface, clipRect); -} - -/** - * Standard button class. - */ - -class Button : public Widget { -public: - Button(Dialog *parent, int x, int y, int w, int h) - : Widget(parent, 2) { - setHitRect(x, y, w, h); - } - - virtual void onMouseExit() { - setState(0); - } - - virtual void onMouseDown(int x, int y) { - setState(1); - } - - virtual void onMouseUp(int x, int y) { - if (getState() != 0) { - setState(0); - _parent->onAction(this); - } - } -}; - -/** - * Scroll buttons are used to scroll the savegame list. The difference between - * this and a normal button is that we want this to repeat. - */ - -class ScrollButton : public Widget { -private: - uint32 _holdCounter; - -public: - ScrollButton(Dialog *parent, int x, int y, int w, int h) - : Widget(parent, 2), _holdCounter(0) { - setHitRect(x, y, w, h); - } - - virtual void onMouseExit() { - setState(0); - } - - virtual void onMouseDown(int x, int y) { - setState(1); - _parent->onAction(this); - _holdCounter = 0; - } - - virtual void onMouseUp(int x, int y) { - setState(0); - } - - virtual void onTick() { - if (getState() != 0) { - _holdCounter++; - if (_holdCounter > 16 && (_holdCounter % 4) == 0) - _parent->onAction(this); - } - } -}; - -/** - * A switch is a button that changes state when clicked, and keeps that state - * until clicked again. - */ - -class Switch : public Widget { -private: - bool _holding, _value; - int _upState, _downState; - -public: - Switch(Dialog *parent, int x, int y, int w, int h) - : Widget(parent, 2), _holding(false), _value(false), - _upState(0), _downState(1) { - setHitRect(x, y, w, h); - } - - // The sound mute switches have 0 as their "down" state and 1 as - // their "up" state, so this function is needed to get consistent - // behaviour. - - void reverseStates() { - _upState = 1; - _downState = 0; - } - - void setValue(bool value) { - _value = value; - if (_value) - setState(_downState); - else - setState(_upState); - } - - bool getValue() { - return _value; - } - - virtual void onMouseExit() { - if (_holding && !_value) - setState(_upState); - _holding = false; - } - - virtual void onMouseDown(int x, int y) { - _holding = true; - setState(_downState); - } - - virtual void onMouseUp(int x, int y) { - if (_holding) { - _holding = false; - _value = !_value; - if (_value) - setState(_downState); - else - setState(_upState); - _parent->onAction(this, getState()); - } - } -}; - -/** - * A slider is used to specify a value within a pre-defined range. - */ - -class Slider : public Widget { -private: - Widget *_background; - bool _dragging; - int _value, _targetValue; - int _maxValue; - int _valueStep; - int _dragOffset; - - int posFromValue(int value) { - return _hitRect.left + (value * (_hitRect.width() - 38)) / _maxValue; - } - - int valueFromPos(int x) { - return (int)((double)(_maxValue * (x - _hitRect.left)) / (double)(_hitRect.width() - 38) + 0.5); - } - -public: - Slider(Dialog *parent, Widget *background, int max, - int x, int y, int w, int h, int step, Widget *base = NULL) - : Widget(parent, 1), _background(background), - _dragging(false), _value(0), _targetValue(0), - _maxValue(max), _valueStep(step) { - setHitRect(x, y, w, h); - - if (_valueStep <= 0) - _valueStep = 1; - - if (base) - linkSurfaceImages(base, x, y); - else - createSurfaceImages(3406, x, y); - } - - virtual void paint(Common::Rect *clipRect = NULL) { - // This will redraw a bit more than is strictly necessary, - // but I doubt that will make any noticeable difference. - - _background->paint(&_hitRect); - Widget::paint(clipRect); - } - - void setValue(int value) { - _value = value; - _targetValue = value; - _sprites[0].x = posFromValue(_value); - paint(); - } - - int getValue() { - return _value; - } - - virtual void onMouseMove(int x, int y) { - if (_dragging) { - int newX = x - _dragOffset; - int newValue; - - if (newX < _hitRect.left) - newX = _hitRect.left; - else if (newX + 38 > _hitRect.right) - newX = _hitRect.right - 38; - - _sprites[0].x = newX; - - newValue = valueFromPos(newX); - if (newValue != _value) { - _value = newValue; - _targetValue = newValue; - _parent->onAction(this, newValue); - } - - paint(); - } - } - - virtual void onMouseDown(int x, int y) { - if (x >= _sprites[0].x && x < _sprites[0].x + 38) { - _dragging = true; - _dragOffset = x - _sprites[0].x; - } else if (x < _sprites[0].x) { - if (_targetValue >= _valueStep) - _targetValue -= _valueStep; - else - _targetValue = 0; - } else { - if (_targetValue < _maxValue - _valueStep) - _targetValue += _valueStep; - else - _targetValue = _maxValue; - } - } - - virtual void releaseMouse(int x, int y) { - if (_dragging) - _dragging = false; - } - - virtual void onTick() { - if (!_dragging) { - int target = posFromValue(_targetValue); - - if (target != _sprites[0].x) { - if (target < _sprites[0].x) { - _sprites[0].x -= 4; - if (_sprites[0].x < target) - _sprites[0].x = target; - } else if (target > _sprites[0].x) { - _sprites[0].x += 4; - if (_sprites[0].x > target) - _sprites[0].x = target; - } - - int newValue = valueFromPos(_sprites[0].x); - if (newValue != _value) { - _value = newValue; - _parent->onAction(this, newValue); - } - - paint(); - } - } - } -}; - -/** - * The "mini" dialog. - */ - -MiniDialog::MiniDialog(Sword2Engine *vm, uint32 headerTextId, uint32 okTextId, uint32 cancelTextId) : Dialog(vm) { - _headerTextId = headerTextId; - _okTextId = okTextId; - _cancelTextId = cancelTextId; - - _fr = new FontRendererGui(_vm, _vm->_controlsFontId); - - _panel = new Widget(this, 1); - _panel->createSurfaceImages(1996, 203, 104); - - _okButton = new Button(this, 243, 214, 24, 24); - _okButton->createSurfaceImages(2002, 243, 214); - - _cancelButton = new Button(this, 243, 276, 24, 24); - _cancelButton->linkSurfaceImages(_okButton, 243, 276); - - registerWidget(_panel); - registerWidget(_okButton); - registerWidget(_cancelButton); -} - -MiniDialog::~MiniDialog() { - delete _fr; -} - -void MiniDialog::paint() { - Dialog::paint(); - - if (_headerTextId) - _fr->drawText(_headerTextId, 310, 134, FontRendererGui::kAlignCenter); - _fr->drawText(_okTextId, 270, 214); - _fr->drawText(_cancelTextId, 270, 276); -} - -void MiniDialog::onAction(Widget *widget, int result) { - if (widget == _okButton) - setResult(1); - else if (widget == _cancelButton) - setResult(0); -} - -StartDialog::StartDialog(Sword2Engine *vm) : MiniDialog(vm, 0) {} - -int StartDialog::runModal() { - while (1) { - MiniDialog startDialog(_vm, 0, TEXT_RESTART, TEXT_RESTORE); - - if (startDialog.runModal()) - return 1; - - if (_vm->_quit) - return 0; - - RestoreDialog restoreDialog(_vm); - - if (restoreDialog.runModal()) - return 0; - - if (_vm->_quit) - return 0; - } - - return 1; -} - -/** - * The restart dialog. - */ - -RestartDialog::RestartDialog(Sword2Engine *vm) : MiniDialog(vm, TEXT_RESTART) {} - -int RestartDialog::runModal() { - int result = MiniDialog::runModal(); - - if (result) - _vm->restartGame(); - - return result; -} - -/** - * The quit dialog. - */ - -QuitDialog::QuitDialog(Sword2Engine *vm) : MiniDialog(vm, TEXT_QUIT) {} - -int QuitDialog::runModal() { - int result = MiniDialog::runModal(); - - if (result) - _vm->closeGame(); - - return result; -} - -/** - * The game settings dialog. - */ - -OptionsDialog::OptionsDialog(Sword2Engine *vm) : Dialog(vm) { - _fr = new FontRendererGui(_vm, _vm->_controlsFontId); - - _mixer = _vm->_mixer; - - _panel = new Widget(this, 1); - _panel->createSurfaceImages(3405, 0, 40); - - _objectLabelsSwitch = new Switch(this, 304, 100, 53, 32); - _objectLabelsSwitch->createSurfaceImages(3687, 304, 100); - - _subtitlesSwitch = new Switch(this, 510, 100, 53, 32); - _subtitlesSwitch->linkSurfaceImages(_objectLabelsSwitch, 510, 100); - - _reverseStereoSwitch = new Switch(this, 304, 293, 53, 32); - _reverseStereoSwitch->linkSurfaceImages(_objectLabelsSwitch, 304, 293); - - _musicSwitch = new Switch(this, 516, 157, 40, 32); - _musicSwitch->createSurfaceImages(3315, 516, 157); - _musicSwitch->reverseStates(); - - _speechSwitch = new Switch(this, 516, 205, 40, 32); - _speechSwitch->linkSurfaceImages(_musicSwitch, 516, 205); - _speechSwitch->reverseStates(); - - _fxSwitch = new Switch(this, 516, 250, 40, 32); - _fxSwitch->linkSurfaceImages(_musicSwitch, 516, 250); - _fxSwitch->reverseStates(); - - int volStep = Audio::Mixer::kMaxMixerVolume / 10; - - _musicSlider = new Slider(this, _panel, Audio::Mixer::kMaxMixerVolume, 309, 161, 170, 27, volStep); - _speechSlider = new Slider(this, _panel, Audio::Mixer::kMaxMixerVolume, 309, 208, 170, 27, volStep, _musicSlider); - _fxSlider = new Slider(this, _panel, Audio::Mixer::kMaxMixerVolume, 309, 254, 170, 27, volStep, _musicSlider); - _gfxSlider = new Slider(this, _panel, 3, 309, 341, 170, 27, 1, _musicSlider); - - _gfxPreview = new Widget(this, 4); - _gfxPreview->createSurfaceImages(256, 495, 310); - - _okButton = new Button(this, 203, 382, 53, 32); - _okButton->createSurfaceImages(901, 203, 382); - - _cancelButton = new Button(this, 395, 382, 53, 32); - _cancelButton->linkSurfaceImages(_okButton, 395, 382); - - registerWidget(_panel); - registerWidget(_objectLabelsSwitch); - registerWidget(_subtitlesSwitch); - registerWidget(_reverseStereoSwitch); - registerWidget(_musicSwitch); - registerWidget(_speechSwitch); - registerWidget(_fxSwitch); - registerWidget(_musicSlider); - registerWidget(_speechSlider); - registerWidget(_fxSlider); - registerWidget(_gfxSlider); - registerWidget(_gfxPreview); - registerWidget(_okButton); - registerWidget(_cancelButton); - - _objectLabelsSwitch->setValue(_vm->_mouse->getObjectLabels()); - _subtitlesSwitch->setValue(_vm->getSubtitles()); - _reverseStereoSwitch->setValue(_vm->_sound->isReverseStereo()); - _musicSwitch->setValue(!_vm->_sound->isMusicMute()); - _speechSwitch->setValue(!_vm->_sound->isSpeechMute()); - _fxSwitch->setValue(!_vm->_sound->isFxMute()); - - _musicSlider->setValue(_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType)); - _speechSlider->setValue(_mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType)); - _fxSlider->setValue(_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType)); - - _gfxSlider->setValue(_vm->_screen->getRenderLevel()); - _gfxPreview->setState(_vm->_screen->getRenderLevel()); -} - -OptionsDialog::~OptionsDialog() { - delete _fr; -} - -void OptionsDialog::paint() { - Dialog::paint(); - - int maxWidth = 0; - int width; - - uint32 alignTextIds[] = { - TEXT_OBJECT_LABELS, - TEXT_MUSIC_VOLUME, - TEXT_SPEECH_VOLUME, - TEXT_FX_VOLUME, - TEXT_GFX_QUALITY, - TEXT_REVERSE_STEREO - }; - - for (int i = 0; i < ARRAYSIZE(alignTextIds); i++) { - width = _fr->getTextWidth(alignTextIds[i]); - if (width > maxWidth) - maxWidth = width; - } - - _fr->drawText(TEXT_OPTIONS, 321, 55, FontRendererGui::kAlignCenter); - _fr->drawText(TEXT_SUBTITLES, 500, 103, FontRendererGui::kAlignRight); - _fr->drawText(TEXT_OBJECT_LABELS, 299 - maxWidth, 103); - _fr->drawText(TEXT_MUSIC_VOLUME, 299 - maxWidth, 161); - _fr->drawText(TEXT_SPEECH_VOLUME, 299 - maxWidth, 208); - _fr->drawText(TEXT_FX_VOLUME, 299 - maxWidth, 254); - _fr->drawText(TEXT_REVERSE_STEREO, 299 - maxWidth, 296); - _fr->drawText(TEXT_GFX_QUALITY, 299 - maxWidth, 341); - _fr->drawText(TEXT_OK, 193, 382, FontRendererGui::kAlignRight); - _fr->drawText(TEXT_CANCEL, 385, 382, FontRendererGui::kAlignRight); -} - -void OptionsDialog::onAction(Widget *widget, int result) { - // Since there is music playing while the dialog is displayed we need - // to update music volume immediately. - - if (widget == _musicSwitch) { - _vm->_sound->muteMusic(result != 0); - } else if (widget == _musicSlider) { - _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, result); - _vm->_sound->muteMusic(result == 0); - _musicSwitch->setValue(result != 0); - } else if (widget == _speechSlider) { - _speechSwitch->setValue(result != 0); - } else if (widget == _fxSlider) { - _fxSwitch->setValue(result != 0); - } else if (widget == _gfxSlider) { - _gfxPreview->setState(result); - _vm->_screen->setRenderLevel(result); - } else if (widget == _okButton) { - // Apply the changes - _vm->setSubtitles(_subtitlesSwitch->getValue()); - _vm->_mouse->setObjectLabels(_objectLabelsSwitch->getValue()); - _vm->_sound->muteMusic(!_musicSwitch->getValue()); - _vm->_sound->muteSpeech(!_speechSwitch->getValue()); - _vm->_sound->muteFx(!_fxSwitch->getValue()); - _vm->_sound->setReverseStereo(_reverseStereoSwitch->getValue()); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, _musicSlider->getValue()); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, _speechSlider->getValue()); - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, _fxSlider->getValue()); - _vm->_screen->setRenderLevel(_gfxSlider->getValue()); - - _vm->writeSettings(); - setResult(1); - } else if (widget == _cancelButton) { - // Revert the changes - _vm->readSettings(); - setResult(0); - } -} - -// Slot button actions. Note that keyboard input generates positive actions - -enum { - kSelectSlot = -1, - kDeselectSlot = -2, - kWheelDown = -3, - kWheelUp = -4, - kStartEditing = -5, - kCursorTick = -6 -}; - -class Slot : public Widget { -private: - int _mode; - FontRendererGui *_fr; - byte _text[SAVE_DESCRIPTION_LEN]; - bool _clickable; - bool _editable; - -public: - Slot(Dialog *parent, int x, int y, int w, int h) - : Widget(parent, 2), _clickable(false), _editable(false) { - setHitRect(x, y, w, h); - _text[0] = 0; - } - - void setMode(int mode) { - _mode = mode; - } - - void setClickable(bool clickable) { - _clickable = clickable; - } - - void setEditable(bool editable) { - _editable = editable; - _vm->_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, editable); - } - - bool isEditable() { - return _editable; - } - - void setText(FontRendererGui *fr, int slot, byte *text) { - _fr = fr; - if (text) - sprintf((char *)_text, "%d. %s", slot, text); - else - sprintf((char *)_text, "%d. ", slot); - } - - byte *getText() { - return &_text[0]; - } - - virtual void paint(Common::Rect *clipRect = NULL) { - Widget::paint(); - - // HACK: The main dialog is responsible for drawing the text - // when in editing mode. - - if (!_editable) - _fr->drawText(_text, _sprites[0].x + 16, _sprites[0].y + 4 + 2 * getState()); - } - - virtual void onMouseDown(int x, int y) { - if (_clickable) { - if (getState() == 0) { - setState(1); - _parent->onAction(this, kSelectSlot); - if (_mode == kSaveDialog) - _parent->onAction(this, kStartEditing); - } else if (_mode == kRestoreDialog) { - setState(0); - _parent->onAction(this, kDeselectSlot); - } - } - } - - virtual void onWheelUp(int x, int y) { - _parent->onAction(this, kWheelUp); - } - - virtual void onWheelDown(int x, int y) { - _parent->onAction(this, kWheelDown); - } - - virtual void onKey(KeyboardEvent *ke) { - if (_editable) { - if (ke->keycode == 8) - _parent->onAction(this, 8); - else if (ke->ascii >= ' ' && ke->ascii <= 255) { - // Accept the character if the font renderer - // has what looks like a valid glyph for it. - if (_fr->getCharWidth(ke->ascii)) - _parent->onAction(this, ke->ascii); - } - } - } - - virtual void onTick() { - if (_editable) - _parent->onAction(this, kCursorTick); - } - - void setY(int y) { - for (int i = 0; i < _numStates; i++) - _sprites[i].y = y; - setHitRect(_hitRect.left, y, _hitRect.width(), _hitRect.height()); - } - - int getY() { - return _sprites[0].y; - } -}; - -SaveRestoreDialog::SaveRestoreDialog(Sword2Engine *vm, int mode) : Dialog(vm) { - int i; - - _mode = mode; - _selectedSlot = -1; - - // FIXME: The "control font" and the "red font" are currently always - // the same font, so one should be eliminated. - - _fr1 = new FontRendererGui(_vm, _vm->_controlsFontId); - _fr2 = new FontRendererGui(_vm, _vm->_redFontId); - - _panel = new Widget(this, 1); - _panel->createSurfaceImages(2016, 0, 40); - - for (i = 0; i < 4; i++) { - _slotButton[i] = new Slot(this, 114, 0, 384, 36); - _slotButton[i]->createSurfaceImages(2006 + i, 114, 0); - _slotButton[i]->setMode(mode); - _slotButton[i + 4] = new Slot(this, 114, 0, 384, 36); - _slotButton[i + 4]->linkSurfaceImages(_slotButton[i], 114, 0); - _slotButton[i + 4]->setMode(mode); - } - - updateSlots(); - - _zupButton = new ScrollButton(this, 516, 65, 17, 17); - _zupButton->createSurfaceImages(1982, 516, 65); - - _upButton = new ScrollButton(this, 516, 85, 17, 17); - _upButton->createSurfaceImages(2067, 516, 85); - - _downButton = new ScrollButton(this, 516, 329, 17, 17); - _downButton->createSurfaceImages(1986, 516, 329); - - _zdownButton = new ScrollButton(this, 516, 350, 17, 17); - _zdownButton->createSurfaceImages(1988, 516, 350); - - _okButton = new Button(this, 130, 377, 24, 24); - _okButton->createSurfaceImages(2002, 130, 377); - - _cancelButton = new Button(this, 350, 377, 24, 24); - _cancelButton->linkSurfaceImages(_okButton, 350, 377); - - registerWidget(_panel); - - for (i = 0; i < 8; i++) - registerWidget(_slotButton[i]); - - registerWidget(_zupButton); - registerWidget(_upButton); - registerWidget(_downButton); - registerWidget(_zdownButton); - registerWidget(_okButton); - registerWidget(_cancelButton); -} - -SaveRestoreDialog::~SaveRestoreDialog() { - delete _fr1; - delete _fr2; -} - -// There aren't really a hundred different button objects of course, there are -// only eight. Re-arrange them to simulate scrolling. - -void SaveRestoreDialog::updateSlots() { - for (int i = 0; i < 8; i++) { - Slot *slot = _slotButton[(baseSlot + i) % 8]; - FontRendererGui *fr; - byte description[SAVE_DESCRIPTION_LEN]; - - slot->setY(72 + i * 36); - - if (baseSlot + i == _selectedSlot) { - slot->setEditable(_mode == kSaveDialog); - slot->setState(1); - fr = _fr2; - } else { - slot->setEditable(false); - slot->setState(0); - fr = _fr1; - } - - if (_vm->getSaveDescription(baseSlot + i, description) == SR_OK) { - slot->setText(fr, baseSlot + i, description); - slot->setClickable(true); - } else { - slot->setText(fr, baseSlot + i, NULL); - slot->setClickable(_mode == kSaveDialog); - } - - if (slot->isEditable()) - drawEditBuffer(slot); - else - slot->paint(); - } -} - -void SaveRestoreDialog::drawEditBuffer(Slot *slot) { - if (_selectedSlot == -1) - return; - - // This will redraw a bit more than is strictly necessary, but I doubt - // that will make any noticeable difference. - - slot->paint(); - _fr2->drawText(_editBuffer, 130, 78 + (_selectedSlot - baseSlot) * 36); -} - -void SaveRestoreDialog::onAction(Widget *widget, int result) { - if (widget == _zupButton) { - if (baseSlot > 0) { - if (baseSlot >= 8) - baseSlot -= 8; - else - baseSlot = 0; - updateSlots(); - } - } else if (widget == _upButton) { - if (baseSlot > 0) { - baseSlot--; - updateSlots(); - } - } else if (widget == _downButton) { - if (baseSlot < 92) { - baseSlot++; - updateSlots(); - } - } else if (widget == _zdownButton) { - if (baseSlot < 92) { - if (baseSlot <= 84) - baseSlot += 8; - else - baseSlot = 92; - updateSlots(); - } - } else if (widget == _okButton) { - setResult(1); - } else if (widget == _cancelButton) { - setResult(0); - } else { - Slot *slot = (Slot *)widget; - int textWidth; - byte tmp; - int i; - int j; - - switch (result) { - case kWheelUp: - onAction(_upButton); - break; - case kWheelDown: - onAction(_downButton); - break; - case kSelectSlot: - case kDeselectSlot: - if (result == kSelectSlot) - _selectedSlot = baseSlot + (slot->getY() - 72) / 35; - else if (result == kDeselectSlot) - _selectedSlot = -1; - - for (i = 0; i < 8; i++) - if (widget == _slotButton[i]) - break; - - for (j = 0; j < 8; j++) { - if (j != i) { - _slotButton[j]->setEditable(false); - _slotButton[j]->setState(0); - } - } - break; - case kStartEditing: - if (_selectedSlot >= 10) - _firstPos = 5; - else - _firstPos = 4; - - strcpy((char *)_editBuffer, (char *)slot->getText()); - _editPos = strlen((char *)_editBuffer); - _cursorTick = 0; - _editBuffer[_editPos] = '_'; - _editBuffer[_editPos + 1] = 0; - slot->setEditable(true); - drawEditBuffer(slot); - break; - case kCursorTick: - _cursorTick++; - if (_cursorTick == 7) { - _editBuffer[_editPos] = ' '; - drawEditBuffer(slot); - } else if (_cursorTick == 14) { - _cursorTick = 0; - _editBuffer[_editPos] = '_'; - drawEditBuffer(slot); - } - break; - case 8: - if (_editPos > _firstPos) { - _editBuffer[_editPos - 1] = _editBuffer[_editPos]; - _editBuffer[_editPos--] = 0; - drawEditBuffer(slot); - } - break; - default: - tmp = _editBuffer[_editPos]; - _editBuffer[_editPos] = 0; - textWidth = _fr2->getTextWidth(_editBuffer); - _editBuffer[_editPos] = tmp; - - if (textWidth < 340 && _editPos < SAVE_DESCRIPTION_LEN - 2) { - _editBuffer[_editPos + 1] = _editBuffer[_editPos]; - _editBuffer[_editPos + 2] = 0; - _editBuffer[_editPos++] = result; - drawEditBuffer(slot); - } - break; - } - } -} - -void SaveRestoreDialog::paint() { - Dialog::paint(); - - _fr1->drawText((_mode == kRestoreDialog) ? TEXT_RESTORE : TEXT_SAVE, 165, 377); - _fr1->drawText(TEXT_CANCEL, 382, 377); -} - -void SaveRestoreDialog::setResult(int result) { - if (result) { - if (_selectedSlot == -1) - return; - - if (_mode == kSaveDialog) { - if (_editPos <= _firstPos) - return; - } - } - - Dialog::setResult(result); -} - -int SaveRestoreDialog::runModal() { - int result = Dialog::runModal(); - - if (result) { - switch (_mode) { - case kSaveDialog: - // Remove the cursor character from the savegame name - _editBuffer[_editPos] = 0; - - if (_vm->saveGame(_selectedSlot, (byte *)&_editBuffer[_firstPos]) != SR_OK) - result = 0; - break; - case kRestoreDialog: - if (_vm->restoreGame(_selectedSlot) != SR_OK) - result = 0; - break; - } - } - - return result; -} - -} // End of namespace Sword2 diff --git a/sword2/controls.h b/sword2/controls.h deleted file mode 100644 index 719489b3ae..0000000000 --- a/sword2/controls.h +++ /dev/null @@ -1,183 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef _CONTROL_S -#define _CONTROL_S - -#include "sword2/defs.h" - -#define MAX_WIDGETS 25 - -namespace Sword2 { - -class Sword2Engine; -class FontRendererGui; -class Widget; -class Switch; -class Slider; -class Button; -class ScrollButton; -class Slot; - -enum { - kSaveDialog, - kRestoreDialog -}; - -/** - * Base class for all dialogs. - */ - -class Dialog { -private: - int _numWidgets; - Widget *_widgets[MAX_WIDGETS]; - bool _finish; - int _result; - -public: - Sword2Engine *_vm; - - Dialog(Sword2Engine *vm); - virtual ~Dialog(); - - void registerWidget(Widget *widget); - - virtual void paint(); - virtual void setResult(int result); - - virtual int runModal(); - - virtual void onAction(Widget *widget, int result = 0) {} -}; - -class OptionsDialog : public Dialog { -private: - FontRendererGui *_fr; - Widget *_panel; - Switch *_objectLabelsSwitch; - Switch *_subtitlesSwitch; - Switch *_reverseStereoSwitch; - Switch *_musicSwitch; - Switch *_speechSwitch; - Switch *_fxSwitch; - Slider *_musicSlider; - Slider *_speechSlider; - Slider *_fxSlider; - Slider *_gfxSlider; - Widget *_gfxPreview; - Button *_okButton; - Button *_cancelButton; - - Audio::Mixer *_mixer; - -public: - OptionsDialog(Sword2Engine *vm); - ~OptionsDialog(); - - virtual void paint(); - virtual void onAction(Widget *widget, int result = 0); -}; - -class SaveRestoreDialog : public Dialog { -private: - int _mode, _selectedSlot; - byte _editBuffer[SAVE_DESCRIPTION_LEN]; - int _editPos, _firstPos; - int _cursorTick; - - FontRendererGui *_fr1; - FontRendererGui *_fr2; - Widget *_panel; - Slot *_slotButton[8]; - ScrollButton *_zupButton; - ScrollButton *_upButton; - ScrollButton *_downButton; - ScrollButton *_zdownButton; - Button *_okButton; - Button *_cancelButton; - -public: - SaveRestoreDialog(Sword2Engine *vm, int mode); - ~SaveRestoreDialog(); - - void updateSlots(); - void drawEditBuffer(Slot *slot); - - virtual void onAction(Widget *widget, int result = 0); - virtual void paint(); - virtual void setResult(int result); - virtual int runModal(); -}; - -/** - * A "mini" dialog is usually a yes/no question, but also used for the - * restart/restore dialog at the beginning of the game. - */ - -class MiniDialog : public Dialog { -private: - uint32 _headerTextId; - uint32 _okTextId; - uint32 _cancelTextId; - FontRendererGui *_fr; - Widget *_panel; - Button *_okButton; - Button *_cancelButton; - -public: - MiniDialog(Sword2Engine *vm, uint32 headerTextId, uint32 okTextId = TEXT_OK, uint32 cancelTextId = TEXT_CANCEL); - virtual ~MiniDialog(); - virtual void paint(); - virtual void onAction(Widget *widget, int result = 0); -}; - -class StartDialog : public MiniDialog { -public: - StartDialog(Sword2Engine *vm); - virtual int runModal(); -}; - -class RestartDialog : public MiniDialog { -public: - RestartDialog(Sword2Engine *vm); - virtual int runModal(); -}; - -class QuitDialog : public MiniDialog { -public: - QuitDialog(Sword2Engine *vm); - virtual int runModal(); -}; - -class SaveDialog : public SaveRestoreDialog { -public: - SaveDialog(Sword2Engine *vm) : SaveRestoreDialog(vm, kSaveDialog) {} -}; - -class RestoreDialog : public SaveRestoreDialog { -public: - RestoreDialog(Sword2Engine *vm) : SaveRestoreDialog(vm, kRestoreDialog) {} -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/d_draw.cpp b/sword2/d_draw.cpp deleted file mode 100644 index 7f278996fb..0000000000 --- a/sword2/d_draw.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "common/system.h" -#include "sword2/sword2.h" -#include "sword2/mouse.h" - -namespace Sword2 { - -/** - * @return the graphics detail setting - */ - -int8 Screen::getRenderLevel() { - return _renderLevel; -} - -void Screen::setRenderLevel(int8 level) { - _renderLevel = level; - - switch (_renderLevel) { - case 0: - // Lowest setting: no fancy stuff - _renderCaps = 0; - break; - case 1: - // Medium-low setting: transparency-blending - _renderCaps = RDBLTFX_SPRITEBLEND; - break; - case 2: - // Medium-high setting: transparency-blending + shading - _renderCaps = RDBLTFX_SPRITEBLEND | RDBLTFX_SHADOWBLEND; - break; - case 3: - // Highest setting: transparency-blending + shading + - // edge-blending + improved stretching - _renderCaps = RDBLTFX_SPRITEBLEND | RDBLTFX_SHADOWBLEND | RDBLTFX_EDGEBLEND; - break; - } -} - -/** - * Fill the screen buffer with palette colour zero. Note that it does not - * touch the menu areas of the screen. - */ - -void Screen::clearScene() { - memset(_buffer + MENUDEEP * _screenWide, 0, _screenWide * RENDERDEEP); - _needFullRedraw = true; -} - -} // End of namespace Sword2 diff --git a/sword2/debug.cpp b/sword2/debug.cpp deleted file mode 100644 index 53fc200241..0000000000 --- a/sword2/debug.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "sword2/sword2.h" -#include "sword2/console.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/maketext.h" -#include "sword2/memory.h" -#include "sword2/mouse.h" -#include "sword2/resman.h" -#include "sword2/router.h" - -namespace Sword2 { - -void Debugger::clearDebugTextBlocks() { - uint8 blockNo = 0; - - while (blockNo < MAX_DEBUG_TEXTS && _debugTextBlocks[blockNo] > 0) { - // kill the system text block - _vm->_fontRenderer->killTextBloc(_debugTextBlocks[blockNo]); - - // clear this element of our array of block numbers - _debugTextBlocks[blockNo] = 0; - - blockNo++; - } -} - -void Debugger::makeDebugTextBlock(char *text, int16 x, int16 y) { - uint8 blockNo = 0; - - while (blockNo < MAX_DEBUG_TEXTS && _debugTextBlocks[blockNo] > 0) - blockNo++; - - assert(blockNo < MAX_DEBUG_TEXTS); - - _debugTextBlocks[blockNo] = _vm->_fontRenderer->buildNewBloc((byte *)text, x, y, 640 - x, 0, RDSPR_DISPLAYALIGN, CONSOLE_FONT_ID, NO_JUSTIFICATION); -} - -void Debugger::buildDebugText() { - char buf[128]; - - int32 showVarNo; // for variable watching - int32 showVarPos; - int32 varNo; - - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - // clear the array of text block numbers for the debug text - clearDebugTextBlocks(); - - // mouse coords - // print mouse coords beside mouse-marker, if it's being displayed - if (_displayMouseMarker) { - int mouseX, mouseY; - - _vm->_mouse->getPos(mouseX, mouseY); - - sprintf(buf, "%d,%d", mouseX + screenInfo->scroll_offset_x, mouseY + screenInfo->scroll_offset_y); - if (mouseX > 560) - makeDebugTextBlock(buf, mouseX - 50, mouseY - 15); - else - makeDebugTextBlock(buf, mouseX + 5, mouseY - 15); - } - - // mouse area coords - - // defining a mouse area the easy way, by creating a box on-screen - if (_draggingRectangle || _vm->_logic->readVar(SYSTEM_TESTING_ANIMS)) { - // so we can see what's behind the lines - _rectFlicker = !_rectFlicker; - - sprintf(buf, "x1=%d", _rectX1); - makeDebugTextBlock(buf, 0, 120); - - sprintf(buf, "y1=%d", _rectY1); - makeDebugTextBlock(buf, 0, 135); - - sprintf(buf, "x2=%d", _rectX2); - makeDebugTextBlock(buf, 0, 150); - - sprintf(buf, "y2=%d", _rectY2); - makeDebugTextBlock(buf, 0, 165); - } - - // testingSnR indicator - - if (_testingSnR) { // see fnAddHuman() - sprintf(buf, "TESTING LOGIC STABILITY!"); - makeDebugTextBlock(buf, 0, 105); - } - -#ifdef SWORD2_DEBUG - // speed-up indicator - - if (_vm->_renderSkip) { // see sword2.cpp - sprintf(buf, "SKIPPING FRAMES FOR SPEED-UP!"); - makeDebugTextBlock(buf, 0, 120); - } -#endif - - // debug info at top of screen - enabled/disabled as one complete unit - - if (_displayTime) { - int32 time = _vm->getMillis(); - - if ((time - _startTime) / 1000 >= 10000) - _startTime = time; - - time -= _startTime; - sprintf(buf, "Time %.2d:%.2d:%.2d.%.3d", (time / 3600000) % 60, (time / 60000) % 60, (time / 1000) % 60, time % 1000); - makeDebugTextBlock(buf, 500, 360); - sprintf(buf, "Game %d", _vm->_gameCycle); - makeDebugTextBlock(buf, 500, 380); - } - - // current text number & speech-sample resource id - - if (_displayTextNumbers) { - if (_textNumber) { - if (_vm->_logic->readVar(SYSTEM_TESTING_TEXT)) { - if (_vm->_logic->readVar(SYSTEM_WANT_PREVIOUS_LINE)) - sprintf(buf, "backwards"); - else - sprintf(buf, "forwards"); - - makeDebugTextBlock(buf, 0, 340); - } - - sprintf(buf, "res: %d", _textNumber / SIZE); - makeDebugTextBlock(buf, 0, 355); - - sprintf(buf, "pos: %d", _textNumber & 0xffff); - makeDebugTextBlock(buf, 0, 370); - - sprintf(buf, "TEXT: %d", _vm->_logic->_officialTextNumber); - makeDebugTextBlock(buf, 0, 385); - } - } - - // resource number currently being checking for animation - - if (_vm->_logic->readVar(SYSTEM_TESTING_ANIMS)) { - sprintf(buf, "trying resource %d", _vm->_logic->readVar(SYSTEM_TESTING_ANIMS)); - makeDebugTextBlock(buf, 0, 90); - } - - // general debug info - - if (_displayDebugText) { - byte name[NAME_LEN]; - -/* - // CD in use - sprintf(buf, "CD-%d", currentCD); - makeDebugTextBlock(buf, 0, 0); -*/ - - // mouse coords & object pointed to - - if (_vm->_logic->readVar(CLICKED_ID)) - sprintf(buf, "last click at %d,%d (id %d: %s)", - _vm->_logic->readVar(MOUSE_X), - _vm->_logic->readVar(MOUSE_Y), - _vm->_logic->readVar(CLICKED_ID), - _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID), name)); - else - sprintf(buf, "last click at %d,%d (---)", - _vm->_logic->readVar(MOUSE_X), - _vm->_logic->readVar(MOUSE_Y)); - - makeDebugTextBlock(buf, 0, 15); - - uint32 mouseTouching = _vm->_mouse->getMouseTouching(); - - int mouseX, mouseY; - - _vm->_mouse->getPos(mouseX, mouseY); - - if (mouseTouching) - sprintf(buf, "mouse %d,%d (id %d: %s)", - mouseX + screenInfo->scroll_offset_x, - mouseY + screenInfo->scroll_offset_y, - mouseTouching, - _vm->_resman->fetchName(mouseTouching, name)); - else - sprintf(buf, "mouse %d,%d (not touching)", - mouseX + screenInfo->scroll_offset_x, - mouseY + screenInfo->scroll_offset_y); - - makeDebugTextBlock(buf, 0, 30); - - // player coords & graphic info - // if player objct has a graphic - - if (_graphAnimRes) - sprintf(buf, "player %d,%d %s (%d) #%d/%d", - screenInfo->player_feet_x, - screenInfo->player_feet_y, - _vm->_resman->fetchName(_graphAnimRes, name), - _graphAnimRes, - _graphAnimPc, - _graphNoFrames); - else - sprintf(buf, "player %d,%d --- %d", - screenInfo->player_feet_x, - screenInfo->player_feet_y, - _graphAnimPc); - - makeDebugTextBlock(buf, 0, 45); - - // frames-per-second counter - - sprintf(buf, "fps %d", _vm->_screen->getFps()); - makeDebugTextBlock(buf, 440, 0); - - // location number - - sprintf(buf, "location=%d", _vm->_logic->readVar(LOCATION)); - makeDebugTextBlock(buf, 440, 15); - - // "result" variable - - sprintf(buf, "result=%d", _vm->_logic->readVar(RESULT)); - makeDebugTextBlock(buf, 440, 30); - - // no. of events in event list - - sprintf(buf, "events=%d", _vm->_logic->countEvents()); - makeDebugTextBlock(buf, 440, 45); - - // sprite list usage - - sprintf(buf, "bgp0: %d/%d", _vm->_screen->getCurBgp0(), MAX_bgp0_sprites); - makeDebugTextBlock(buf, 560, 0); - - sprintf(buf, "bgp1: %d/%d", _vm->_screen->getCurBgp1(), MAX_bgp1_sprites); - makeDebugTextBlock(buf, 560, 15); - - sprintf(buf, "back: %d/%d", _vm->_screen->getCurBack(), MAX_back_sprites); - makeDebugTextBlock(buf, 560, 30); - - sprintf(buf, "sort: %d/%d", _vm->_screen->getCurSort(), MAX_sort_sprites); - makeDebugTextBlock(buf, 560, 45); - - sprintf(buf, "fore: %d/%d", _vm->_screen->getCurFore(), MAX_fore_sprites); - makeDebugTextBlock(buf, 560, 60); - - sprintf(buf, "fgp0: %d/%d", _vm->_screen->getCurFgp0(), MAX_fgp0_sprites); - makeDebugTextBlock(buf, 560, 75); - - sprintf(buf, "fgp1: %d/%d", _vm->_screen->getCurFgp1(), MAX_fgp1_sprites); - makeDebugTextBlock(buf, 560, 90); - - // largest layer & sprite - - // NB. Strings already constructed in Build_display.cpp - makeDebugTextBlock(_vm->_screen->getLargestLayerInfo(), 0, 60); - makeDebugTextBlock(_vm->_screen->getLargestSpriteInfo(), 0, 75); - - // "waiting for person" indicator - set form fnTheyDo and - // fnTheyDoWeWait - - if (_speechScriptWaiting) { - sprintf(buf, "script waiting for %s (%d)", - _vm->_resman->fetchName(_speechScriptWaiting, name), - _speechScriptWaiting); - makeDebugTextBlock(buf, 0, 90); - } - - // variable watch display - - showVarPos = 115; // y-coord for first showVar - - for (showVarNo = 0; showVarNo < MAX_SHOWVARS; showVarNo++) { - varNo = _showVar[showVarNo]; // get variable number - - // if non-zero ie. cannot watch 'id' but not needed - // anyway because it changes throughout the logic loop - - if (varNo) { - sprintf(buf, "var(%d) = %d", varNo, _vm->_logic->readVar(varNo)); - makeDebugTextBlock(buf, 530, showVarPos); - showVarPos += 15; // next line down - } - } - - // memory indicator - this should come last, to show all the - // sprite blocks above! - - uint32 totAlloc = _vm->_memory->getTotAlloc(); - int16 numBlocks = _vm->_memory->getNumBlocks(); - - if (totAlloc < 1024) - sprintf(buf, "%u bytes in %d memory blocks", totAlloc, numBlocks); - else if (totAlloc < 1024 * 1024) - sprintf(buf, "%uK in %d memory blocks", totAlloc / 1024, numBlocks); - else - sprintf(buf, "%.02fM in %d memory blocks", totAlloc / 1048576., numBlocks); - - makeDebugTextBlock(buf, 0, 0); - } -} - -void Debugger::drawDebugGraphics() { - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - // walk-grid - - if (_displayWalkGrid) - _vm->_logic->_router->plotWalkGrid(); - - // player feet coord marker - - if (_displayPlayerMarker) - plotCrossHair(screenInfo->player_feet_x, screenInfo->player_feet_y, 215); - - // mouse marker & coords - - if (_displayMouseMarker) { - int mouseX, mouseY; - - _vm->_mouse->getPos(mouseX, mouseY); - - plotCrossHair(mouseX + screenInfo->scroll_offset_x, mouseY + screenInfo->scroll_offset_y, 215); - } - - // mouse area rectangle / sprite box rectangle when testing anims - - if (_vm->_logic->readVar(SYSTEM_TESTING_ANIMS)) { - // draw box around current frame - drawRect(_rectX1, _rectY1, _rectX2, _rectY2, 184); - } else if (_draggingRectangle) { - // defining a mouse area the easy way, by creating a box - // on-screen - if (_rectFlicker) - drawRect(_rectX1, _rectY1, _rectX2, _rectY2, 184); - } -} - -void Debugger::plotCrossHair(int16 x, int16 y, uint8 pen) { - _vm->_screen->plotPoint(x, y, pen); - - _vm->_screen->drawLine(x - 2, y, x - 5, y, pen); - _vm->_screen->drawLine(x + 2, y, x + 5, y, pen); - - _vm->_screen->drawLine(x, y - 2, x, y - 5, pen); - _vm->_screen->drawLine(x, y + 2, x, y + 5, pen); -} - -void Debugger::drawRect(int16 x1, int16 y1, int16 x2, int16 y2, uint8 pen) { - _vm->_screen->drawLine(x1, y1, x2, y1, pen); // top edge - _vm->_screen->drawLine(x1, y2, x2, y2, pen); // bottom edge - _vm->_screen->drawLine(x1, y1, x1, y2, pen); // left edge - _vm->_screen->drawLine(x2, y1, x2, y2, pen); // right edge -} - -} // End of namespace Sword2 diff --git a/sword2/debug.h b/sword2/debug.h deleted file mode 100644 index 9b0b40f9ec..0000000000 --- a/sword2/debug.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef D_DEBUG -#define D_DEBUG - -// FIXME: I don't know how large this constant used to be -#define MAX_DEBUG_TEXTS 55 - -#define MAX_SHOWVARS 15 - -namespace Sword2 { -} // End of namespace Sword2 - -#endif diff --git a/sword2/defs.h b/sword2/defs.h deleted file mode 100644 index 4acb484f34..0000000000 --- a/sword2/defs.h +++ /dev/null @@ -1,205 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef DEFS -#define DEFS - -#define SIZE 0x10000 // 65536 items per section -#define NuSIZE 0xffff // & with this - -// Return codes - -enum { - // Generic error codes - RD_OK = 0x00000000, - RDERR_UNKNOWN = 0x00000001, - RDERR_OUTOFMEMORY = 0x00000003, - RDERR_INVALIDFILENAME = 0x00000004, - - // Drawing error codes - RDERR_DECOMPRESSION = 0x00010007, - - // Sprite drawing error codes - RDERR_NOTIMPLEMENTED = 0x00060001, - RDERR_NOTCLOSED = 0x00050005, - RDERR_NOTOPEN = 0x00050006, - - // Menubar error codes - RDERR_INVALIDMENU = 0x00060000, - RDERR_INVALIDPOCKET = 0x00060001, - RDERR_INVALIDCOMMAND = 0x00060002, - - // Palette fading error codes - RDERR_FADEINCOMPLETE = 0x00070000, - - // Sound engine error codes - RDERR_SPEECHPLAYING = 0x00080004, - RDERR_SPEECHNOTPLAYING = 0x00080005, - RDERR_INVALIDWAV = 0x00080006, - RDERR_FXALREADYOPEN = 0x00080009, - RDERR_FXNOTOPEN = 0x0008000B, - RDERR_INVALIDID = 0x0008000D -}; - -// Text ids for the control panel etc. - -enum { - TEXT_OK = 0x08EB0000, - TEXT_CANCEL = 0x08EB0001, - TEXT_RESTORE = 0x08EB0002, - TEXT_SAVE = 0x08EB0003, - TEXT_QUIT = 0x08EB0004, - TEXT_RESTART = 0x08EB0005, - TEXT_OPTIONS = 0x08EB000A, - TEXT_SUBTITLES = 0x08EB000B, - TEXT_OBJECT_LABELS = 0x08EB000C, - TEXT_MUSIC_VOLUME = 0x08EB000E, - TEXT_SPEECH_VOLUME = 0x08EB000F, - TEXT_FX_VOLUME = 0x08EB0010, - TEXT_GFX_QUALITY = 0x08EB0011, - TEXT_REVERSE_STEREO = 0x08EB0015, - TEXT_RESTORE_CANT_OPEN = 0x0CBA017E, - TEXT_RESTORE_INCOMPATIBLE = 0x0CBA017F, - TEXT_RESTORE_FAILED = 0x0CBA0181, - TEXT_SAVE_CANT_OPEN = 0x0CBA0182, - TEXT_SAVE_FAILED = 0x0CBA0184 -}; - -// Always 8 (George object used for Nico player character as well) -#define CUR_PLAYER_ID 8 - -// Global variable references - -enum { - ID = 0, - RESULT = 1, - PLAYER_ACTION = 2, - // CUR_PLAYER_ID = 3, - PLAYER_ID = 305, - TALK_FLAG = 13, - - MOUSE_X = 4, - MOUSE_Y = 5, - LEFT_BUTTON = 109, - RIGHT_BUTTON = 110, - CLICKED_ID = 178, - - IN_SUBJECT = 6, - COMBINE_BASE = 7, - OBJECT_HELD = 14, - - SPEECH_ID = 9, - INS1 = 10, - INS2 = 11, - INS3 = 12, - INS4 = 60, - INS5 = 61, - INS_COMMAND = 59, - - PLAYER_FEET_X = 141, - PLAYER_FEET_Y = 142, - PLAYER_CUR_DIR = 937, - - // for debug.cpp - LOCATION = 62, - - // so scripts can force scroll offsets - SCROLL_X = 345, - SCROLL_Y = 346, - - EXIT_CLICK_ID = 710, - EXIT_FADING = 713, - - SYSTEM_TESTING_ANIMS = 912, - SYSTEM_TESTING_TEXT = 1230, - SYSTEM_WANT_PREVIOUS_LINE = 1245, - - // 1=on 0=off (set in fnAddHuman and fnNoHuman) - MOUSE_AVAILABLE = 686, - - // used in fnChoose - AUTO_SELECTED = 1115, - - // see fnStartConversation and fnChooser - CHOOSER_COUNT_FLAG = 15, - - // signifies a demo mode - DEMO = 1153, - - // Indicates to script whether this is the Playstation version. - // PSXFLAG = 1173, - - // for the poor PSX so it knows what language is running. - // GAME_LANGUAGE = 111, - - // 1 = dead - DEAD = 1256, - - // If set indicates that the speech anim is to run through only once. - SPEECHANIMFLAG = 1278, - - // for the engine - SCROLL_OFFSET_X = 1314 -}; - -// Resource IDs - -enum { - // mouse mointers - It's pretty much safe to do it like this - NORMAL_MOUSE_ID = 17, - SCROLL_LEFT_MOUSE_ID = 1440, - SCROLL_RIGHT_MOUSE_ID = 1441, - - // Console Font - does not use game text - only English required - CONSOLE_FONT_ID = 340, - - // Speech Font - ENGLISH_SPEECH_FONT_ID = 341, - FINNISH_SPEECH_FONT_ID = 956, - POLISH_SPEECH_FONT_ID = 955, - - // Control Panel Font (and un-selected savegame descriptions) - ENGLISH_CONTROLS_FONT_ID = 2005, - FINNISH_CONTROLS_FONT_ID = 959, - POLISH_CONTROLS_FONT_ID = 3686, - - // Red Font (for selected savegame descriptions) - // BS2 doesn't draw selected savegames in red, so I guess this is a - // left-over from BS1 - ENGLISH_RED_FONT_ID = 2005, // 1998 // Redfont - FINNISH_RED_FONT_ID = 959, // 960 // FinRedFn - POLISH_RED_FONT_ID = 3686, // 3688 // PolRedFn - - // Control panel palette resource id - CONTROL_PANEL_PALETTE = 261, - - // res id's of the system menu icons - OPTIONS_ICON = 344, - QUIT_ICON = 335, - SAVE_ICON = 366, - RESTORE_ICON = 364, - RESTART_ICON = 342, - - // conversation exit icon, 'EXIT' menu icon (used in fnChoose) - EXIT_ICON = 65 -}; - -#endif diff --git a/sword2/events.cpp b/sword2/events.cpp deleted file mode 100644 index e8090414aa..0000000000 --- a/sword2/events.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/logic.h" - -namespace Sword2 { - -void Logic::sendEvent(uint32 id, uint32 interact_id) { - for (int i = 0; i < ARRAYSIZE(_eventList); i++) { - if (_eventList[i].id == id || !_eventList[i].id) { - _eventList[i].id = id; - _eventList[i].interact_id = interact_id; - return; - } - } - - error("sendEvent() ran out of event slots"); -} - -void Logic::setPlayerActionEvent(uint32 id, uint32 interact_id) { - // Full script id of action script number 2 - sendEvent(id, (interact_id << 16) | 2); -} - -int Logic::checkEventWaiting() { - for (int i = 0; i < ARRAYSIZE(_eventList); i++) { - if (_eventList[i].id == readVar(ID)) - return 1; - } - - return 0; -} - -void Logic::startEvent() { - // call this from stuff like fnWalk - // you must follow with a return IR_TERMINATE - - for (int i = 0; i < ARRAYSIZE(_eventList); i++) { - if (_eventList[i].id == readVar(ID)) { - logicOne(_eventList[i].interact_id); - _eventList[i].id = 0; - return; - } - } - - error("startEvent() can't find event for id %d", readVar(ID)); -} - -void Logic::clearEvent(uint32 id) { - for (int i = 0; i < ARRAYSIZE(_eventList); i++) { - if (_eventList[i].id == id) { - _eventList[i].id = 0; - return; - } - } -} - -void Logic::killAllIdsEvents(uint32 id) { - for (int i = 0; i < ARRAYSIZE(_eventList); i++) { - if (_eventList[i].id == id) - _eventList[i].id = 0; - } -} - -// For the debugger - -uint32 Logic::countEvents() { - uint32 count = 0; - - for (int i = 0; i < ARRAYSIZE(_eventList); i++) { - if (_eventList[i].id) - count++; - } - - return count; -} - -} // End of namespace Sword2 diff --git a/sword2/function.cpp b/sword2/function.cpp deleted file mode 100644 index e749e7b497..0000000000 --- a/sword2/function.cpp +++ /dev/null @@ -1,2479 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "common/system.h" -#include "common/file.h" - -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/build_display.h" -#include "sword2/console.h" -#include "sword2/interpreter.h" -#include "sword2/logic.h" -#include "sword2/maketext.h" -#include "sword2/mouse.h" -#include "sword2/resman.h" -#include "sword2/router.h" -#include "sword2/sound.h" -#include "sword2/animation.h" - -namespace Sword2 { - -int32 Logic::fnTestFunction(int32 *params) { - // params: 0 address of a flag - return IR_CONT; -} - -int32 Logic::fnTestFlags(int32 *params) { - // params: 0 value of flag - return IR_CONT; -} - -int32 Logic::fnRegisterStartPoint(int32 *params) { - // params: 0 id of startup script to call - key - // 1 pointer to ascii message - - int32 key = params[0]; - char *name = (char *)decodePtr(params[1]); - - _vm->registerStartPoint(key, name); - return IR_CONT; -} - -int32 Logic::fnInitBackground(int32 *params) { - // this screen defines the size of the back buffer - - // params: 0 res id of normal background layer - cannot be 0 - // 1 1 yes 0 no for a new palette - - _vm->_screen->initBackground(params[0], params[1]); - return IR_CONT; -} - -/** - * This function is used by start scripts. - */ - -int32 Logic::fnSetSession(int32 *params) { - // params: 0 id of new run list - - expressChangeSession(params[0]); - return IR_CONT; -} - -int32 Logic::fnBackSprite(int32 *params) { - // params: 0 pointer to object's graphic structure - _router->setSpriteStatus(decodePtr(params[0]), BACK_SPRITE); - return IR_CONT; -} - -int32 Logic::fnSortSprite(int32 *params) { - // params: 0 pointer to object's graphic structure - _router->setSpriteStatus(decodePtr(params[0]), SORT_SPRITE); - return IR_CONT; -} - -int32 Logic::fnForeSprite(int32 *params) { - // params: 0 pointer to object's graphic structure - _router->setSpriteStatus(decodePtr(params[0]), FORE_SPRITE); - return IR_CONT; -} - -int32 Logic::fnRegisterMouse(int32 *params) { - // this call would be made from an objects service script 0 - // the object would be one with no graphic but with a mouse - i.e. a - // floor or one whose mouse area is manually defined rather than - // intended to fit sprite shape - - // params: 0 pointer to ObjectMouse or 0 for no write to mouse - // list - - _vm->_mouse->registerMouse(decodePtr(params[0]), NULL); - return IR_CONT; -} - -int32 Logic::fnAnim(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 pointer to object's graphic structure - // 2 resource id of animation file - - // Normal forward animation - return _router->doAnimate( - decodePtr(params[0]), - decodePtr(params[1]), - params[2], false); -} - -int32 Logic::fnRandom(int32 *params) { - // params: 0 min - // 1 max - - writeVar(RESULT, _vm->_rnd.getRandomNumberRng(params[0], params[1])); - return IR_CONT; -} - -int32 Logic::fnPreLoad(int32 *params) { - // Forces a resource into memory before it's "officially" opened for - // use. eg. if an anim needs to run on smoothly from another, - // "preloading" gets it into memory in advance to avoid the cacheing - // delay that normally occurs before the first frame. - - // params: 0 resource to preload - - _vm->_resman->openResource(params[0]); - _vm->_resman->closeResource(params[0]); - return IR_CONT; -} - -int32 Logic::fnAddSubject(int32 *params) { - // params: 0 id - // 1 daves reference number - _vm->_mouse->addSubject(params[0], params[1]); - return IR_CONT; -} - -int32 Logic::fnInteract(int32 *params) { - // Run targets action on a subroutine. Called by player on his base - // level 0 idle, for example. - - // params: 0 id of target from which we derive action script - // reference - - writeVar(PLAYER_ACTION, 0); // must clear this - logicUp((params[0] << 16) | 2); // 3rd script of clicked on id - - // Out, up and around again - pc is saved for current level to be - // returned to. - return IR_GOSUB; -} - -int32 Logic::fnChoose(int32 *params) { - // params: none - - // This opcode is used to open the conversation menu. The human is - // switched off so there will be no normal mouse engine. - - // The player's choice is piggy-backed on the standard opcode return - // values, to be used with the CP_JUMP_ON_RETURNED opcode. As far as I - // can tell, this is the only function that uses that feature. - - uint32 response = _vm->_mouse->chooseMouse(); - - if (response == (uint32)-1) - return IR_REPEAT; - - return IR_CONT | (response << 3); -} - -/** - * Walk mega to (x,y,dir). Set RESULT to 0 if it succeeded. Otherwise, set - * RESULT to 1. - */ - -int32 Logic::fnWalk(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 pointer to object's graphic structure - // 2 pointer to object's mega structure - // 3 pointer to object's walkdata structure - // 4 target x-coord - // 5 target y-coord - // 6 target direction (8 means end walk on ANY direction) - - return _router->doWalk( - decodePtr(params[0]), - decodePtr(params[1]), - decodePtr(params[2]), - decodePtr(params[3]), - params[4], params[5], params[6]); -} - -/** - * Walk mega to start position of anim - */ - -int32 Logic::fnWalkToAnim(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 pointer to object's graphic structure - // 2 pointer to object's mega structure - // 3 pointer to object's walkdata structure - // 4 anim resource id - - return _router->walkToAnim( - decodePtr(params[0]), - decodePtr(params[1]), - decodePtr(params[2]), - decodePtr(params[3]), - params[4]); -} - -/** - * Turn mega to the specified direction. - */ - -int32 Logic::fnTurn(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 pointer to object's graphic structure - // 2 pointer to object's mega structure - // 3 pointer to object's walkdata structure - // 4 target direction - - return _router->doFace( - decodePtr(params[0]), - decodePtr(params[1]), - decodePtr(params[2]), - decodePtr(params[3]), - params[4]); -} - -/** - * Stand mega at (x,y,dir) - * Sets up the graphic object, but also needs to set the new 'current_dir' in - * the mega object, so the router knows in future - */ - -int32 Logic::fnStandAt(int32 *params) { - // params: 0 pointer to object's graphic structure - // 1 pointer to object's mega structure - // 2 target x-coord - // 3 target y-coord - // 4 target direction - - _router->standAt( - decodePtr(params[0]), - decodePtr(params[1]), - params[2], params[3], params[4]); - return IR_CONT; -} - -/** - * Stand mega into the specified direction at current feet coords. - * Just needs to call standAt() with current feet coords. - */ - -int32 Logic::fnStand(int32 *params) { - // params: 0 pointer to object's graphic structure - // 1 pointer to object's mega structure - // 2 target direction - byte *ob_mega = decodePtr(params[1]); - - ObjectMega obMega(ob_mega); - - _router->standAt( - decodePtr(params[0]), - ob_mega, obMega.getFeetX(), obMega.getFeetY(), params[2]); - return IR_CONT; -} - -/** - * stand mega at end position of anim - */ - -int32 Logic::fnStandAfterAnim(int32 *params) { - // params: 0 pointer to object's graphic structure - // 1 pointer to object's mega structure - // 2 anim resource id - - _router->standAfterAnim( - decodePtr(params[0]), - decodePtr(params[1]), - params[2]); - return IR_CONT; -} - -int32 Logic::fnPause(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 number of game-cycles to pause - - // NB. Pause-value of 0 causes script to continue, 1 causes a 1-cycle - // quit, 2 gives 2 cycles, etc. - - ObjectLogic obLogic(decodePtr(params[0])); - - if (obLogic.getLooping() == 0) { - obLogic.setLooping(1); - obLogic.setPause(params[1]); - } - - if (obLogic.getPause()) { - obLogic.setPause(obLogic.getPause() - 1); - return IR_REPEAT; - } - - obLogic.setLooping(0); - return IR_CONT; -} - -int32 Logic::fnMegaTableAnim(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 pointer to object's graphic structure - // 2 pointer to object's mega structure - // 3 pointer to animation table - - // Normal forward anim - return _router->megaTableAnimate( - decodePtr(params[0]), - decodePtr(params[1]), - decodePtr(params[2]), - decodePtr(params[3]), - false); -} - -int32 Logic::fnAddMenuObject(int32 *params) { - // params: 0 pointer to a MenuObject structure to copy down - - _vm->_mouse->addMenuObject(decodePtr(params[0])); - return IR_CONT; -} - -/** - * Start a conversation. - * - * Note that fnStartConversation() might accidentally be called every time the - * script loops back for another chooser, but we only want to reset the chooser - * count flag the first time this function is called, i.e. when the talk flag - * is zero. - */ - -int32 Logic::fnStartConversation(int32 *params) { - // params: none - - _vm->_mouse->startConversation(); - return IR_CONT; -} - -/** - * End a conversation. - */ - -int32 Logic::fnEndConversation(int32 *params) { - // params: none - - _vm->_mouse->endConversation(); - return IR_CONT; -} - -int32 Logic::fnSetFrame(int32 *params) { - // params: 0 pointer to object's graphic structure - // 1 resource id of animation file - // 2 frame flag (0=first 1=last) - - int32 res = params[1]; - assert(res); - - // open the resource (& check it's valid) - byte *anim_file = _vm->_resman->openResource(res); - - assert(_vm->_resman->fetchType(res) == ANIMATION_FILE); - - // set up pointer to the animation header - AnimHeader anim_head; - - anim_head.read(_vm->fetchAnimHeader(anim_file)); - - // set up anim resource in graphic object - ObjectGraphic obGraph(decodePtr(params[0])); - - obGraph.setAnimResource(res); - obGraph.setAnimPc(params[2] ? anim_head.noAnimFrames - 1 : 0); - - // Close the anim file and drop out of script - _vm->_resman->closeResource(obGraph.getAnimResource()); - return IR_CONT; -} - -int32 Logic::fnRandomPause(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 minimum number of game-cycles to pause - // 2 maximum number of game-cycles to pause - - ObjectLogic obLogic(decodePtr(params[0])); - int32 pars[2]; - - if (obLogic.getLooping() == 0) { - pars[0] = params[1]; - pars[1] = params[2]; - fnRandom(pars); - pars[1] = readVar(RESULT); - } - - pars[0] = params[0]; - return fnPause(pars); -} - -int32 Logic::fnRegisterFrame(int32 *params) { - // this call would be made from an objects service script 0 - - // params: 0 pointer to mouse structure or NULL for no write to - // mouse list (non-zero means write sprite-shape to - // mouse list) - // 1 pointer to graphic structure - // 2 pointer to mega structure or NULL if not a mega - - _vm->_screen->registerFrame( - decodePtr(params[0]), - decodePtr(params[1]), - decodePtr(params[2])); - return IR_CONT; -} - -int32 Logic::fnNoSprite(int32 *params) { - // params: 0 pointer to object's graphic structure - _router->setSpriteStatus(decodePtr(params[0]), NO_SPRITE); - return IR_CONT; -} - -int32 Logic::fnSendSync(int32 *params) { - // params: 0 sync's recipient - // 1 sync value - - sendSync(params[0], params[1]); - return IR_CONT; -} - -int32 Logic::fnUpdatePlayerStats(int32 *params) { - // engine needs to know certain info about the player - - // params: 0 pointer to mega structure - - ObjectMega obMega(decodePtr(params[0])); - - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - screenInfo->player_feet_x = obMega.getFeetX(); - screenInfo->player_feet_y = obMega.getFeetY(); - - // for the script - writeVar(PLAYER_FEET_X, obMega.getFeetX()); - writeVar(PLAYER_FEET_Y, obMega.getFeetY()); - writeVar(PLAYER_CUR_DIR, obMega.getCurDir()); - writeVar(SCROLL_OFFSET_X, screenInfo->scroll_offset_x); - - debug(5, "fnUpdatePlayerStats: %d %d", - obMega.getFeetX(), obMega.getFeetY()); - - return IR_CONT; -} - -int32 Logic::fnPassGraph(int32 *params) { - // makes an engine local copy of passed ObjectGraphic - run script 4 - // of an object to request this used by fnTurnTo(id) etc - // - // remember, we cannot simply read a compact any longer but instead - // must request it from the object itself - - // params: 0 pointer to an ObjectGraphic structure - - warning("fnPassGraph() is a no-op now"); - return IR_CONT; -} - -int32 Logic::fnInitFloorMouse(int32 *params) { - // params: 0 pointer to object's mouse structure - - byte *ob_mouse = decodePtr(params[0]); - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - // floor is always lowest priority - - ObjectMouse mouse; - - mouse.x1 = 0; - mouse.y1 = 0; - mouse.x2 = screenInfo->screen_wide - 1; - mouse.y2 = screenInfo->screen_deep - 1; - mouse.priority = 9; - mouse.pointer = NORMAL_MOUSE_ID; - - mouse.write(ob_mouse); - return IR_CONT; -} - -int32 Logic::fnPassMega(int32 *params) { - // makes an engine local copy of passed mega_structure - run script 4 - // of an object to request this used by fnTurnTo(id) etc - // - // remember, we cannot simply read a compact any longer but instead - // must request it from the object itself - - // params: 0 pointer to a mega structure - - memcpy(_engineMega, decodePtr(params[0]), ObjectMega::size()); - return IR_CONT; -} - -/** - * Turn mega to face point (x,y) on the floor - */ - -int32 Logic::fnFaceXY(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 pointer to object's graphic structure - // 2 pointer to object's mega structure - // 3 pointer to object's walkdata structure - // 4 target x-coord - // 5 target y-coord - - return _router->faceXY( - decodePtr(params[0]), - decodePtr(params[1]), - decodePtr(params[2]), - decodePtr(params[3]), - params[4], params[5]); -} - -/** - * Causes no more objects in this logic loop to be processed. The logic engine - * will restart at the beginning of the new list. The current screen will not - * be drawn! - */ - -int32 Logic::fnEndSession(int32 *params) { - // params: 0 id of new run-list - - // terminate current and change to next run-list - expressChangeSession(params[0]); - - // stop the script - logic engine will now go around and the new - // screen will begin - return IR_STOP; -} - -int32 Logic::fnNoHuman(int32 *params) { - // params: none - - _vm->_mouse->noHuman(); - return IR_CONT; -} - -int32 Logic::fnAddHuman(int32 *params) { - // params: none - - _vm->_mouse->addHuman(); - return IR_CONT; -} - -/** - * Wait for a target to become waiting, i.e. not busy. - */ - -int32 Logic::fnWeWait(int32 *params) { - // params: 0 target - - assert(_vm->_resman->fetchType(params[0]) == GAME_OBJECT); - - // Run the target's get-speech-state script - runResScript(params[0], 5); - - if (readVar(RESULT) == 0) { - // The target is busy. Try again. - _vm->_debugger->_speechScriptWaiting = params[0]; - return IR_REPEAT; - } - - // The target is waiting, i.e. not busy. - - _vm->_debugger->_speechScriptWaiting = 0; - return IR_CONT; -} - -/** - * Wait for a target to become waiting, i.e. not busy, send a command to it, - * then wait for it to finish. - */ - -int32 Logic::fnTheyDoWeWait(int32 *params) { - // params: 0 pointer to ob_logic - // 1 target - // 2 command - // 3 ins1 - // 4 ins2 - // 5 ins3 - // 6 ins4 - // 7 ins5 - - assert(_vm->_resman->fetchType(params[1]) == GAME_OBJECT); - - // Run the target's get-speech-state script - runResScript(params[1], 5); - - ObjectLogic obLogic(decodePtr(params[0])); - - if (readVar(RESULT) == 1 && readVar(INS_COMMAND) == 0 && obLogic.getLooping() == 0) { - // The target is waiting, i.e. not busy, and there is no other - // command queued. We haven't sent the command yet, so do it. - - debug(5, "fnTheyDoWeWait: sending command to %d", params[1]); - - _vm->_debugger->_speechScriptWaiting = params[1]; - obLogic.setLooping(1); - - writeVar(SPEECH_ID, params[1]); - writeVar(INS_COMMAND, params[2]); - writeVar(INS1, params[3]); - writeVar(INS2, params[4]); - writeVar(INS3, params[5]); - writeVar(INS4, params[6]); - writeVar(INS5, params[7]); - - return IR_REPEAT; - } - - if (obLogic.getLooping() == 0) { - // The command has not been sent yet. Keep waiting. - _vm->_debugger->_speechScriptWaiting = params[1]; - return IR_REPEAT; - } - - if (readVar(RESULT) == 0) { - // The command has been sent, and the target is busy doing it. - // Wait for it to finish. - - debug(5, "fnTheyDoWeWait: Waiting for %d to finish", params[1]); - - _vm->_debugger->_speechScriptWaiting = params[1]; - return IR_REPEAT; - } - - debug(5, "fnTheyDoWeWait: %d finished", params[1]); - - obLogic.setLooping(0); - _vm->_debugger->_speechScriptWaiting = 0; - return IR_CONT; -} - -/** - * Wait for a target to become waiting, i.e. not busy, then send a command to - * it. - */ - -int32 Logic::fnTheyDo(int32 *params) { - // params: 0 target - // 1 command - // 2 ins1 - // 3 ins2 - // 4 ins3 - // 5 ins4 - // 6 ins5 - - assert(_vm->_resman->fetchType(params[0]) == GAME_OBJECT); - - // Run the target's get-speech-state script - runResScript(params[0], 5); - - if (readVar(RESULT) == 1 && !readVar(INS_COMMAND)) { - // The target is waiting, i.e. not busy, and there is no other - // command queued. Send the command. - - debug(5, "fnTheyDo: sending command to %d", params[0]); - - _vm->_debugger->_speechScriptWaiting = 0; - - writeVar(SPEECH_ID, params[0]); - writeVar(INS_COMMAND, params[1]); - writeVar(INS1, params[2]); - writeVar(INS2, params[3]); - writeVar(INS3, params[4]); - writeVar(INS4, params[5]); - writeVar(INS5, params[6]); - - return IR_CONT; - } - - // The target is busy. Come back again next cycle. - - _vm->_debugger->_speechScriptWaiting = params[0]; - return IR_REPEAT; -} - -/** - * Route to the left or right hand side of target id, if possible. - */ - -int32 Logic::fnWalkToTalkToMega(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 pointer to object's graphic structure - // 2 pointer to object's mega structure - // 3 pointer to object's walkdata structure - // 4 id of target mega to face - // 5 separation - - return _router->walkToTalkToMega( - decodePtr(params[0]), - decodePtr(params[1]), - decodePtr(params[2]), - decodePtr(params[3]), - params[4], params[5]); -} - -int32 Logic::fnFadeDown(int32 *params) { - // NONE means up! can only be called when screen is fully faded up - - // multiple calls wont have strange effects - - // params: none - - if (_vm->_screen->getFadeStatus() == RDFADE_NONE) - _vm->_screen->fadeDown(); - - return IR_CONT; -} - -enum { - S_OB_GRAPHIC = 0, - S_OB_SPEECH = 1, - S_OB_LOGIC = 2, - S_OB_MEGA = 3, - - S_TEXT = 4, - S_WAV = 5, - S_ANIM = 6, - S_DIR_TABLE = 7, - S_ANIM_MODE = 8 -}; - -/** - * It's the super versatile fnSpeak. Text and wavs can be selected in any - * combination. - * - * @note We can assume no human - there should be no human, at least! - */ - -int32 Logic::fnISpeak(int32 *params) { - // params: 0 pointer to ob_graphic - // 1 pointer to ob_speech - // 2 pointer to ob_logic - // 3 pointer to ob_mega - // 4 encoded text number - // 5 wav res id - // 6 anim res id - // 7 anim table res id - // 8 animation mode 0 lip synced, - // 1 just straight animation - - static bool cycle_skip = false; - static bool speechRunning; - - // Set up the pointers which we know we'll always need - - ObjectLogic obLogic(decodePtr(params[S_OB_LOGIC])); - ObjectGraphic obGraph(decodePtr(params[S_OB_GRAPHIC])); - - // FIRST TIME ONLY: create the text, load the wav, set up the anim, - // etc. - - if (obLogic.getLooping() == 0) { - // New fudge to wait for smacker samples to finish - // since they can over-run into the game - - if (_vm->_sound->getSpeechStatus() != RDSE_SAMPLEFINISHED) - return IR_REPEAT; - - // New fudge for 'fx' subtitles: If subtitles switched off, and - // we don't want to use a wav for this line either, then just - // quit back to script right now! - - if (!_vm->getSubtitles() && !wantSpeechForLine(params[S_WAV])) - return IR_CONT; - - // Drop out for 1st cycle to allow walks/anims to end and - // display last frame before system locks while speech loaded - - if (!cycle_skip) { - cycle_skip = true; - return IR_REPEAT; - } - - cycle_skip = false; - - _vm->_debugger->_textNumber = params[S_TEXT]; - - // Pull out the text line to get the official text number - // (for wav id). Once the wav id's go into all script text - // commands, we'll only need this for debugging. - - uint32 text_res = params[S_TEXT] / SIZE; - uint32 local_text = params[S_TEXT] & 0xffff; - - // For testing all text & speech! - // - // A script loop can send any text number to fnISpeak and it - // will only run the valid ones or return with 'result' equal - // to '1' or '2' to mean 'invalid text resource' and 'text - // number out of range' respectively - // - // See 'testing_routines' object in George's Player Character - // section of linc - - if (readVar(SYSTEM_TESTING_TEXT)) { - if (!_vm->_resman->checkValid(text_res)) { - // Not a valid resource number - invalid (null - // resource) - writeVar(RESULT, 1); - return IR_CONT; - } - - if (_vm->_resman->fetchType(text_res) != TEXT_FILE) { - // Invalid - not a text resource - _vm->_resman->closeResource(text_res); - writeVar(RESULT, 1); - return IR_CONT; - } - - if (!_vm->checkTextLine(_vm->_resman->openResource(text_res), local_text)) { - // Line number out of range - _vm->_resman->closeResource(text_res); - writeVar(RESULT, 2); - return IR_CONT; - } - - _vm->_resman->closeResource(text_res); - writeVar(RESULT, 0); - } - - byte *text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text); - _officialTextNumber = READ_LE_UINT16(text); - _vm->_resman->closeResource(text_res); - - // Prevent dud lines from appearing while testing text & speech - // since these will not occur in the game anyway - - if (readVar(SYSTEM_TESTING_TEXT)) { - // If actor number is 0 and text line is just a 'dash' - // character - if (_officialTextNumber == 0 && text[2] == '-' && text[3] == 0) { - writeVar(RESULT, 3); - return IR_CONT; - } - } - - // Set the 'looping_flag' and the text-click-delays. We can - // left-click past the text after half a second, and - // right-click past it after a quarter of a second. - - obLogic.setLooping(1); - _leftClickDelay = 6; - _rightClickDelay = 3; - - if (readVar(PLAYER_ID) != CUR_PLAYER_ID) - debug(5, "(%d) Nico: %s", _officialTextNumber, text + 2); - else { - byte buf[NAME_LEN]; - - debug(5, "(%d) %s: %s", _officialTextNumber, _vm->_resman->fetchName(readVar(ID), buf), text + 2); - } - - // Set up the speech animation - - if (params[S_ANIM]) { - // Just a straight anim. - _animId = params[6]; - } else if (params[S_DIR_TABLE]) { - // Use this direction table to derive the anim - // NB. ASSUMES WE HAVE A MEGA OBJECT!! - - ObjectMega obMega(decodePtr(params[S_OB_MEGA])); - byte *anim_table = decodePtr(params[S_DIR_TABLE]); - - _animId = READ_LE_UINT32(anim_table + 4 * obMega.getCurDir()); - } else { - // No animation choosen - _animId = 0; - } - - if (_animId) { - // Set the talker's graphic to the first frame of this - // speech anim for now. - - _speechAnimType = readVar(SPEECHANIMFLAG); - obGraph.setAnimResource(_animId); - obGraph.setAnimPc(0); - } - - // Default back to looped lip synced anims. - writeVar(SPEECHANIMFLAG, 0); - - // Set up _textX and _textY for speech panning and/or text - // sprite position. - - locateTalker(params); - - // Is it to be speech or subtitles or both? - - // Assume not running until know otherwise - speechRunning = false; - - // New fudge for 'fx' subtitles: If speech is selected, and - // this line is allowed speech (not if it's an fx subtitle!) - - if (!_vm->_sound->isSpeechMute() && wantSpeechForLine(_officialTextNumber)) { - // If the wavId parameter is zero because not yet - // compiled into speech command, we can still get it - // from the 1st 2 chars of the text line. - - if (!params[S_WAV]) - params[S_WAV] = (int32)_officialTextNumber; - - // Panning goes from -16 (left) to 16 (right) - int8 speech_pan = ((_textX - 320) * 16) / 320; - - if (speech_pan < -16) - speech_pan = -16; - else if (speech_pan > 16) - speech_pan = 16; - - uint32 rv = _vm->_sound->playCompSpeech(params[S_WAV], 16, speech_pan); - - if (rv == RD_OK) { - // Ok, we've got something to play. Set it - // playing now. (We might want to do this the - // next cycle, don't know yet.) - - speechRunning = true; - _vm->_sound->unpauseSpeech(); - } else { - debug(5, "ERROR: PlayCompSpeech(wav=%d (res=%d pos=%d)) returned %.8x", params[S_WAV], text_res, local_text, rv); - } - } - - if (_vm->getSubtitles() || !speechRunning) { - // We want subtitles, or the speech failed to load. - // Either way, we're going to show the text so create - // the text sprite. - - formText(params); - } - } - - // EVERY TIME: run a cycle of animation, if there is one - - if (_animId) { - // There is an animation - Increment the anim frame number. - obGraph.setAnimPc(obGraph.getAnimPc() + 1); - - byte *anim_file = _vm->_resman->openResource(obGraph.getAnimResource()); - AnimHeader anim_head; - - anim_head.read(_vm->fetchAnimHeader(anim_file)); - - if (!_speechAnimType) { - // ANIM IS TO BE LIP-SYNC'ED & REPEATING - - if (obGraph.getAnimPc() == (int32)anim_head.noAnimFrames) { - // End of animation - restart from frame 0 - obGraph.setAnimPc(0); - } else if (speechRunning && _vm->_sound->amISpeaking() == RDSE_QUIET) { - // The speech is running, but we're at a quiet - // bit. Restart from frame 0 (closed mouth). - obGraph.setAnimPc(0); - } - } else { - // ANIM IS TO PLAY ONCE ONLY - if (obGraph.getAnimPc() == (int32)anim_head.noAnimFrames - 1) { - // Reached the last frame of the anim. Hold - // anim on this last frame - _animId = 0; - } - } - - _vm->_resman->closeResource(obGraph.getAnimResource()); - } else if (_speechAnimType) { - // Placed here so we actually display the last frame of the - // anim. - _speechAnimType = 0; - } - - // EVERY TIME: FIND OUT IF WE NEED TO STOP THE SPEECH NOW... - - // If there is a wav then we're using that to end the speech naturally - - bool speechFinished = false; - - // If playing a sample - - if (speechRunning) { - // Has it finished? - if (_vm->_sound->getSpeechStatus() == RDSE_SAMPLEFINISHED) - speechFinished = true; - } else if (!speechRunning && _speechTime) { - // Counting down text time because there is no sample - this - // ends the speech - - // if no sample then we're using _speechTime to end speech - // naturally - - _speechTime--; - if (!_speechTime) - speechFinished = true; - } - - // Ok, all is running along smoothly - but a click means stop - // unnaturally - - int mouseX, mouseY; - - _vm->_mouse->getPos(mouseX, mouseY); - - // So that we can go to the options panel while text & speech is - // being tested - if (readVar(SYSTEM_TESTING_TEXT) == 0 || mouseY > 0) { - MouseEvent *me = _vm->mouseEvent(); - - // Note that we now have TWO click-delays - one for LEFT - // button, one for RIGHT BUTTON - - if ((!_leftClickDelay && me && (me->buttons & RD_LEFTBUTTONDOWN)) || - (!_rightClickDelay && me && (me->buttons & RD_RIGHTBUTTONDOWN))) { - // Mouse click, after click_delay has expired -> end - // the speech. - - // if testing text & speech - if (readVar(SYSTEM_TESTING_TEXT)) { - // and RB used to click past text - if (me->buttons & RD_RIGHTBUTTONDOWN) { - // then we want the previous line again - writeVar(SYSTEM_WANT_PREVIOUS_LINE, 1); - } else { - // LB just want next line again - writeVar(SYSTEM_WANT_PREVIOUS_LINE, 0); - } - } - - speechFinished = true; - - // if speech sample playing, halt it prematurely - if (speechRunning) - _vm->_sound->stopSpeech(); - } - } - - // If we are finishing the speech this cycle, do the business - - // !speechAnimType, as we want an anim which is playing once to have - // finished. - - if (speechFinished && !_speechAnimType) { - // If there is text, kill it - if (_speechTextBlocNo) { - _vm->_fontRenderer->killTextBloc(_speechTextBlocNo); - _speechTextBlocNo = 0; - } - - // if there is a speech anim, end it on closed mouth frame - if (_animId) { - _animId = 0; - obGraph.setAnimPc(0); - } - - speechRunning = false; - - // no longer in a script function loop - obLogic.setLooping(0); - - _vm->_debugger->_textNumber = 0; - - // reset to zero, in case text line not even extracted (since - // this number comes from the text line) - _officialTextNumber = 0; - - writeVar(RESULT, 0); - return IR_CONT; - } - - // Speech still going, so decrement the click_delay if it's still - // active - - if (_leftClickDelay) - _leftClickDelay--; - - if (_rightClickDelay) - _rightClickDelay--; - - return IR_REPEAT; -} - -/** - * Reset the object and restart script 1 on level 0 - */ - -int32 Logic::fnTotalRestart(int32 *params) { - // mega runs this to restart its base logic again - like being cached - // in again - - // params: none - - _curObjectHub.setLogicLevel(0); - _curObjectHub.setScriptPc(0, 1); - - return IR_TERMINATE; -} - -int32 Logic::fnSetWalkGrid(int32 *params) { - // params: none - - warning("fnSetWalkGrid() is no longer a valid opcode"); - return IR_CONT; -} - -/** - * Receive and sequence the commands sent from the conversation script. We have - * to do this in a slightly tweeky manner as we can no longer have generic - * scripts. - */ - -enum { - INS_talk = 1, - INS_anim = 2, - INS_reverse_anim = 3, - INS_walk = 4, - INS_turn = 5, - INS_face = 6, - INS_trace = 7, - INS_no_sprite = 8, - INS_sort = 9, - INS_foreground = 10, - INS_background = 11, - INS_table_anim = 12, - INS_reverse_table_anim = 13, - INS_walk_to_anim = 14, - INS_set_frame = 15, - INS_stand_after_anim = 16, - INS_quit = 42 -}; - -int32 Logic::fnSpeechProcess(int32 *params) { - // params: 0 pointer to ob_graphic - // 1 pointer to ob_speech - // 2 pointer to ob_logic - // 3 pointer to ob_mega - // 4 pointer to ob_walkdata - - ObjectSpeech obSpeech(decodePtr(params[1])); - - while (1) { - int32 pars[9]; - - // Check which command we're waiting for, and call the - // appropriate function. Once we're done, clear the command - // and set wait_state to 1. - // - // Note: we could save a var and ditch wait_state and check - // 'command' for non zero means busy - // - // Note: I can't see that we ever check the value of wait_state - // but perhaps it accesses that memory location directly? - - switch (obSpeech.getCommand()) { - case 0: - break; - case INS_talk: - pars[0] = params[0]; // ob_graphic - pars[1] = params[1]; // ob_speech - pars[2] = params[2]; // ob_logic - pars[3] = params[3]; // ob_mega - pars[4] = obSpeech.getIns1(); // encoded text number - pars[5] = obSpeech.getIns2(); // wav res id - pars[6] = obSpeech.getIns3(); // anim res id - pars[7] = obSpeech.getIns4(); // anim table res id - pars[8] = obSpeech.getIns5(); // animation mode - 0 lip synced, 1 just straight animation - - if (fnISpeak(pars) != IR_REPEAT) { - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - } - - return IR_REPEAT; - case INS_turn: - pars[0] = params[2]; // ob_logic - pars[1] = params[0]; // ob_graphic - pars[2] = params[3]; // ob_mega - pars[3] = params[4]; // ob_walkdata - pars[4] = obSpeech.getIns1(); // direction to turn to - - if (fnTurn(pars) != IR_REPEAT) { - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - } - - return IR_REPEAT; - case INS_face: - pars[0] = params[2]; // ob_logic - pars[1] = params[0]; // ob_graphic - pars[2] = params[3]; // ob_mega - pars[3] = params[4]; // ob_walkdata - pars[4] = obSpeech.getIns1(); // target - - if (fnFaceMega(pars) != IR_REPEAT) { - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - } - - return IR_REPEAT; - case INS_anim: - pars[0] = params[2]; // ob_logic - pars[1] = params[0]; // ob_graphic - pars[2] = obSpeech.getIns1(); // anim res - - if (fnAnim(pars) != IR_REPEAT) { - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - } - - return IR_REPEAT; - case INS_reverse_anim: - pars[0] = params[2]; // ob_logic - pars[1] = params[0]; // ob_graphic - pars[2] = obSpeech.getIns1(); // anim res - - if (fnReverseAnim(pars) != IR_REPEAT) { - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - } - - return IR_REPEAT; - case INS_table_anim: - pars[0] = params[2]; // ob_logic - pars[1] = params[0]; // ob_graphic - pars[2] = params[3]; // ob_mega - pars[3] = obSpeech.getIns1(); // pointer to anim table - - if (fnMegaTableAnim(pars) != IR_REPEAT) { - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - } - - return IR_REPEAT; - case INS_reverse_table_anim: - pars[0] = params[2]; // ob_logic - pars[1] = params[0]; // ob_graphic - pars[2] = params[3]; // ob_mega - pars[3] = obSpeech.getIns1(); // pointer to anim table - - if (fnReverseMegaTableAnim(pars) != IR_REPEAT) { - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - } - - return IR_REPEAT; - case INS_no_sprite: - fnNoSprite(params); // ob_graphic - - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - return IR_REPEAT ; - case INS_sort: - fnSortSprite(params); // ob_graphic - - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - return IR_REPEAT; - case INS_foreground: - fnForeSprite(params); // ob_graphic - - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - return IR_REPEAT; - case INS_background: - fnBackSprite(params); // ob_graphic - - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - return IR_REPEAT; - case INS_walk: - pars[0] = params[2]; // ob_logic - pars[1] = params[0]; // ob_graphic - pars[2] = params[3]; // ob_mega - pars[3] = params[4]; // ob_walkdata - pars[4] = obSpeech.getIns1(); // target x - pars[5] = obSpeech.getIns2(); // target y - pars[6] = obSpeech.getIns3(); // target direction - - if (fnWalk(pars) != IR_REPEAT) { - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - } - - return IR_REPEAT; - case INS_walk_to_anim: - pars[0] = params[2]; // ob_logic - pars[1] = params[0]; // ob_graphic - pars[2] = params[3]; // ob_mega - pars[3] = params[4]; // ob_walkdata - pars[4] = obSpeech.getIns1(); // anim resource - - if (fnWalkToAnim(pars) != IR_REPEAT) { - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - } - - return IR_REPEAT; - case INS_stand_after_anim: - pars[0] = params[0]; // ob_graphic - pars[1] = params[3]; // ob_mega - pars[2] = obSpeech.getIns1(); // anim resource - - fnStandAfterAnim(pars); - - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - return IR_REPEAT; - case INS_set_frame: - pars[0] = params[0]; // ob_graphic - pars[1] = obSpeech.getIns1(); // anim_resource - pars[2] = obSpeech.getIns2(); // FIRST_FRAME or LAST_FRAME - fnSetFrame(pars); - - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - return IR_REPEAT; - case INS_quit: - // That's it - we're finished with this - obSpeech.setCommand(0); - // obSpeech.setWaitState(0); - return IR_CONT; - default: - // Unimplemented command - just cancel - obSpeech.setCommand(0); - obSpeech.setWaitState(1); - break; - } - - if (readVar(SPEECH_ID) == readVar(ID)) { - // There's a new command for us! Grab the command - - // potentially we only have this cycle to do this - and - // set things up so that the command will be picked up - // on the next iteration of the while loop. - - debug(5, "fnSpeechProcess: Received new command %d", readVar(INS_COMMAND)); - - writeVar(SPEECH_ID, 0); - - obSpeech.setCommand(readVar(INS_COMMAND)); - obSpeech.setIns1(readVar(INS1)); - obSpeech.setIns2(readVar(INS2)); - obSpeech.setIns3(readVar(INS3)); - obSpeech.setIns4(readVar(INS4)); - obSpeech.setIns5(readVar(INS5)); - obSpeech.setWaitState(0); - - writeVar(INS_COMMAND, 0); - } else { - // No new command. We could run a blink anim (or - // something) here. - - obSpeech.setWaitState(1); - return IR_REPEAT; - } - } -} - -int32 Logic::fnSetScaling(int32 *params) { - // params: 0 pointer to object's mega structure - // 1 scale constant A - // 2 scale constant B - - // 256 * s = A * y + B - - // Where s is system scale, which itself is (256 * actual_scale) ie. - // s == 128 is half size - - ObjectMega obMega(decodePtr(params[0])); - - obMega.setScaleA(params[1]); - obMega.setScaleB(params[2]); - - return IR_CONT; -} - -int32 Logic::fnStartEvent(int32 *params) { - // params: none - - startEvent(); - return IR_TERMINATE; -} - -int32 Logic::fnCheckEventWaiting(int32 *params) { - // params: none - - writeVar(RESULT, checkEventWaiting()); - return IR_CONT; -} - -int32 Logic::fnRequestSpeech(int32 *params) { - // change current script - must be followed by a TERMINATE script - // directive - - // params: 0 id of target to catch the event and startup speech - // servicing - - // Full script id to interact with - megas run their own 7th script - sendEvent(params[0], (params[0] << 16) | 6); - return IR_CONT; -} - -int32 Logic::fnGosub(int32 *params) { - // params: 0 id of script - - // Hurray, script subroutines. Logic goes up - pc is saved for current - // level. - logicUp(params[0]); - return IR_GOSUB; -} - -/** - * Wait for a target to become waiting, i.e. not busy, or until we time out. - * This is useful when clicking on a target to talk to it, and it doesn't - * reply. This way, we won't lock up. - * - * If the target becomes waiting, RESULT is set to 0. If we time out, RESULT is - * set to 1. - */ - -int32 Logic::fnTimedWait(int32 *params) { - // params: 0 ob_logic - // 1 target - // 2 number of cycles before give up - - assert(_vm->_resman->fetchType(params[1]) == GAME_OBJECT); - - ObjectLogic obLogic(decodePtr(params[0])); - - if (obLogic.getLooping() == 0) { - // This is the first time, so set up the time-out. - obLogic.setLooping(params[2]); - } - - // Run the target's get-speech-state script - runResScript(params[1], 5); - - if (readVar(RESULT) == 1) { - // The target is waiting, i.e. not busy - - _vm->_debugger->_speechScriptWaiting = 0; - - obLogic.setLooping(0); - writeVar(RESULT, 0); - return IR_CONT; - } - - obLogic.setLooping(obLogic.getLooping() - 1); - - if (obLogic.getLooping() == 0) { - // Time's up. - - debug(5, "fnTimedWait: Timed out waiting for %d", params[1]); - _vm->_debugger->_speechScriptWaiting = 0; - - // Clear the event that hasn't been picked up - in theory, - // none of this should ever happen. - - killAllIdsEvents(params[1]); - writeVar(RESULT, 1); - return IR_CONT; - } - - // Target is busy. Keep trying. - - _vm->_debugger->_speechScriptWaiting = params[1]; - return IR_REPEAT; -} - -int32 Logic::fnPlayFx(int32 *params) { - // params: 0 sample resource id - // 1 type (FX_SPOT, FX_RANDOM, FX_LOOP) - // 2 delay (0..65535) - // 3 volume (0..16) - // 4 pan (-16..16) - - // example script: - // fnPlayFx (FXWATER, FX_LOOP, 0, 10, 15); - // // fx_water is just a local script flag - // fx_water = result; - // . - // . - // . - // fnStopFx (fx_water); - - int32 res = params[0]; - int32 type = params[1]; - int32 delay = params[2]; - int32 volume = params[3]; - int32 pan = params[4]; - - _vm->_sound->queueFx(res, type, delay, volume, pan); - return IR_CONT; -} - -int32 Logic::fnStopFx(int32 *params) { - // params: 0 position in queue - if (_vm->_sound->stopFx(params[0]) != RD_OK) - debug(5, "SFX ERROR: Trying to stop an inactive sound slot"); - - return IR_CONT; -} - -/** - * Start a tune playing, to play once or to loop until stopped or next one - * played. - */ - -int32 Logic::fnPlayMusic(int32 *params) { - // params: 0 tune id - // 1 loop flag (0 or 1) - - char filename[128]; - bool loopFlag; - uint32 rv; - - loopFlag = (params[1] == FX_LOOP); - - rv = _vm->_sound->streamCompMusic(params[0], loopFlag); - - if (rv) - debug(5, "ERROR: streamCompMusic(%s, %d, %d) returned error 0x%.8x", filename, params[0], loopFlag, rv); - - return IR_CONT; -} - -int32 Logic::fnStopMusic(int32 *params) { - // params: none - - _vm->_sound->stopMusic(false); - return IR_CONT; -} - -int32 Logic::fnSetValue(int32 *params) { - // temp. function! - - // used for setting far-referenced megaset resource field in mega - // object, from start script - - // params: 0 pointer to object's mega structure - // 1 value to set it to - - ObjectMega obMega(decodePtr(params[0])); - - obMega.setMegasetRes(params[1]); - return IR_CONT; -} - -int32 Logic::fnNewScript(int32 *params) { - // change current script - must be followed by a TERMINATE script - // directive - - // params: 0 id of script - - writeVar(PLAYER_ACTION, 0); // must clear this - logicReplace(params[0]); - return IR_TERMINATE; -} - -/** - * Like getSync(), but called from scripts. Sets the RESULT variable to - * the sync value, or 0 if none is found. - */ - -int32 Logic::fnGetSync(int32 *params) { - // params: none - - int slot = getSync(); - - writeVar(RESULT, (slot != -1) ? _syncList[slot].sync : 0); - return IR_CONT; -} - -/** - * Wait for sync to happen. Sets the RESULT variable to the sync value, once - * it has been found. - */ - -int32 Logic::fnWaitSync(int32 *params) { - // params: none - - debug(6, "fnWaitSync: %d waits", readVar(ID)); - - int slot = getSync(); - - if (slot == -1) - return IR_REPEAT; - - debug(5, "fnWaitSync: %d got sync %d", readVar(ID), _syncList[slot].sync); - writeVar(RESULT, _syncList[slot].sync); - return IR_CONT; -} - -int32 Logic::fnRegisterWalkGrid(int32 *params) { - // params: none - - warning("fnRegisterWalkGrid() is no longer a valid opcode"); - return IR_CONT; -} - -int32 Logic::fnReverseMegaTableAnim(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 pointer to object's graphic structure - // 2 pointer to object's mega structure - // 3 pointer to animation table - - // Reverse anim - return _router->megaTableAnimate( - decodePtr(params[0]), - decodePtr(params[1]), - decodePtr(params[2]), - decodePtr(params[3]), - true); -} - -int32 Logic::fnReverseAnim(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 pointer to object's graphic structure - // 2 resource id of animation file - - // Reverse anim - return _router->doAnimate( - decodePtr(params[0]), - decodePtr(params[1]), - params[2], true); -} - -/** - * Mark this object for killing - to be killed when player leaves this screen. - * Object reloads and script restarts upon re-entry to screen, which causes - * this object's startup logic to be re-run every time we enter the screen. - * "Which is nice." - * - * @note Call ONCE from object's logic script, i.e. in startup code, so not - * re-called every time script frops off and restarts! - */ - -int32 Logic::fnAddToKillList(int32 *params) { - // params: none - uint32 id = readVar(ID); - - // DON'T EVER KILL GEORGE! - if (id == CUR_PLAYER_ID) - return IR_CONT; - - // Scan the list to see if it's already included - - for (uint32 i = 0; i < _kills; i++) { - if (_objectKillList[i] == id) - return IR_CONT; - } - - assert(_kills < OBJECT_KILL_LIST_SIZE); // no room at the inn - - _objectKillList[_kills++] = id; - - // "another one bites the dust" - - // When we leave the screen, all these object resources are to be - // cleaned out of memory and the kill list emptied by doing - // '_kills = 0', ensuring that all resources are in fact still in - // memory and, more importantly, closed before killing! - - return IR_CONT; -} - -/** - * Set the standby walk coords to be used by fnWalkToAnim() and - * fnStandAfterAnim() when the anim header's start/end coords are zero. - * Useful during development; can stay in final game anyway. - */ - -int32 Logic::fnSetStandbyCoords(int32 *params) { - // params: 0 x-coord - // 1 y-coord - // 2 direction (0..7) - - _router->setStandbyCoords(params[0], params[1], params[2]); - return IR_CONT; -} - -int32 Logic::fnBackPar0Sprite(int32 *params) { - // params: 0 pointer to object's graphic structure - _router->setSpriteStatus(decodePtr(params[0]), BGP0_SPRITE); - return IR_CONT; -} - -int32 Logic::fnBackPar1Sprite(int32 *params) { - // params: 0 pointer to object's graphic structure - _router->setSpriteStatus(decodePtr(params[0]), BGP1_SPRITE); - return IR_CONT; -} - -int32 Logic::fnForePar0Sprite(int32 *params) { - // params: 0 pointer to object's graphic structure - _router->setSpriteStatus(decodePtr(params[0]), FGP0_SPRITE); - return IR_CONT; -} - -int32 Logic::fnForePar1Sprite(int32 *params) { - // params: 0 pointer to object's graphic structure - _router->setSpriteStatus(decodePtr(params[0]), FGP1_SPRITE); - return IR_CONT; -} - -int32 Logic::fnSetPlayerActionEvent(int32 *params) { - // we want to intercept the player character and have him interact - // with an object - from script this code is the same as the mouse - // engine calls when you click on an object - here, a third party - // does the clicking IYSWIM - - // note - this routine used CUR_PLAYER_ID as the target - - // params: 0 id to interact with - - setPlayerActionEvent(CUR_PLAYER_ID, params[0]); - return IR_CONT; -} - -/** - * Set the special scroll offset variables - * - * Call when starting screens and to change the camera within screens - * - * call AFTER fnInitBackground() to override the defaults - */ - -int32 Logic::fnSetScrollCoordinate(int32 *params) { - // params: 0 feet_x value - // 1 feet_y value - - // Called feet_x and feet_y to retain intellectual compatibility with - // Sword1! - // - // feet_x & feet_y refer to the physical screen coords where the - // system will try to maintain George's feet - - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - screenInfo->feet_x = params[0]; - screenInfo->feet_y = params[1]; - return IR_CONT; -} - -/** - * Stand mega at start position of anim - */ - -int32 Logic::fnStandAtAnim(int32 *params) { - // params: 0 pointer to object's graphic structure - // 1 pointer to object's mega structure - // 2 anim resource id - - _router->standAtAnim( - decodePtr(params[0]), - decodePtr(params[1]), - params[2]); - return IR_CONT; -} - -#define SCROLL_MOUSE_WIDTH 20 - -int32 Logic::fnSetScrollLeftMouse(int32 *params) { - // params: 0 pointer to object's mouse structure - - byte *ob_mouse = decodePtr(params[0]); - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - // Highest priority - - ObjectMouse mouse; - - mouse.x1 = 0; - mouse.y1 = 0; - mouse.x2 = screenInfo->scroll_offset_x + SCROLL_MOUSE_WIDTH; - mouse.y2 = screenInfo->screen_deep - 1; - mouse.priority = 0; - - if (screenInfo->scroll_offset_x > 0) { - // not fully scrolled to the left - mouse.pointer = SCROLL_LEFT_MOUSE_ID; - } else { - // so the mouse area doesn't get registered - mouse.pointer = 0; - } - - mouse.write(ob_mouse); - return IR_CONT; -} - -int32 Logic::fnSetScrollRightMouse(int32 *params) { - // params: 0 pointer to object's mouse structure - - byte *ob_mouse = decodePtr(params[0]); - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - // Highest priority - - ObjectMouse mouse; - - mouse.x1 = screenInfo->scroll_offset_x + _vm->_screen->getScreenWide() - SCROLL_MOUSE_WIDTH; - mouse.y1 = 0; - mouse.x2 = screenInfo->screen_wide - 1; - mouse.y2 = screenInfo->screen_deep - 1; - mouse.priority = 0; - - if (screenInfo->scroll_offset_x < screenInfo->max_scroll_offset_x) { - // not fully scrolled to the right - mouse.pointer = SCROLL_RIGHT_MOUSE_ID; - } else { - // so the mouse area doesn't get registered - mouse.pointer = 0; - } - - mouse.write(ob_mouse); - return IR_CONT; -} - -int32 Logic::fnColour(int32 *params) { - // set border colour - useful during script development - // eg. set to colour during a timer situation, then black when timed - // out - - // params 0: colour (see defines above) - -#ifdef SWORD2_DEBUG - // what colour? - switch (params[0]) { - case BLACK: - _vm->_screen->setPalette(0, 1, black, RDPAL_INSTANT); - break; - case WHITE: - _vm->_screen->setPalette(0, 1, white, RDPAL_INSTANT); - break; - case RED: - _vm->_screen->setPalette(0, 1, red, RDPAL_INSTANT); - break; - case GREEN: - _vm->_screen->setPalette(0, 1, green, RDPAL_INSTANT); - break; - case BLUE: - _vm->_screen->setPalette(0, 1, blue, RDPAL_INSTANT); - break; - } -#endif - - return IR_CONT; -} - -#ifdef SWORD2_DEBUG -#define BLACK 0 -#define WHITE 1 -#define RED 2 -#define GREEN 3 -#define BLUE 4 - -static uint8 black[4] = { 0, 0, 0, 0 }; -static uint8 white[4] = { 255, 255, 255, 0 }; -static uint8 red[4] = { 255, 0, 0, 0 }; -static uint8 green[4] = { 0, 255, 0, 0 }; -static uint8 blue[4] = { 0, 0, 255, 0 }; -#endif - -int32 Logic::fnFlash(int32 *params) { - // flash colour 0 (ie. border) - useful during script development - // eg. fnFlash(BLUE) where a text line is missed; RED when some code - // missing, etc - - // params: 0 colour to flash - -#ifdef SWORD2_DEBUG - // what colour? - switch (params[0]) { - case WHITE: - _vm->_screen->setPalette(0, 1, white, RDPAL_INSTANT); - break; - case RED: - _vm->_screen->setPalette(0, 1, red, RDPAL_INSTANT); - break; - case GREEN: - _vm->_screen->setPalette(0, 1, green, RDPAL_INSTANT); - break; - case BLUE: - _vm->_screen->setPalette(0, 1, blue, RDPAL_INSTANT); - break; - } - - // There used to be a busy-wait loop here, so I don't know how long - // the delay was meant to be. Probably doesn't matter much. - - _vm->_screen->updateDisplay(); - _vm->_system->delayMillis(250); - _vm->_screen->setPalette(0, 1, black, RDPAL_INSTANT); -#endif - - return IR_CONT; -} - -int32 Logic::fnPreFetch(int32 *params) { - // Go fetch resource in the background. - - // params: 0 resource to fetch [guess] - - return IR_CONT; -} - -/** - * Reverse of fnPassPlayerSaveData() - run script 8 of player object. - */ - -int32 Logic::fnGetPlayerSaveData(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 pointer to object's graphic structure - // 2 pointer to object's mega structure - - byte *ob_logic = decodePtr(params[0]); - byte *ob_graph = decodePtr(params[1]); - byte *ob_mega = decodePtr(params[2]); - - // Copy from savegame buffers to player object - - memcpy(ob_logic, _saveLogic, ObjectLogic::size()); - memcpy(ob_graph, _saveGraphic, ObjectGraphic::size()); - memcpy(ob_mega, _saveMega, ObjectMega::size()); - - // Any walk-data must be cleared - the player will be set to stand if - // he was walking when saved. - - ObjectMega obMega(ob_mega); - - if (obMega.getIsWalking()) { - ObjectLogic obLogic(ob_logic); - - obMega.setIsWalking(0); - - int32 pars[3]; - - pars[0] = params[1]; // ob_graphic; - pars[1] = params[2]; // ob_mega - pars[2] = obMega.getCurDir(); - - fnStand(pars); - - // Reset looping flag (which would have been 1 during fnWalk) - obLogic.setLooping(0); - } - - return IR_CONT; -} - -/** - * Copies the 4 essential player structures into the savegame header - run - * script 7 of player object to request this. - * - * Remember, we cannot simply read a compact any longer but instead must - * request it from the object itself. - */ - -int32 Logic::fnPassPlayerSaveData(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 pointer to object's graphic structure - // 2 pointer to object's mega structure - - // Copy from player object to savegame buffers - - memcpy(_saveLogic, decodePtr(params[0]), ObjectLogic::size()); - memcpy(_saveGraphic, decodePtr(params[1]), ObjectGraphic::size()); - memcpy(_saveMega, decodePtr(params[2]), ObjectMega::size()); - - return IR_CONT; -} - -int32 Logic::fnSendEvent(int32 *params) { - // we want to intercept the player character and have him interact - // with an object - from script - - // params: 0 id to receive event - // 1 script to run - - sendEvent(params[0], params[1]); - return IR_CONT; -} - -/** - * Add this walkgrid resource to the list of those used for routing in this - * location. Note that this is ignored if the resource is already in the list. - */ - -int32 Logic::fnAddWalkGrid(int32 *params) { - // params: 0 id of walkgrid resource - - // All objects that add walkgrids must be restarted whenever we - // re-enter a location. - - // DON'T EVER KILL GEORGE! - if (readVar(ID) != CUR_PLAYER_ID) { - // Need to call this in case it wasn't called in script! - fnAddToKillList(NULL); - } - - _router->addWalkGrid(params[0]); - fnPreLoad(params); - return IR_CONT; -} - -/** - * Remove this walkgrid resource from the list of those used for routing in - * this location. Note that this is ignored if the resource isn't actually - * in the list. - */ - -int32 Logic::fnRemoveWalkGrid(int32 *params) { - // params: 0 id of walkgrid resource - - _router->removeWalkGrid(params[0]); - return IR_CONT; -} - -// like fnCheckEventWaiting, but starts the event rather than setting RESULT -// to 1 - -int32 Logic::fnCheckForEvent(int32 *params) { - // params: none - - if (checkEventWaiting()) { - startEvent(); - return IR_TERMINATE; - } - - return IR_CONT; -} - -// combination of fnPause and fnCheckForEvent -// - ie. does a pause, but also checks for event each cycle - -int32 Logic::fnPauseForEvent(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 number of game-cycles to pause - - ObjectLogic obLogic(decodePtr(params[0])); - - if (checkEventWaiting()) { - obLogic.setLooping(0); - startEvent(); - return IR_TERMINATE; - } - - return fnPause(params); -} - -int32 Logic::fnClearEvent(int32 *params) { - // params: none - - clearEvent(readVar(ID)); - return IR_CONT; -} - -int32 Logic::fnFaceMega(int32 *params) { - // params: 0 pointer to object's logic structure - // 1 pointer to object's graphic structure - // 2 pointer to object's mega structure - // 3 pointer to object's walkdata structure - // 4 id of target mega to face - - return _router->faceMega( - decodePtr(params[0]), - decodePtr(params[1]), - decodePtr(params[2]), - decodePtr(params[3]), - params[4]); -} - -int32 Logic::fnPlaySequence(int32 *params) { - // params: 0 pointer to null-terminated ascii filename - // 1 number of frames in the sequence, used for PSX. - - char filename[30]; - MovieTextObject *sequenceSpeechArray[MAX_SEQUENCE_TEXT_LINES + 1]; - - // The original code had some #ifdef blocks for skipping or muting the - // cutscenes - fondly described as "the biggest fudge in the history - // of computer games" - but at the very least we want to show the - // cutscene subtitles, so I removed them. - - debug(5, "fnPlaySequence(\"%s\");", (const char *)decodePtr(params[0])); - - // add the appropriate file extension & play it - - strcpy(filename, (const char *)decodePtr(params[0])); - - // Write to walkthrough file (zebug0.txt) - debug(5, "PLAYING SEQUENCE \"%s\"", filename); - - // now create the text sprites, if any - - if (_sequenceTextLines) - createSequenceSpeech(sequenceSpeechArray); - - // don't want to carry on streaming game music when smacker starts! - fnStopMusic(NULL); - - // pause sfx during sequence - _vm->_sound->pauseFx(); - - MoviePlayer player(_vm); - uint32 rv; - - if (_sequenceTextLines && !readVar(DEMO)) - rv = player.play(filename, sequenceSpeechArray, _smackerLeadIn, _smackerLeadOut); - else - rv = player.play(filename, NULL, _smackerLeadIn, _smackerLeadOut); - - // check the error return-value - if (rv) - debug(5, "MoviePlayer.play(\"%s\") returned 0x%.8x", filename, rv); - - // unpause sound fx again, in case we're staying in same location - _vm->_sound->unpauseFx(); - - _smackerLeadIn = 0; - _smackerLeadOut = 0; - - // now clear the text sprites, if any - - if (_sequenceTextLines) - clearSequenceSpeech(sequenceSpeechArray); - - // now clear the screen in case the Sequence was quitted (using ESC) - // rather than fading down to black - - _vm->_screen->clearScene(); - - // zero the entire palette in case we're about to fade up! - - byte pal[4 * 256]; - - memset(pal, 0, sizeof(pal)); - _vm->_screen->setPalette(0, 256, pal, RDPAL_INSTANT); - - debug(5, "fnPlaySequence FINISHED"); - return IR_CONT; -} - -int32 Logic::fnShadedSprite(int32 *params) { - // params: 0 pointer to object's graphic structure - _router->setSpriteShading(decodePtr(params[0]), SHADED_SPRITE); - return IR_CONT; -} - -int32 Logic::fnUnshadedSprite(int32 *params) { - // params: 0 pointer to object's graphic structure - _router->setSpriteShading(decodePtr(params[0]), UNSHADED_SPRITE); - return IR_CONT; -} - -int32 Logic::fnFadeUp(int32 *params) { - // params: none - - _vm->_screen->waitForFade(); - - if (_vm->_screen->getFadeStatus() == RDFADE_BLACK) - _vm->_screen->fadeUp(); - - return IR_CONT; -} - -int32 Logic::fnDisplayMsg(int32 *params) { - // Display a message to the user on the screen. - - // params: 0 Text number of message to be displayed. - - uint32 local_text = params[0] & 0xffff; - uint32 text_res = params[0] / SIZE; - - // Display message for three seconds. - - // +2 to skip the encoded text number in the first 2 chars; 3 is - // duration in seconds - - _vm->_screen->displayMsg(_vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text) + 2, 3); - _vm->_resman->closeResource(text_res); - - return IR_CONT; -} - -int32 Logic::fnSetObjectHeld(int32 *params) { - // params: 0 luggage icon to set - uint32 res = (uint32)params[0]; - - _vm->_mouse->setObjectHeld(res); - return IR_CONT; -} - -int32 Logic::fnAddSequenceText(int32 *params) { - // params: 0 text number - // 1 frame number to start the text displaying - // 2 frame number to stop the text dispalying - - assert(_sequenceTextLines < MAX_SEQUENCE_TEXT_LINES); - - _sequenceTextList[_sequenceTextLines].textNumber = params[0]; - _sequenceTextList[_sequenceTextLines].startFrame = params[1]; - _sequenceTextList[_sequenceTextLines].endFrame = params[2]; - _sequenceTextLines++; - return IR_CONT; -} - -int32 Logic::fnResetGlobals(int32 *params) { - // fnResetGlobals is used by the demo - so it can loop back & restart - // itself - - // params: none - - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - byte *globals = _vm->_resman->openResource(1) + ResHeader::size(); - int32 size = _vm->_resman->fetchLen(1) - ResHeader::size(); - - debug(5, "globals size: %d", size); - - // blank each global variable - memset(globals, 0, size); - - _vm->_resman->closeResource(1); - - // all objects but george - _vm->_resman->killAllObjects(false); - - // FOR THE DEMO - FORCE THE SCROLLING TO BE RESET! - // - this is taken from fnInitBackground - - // switch on scrolling (2 means first time on screen) - screenInfo->scroll_flag = 2; - - // Used to be IR_CONT, but that's a bad idea. We may just have killed - // our own script resource -- continuing will cause a bad memory read - // access. - return IR_STOP; -} - -int32 Logic::fnSetPalette(int32 *params) { - // params: 0 resource number of palette file, or 0 if it's to be - // the palette from the current screen - - _vm->_screen->setFullPalette(params[0]); - return IR_CONT; -} - -// use this in the object's service script prior to registering the mouse area -// ie. before fnRegisterMouse or fnRegisterFrame -// - best if kept at very top of service script - -int32 Logic::fnRegisterPointerText(int32 *params) { - // params: 0 local id of text line to use as pointer text - - _vm->_mouse->registerPointerText(params[0]); - return IR_CONT; -} - -int32 Logic::fnFetchWait(int32 *params) { - // Fetches a resource in the background but prevents the script from - // continuing until the resource is in memory. - - // params: 0 resource to fetch [guess] - - return IR_CONT; -} - -int32 Logic::fnRelease(int32 *params) { - // Releases a resource from memory. Used for freeing memory for - // sprites that have just been used and will not be used again. - // Sometimes it is better to kick out a sprite straight away so that - // the memory can be used for more frequent animations. - - // params: 0 resource to release [guess] - - return IR_CONT; -} - -int32 Logic::fnPrepareMusic(int32 *params) { - // params: 1 id of music to prepare [guess] - return IR_CONT; -} - -int32 Logic::fnSoundFetch(int32 *params) { - // params: 0 id of sound to fetch [guess] - return IR_CONT; -} - -int32 Logic::fnSmackerLeadIn(int32 *params) { - // params: 0 id of lead-in music - - // ready for use in fnPlaySequence - _smackerLeadIn = params[0]; - return IR_CONT; -} - -int32 Logic::fnSmackerLeadOut(int32 *params) { - // params: 0 id of lead-out music - - // ready for use in fnPlaySequence - _smackerLeadOut = params[0]; - return IR_CONT; -} - -/** - * Stops all FX and clears the entire FX queue. - */ - -int32 Logic::fnStopAllFx(int32 *params) { - // params: none - - _vm->_sound->clearFxQueue(); - return IR_CONT; -} - -int32 Logic::fnCheckPlayerActivity(int32 *params) { - // Used to decide when to trigger music cues described as "no player - // activity for a while" - - // params: 0 threshold delay in seconds, ie. what we want to - // check the actual delay against - - uint32 seconds = (uint32)params[0]; - - _vm->_mouse->checkPlayerActivity(seconds); - return IR_CONT; -} - -int32 Logic::fnResetPlayerActivityDelay(int32 *params) { - // Use if you want to deliberately reset the "no player activity" - // counter for any reason - - // params: none - - _vm->_mouse->resetPlayerActivityDelay(); - return IR_CONT; -} - -int32 Logic::fnCheckMusicPlaying(int32 *params) { - // params: none - - // sets result to no. of seconds of current tune remaining - // or 0 if no music playing - - // in seconds, rounded up to the nearest second - writeVar(RESULT, _vm->_sound->musicTimeRemaining()); - return IR_CONT; -} - -int32 Logic::fnPlayCredits(int32 *params) { - // This function just quits the game if this is the playable demo, ie. - // credits are NOT played in the demo any more! - - // params: none - - if (readVar(DEMO)) { - _vm->closeGame(); - return IR_STOP; - } - - _vm->_screen->rollCredits(); - return IR_CONT; -} - -int32 Logic::fnSetScrollSpeedNormal(int32 *params) { - // params: none - - _vm->_screen->setScrollFraction(16); - return IR_CONT; -} - -int32 Logic::fnSetScrollSpeedSlow(int32 *params) { - // params: none - - _vm->_screen->setScrollFraction(32); - return IR_CONT; -} - -// Called from speech scripts to remove the chooser bar when it's not -// appropriate to keep it displayed - -int32 Logic::fnRemoveChooser(int32 *params) { - // params: none - - _vm->_mouse->hideMenu(RDMENU_BOTTOM); - return IR_CONT; -} - -/** - * Alter the volume and pan of a currently playing FX - */ - -int32 Logic::fnSetFxVolAndPan(int32 *params) { - // params: 0 id of fx (ie. the id returned in 'result' from - // fnPlayFx - // 1 new volume (0..16) - // 2 new pan (-16..16) - - debug(5, "fnSetFxVolAndPan(%d, %d, %d)", params[0], params[1], params[2]); - - _vm->_sound->setFxIdVolumePan(params[0], params[1], params[2]); - return IR_CONT; -} - -/** - * Alter the volume of a currently playing FX - */ - -int32 Logic::fnSetFxVol(int32 *params) { - // params: 0 id of fx (ie. the id returned in 'result' from - // fnPlayFx - // 1 new volume (0..16) - - _vm->_sound->setFxIdVolumePan(params[0], params[1]); - return IR_CONT; -} - -int32 Logic::fnRestoreGame(int32 *params) { - // params: none - return IR_CONT; -} - -int32 Logic::fnRefreshInventory(int32 *params) { - // Called from 'menu_look_or_combine' script in 'menu_master' object - // to update the menu to display a combined object while George runs - // voice-over. Note that 'object_held' must be set to the graphic of - // the combined object - - // params: none - - _vm->_mouse->refreshInventory(); - return IR_CONT; -} - -int32 Logic::fnChangeShadows(int32 *params) { - // params: none - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - // if last screen was using a shading mask (see below) - if (screenInfo->mask_flag) { - uint32 rv = _vm->_screen->closeLightMask(); - if (rv) - error("Driver Error %.8x", rv); - screenInfo->mask_flag = false; - } - - return IR_CONT; -} - -} // End of namespace Sword2 diff --git a/sword2/header.h b/sword2/header.h deleted file mode 100644 index 9aefa52832..0000000000 --- a/sword2/header.h +++ /dev/null @@ -1,502 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef _HEADER -#define _HEADER - -#include "common/stream.h" - -namespace Sword2 { - -//---------------------------------------------------------- -// SYSTEM FILE & FRAME HEADERS -//---------------------------------------------------------- - -//---------------------------------------------------------- -// ALL FILES -//---------------------------------------------------------- - -// Standard File Header - -#define NAME_LEN 34 - -struct ResHeader { - uint8 fileType; // Byte to define file type (see below) - uint8 compType; // Type of file compression used ie. - // on whole file (see below) - uint32 compSize; // Length of compressed file (ie. - // length on disk) - uint32 decompSize; // Length of decompressed file held in - // memory (NB. frames still held - // compressed) - byte name[NAME_LEN]; // Name of object - - static const int size() { - return 44; - } - - void read(byte *addr) { - Common::MemoryReadStream readS(addr, size()); - - fileType = readS.readByte(); - compType = readS.readByte(); - compSize = readS.readUint32LE(); - decompSize = readS.readUint32LE(); - readS.read(name, NAME_LEN); - } - - void write(byte *addr) { - Common::MemoryWriteStream writeS(addr, size()); - - writeS.writeByte(fileType); - writeS.writeByte(compType); - writeS.writeUint32LE(compSize); - writeS.writeUint32LE(decompSize); - writeS.write(name, NAME_LEN); - } -}; - -// fileType - -enum { - // 0 something's wrong! - ANIMATION_FILE = 1, // All normal animations & sprites - // including mega-sets & font files - // which are the same format (but all - // frames always uncompressed) - SCREEN_FILE = 2, // Each contains background, palette, - // layer sprites, parallax layers & - // shading mask - GAME_OBJECT = 3, // Each contains object hub + - // structures + script data - WALK_GRID_FILE = 4, // Walk-grid data - GLOBAL_VAR_FILE = 5, // All the global script variables in - // one file; "there can be only one" - PARALLAX_FILE_null = 6, // NOT USED - RUN_LIST = 7, // Each contains a list of object - // resource id's - TEXT_FILE = 8, // Each contains all the lines of text - // for a location or a character's - // conversation script - SCREEN_MANAGER = 9, // One for each location; this contains - // special startup scripts - MOUSE_FILE = 10, // Mouse pointers and luggage icons - // (sprites in General / Mouse pointers - // & Luggage icons) - WAV_FILE = 11, // WAV file - ICON_FILE = 12, // Menu icon (sprites in General / Menu - // icons) - PALETTE_FILE = 13 // separate palette file (see also - // _paletteHeader) -}; - -// compType - -enum { - NO_COMPRESSION = 0, - FILE_COMPRESSION = 1 // standard whole-file compression - // (not yet devised!) -}; - -//---------------------------------------------------------- -// (1) ANIMATION FILES -//---------------------------------------------------------- - -// an animation file consists of: -// -// standard file header -// animation header -// a string of CDT entries (one per frame of the anim) -// a 16-byte colour table ONLY if (runTimeComp==RLE16) -// a string of groups of (frame header + frame data) - -// Animation Header - -struct AnimHeader { - uint8 runTimeComp; // Type of runtime compression used for the - // frame data (see below) - uint16 noAnimFrames; // Number of frames in the anim (ie. no. of - // CDT entries) - uint16 feetStartX; // Start coords for mega to walk to, before - uint16 feetStartY; // running anim - uint8 feetStartDir; // Direction to start in before running anim - uint16 feetEndX; // End coords for mega to stand at after - uint16 feetEndY; // running anim (vital if anim starts from an - // off-screen position, or ends in a different - // place from the start) - uint8 feetEndDir; // Direction to start in after running anim - uint16 blend; - - static const int size() { - return 15; - } - - void read(byte *addr) { - Common::MemoryReadStream readS(addr, size()); - - runTimeComp = readS.readByte(); - noAnimFrames = readS.readUint16LE(); - feetStartX = readS.readUint16LE(); - feetStartY = readS.readUint16LE(); - feetStartDir = readS.readByte(); - feetEndX = readS.readUint16LE(); - feetEndY = readS.readUint16LE(); - feetEndDir = readS.readByte(); - blend = readS.readUint16LE(); - } - - void write(byte *addr) { - Common::MemoryWriteStream writeS(addr, size()); - - writeS.writeByte(runTimeComp); - writeS.writeUint16LE(noAnimFrames); - writeS.writeUint16LE(feetStartX); - writeS.writeUint16LE(feetStartY); - writeS.writeByte(feetStartDir); - writeS.writeUint16LE(feetEndX); - writeS.writeUint16LE(feetEndY); - writeS.writeByte(feetEndDir); - writeS.writeUint16LE(blend); - } - -}; - -// runtimeComp - compression used on each frame of the anim - -enum { - NONE = 0, // No frame compression - RLE256 = 1, // James's RLE for 256-colour sprites - RLE16 = 2 // James's RLE for 16- or 17-colour sprites - // (raw blocks have max 16 colours for 2 pixels - // per byte, so '0's are encoded only as FLAT - // for 17-colour sprites eg. George's mega-set) -}; - -// CDT Entry - -struct CdtEntry { - int16 x; // sprite x-coord OR offset to add to mega's - // feet x-coord to calc sprite y-coord - int16 y; // sprite y-coord OR offset to add to mega's - // feet y-coord to calc sprite y-coord - uint32 frameOffset; // points to start of frame header (from start - // of file header) - uint8 frameType; // 0 = print sprite normally with top-left - // corner at (x,y), otherwise see below... - - static const int size() { - return 9; - } - - void read(byte *addr) { - Common::MemoryReadStream readS(addr, size()); - - x = readS.readUint16LE(); - y = readS.readUint16LE(); - frameOffset = readS.readUint32LE(); - frameType = readS.readByte(); - } - - void write(byte *addr) { - Common::MemoryWriteStream writeS(addr, size()); - - writeS.writeUint16LE(x); - writeS.writeUint16LE(y); - writeS.writeUint32LE(frameOffset); - writeS.writeByte(frameType); - } -}; - -// 'frameType' bit values - -enum { - FRAME_OFFSET = 1, // Print at (feetX + x, feetY + y), with - // scaling according to feetY - FRAME_FLIPPED = 2, // Print the frame flipped Left->Right - FRAME_256_FAST = 4 // Frame has been compressed using Pauls fast - // RLE 256 compression. -}; - -// Frame Header - -struct FrameHeader { - uint32 compSize; // Compressed size of frame - NB. compression - // type is now in Anim Header - uint16 width; // Dimensions of frame - uint16 height; - - static const int size() { - return 8; - } - - void read(byte *addr) { - Common::MemoryReadStream readS(addr, size()); - - compSize = readS.readUint32LE(); - width = readS.readUint16LE(); - height = readS.readUint16LE(); - } - - void write(byte *addr) { - Common::MemoryWriteStream writeS(addr, size()); - - writeS.writeUint32LE(compSize); - writeS.writeUint16LE(width); - writeS.writeUint16LE(height); - } -}; - -//---------------------------------------------------------- -// (2) SCREEN FILES -//---------------------------------------------------------- -// a screen file consists of: -// -// standard file header -// multi screen header -// 4 * 256 bytes of palette data -// 256k palette match table -// 2 background parallax layers -// 1 background layer with screen header -// 2 foreground parallax layers -// a string of layer headers -// a string of layer masks - -// Multi screen header -// Goes at the beginning of a screen file after the standard header. -// Gives offsets from start of table of each of the components - -struct MultiScreenHeader { - uint32 palette; - uint32 bg_parallax[2]; - uint32 screen; - uint32 fg_parallax[2]; - uint32 layers; - uint32 paletteTable; - uint32 maskOffset; - - static const int size() { - return 36; - } - - void read(byte *addr) { - Common::MemoryReadStream readS(addr, size()); - - palette = readS.readUint32LE(); - bg_parallax[0] = readS.readUint32LE(); - bg_parallax[1] = readS.readUint32LE(); - screen = readS.readUint32LE(); - fg_parallax[0] = readS.readUint32LE(); - fg_parallax[1] = readS.readUint32LE(); - layers = readS.readUint32LE(); - paletteTable = readS.readUint32LE(); - maskOffset = readS.readUint32LE(); - } - - void write(byte *addr) { - Common::MemoryWriteStream writeS(addr, size()); - - writeS.writeUint32LE(palette); - writeS.writeUint32LE(bg_parallax[0]); - writeS.writeUint32LE(bg_parallax[1]); - writeS.writeUint32LE(screen); - writeS.writeUint32LE(fg_parallax[0]); - writeS.writeUint32LE(fg_parallax[1]); - writeS.writeUint32LE(layers); - writeS.writeUint32LE(paletteTable); - writeS.writeUint32LE(maskOffset); - } -}; - -// Screen Header - -struct ScreenHeader { - uint16 width; // dimensions of the background screen - uint16 height; - uint16 noLayers; // number of layer areas - - static const int size() { - return 6; - } - - void read(byte *addr) { - Common::MemoryReadStream readS(addr, size()); - - width = readS.readUint16LE(); - height = readS.readUint16LE(); - noLayers = readS.readUint16LE(); - } - - void write(byte *addr) { - Common::MemoryWriteStream writeS(addr, size()); - - writeS.writeUint16LE(width); - writeS.writeUint16LE(height); - writeS.writeUint16LE(noLayers); - } -}; - -// Layer Header - -// Note that all the layer headers are kept together, rather than being placed -// before each layer mask, in order to simplify the sort routine. - -struct LayerHeader { - uint16 x; // coordinates of top-left pixel of area - uint16 y; - uint16 width; - uint16 height; - uint32 maskSize; - uint32 offset; // where to find mask data (from start of - // standard file header) - - static const int size() { - return 16; - } - - void read(byte *addr) { - Common::MemoryReadStream readS(addr, size()); - - x = readS.readUint16LE(); - y = readS.readUint16LE(); - width = readS.readUint16LE(); - height = readS.readUint16LE(); - maskSize = readS.readUint32LE(); - offset = readS.readUint32LE(); - } - - void write(byte *addr) { - Common::MemoryWriteStream writeS(addr, size()); - - writeS.writeUint16LE(x); - writeS.writeUint16LE(y); - writeS.writeUint16LE(width); - writeS.writeUint16LE(height); - writeS.writeUint32LE(maskSize); - writeS.writeUint32LE(offset); - } -}; - -//---------------------------------------------------------- -// (3) SCRIPT OBJECT FILES -//---------------------------------------------------------- -// a script object file consists of: -// -// standard file header -// script object header -// script object data - -//---------------------------------------------------------- -// (5) PALETTE FILES -//---------------------------------------------------------- -// a palette file consists of: -// -// standard file header -// 4 * 256 bytes of palette data -// 256k palette match table - -// an object hub - which represents all that remains of the compact concept - -class ObjectHub { - // int32 type; // type of object - // uint32 logic_level; // what level? - // uint32 logic[3] // NOT USED - // uint32 script_id[3] // need this if script - // uint32 script_pc[3] // need this also - -private: - byte *_addr; - -public: - ObjectHub() { - _addr = NULL; - } - - static const int size() { - return 44; - } - - byte *data() { - return _addr; - } - - void setAddress(byte *addr) { - _addr = addr; - } - - byte *getScriptPcPtr(int level) { - return _addr + 32 + 4 * level; - } - - uint32 getLogicLevel() { - return READ_LE_UINT32(_addr + 4); - } - uint32 getScriptId(int level) { - return READ_LE_UINT32(_addr + 20 + 4 * level); - } - uint32 getScriptPc(int level) { - return READ_LE_UINT32(_addr + 32 + 4 * level); - } - - void setLogicLevel(uint32 x) { - WRITE_LE_UINT32(_addr + 4, x); - } - void setScriptId(int level, uint32 x) { - WRITE_LE_UINT32(_addr + 20 + 4 * level, x); - } - void setScriptPc(int level, uint32 x) { - WRITE_LE_UINT32(_addr + 32 + 4 * level, x); - } -}; - -// (6) text module header - -struct TextHeader { - uint32 noOfLines; // how many lines of text are there in this - // module - - static const int size() { - return 4; - } - - void read(byte *addr) { - Common::MemoryReadStream readS(addr, size()); - - noOfLines = readS.readUint32LE(); - } - - void write(byte *addr) { - Common::MemoryWriteStream writeS(addr, size()); - - writeS.writeUint32LE(noOfLines); - } -}; - -// a text file has: -// -// ResHeader -// TextHeader -// look up table, to -// line of text,0 -// line of text,0 - -} // End of namespace Sword2 - -#endif diff --git a/sword2/icons.cpp b/sword2/icons.cpp deleted file mode 100644 index 980c20e3b4..0000000000 --- a/sword2/icons.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "common/stream.h" -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/mouse.h" -#include "sword2/resman.h" - -namespace Sword2 { - -void Mouse::addMenuObject(byte *ptr) { - assert(_totalTemp < TOTAL_engine_pockets); - - Common::MemoryReadStream readS(ptr, 2 * sizeof(int32)); - - _tempList[_totalTemp].icon_resource = readS.readSint32LE(); - _tempList[_totalTemp].luggage_resource = readS.readSint32LE(); - _totalTemp++; -} - -void Mouse::addSubject(int32 id, int32 ref) { - uint32 in_subject = _vm->_logic->readVar(IN_SUBJECT); - - if (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[in_subject].res = id; - _subjectList[in_subject].ref = ref; - _vm->_logic->writeVar(IN_SUBJECT, in_subject + 1); - } -} - -/** - * Create and start the inventory (bottom) menu - */ - -void Mouse::buildMenu() { - uint32 i, j; - - // Clear the temporary inventory list, since we are going to build a - // new one from scratch. - - for (i = 0; i < TOTAL_engine_pockets; i++) - _tempList[i].icon_resource = 0; - - _totalTemp = 0; - - // Run the 'build_menu' script in the 'menu_master' object. This will - // register all carried menu objects. - - _vm->_logic->runResScript(MENU_MASTER_OBJECT, 0); - - // Create a new master list based on the old master inventory list and - // the new temporary inventory list. The purpose of all this is, as - // far as I can tell, that the new list is ordered in the same way as - // the old list, with new objects added to the end of it. - - // Compare new with old. Anything in master thats not in new gets - // removed from master - if found in new too, remove from temp - - for (i = 0; i < _totalMasters; i++) { - bool found_in_temp = false; - - for (j = 0; j < TOTAL_engine_pockets; j++) { - if (_masterMenuList[i].icon_resource == _tempList[j].icon_resource) { - // We alread know about this object, so kill it - // in the temporary list. - _tempList[j].icon_resource = 0; - found_in_temp = true; - break; - } - } - - if (!found_in_temp) { - // The object is in the master list, but not in the - // temporary list. The player must have lost the object - // since the last time we checked, so kill it in the - // master list. - _masterMenuList[i].icon_resource = 0; - } - } - - // Eliminate blank entries from the master list. - - _totalMasters = 0; - - for (i = 0; i < TOTAL_engine_pockets; i++) { - if (_masterMenuList[i].icon_resource) { - if (i != _totalMasters) { - memcpy(&_masterMenuList[_totalMasters], &_masterMenuList[i], sizeof(MenuObject)); - _masterMenuList[i].icon_resource = 0; - } - _totalMasters++; - } - } - - // Add the new objects - i.e. the ones still in the temporary list but - // not yet in the master list - to the end of the master. - - for (i = 0; i < TOTAL_engine_pockets; i++) { - if (_tempList[i].icon_resource) { - memcpy(&_masterMenuList[_totalMasters++], &_tempList[i], sizeof(MenuObject)); - } - } - - // Initialise the menu from the master list. - - for (i = 0; i < 15; i++) { - uint32 res = _masterMenuList[i].icon_resource; - byte *icon = NULL; - - if (res) { - bool icon_coloured; - - uint32 object_held = _vm->_logic->readVar(OBJECT_HELD); - uint32 combine_base = _vm->_logic->readVar(COMBINE_BASE); - - if (_examiningMenuIcon) { - // When examining an object, that object is - // coloured. The rest are greyed out. - icon_coloured = (res == object_held); - } else if (combine_base) { - // When combining two menu object (i.e. using - // one on another), both are coloured. The rest - // are greyed out. - icon_coloured = (res == object_held || combine_base); - } else { - // If an object is selected but we are not yet - // doing anything with it, the selected object - // is greyed out. The rest are coloured. - icon_coloured = (res != object_held); - } - - icon = _vm->_resman->openResource(res) + ResHeader::size(); - - // The coloured icon is stored directly after the - // greyed out one. - - if (icon_coloured) - icon += (RDMENU_ICONWIDE * RDMENU_ICONDEEP); - } - - setMenuIcon(RDMENU_BOTTOM, i, icon); - - if (res) - _vm->_resman->closeResource(res); - } - - showMenu(RDMENU_BOTTOM); -} - -/** - * Build a fresh system (top) menu. - */ - -void Mouse::buildSystemMenu() { - uint32 icon_list[5] = { - OPTIONS_ICON, - QUIT_ICON, - SAVE_ICON, - RESTORE_ICON, - RESTART_ICON - }; - - // Build them all high in full colour - when one is clicked on all the - // rest will grey out. - - for (int i = 0; i < ARRAYSIZE(icon_list); i++) { - byte *icon = _vm->_resman->openResource(icon_list[i]) + ResHeader::size(); - - // The only case when an icon is grayed is when the player - // is dead. Then SAVE is not available. - - if (!_vm->_logic->readVar(DEAD) || icon_list[i] != SAVE_ICON) - icon += (RDMENU_ICONWIDE * RDMENU_ICONDEEP); - - setMenuIcon(RDMENU_TOP, i, icon); - _vm->_resman->closeResource(icon_list[i]); - } - - showMenu(RDMENU_TOP); -} - -} // End of namespace Sword2 diff --git a/sword2/icons.h b/sword2/icons.h deleted file mode 100644 index ab5ea578ca..0000000000 --- a/sword2/icons.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef _ICONS -#define _ICONS - -#define MENU_MASTER_OBJECT 44 -#define TOTAL_subjects (375 - 256 + 1) // the speech subject bar -#define TOTAL_engine_pockets (15 + 10) // +10 for overflow - -namespace Sword2 { - -// define these in a script and then register them with the system - -struct MenuObject { - int32 icon_resource; // icon graphic graphic - int32 luggage_resource; // luggage icon resource (for attaching to - // mouse pointer) -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/interpreter.cpp b/sword2/interpreter.cpp deleted file mode 100644 index 1a6e7080b8..0000000000 --- a/sword2/interpreter.cpp +++ /dev/null @@ -1,753 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "common/util.h" -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/interpreter.h" -#include "sword2/logic.h" -#include "sword2/memory.h" -#include "sword2/resman.h" - -namespace Sword2 { - -#define STACK_SIZE 10 - -// The machine code table - -#ifndef REDUCE_MEMORY_USAGE -# define OPCODE(x) { &Logic::x, #x } -#else -# define OPCODE(x) { &Logic::x, "" } -#endif - -typedef int32 (Logic::*OpcodeProc)(int32 *); -struct OpcodeEntry { - OpcodeProc proc; - const char *desc; -}; - -static const OpcodeEntry opcodes[] = { - /* 00 */ - OPCODE(fnTestFunction), - OPCODE(fnTestFlags), - OPCODE(fnRegisterStartPoint), - OPCODE(fnInitBackground), - /* 04 */ - OPCODE(fnSetSession), - OPCODE(fnBackSprite), - OPCODE(fnSortSprite), - OPCODE(fnForeSprite), - /* 08 */ - OPCODE(fnRegisterMouse), - OPCODE(fnAnim), - OPCODE(fnRandom), - OPCODE(fnPreLoad), - /* 0C */ - OPCODE(fnAddSubject), - OPCODE(fnInteract), - OPCODE(fnChoose), - OPCODE(fnWalk), - /* 10 */ - OPCODE(fnWalkToAnim), - OPCODE(fnTurn), - OPCODE(fnStandAt), - OPCODE(fnStand), - /* 14 */ - OPCODE(fnStandAfterAnim), - OPCODE(fnPause), - OPCODE(fnMegaTableAnim), - OPCODE(fnAddMenuObject), - /* 18 */ - OPCODE(fnStartConversation), - OPCODE(fnEndConversation), - OPCODE(fnSetFrame), - OPCODE(fnRandomPause), - /* 1C */ - OPCODE(fnRegisterFrame), - OPCODE(fnNoSprite), - OPCODE(fnSendSync), - OPCODE(fnUpdatePlayerStats), - /* 20 */ - OPCODE(fnPassGraph), - OPCODE(fnInitFloorMouse), - OPCODE(fnPassMega), - OPCODE(fnFaceXY), - /* 24 */ - OPCODE(fnEndSession), - OPCODE(fnNoHuman), - OPCODE(fnAddHuman), - OPCODE(fnWeWait), - /* 28 */ - OPCODE(fnTheyDoWeWait), - OPCODE(fnTheyDo), - OPCODE(fnWalkToTalkToMega), - OPCODE(fnFadeDown), - /* 2C */ - OPCODE(fnISpeak), - OPCODE(fnTotalRestart), - OPCODE(fnSetWalkGrid), - OPCODE(fnSpeechProcess), - /* 30 */ - OPCODE(fnSetScaling), - OPCODE(fnStartEvent), - OPCODE(fnCheckEventWaiting), - OPCODE(fnRequestSpeech), - /* 34 */ - OPCODE(fnGosub), - OPCODE(fnTimedWait), - OPCODE(fnPlayFx), - OPCODE(fnStopFx), - /* 38 */ - OPCODE(fnPlayMusic), - OPCODE(fnStopMusic), - OPCODE(fnSetValue), - OPCODE(fnNewScript), - /* 3C */ - OPCODE(fnGetSync), - OPCODE(fnWaitSync), - OPCODE(fnRegisterWalkGrid), - OPCODE(fnReverseMegaTableAnim), - /* 40 */ - OPCODE(fnReverseAnim), - OPCODE(fnAddToKillList), - OPCODE(fnSetStandbyCoords), - OPCODE(fnBackPar0Sprite), - /* 44 */ - OPCODE(fnBackPar1Sprite), - OPCODE(fnForePar0Sprite), - OPCODE(fnForePar1Sprite), - OPCODE(fnSetPlayerActionEvent), - /* 48 */ - OPCODE(fnSetScrollCoordinate), - OPCODE(fnStandAtAnim), - OPCODE(fnSetScrollLeftMouse), - OPCODE(fnSetScrollRightMouse), - /* 4C */ - OPCODE(fnColour), - OPCODE(fnFlash), - OPCODE(fnPreFetch), - OPCODE(fnGetPlayerSaveData), - /* 50 */ - OPCODE(fnPassPlayerSaveData), - OPCODE(fnSendEvent), - OPCODE(fnAddWalkGrid), - OPCODE(fnRemoveWalkGrid), - /* 54 */ - OPCODE(fnCheckForEvent), - OPCODE(fnPauseForEvent), - OPCODE(fnClearEvent), - OPCODE(fnFaceMega), - /* 58 */ - OPCODE(fnPlaySequence), - OPCODE(fnShadedSprite), - OPCODE(fnUnshadedSprite), - OPCODE(fnFadeUp), - /* 5C */ - OPCODE(fnDisplayMsg), - OPCODE(fnSetObjectHeld), - OPCODE(fnAddSequenceText), - OPCODE(fnResetGlobals), - /* 60 */ - OPCODE(fnSetPalette), - OPCODE(fnRegisterPointerText), - OPCODE(fnFetchWait), - OPCODE(fnRelease), - /* 64 */ - OPCODE(fnPrepareMusic), - OPCODE(fnSoundFetch), - OPCODE(fnPrepareMusic), // Again, apparently - OPCODE(fnSmackerLeadIn), - /* 68 */ - OPCODE(fnSmackerLeadOut), - OPCODE(fnStopAllFx), - OPCODE(fnCheckPlayerActivity), - OPCODE(fnResetPlayerActivityDelay), - /* 6C */ - OPCODE(fnCheckMusicPlaying), - OPCODE(fnPlayCredits), - OPCODE(fnSetScrollSpeedNormal), - OPCODE(fnSetScrollSpeedSlow), - /* 70 */ - OPCODE(fnRemoveChooser), - OPCODE(fnSetFxVolAndPan), - OPCODE(fnSetFxVol), - OPCODE(fnRestoreGame), - /* 74 */ - OPCODE(fnRefreshInventory), - OPCODE(fnChangeShadows) -}; - -#define push(value) \ -do { \ - assert(stackPtr < ARRAYSIZE(stack)); \ - stack[stackPtr++] = (value); \ -} while (false) - -#define push_ptr(ptr) push(_vm->_memory->encodePtr(ptr)) - -#define pop() (assert(stackPtr < ARRAYSIZE(stack)), stack[--stackPtr]) - -int Logic::runResScript(uint32 scriptRes, uint32 offset) { - byte *scriptAddr; - int result; - - scriptAddr = _vm->_resman->openResource(scriptRes); - result = runScript(scriptAddr, scriptAddr, offset); - _vm->_resman->closeResource(scriptRes); - - return result; -} - -int Logic::runResObjScript(uint32 scriptRes, uint32 objRes, uint32 offset) { - byte *scriptAddr, *objAddr; - int result; - - scriptAddr = _vm->_resman->openResource(scriptRes); - objAddr = _vm->_resman->openResource(objRes); - result = runScript(scriptAddr, objAddr, offset); - _vm->_resman->closeResource(objRes); - _vm->_resman->closeResource(scriptRes); - - return result; -} - -int Logic::runScript(byte *scriptData, byte *objectData, uint32 offset) { - byte pc[4]; - - WRITE_LE_UINT32(pc, offset); - return runScript2(scriptData, objectData, pc); -} - -// This form of the runScript function is only called directly from -// the processSession() function, which uses it to update the script PC in the -// current object hub. For reasons which I do not understand, I couldn't get it -// to work if I called the function first with a dummy offset variable, and -// and then updated the object hub myself. - -int Logic::runScript2(byte *scriptData, byte *objectData, byte *offsetPtr) { - // Interestingly, unlike our BASS engine the stack is a local variable. - // I don't know whether or not this is relevant to the working of the - // BS2 engine. - - int32 stack[STACK_SIZE]; - int32 stackPtr = 0; - - uint32 offset = READ_LE_UINT32(offsetPtr); - - ResHeader header; - - header.read(scriptData); - - scriptData += ResHeader::size() + ObjectHub::size(); - - // The script data format: - // int32_TYPE 1 Size of variable space in bytes - // ... The variable space - // int32_TYPE 1 numberOfScripts - // int32_TYPE numberOfScripts The offsets for each script - - // Initialise some stuff - - uint32 ip = 0; // Code pointer - int scriptNumber; - - // Get the start of variables and start of code - - byte *localVars = scriptData + 4; - byte *code = scriptData + READ_LE_UINT32(scriptData) + 4; - uint32 noScripts = READ_LE_UINT32(code); - - code += 4; - - byte *offsetTable = code; - - if (offset < noScripts) { - ip = READ_LE_UINT32(offsetTable + offset * 4); - scriptNumber = offset; - debug(8, "Starting script %d from %d", scriptNumber, ip); - } else { - uint i; - - ip = offset; - - for (i = 1; i < noScripts; i++) { - if (READ_LE_UINT32(offsetTable + 4 * i) >= ip) - break; - } - - scriptNumber = i - 1; - debug(8, "Resuming script %d from %d", scriptNumber, ip); - } - - // There are a couple of known script bugs related to interacting with - // certain objects. We try to work around a few of them. - - bool checkMopBug = false; - bool checkPyramidBug = false; - bool checkElevatorBug = false; - - if (scriptNumber == 2) { - if (strcmp((char *)header.name, "mop_73") == 0) - checkMopBug = true; - else if (strcmp((char *)header.name, "titipoco_81") == 0) - checkPyramidBug = true; - else if (strcmp((char *)header.name, "lift_82") == 0) - checkElevatorBug = true; - } - - code += noScripts * 4; - - // Code should now be pointing at an identifier and a checksum - byte *checksumBlock = code; - - code += 4 * 3; - - if (READ_LE_UINT32(checksumBlock) != 12345678) { - error("Invalid script in object %s", header.name); - return 0; - } - - int32 codeLen = READ_LE_UINT32(checksumBlock + 4); - int32 checksum = 0; - - for (int i = 0; i < codeLen; i++) - checksum += (unsigned char) code[i]; - - if (checksum != (int32)READ_LE_UINT32(checksumBlock + 8)) { - debug(1, "Checksum error in object %s", header.name); - // This could be bad, but there has been a report about someone - // who had problems running the German version because of - // checksum errors. Could there be a version where checksums - // weren't properly calculated? - } - - bool runningScript = true; - - int parameterReturnedFromMcodeFunction = 0; // Allow scripts to return things - int savedStartOfMcode = 0; // For saving start of mcode commands - - while (runningScript) { - int i; - int32 a, b; - int curCommand, parameter, value; // Command and parameter variables - int retVal; - int caseCount; - bool foundCase; - byte *ptr; - - curCommand = code[ip++]; - - switch (curCommand) { - - // Script-related opcodes - - case CP_END_SCRIPT: - // End the script - runningScript = false; - - // WORKAROUND: The dreaded pyramid bug makes the torch - // untakeable when you speak to Titipoco. This is - // because one of the conditions for the torch to be - // takeable is that Titipoco isn't doing anything out - // of the ordinary. Global variable 913 has to be 0 to - // signify that he is in his "idle" state. - // - // Unfortunately, simply the act of speaking to him - // sets variable 913 to 1 (probably to stop him from - // turning around every now and then). The script may - // then go on to set the variable to different values - // to trigger various behaviours in him, but if you - // have run out of these cases the script won't ever - // set it back to 0 again. - // - // So if his click hander finishes, and variable 913 is - // 1, we set it back to 0 manually. - - if (checkPyramidBug && readVar(913) == 1) { - warning("Working around pyramid bug: Resetting Titipoco's state"); - writeVar(913, 0); - } - - // WORKAROUND: The not-so-known-but-should-be-dreaded - // elevator bug. - // - // The click handler for the top of the elevator only - // handles using the elevator, not examining it. When - // examining it, the mouse cursor is removed but never - // restored. - - if (checkElevatorBug && readVar(RIGHT_BUTTON)) { - warning("Working around elevator bug: Restoring mouse pointer"); - fnAddHuman(NULL); - } - - debug(9, "CP_END_SCRIPT"); - break; - case CP_QUIT: - // Quit out for a cycle - WRITE_LE_UINT32(offsetPtr, ip); - debug(9, "CP_QUIT"); - return 0; - case CP_TERMINATE: - // Quit out immediately without affecting the offset - // pointer - debug(9, "CP_TERMINATE"); - return 3; - case CP_RESTART_SCRIPT: - // Start the script again - ip = FROM_LE_32(offsetTable[scriptNumber]); - debug(9, "CP_RESTART_SCRIPT"); - break; - - // Stack-related opcodes - - case CP_PUSH_INT32: - // Push a long word value on to the stack - Read32ip(parameter); - push(parameter); - debug(9, "CP_PUSH_INT32: %d", parameter); - break; - case CP_PUSH_LOCAL_VAR32: - // Push the contents of a local variable - Read16ip(parameter); - push(READ_LE_UINT32(localVars + parameter)); - debug(9, "CP_PUSH_LOCAL_VAR32: localVars[%d] => %d", parameter / 4, READ_LE_UINT32(localVars + parameter)); - break; - case CP_PUSH_GLOBAL_VAR32: - // Push a global variable - Read16ip(parameter); - push(readVar(parameter)); - debug(9, "CP_PUSH_GLOBAL_VAR32: scriptVars[%d] => %d", parameter, readVar(parameter)); - break; - case CP_PUSH_LOCAL_ADDR: - // Push the address of a local variable - - // From what I understand, some scripts store data - // (e.g. mouse pointers) in their local variable space - // from the very beginning, and use this mechanism to - // pass that data to the opcode function. I don't yet - // know the conceptual difference between this and the - // CP_PUSH_DEREFERENCED_STRUCTURE opcode. - - Read16ip(parameter); - push_ptr(localVars + parameter); - debug(9, "CP_PUSH_LOCAL_ADDR: &localVars[%d] => %p", parameter / 4, localVars + parameter); - break; - case CP_PUSH_STRING: - // Push the address of a string on to the stack - // Get the string size - Read8ip(parameter); - - // ip now points to the string - ptr = code + ip; - push_ptr(ptr); - debug(9, "CP_PUSH_STRING: \"%s\"", ptr); - ip += (parameter + 1); - break; - case CP_PUSH_DEREFERENCED_STRUCTURE: - // Push the address of a dereferenced structure - Read32ip(parameter); - ptr = objectData + 4 + ResHeader::size() + ObjectHub::size() + parameter; - push_ptr(ptr); - debug(9, "CP_PUSH_DEREFERENCED_STRUCTURE: %d => %p", parameter, ptr); - break; - case CP_POP_LOCAL_VAR32: - // Pop a value into a local word variable - Read16ip(parameter); - value = pop(); - WRITE_LE_UINT32(localVars + parameter, value); - debug(9, "CP_POP_LOCAL_VAR32: localVars[%d] = %d", parameter / 4, value); - break; - case CP_POP_GLOBAL_VAR32: - // Pop a global variable - Read16ip(parameter); - value = pop(); - - // WORKAROUND for bug #1214168: The not-at-all dreaded - // mop bug. - // - // At the London Docks, global variable 1003 keeps - // track of Nico: - // - // 0: Hiding behind the first crate. - // 1: Hiding behind the second crate. - // 2: Standing in plain view on the deck. - // 3: Hiding on the roof. - // - // The bug happens when trying to pick up the mop while - // hiding on the roof. Nico climbs down, the mop is - // picked up, but the variable remains set to 3. - // Visually, everything looks ok. But as far as the - // scripts are concerned, she's still hiding up on the - // roof. This is not fatal, but leads to a number of - // glitches until the state is corrected. E.g. trying - // to climb back up the ladder will cause Nico to climb - // down again. - // - // Global variable 1017 keeps track of the mop. Setting - // it to 2 means that the mop has been picked up. We - // use that as the signal that Nico's state needs to be - // updated as well. - - if (checkMopBug && parameter == 1017 && readVar(1003) != 2) { - warning("Working around mop bug: Setting Nico's state"); - writeVar(1003, 2); - } - - writeVar(parameter, value); - debug(9, "CP_POP_GLOBAL_VAR32: scriptsVars[%d] = %d", parameter, value); - break; - case CP_ADDNPOP_LOCAL_VAR32: - Read16ip(parameter); - value = READ_LE_UINT32(localVars + parameter) + pop(); - WRITE_LE_UINT32(localVars + parameter, value); - debug(9, "CP_ADDNPOP_LOCAL_VAR32: localVars[%d] => %d", parameter / 4, value); - break; - case CP_SUBNPOP_LOCAL_VAR32: - Read16ip(parameter); - value = READ_LE_UINT32(localVars + parameter) - pop(); - WRITE_LE_UINT32(localVars + parameter, value); - debug(9, "CP_SUBNPOP_LOCAL_VAR32: localVars[%d] => %d", parameter / 4, value); - break; - case CP_ADDNPOP_GLOBAL_VAR32: - // Add and pop a global variable - Read16ip(parameter); - value = readVar(parameter) + pop(); - writeVar(parameter, value); - debug(9, "CP_ADDNPOP_GLOBAL_VAR32: scriptVars[%d] => %d", parameter, value); - break; - case CP_SUBNPOP_GLOBAL_VAR32: - // Sub and pop a global variable - Read16ip(parameter); - value = readVar(parameter) - pop(); - writeVar(parameter, value); - debug(9, "CP_SUBNPOP_GLOBAL_VAR32: scriptVars[%d] => %d", parameter, value); - break; - - // Jump opcodes - - case CP_SKIPONTRUE: - // Skip if the value on the stack is true - Read32ipLeaveip(parameter); - value = pop(); - if (!value) { - ip += 4; - debug(9, "CP_SKIPONTRUE: %d (IS FALSE (NOT SKIPPED))", parameter); - } else { - ip += parameter; - debug(9, "CP_SKIPONTRUE: %d (IS TRUE (SKIPPED))", parameter); - } - break; - case CP_SKIPONFALSE: - // Skip if the value on the stack is false - Read32ipLeaveip(parameter); - value = pop(); - if (value) { - ip += 4; - debug(9, "CP_SKIPONFALSE: %d (IS TRUE (NOT SKIPPED))", parameter); - } else { - ip += parameter; - debug(9, "CP_SKIPONFALSE: %d (IS FALSE (SKIPPED))", parameter); - } - break; - case CP_SKIPALWAYS: - // skip a block - Read32ipLeaveip(parameter); - ip += parameter; - debug(9, "CP_SKIPALWAYS: %d", parameter); - break; - case CP_SWITCH: - // switch - value = pop(); - Read32ip(caseCount); - - // Search the cases - foundCase = false; - for (i = 0; i < caseCount && !foundCase; i++) { - if (value == (int32)READ_LE_UINT32(code + ip)) { - // We have found the case, so lets - // jump to it - foundCase = true; - ip += READ_LE_UINT32(code + ip + 4); - } else - ip += 4 * 2; - } - - // If we found no matching case then use the default - - if (!foundCase) - ip += READ_LE_UINT32(code + ip); - - debug(9, "CP_SWITCH: [SORRY, NO DEBUG INFO]"); - break; - case CP_SAVE_MCODE_START: - // Save the start position on an mcode instruction in - // case we need to restart it again - savedStartOfMcode = ip - 1; - debug(9, "CP_SAVE_MCODE_START"); - break; - case CP_CALL_MCODE: - // Call an mcode routine - Read16ip(parameter); - assert(parameter < ARRAYSIZE(opcodes)); - // amount to adjust stack by (no of parameters) - Read8ip(value); - debug(9, "CP_CALL_MCODE: '%s', %d", opcodes[parameter].desc, value); - stackPtr -= value; - assert(stackPtr >= 0); - retVal = (this->*opcodes[parameter].proc)(&stack[stackPtr]); - - switch (retVal & 7) { - case IR_STOP: - // Quit out for a cycle - WRITE_LE_UINT32(offsetPtr, ip); - return 0; - case IR_CONT: - // Continue as normal - break; - case IR_TERMINATE: - // Return without updating the offset - return 2; - case IR_REPEAT: - // Return setting offset to start of this - // function call - WRITE_LE_UINT32(offsetPtr, savedStartOfMcode); - return 0; - case IR_GOSUB: - // that's really neat - WRITE_LE_UINT32(offsetPtr, ip); - return 2; - default: - error("Bad return code (%d) from '%s'", retVal & 7, opcodes[parameter].desc); - } - parameterReturnedFromMcodeFunction = retVal >> 3; - break; - case CP_JUMP_ON_RETURNED: - // Jump to a part of the script depending on - // the return value from an mcode routine - - // Get the maximum value - Read8ip(parameter); - debug(9, "CP_JUMP_ON_RETURNED: %d => %d", - parameterReturnedFromMcodeFunction, - READ_LE_UINT32(code + ip + parameterReturnedFromMcodeFunction * 4)); - ip += READ_LE_UINT32(code + ip + parameterReturnedFromMcodeFunction * 4); - break; - - // Operators - - case OP_ISEQUAL: - b = pop(); - a = pop(); - push(a == b); - debug(9, "OP_ISEQUAL: RESULT = %d", a == b); - break; - case OP_NOTEQUAL: - b = pop(); - a = pop(); - push(a != b); - debug(9, "OP_NOTEQUAL: RESULT = %d", a != b); - break; - case OP_GTTHAN: - b = pop(); - a = pop(); - push(a > b); - debug(9, "OP_GTTHAN: RESULT = %d", a > b); - break; - case OP_LSTHAN: - b = pop(); - a = pop(); - push(a < b); - debug(9, "OP_LSTHAN: RESULT = %d", a < b); - break; - case OP_GTTHANE: - b = pop(); - a = pop(); - push(a >= b); - debug(9, "OP_GTTHANE: RESULT = %d", a >= b); - break; - case OP_LSTHANE: - b = pop(); - a = pop(); - push(a <= b); - debug(9, "OP_LSTHANE: RESULT = %d", a <= b); - break; - case OP_PLUS: - b = pop(); - a = pop(); - push(a + b); - debug(9, "OP_PLUS: RESULT = %d", a + b); - break; - case OP_MINUS: - b = pop(); - a = pop(); - push(a - b); - debug(9, "OP_MINUS: RESULT = %d", a - b); - break; - case OP_TIMES: - b = pop(); - a = pop(); - push(a * b); - debug(9, "OP_TIMES: RESULT = %d", a * b); - break; - case OP_DIVIDE: - b = pop(); - a = pop(); - push(a / b); - debug(9, "OP_DIVIDE: RESULT = %d", a / b); - break; - case OP_ANDAND: - b = pop(); - a = pop(); - push(a && b); - debug(9, "OP_ANDAND: RESULT = %d", a && b); - break; - case OP_OROR: - b = pop(); - a = pop(); - push(a || b); - debug(9, "OP_OROR: RESULT = %d", a || b); - break; - - // Debugging opcodes, I think - - case CP_DEBUGON: - debug(9, "CP_DEBUGON"); - break; - case CP_DEBUGOFF: - debug(9, "CP_DEBUGOFF"); - break; - case CP_TEMP_TEXT_PROCESS: - Read32ip(parameter); - debug(9, "CP_TEMP_TEXT_PROCESS: %d", parameter); - break; - default: - error("Invalid script command %d", curCommand); - return 3; - } - } - - return 1; -} - -} // End of namespace Sword2 diff --git a/sword2/interpreter.h b/sword2/interpreter.h deleted file mode 100644 index 365f818a98..0000000000 --- a/sword2/interpreter.h +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef _INTERPRETER -#define _INTERPRETER - -namespace Sword2 { - -// Interpreter return codes - -enum { - IR_STOP = 0, // Quit for a cycle - IR_CONT = 1, // Continue as normal - IR_TERMINATE = 2, // Return without updating the offset - IR_REPEAT = 3, // Return; offset at start of function call - IR_GOSUB = 4 // Return with updated offset -}; - -// Get parameter fix so that the playstation version can handle words not on -// word boundaries - -#define Read8ip(var) { var = code[ip]; ip++; } -#define Read16ip(var) { var = (int16)READ_LE_UINT16(code + ip); ip += 2; } -#define Read32ip(var) { var = (int32)READ_LE_UINT32(code + ip); ip += 4; } -#define Read32ipLeaveip(var) { var = (int32)READ_LE_UINT32(code + ip); } - -enum { - // Compiled tokens - - CP_END_SCRIPT = 0, - CP_PUSH_LOCAL_VAR32 = 1, // Push a local variable on to the stack - CP_PUSH_GLOBAL_VAR32 = 2, // Push a global variable - CP_POP_LOCAL_VAR32 = 3, // Pop a local variable from the stack - CP_CALL_MCODE = 4, // Call a machine code function - CP_PUSH_LOCAL_ADDR = 5, // Push the address of a local variable - CP_PUSH_INT32 = 6, // Adjust the stack after calling an fn function - CP_SKIPONFALSE = 7, // Skip if the bottom value on the stack is false - CP_SKIPALWAYS = 8, // Skip a block of code - CP_SWITCH = 9, // Switch on last stack value - CP_ADDNPOP_LOCAL_VAR32 = 10, // Add to a local varible - CP_SUBNPOP_LOCAL_VAR32 = 11, // Subtract from a local variable - CP_SKIPONTRUE = 12, // Skip if the bottom value on the stack is true - CP_POP_GLOBAL_VAR32 = 13, // Pop a global variable - CP_ADDNPOP_GLOBAL_VAR32 = 14, // Add to a global variable - CP_SUBNPOP_GLOBAL_VAR32 = 15, // Subtract from a global variable - CP_DEBUGON = 16, // Turn debugging on - CP_DEBUGOFF = 17, // Turn debugging off - CP_QUIT = 18, // Quit for a cycle - CP_TERMINATE = 19, // Quit script completely - - // Operators - - OP_ISEQUAL = 20, // '==' - OP_PLUS = 21, // '+' - OP_MINUS = 22, // '-' - OP_TIMES = 23, // '*' - OP_DIVIDE = 24, // '/' - OP_NOTEQUAL = 25, // '==' - OP_ANDAND = 26, // '&&' - OP_GTTHAN = 27, // '>' - OP_LSTHAN = 28, // '<' - - // More tokens, mixed types - - CP_JUMP_ON_RETURNED = 29, // Use table of jumps with value returned from fn_mcode - CP_TEMP_TEXT_PROCESS = 30, // A dummy text process command for me - CP_SAVE_MCODE_START = 31, // Save the mcode code start for restarting when necessary - CP_RESTART_SCRIPT = 32, // Start the script from the beginning - CP_PUSH_STRING = 33, // Push a pointer to a string on the stack - CP_PUSH_DEREFERENCED_STRUCTURE = 34, // Push the address of a structure thing - OP_GTTHANE = 35, // >= - OP_LSTHANE = 36, // <= - OP_OROR = 37 // || or OR -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/layers.cpp b/sword2/layers.cpp deleted file mode 100644 index 0b59b5a9b1..0000000000 --- a/sword2/layers.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -// high level layer initialising - -// the system supports: -// 1 optional background parallax layer -// 1 not optional normal backdrop layer -// 3 normal sorted layers -// up to 2 foreground parallax layers - -#include "common/stdafx.h" - -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/mouse.h" -#include "sword2/resman.h" -#include "sword2/sound.h" - -namespace Sword2 { - -/** - * This function is called when entering a new room. - * @param res resource id of the normal background layer - * @param new_palette 1 for new palette, otherwise 0 - */ - -void Screen::initBackground(int32 res, int32 new_palette) { - byte buf[NAME_LEN]; - int i; - - assert(res); - - _vm->_sound->clearFxQueue(); - waitForFade(); - - debug(1, "CHANGED TO LOCATION \"%s\"", _vm->_resman->fetchName(res, buf)); - - // if last screen was using a shading mask (see below) - if (_thisScreen.mask_flag) { - if (closeLightMask() != RD_OK) - error("Could not close light mask"); - } - - // Close the previous screen, if one is open - if (_thisScreen.background_layer_id) - closeBackgroundLayer(); - - _thisScreen.background_layer_id = res; - _thisScreen.new_palette = new_palette; - - // ok, now read the resource and pull out all the normal sort layer - // info/and set them up at the beginning of the sort list - why do it - // each cycle - - byte *file = _vm->_resman->openResource(_thisScreen.background_layer_id); - ScreenHeader screen_head; - - screen_head.read(_vm->fetchScreenHeader(file)); - - // set number of special sort layers - _thisScreen.number_of_layers = screen_head.noLayers; - _thisScreen.screen_wide = screen_head.width; - _thisScreen.screen_deep = screen_head.height; - - debug(2, "layers=%d width=%d depth=%d", screen_head.noLayers, screen_head.width, screen_head.height); - - // initialise the driver back buffer - setLocationMetrics(screen_head.width, screen_head.height); - - for (i = 0; i < screen_head.noLayers; i++) { - debug(3, "init layer %d", i); - - LayerHeader layer; - - layer.read(_vm->fetchLayerHeader(file, i)); - - // Add the layer to the sort list. We only provide just enough - // information so that it's clear that it's a layer, and where - // to sort it in relation to other things in the list. - - _sortList[i].layer_number = i + 1; - _sortList[i].sort_y = layer.y + layer.height; - } - - // reset scroll offsets - _thisScreen.scroll_offset_x = 0; - _thisScreen.scroll_offset_y = 0; - - if (screen_head.width > _screenWide || screen_head.height > _screenDeep) { - // The layer is larger than the physical screen. Switch on - // scrolling. (2 means first time on screen) - _thisScreen.scroll_flag = 2; - - // Note: if we've already set the player up then we could do - // the initial scroll set here - - // Calculate the maximum scroll offsets to prevent scrolling - // off the edge. The minimum offsets are both 0. - - _thisScreen.max_scroll_offset_x = screen_head.width - _screenWide; - _thisScreen.max_scroll_offset_y = screen_head.height - (_screenDeep - (MENUDEEP * 2)); - } else { - // The later fits on the phyiscal screen. Switch off scrolling. - _thisScreen.scroll_flag = 0; - } - - resetRenderEngine(); - - // These are the physical screen coords where the system will try to - // maintain George's actual feet coords. - - _thisScreen.feet_x = 320; - _thisScreen.feet_y = 340; - - // shading mask - - MultiScreenHeader screenLayerTable; - - screenLayerTable.read(file + ResHeader::size()); - - if (screenLayerTable.maskOffset) { - SpriteInfo spriteInfo; - - spriteInfo.x = 0; - spriteInfo.y = 0; - spriteInfo.w = screen_head.width; - spriteInfo.h = screen_head.height; - spriteInfo.scale = 0; - spriteInfo.scaledWidth = 0; - spriteInfo.scaledHeight = 0; - spriteInfo.type = 0; - spriteInfo.blend = 0; - spriteInfo.data = _vm->fetchShadingMask(file); - spriteInfo.colourTable = 0; - - if (openLightMask(&spriteInfo) != RD_OK) - error("Could not open light mask"); - - // so we know to close it later! (see above) - _thisScreen.mask_flag = true; - } else { - // no need to close a mask later - _thisScreen.mask_flag = false; - } - - // Background parallax layers - - for (i = 0; i < 2; i++) { - if (screenLayerTable.bg_parallax[i]) - initialiseBackgroundLayer(_vm->fetchBackgroundParallaxLayer(file, i)); - else - initialiseBackgroundLayer(NULL); - } - - // Normal backround layer - - initialiseBackgroundLayer(_vm->fetchBackgroundLayer(file)); - - // Foreground parallax layers - - for (i = 0; i < 2; i++) { - if (screenLayerTable.fg_parallax[i]) - initialiseBackgroundLayer(_vm->fetchForegroundParallaxLayer(file, i)); - else - initialiseBackgroundLayer(NULL); - } - - _vm->_resman->closeResource(_thisScreen.background_layer_id); -} - -} // End of namespace Sword2 diff --git a/sword2/layers.h b/sword2/layers.h deleted file mode 100644 index 88aff933b3..0000000000 --- a/sword2/layers.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef _LAYERS -#define _LAYERS - -namespace Sword2 { - -} // End of namespace Sword2 - -#endif diff --git a/sword2/logic.cpp b/sword2/logic.cpp deleted file mode 100644 index c26d5615b9..0000000000 --- a/sword2/logic.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/resman.h" -#include "sword2/router.h" -#include "sword2/sound.h" - -namespace Sword2 { - -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), - _officialTextNumber(0), _speechTextBlocNo(0) { - - _scriptVars = NULL; - memset(_eventList, 0, sizeof(_eventList)); - memset(_syncList, 0, sizeof(_syncList)); - _router = new Router(_vm); -} - -Logic::~Logic() { - delete _router; -} - -/** - * Do one cycle of the current session. - */ - -int Logic::processSession() { - // might change during the session, so take a copy here - uint32 run_list = _currentRunList; - - _pc = 0; // first object in list - - // by minusing the pc we can cause an immediate cessation of logic - // processing on the current list - - while (_pc != 0xffffffff) { - byte *game_object_list, *head, *raw_script_ad, *raw_data_ad; - uint32 level, ret, script, id; - - game_object_list = _vm->_resman->openResource(run_list) + ResHeader::size(); - - assert(_vm->_resman->fetchType(run_list) == RUN_LIST); - - // read the next id - id = READ_LE_UINT32(game_object_list + 4 * _pc); - _pc++; - - writeVar(ID, id); - - _vm->_resman->closeResource(run_list); - - if (!id) { - // End of list - end the session naturally - return 0; - } - - assert(_vm->_resman->fetchType(id) == GAME_OBJECT); - - head = _vm->_resman->openResource(id); - _curObjectHub.setAddress(head + ResHeader::size()); - - level = _curObjectHub.getLogicLevel(); - - debug(5, "Level %d id(%d) pc(%d)", - level, - _curObjectHub.getScriptId(level), - _curObjectHub.getScriptPc(level)); - - // Do the logic for this object. We keep going until a function - // says to stop - remember, system operations are run via - // function calls to drivers now. - - do { - // There is a distinction between running one of our - // own scripts and that of another object. - - level = _curObjectHub.getLogicLevel(); - script = _curObjectHub.getScriptId(level); - - if (script / SIZE == readVar(ID)) { - // It's our own script - - debug(5, "Run script %d pc=%d", - script / SIZE, - _curObjectHub.getScriptPc(level)); - - // This is the script data. Script and data - // object are the same. - - raw_script_ad = head; - - ret = runScript2(raw_script_ad, raw_script_ad, _curObjectHub.getScriptPcPtr(level)); - } else { - // We're running the script of another game - // object - get our data object address. - - uint8 type = _vm->_resman->fetchType(script / SIZE); - - assert(type == GAME_OBJECT || type == SCREEN_MANAGER); - - raw_script_ad = _vm->_resman->openResource(script / SIZE); - raw_data_ad = head; - - ret = runScript2(raw_script_ad, raw_data_ad, _curObjectHub.getScriptPcPtr(level)); - - _vm->_resman->closeResource(script / SIZE); - - // reset to us for service script - raw_script_ad = raw_data_ad; - } - - if (ret == 1) { - level = _curObjectHub.getLogicLevel(); - - // The script finished - drop down a level - if (level) { - _curObjectHub.setLogicLevel(level - 1); - } else { - // Hmmm, level 0 terminated :-| Let's - // be different this time and simply - // let it restart next go :-) - - // Note that this really does happen a - // lot, so don't make it a warning. - - debug(5, "object %d script 0 terminated!", id); - - // reset to rerun, drop out for a cycle - _curObjectHub.setScriptPc(level, _curObjectHub.getScriptId(level) & 0xffff); - ret = 0; - } - } else if (ret > 2) { - error("processSession: illegal script return type %d", ret); - } - - // if ret == 2 then we simply go around again - a new - // script or subroutine will kick in and run - - // keep processing scripts until 0 for quit is returned - } while (ret); - - // Any post logic system requests to go here - - // Clear any syncs that were waiting for this character - it - // has used them or now looses them - - clearSyncs(readVar(ID)); - - if (_pc != 0xffffffff) { - // The session is still valid so run the graphics/mouse - // service script - runScript(raw_script_ad, raw_script_ad, 0); - } - - // and that's it so close the object resource - - _vm->_resman->closeResource(readVar(ID)); - } - - // Leaving a room so remove all ids that must reboot correctly. Then - // restart the loop. - - for (uint32 i = 0; i < _kills; i++) - _vm->_resman->remove(_objectKillList[i]); - - resetKillList(); - return 1; -} - -/** - * Bring an immediate halt to the session and cause a new one to start without - * a screen update. - */ - -void Logic::expressChangeSession(uint32 sesh_id) { - // Set new session and force the old one to quit. - _currentRunList = sesh_id; - _pc = 0xffffffff; - - // Reset now in case we double-clicked an exit prior to changing screen - writeVar(EXIT_FADING, 0); - - // We're trashing the list - presumably to change room. In theory, - // sync waiting in the list could be left behind and never removed - - // so we trash the lot - memset(_syncList, 0, sizeof(_syncList)); - - // Various clean-ups - _router->clearWalkGridList(); - _vm->_sound->clearFxQueue(); - _router->freeAllRouteMem(); -} - -/** - * @return The private _currentRunList variable. - */ - -uint32 Logic::getRunList() { - return _currentRunList; -} - -/** - * Move the current object up a level. Called by fnGosub command. Remember: - * only the logic object has access to _curObjectHub. - */ - -void Logic::logicUp(uint32 new_script) { - debug(5, "new pc = %d", new_script & 0xffff); - - // going up a level - and we'll keep going this cycle - _curObjectHub.setLogicLevel(_curObjectHub.getLogicLevel() + 1); - - assert(_curObjectHub.getLogicLevel() < 3); // Can be 0, 1, 2 - logicReplace(new_script); -} - -/** - * Force the level to one. - */ - -void Logic::logicOne(uint32 new_script) { - _curObjectHub.setLogicLevel(1); - logicReplace(new_script); -} - -/** - * Change current logic. Script must quit with a TERMINATE directive, which - * does not write to &pc - */ - -void Logic::logicReplace(uint32 new_script) { - uint32 level = _curObjectHub.getLogicLevel(); - - _curObjectHub.setScriptId(level, new_script); - _curObjectHub.setScriptPc(level, new_script & 0xffff); -} - -void Logic::resetKillList() { - _kills = 0; -} - -} // End of namespace Sword2 diff --git a/sword2/logic.h b/sword2/logic.h deleted file mode 100644 index 9e264f603c..0000000000 --- a/sword2/logic.h +++ /dev/null @@ -1,316 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -// logic management - -#ifndef _LOGIC -#define _LOGIC - -#include "sword2/memory.h" - -namespace Sword2 { - -struct MovieTextObject; - -#define MAX_events 10 - -#define TREE_SIZE 3 - -// This must allow for the largest number of objects in a screen -#define OBJECT_KILL_LIST_SIZE 50 - -#define MAX_SEQUENCE_TEXT_LINES 15 - -class Sword2Engine; -class Router; - -struct EventUnit { - uint32 id; - uint32 interact_id; -}; - -class Logic { -private: - Sword2Engine *_vm; - - inline byte *decodePtr(int32 n) { - return _vm->_memory->decodePtr(n); - } - - uint32 _objectKillList[OBJECT_KILL_LIST_SIZE]; - - // keeps note of no. of objects in the kill list - uint32 _kills; - - // denotes the res id of the game-object-list in current use - uint32 _currentRunList; - - //pc during logic loop - uint32 _pc; - - // each object has one of these tacked onto the beginning - ObjectHub _curObjectHub; - - EventUnit _eventList[MAX_events]; - - // Resource id of the wav to use as lead-in/lead-out from smacker - uint32 _smackerLeadIn; - uint32 _smackerLeadOut; - - // keeps count of number of text lines to disaply during the sequence - uint32 _sequenceTextLines; - - // FOR TEXT LINES IN SEQUENCE PLAYER - - struct SequenceTextInfo { - uint32 textNumber; - uint16 startFrame; - uint16 endFrame; - byte *text_mem; - uint32 speechBufferSize; - uint16 *speech_mem; - }; - - SequenceTextInfo _sequenceTextList[MAX_SEQUENCE_TEXT_LINES]; - - void createSequenceSpeech(MovieTextObject *sequenceText[]); - void clearSequenceSpeech(MovieTextObject *sequenceText[]); - - // when not playing a wav we calculate the speech time based upon - // length of ascii - - uint32 _speechTime; - - uint32 _animId; - - // 0 lip synced and repeating - 1 normal once through - uint32 _speechAnimType; - - uint32 _leftClickDelay; // click-delay for LEFT mouse button - uint32 _rightClickDelay; // click-delay for RIGHT mouse button - - // calculated by locateTalker() for use in speech-panning & text-sprite - // positioning - - int16 _textX, _textY; - - void locateTalker(int32 *params); - void formText(int32 *params); - bool wantSpeechForLine(uint32 wavId); - - // Set by fnPassMega() - byte _engineMega[56]; - -public: - Logic(Sword2Engine *vm); - ~Logic(); - - EventUnit *getEventList() { return _eventList; } - byte *getEngineMega() { return _engineMega; } - - byte _saveLogic[8]; - byte _saveGraphic[12]; - byte _saveMega[56]; - - // Point to the global variable data - byte *_scriptVars; - - // "TEXT" - current official text line number - will match the wav - // filenames - - int16 _officialTextNumber; - - // so speech text cleared when running a new start-script - uint32 _speechTextBlocNo; - - uint32 readVar(int n) { - return READ_LE_UINT32(_scriptVars + 4 * n); - } - - void writeVar(int n, uint32 value) { - WRITE_LE_UINT32(_scriptVars + 4 * n, value); - } - - int runResScript(uint32 scriptRes, uint32 offset); - int runResObjScript(uint32 scriptRes, uint32 objRes, uint32 offset); - int runScript(byte *scriptData, byte *objectData, uint32 offset); - int runScript2(byte *scriptData, byte *objectData, byte *offset); - - void sendEvent(uint32 id, uint32 interact_id); - void setPlayerActionEvent(uint32 id, uint32 interact_id); - void startEvent(); - int checkEventWaiting(); - void clearEvent(uint32 id); - void killAllIdsEvents(uint32 id); - - uint32 countEvents(); - - struct SyncUnit { - uint32 id; - uint32 sync; - }; - - // There won't be many, will there? Probably 2 at most i reckon - SyncUnit _syncList[10]; - - void clearSyncs(uint32 id); - void sendSync(uint32 id, uint32 sync); - int getSync(); - - Router *_router; - - int32 fnTestFunction(int32 *params); - int32 fnTestFlags(int32 *params); - int32 fnRegisterStartPoint(int32 *params); - int32 fnInitBackground(int32 *params); - int32 fnSetSession(int32 *params); - int32 fnBackSprite(int32 *params); - int32 fnSortSprite(int32 *params); - int32 fnForeSprite(int32 *params); - int32 fnRegisterMouse(int32 *params); - int32 fnAnim(int32 *params); - int32 fnRandom(int32 *params); - int32 fnPreLoad(int32 *params); - int32 fnAddSubject(int32 *params); - int32 fnInteract(int32 *params); - int32 fnChoose(int32 *params); - int32 fnWalk(int32 *params); - int32 fnWalkToAnim(int32 *params); - int32 fnTurn(int32 *params); - int32 fnStandAt(int32 *params); - int32 fnStand(int32 *params); - int32 fnStandAfterAnim(int32 *params); - int32 fnPause(int32 *params); - int32 fnMegaTableAnim(int32 *params); - int32 fnAddMenuObject(int32 *params); - int32 fnStartConversation(int32 *params); - int32 fnEndConversation(int32 *params); - int32 fnSetFrame(int32 *params); - int32 fnRandomPause(int32 *params); - int32 fnRegisterFrame(int32 *params); - int32 fnNoSprite(int32 *params); - int32 fnSendSync(int32 *params); - int32 fnUpdatePlayerStats(int32 *params); - int32 fnPassGraph(int32 *params); - int32 fnInitFloorMouse(int32 *params); - int32 fnPassMega(int32 *params); - int32 fnFaceXY(int32 *params); - int32 fnEndSession(int32 *params); - int32 fnNoHuman(int32 *params); - int32 fnAddHuman(int32 *params); - int32 fnWeWait(int32 *params); - int32 fnTheyDoWeWait(int32 *params); - int32 fnTheyDo(int32 *params); - int32 fnWalkToTalkToMega(int32 *params); - int32 fnFadeDown(int32 *params); - int32 fnISpeak(int32 *params); - int32 fnTotalRestart(int32 *params); - int32 fnSetWalkGrid(int32 *params); - int32 fnSpeechProcess(int32 *params); - int32 fnSetScaling(int32 *params); - int32 fnStartEvent(int32 *params); - int32 fnCheckEventWaiting(int32 *params); - int32 fnRequestSpeech(int32 *params); - int32 fnGosub(int32 *params); - int32 fnTimedWait(int32 *params); - int32 fnPlayFx(int32 *params); - int32 fnStopFx(int32 *params); - int32 fnPlayMusic(int32 *params); - int32 fnStopMusic(int32 *params); - int32 fnSetValue(int32 *params); - int32 fnNewScript(int32 *params); - int32 fnGetSync(int32 *params); - int32 fnWaitSync(int32 *params); - int32 fnRegisterWalkGrid(int32 *params); - int32 fnReverseMegaTableAnim(int32 *params); - int32 fnReverseAnim(int32 *params); - int32 fnAddToKillList(int32 *params); - int32 fnSetStandbyCoords(int32 *params); - int32 fnBackPar0Sprite(int32 *params); - int32 fnBackPar1Sprite(int32 *params); - int32 fnForePar0Sprite(int32 *params); - int32 fnForePar1Sprite(int32 *params); - int32 fnSetPlayerActionEvent(int32 *params); - int32 fnSetScrollCoordinate(int32 *params); - int32 fnStandAtAnim(int32 *params); - int32 fnSetScrollLeftMouse(int32 *params); - int32 fnSetScrollRightMouse(int32 *params); - int32 fnColour(int32 *params); - int32 fnFlash(int32 *params); - int32 fnPreFetch(int32 *params); - int32 fnGetPlayerSaveData(int32 *params); - int32 fnPassPlayerSaveData(int32 *params); - int32 fnSendEvent(int32 *params); - int32 fnAddWalkGrid(int32 *params); - int32 fnRemoveWalkGrid(int32 *params); - int32 fnCheckForEvent(int32 *params); - int32 fnPauseForEvent(int32 *params); - int32 fnClearEvent(int32 *params); - int32 fnFaceMega(int32 *params); - int32 fnPlaySequence(int32 *params); - int32 fnShadedSprite(int32 *params); - int32 fnUnshadedSprite(int32 *params); - int32 fnFadeUp(int32 *params); - int32 fnDisplayMsg(int32 *params); - int32 fnSetObjectHeld(int32 *params); - int32 fnAddSequenceText(int32 *params); - int32 fnResetGlobals(int32 *params); - int32 fnSetPalette(int32 *params); - int32 fnRegisterPointerText(int32 *params); - int32 fnFetchWait(int32 *params); - int32 fnRelease(int32 *params); - int32 fnPrepareMusic(int32 *params); - int32 fnSoundFetch(int32 *params); - int32 fnSmackerLeadIn(int32 *params); - int32 fnSmackerLeadOut(int32 *params); - int32 fnStopAllFx(int32 *params); - int32 fnCheckPlayerActivity(int32 *params); - int32 fnResetPlayerActivityDelay(int32 *params); - int32 fnCheckMusicPlaying(int32 *params); - int32 fnPlayCredits(int32 *params); - int32 fnSetScrollSpeedNormal(int32 *params); - int32 fnSetScrollSpeedSlow(int32 *params); - int32 fnRemoveChooser(int32 *params); - int32 fnSetFxVolAndPan(int32 *params); - int32 fnSetFxVol(int32 *params); - int32 fnRestoreGame(int32 *params); - int32 fnRefreshInventory(int32 *params); - int32 fnChangeShadows(int32 *params); - - // do one cycle of the current session - int processSession(); - - // cause the logic loop to terminate and drop out - void expressChangeSession(uint32 sesh_id); - - uint32 getRunList(); - - // setup script_id and script_pc in _curObjectHub - called by fnGosub() - void logicUp(uint32 new_script); - - void logicReplace(uint32 new_script); - void logicOne(uint32 new_script); - void resetKillList(); -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/maketext.cpp b/sword2/maketext.cpp deleted file mode 100644 index 5edaf5e41e..0000000000 --- a/sword2/maketext.cpp +++ /dev/null @@ -1,579 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -// MAKETEXT - Constructs a single-frame text sprite: returns a handle to a -// FLOATING memory block containing the sprite, given a -// null-terminated string, max width allowed, pen colour and -// pointer to required character set. -// -// NB 1) The routine does not create a standard file header or -// an anim header for the text sprite - the data simply begins -// with the frame header. -// -// NB 2) If pen colour is zero, it copies the characters into -// the sprite without remapping the colours. -// ie. It can handle both the standard 2-colour font for speech -// and any multicoloured fonts for control panels, etc. -// -// Based on textsprt.c as used for Broken Sword 1, but updated -// for new system by JEL on 9oct96 and updated again (for font -// as a resource) on 5dec96. - -#include "common/stdafx.h" -#include "common/system.h" -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/maketext.h" -#include "sword2/resman.h" - -namespace Sword2 { - -#define MAX_LINES 30 // max character lines in output sprite - -#define BORDER_COL 200 // source colour for character border (only - // needed for remapping colours) -#define LETTER_COL 193 // source colour for bulk of character ( " ) -#define SPACE ' ' -#define FIRST_CHAR SPACE // first character in character set -#define LAST_CHAR 255 // last character in character set -#define DUD 64 // the first "chequered flag" (dud) symbol in - // our character set is in the '@' position - -/** - * This function creates a new text sprite. The sprite data contains a - * FrameHeader, but not a standard file header. - * - * @param sentence pointer to a null-terminated string - * @param maxWidth the maximum allowed text sprite width in pixels - * @param pen the text colour, or zero to use the source colours - * @param fontRes the font resource id - * @param border the border colour; black by default - * @return a handle to a floating memory block containing the text sprite - * @note The sentence must contain no leading, trailing or extra spaces. - * Out-of-range characters in the string are replaced by a special - * error-signal character (chequered flag) - */ - -byte *FontRenderer::makeTextSprite(byte *sentence, uint16 maxWidth, uint8 pen, uint32 fontRes, uint8 border) { - debug(5, "makeTextSprite(\"%s\", maxWidth=%u)", sentence, maxWidth); - - _borderPen = border; - - // Line- and character spacing are hard-wired, rather than being part - // of the resource. - - if (fontRes == _vm->_speechFontId) { - _lineSpacing = -6; - _charSpacing = -3; - } else if (fontRes == CONSOLE_FONT_ID) { - _lineSpacing = 0; - _charSpacing = 1; - } else { - _lineSpacing = 0; - _charSpacing = 0; - } - - // Allocate memory for array of lineInfo structures - - byte *line = (byte *)malloc(MAX_LINES * sizeof(LineInfo)); - - // Get details of sentence breakdown into array of LineInfo structures - // and get the number of lines involved - - uint16 noOfLines = analyseSentence(sentence, maxWidth, fontRes, (LineInfo *)line); - - // Construct the sprite based on the info gathered - returns floating - // mem block - - byte *textSprite = buildTextSprite(sentence, fontRes, pen, (LineInfo *)line, noOfLines); - - free(line); - return textSprite; -} - -uint16 FontRenderer::analyseSentence(byte *sentence, uint16 maxWidth, uint32 fontRes, LineInfo *line) { - // joinWidth = how much extra space is needed to append a word to a - // line. NB. SPACE requires TWICE the '_charSpacing' to join a word - // to line - - uint16 joinWidth = charWidth(SPACE, fontRes) + 2 * _charSpacing; - - uint16 lineNo = 0; - uint16 pos = 0; - bool firstWord = true; - - byte ch; - - do { - uint16 wordWidth = 0; - uint16 wordLength = 0; - - // Calculate the width of the word. - - ch = sentence[pos++]; - - while (ch && ch != SPACE) { - wordWidth += charWidth(ch, fontRes) + _charSpacing; - wordLength++; - ch = sentence[pos++]; - } - - // Don't include any character spacing at the end of the word. - wordWidth -= _charSpacing; - - // 'ch' is now the SPACE or NULL following the word - // 'pos' indexes to the position following 'ch' - - if (firstWord) { - // This is the first word on the line, so no separating - // space is needed. - - line[0].width = wordWidth; - line[0].length = wordLength; - firstWord = false; - } else { - // See how much extra space this word will need to - // fit on current line (with a separating space - // character - also overlapped) - - uint16 spaceNeeded = joinWidth + wordWidth; - - if (line[lineNo].width + spaceNeeded <= maxWidth) { - // The word fits on this line. - line[lineNo].width += spaceNeeded; - line[lineNo].length += (1 + wordLength); - } else { - // The word spills over to the next line, i.e. - // no separating space. - - lineNo++; - - assert(lineNo < MAX_LINES); - - line[lineNo].width = wordWidth; - line[lineNo].length = wordLength; - } - } - } while (ch); - - return lineNo + 1; -} - -/** - * This function creates a new text sprite in a movable memory block. It must - * be locked before use, i.e. lock, draw sprite, unlock/free. The sprite data - * contains a FrameHeader, but not a standard file header. - * - * @param sentence pointer to a null-terminated string - * @param fontRes the font resource id - * @param pen the text colour, or zero to use the source colours - * @param line array of LineInfo structures, created by analyseSentence() - * @param noOfLines the number of lines, i.e. the number of elements in 'line' - * @return a handle to a floating memory block containing the text sprite - * @note The sentence must contain no leading, trailing or extra spaces. - * Out-of-range characters in the string are replaced by a special - * error-signal character (chequered flag) - */ - -byte *FontRenderer::buildTextSprite(byte *sentence, uint32 fontRes, uint8 pen, LineInfo *line, uint16 noOfLines) { - uint16 i; - - // Find the width of the widest line in the output text - - uint16 spriteWidth = 0; - - for (i = 0; i < noOfLines; i++) - if (line[i].width > spriteWidth) - spriteWidth = line[i].width; - - // Find the total height of the text sprite: the total height of the - // text lines, plus the total height of the spacing between them. - - uint16 char_height = charHeight(fontRes); - uint16 spriteHeight = char_height * noOfLines + _lineSpacing * (noOfLines - 1); - - // Allocate memory for the text sprite - - uint32 sizeOfSprite = spriteWidth * spriteHeight; - byte *textSprite = (byte *)malloc(FrameHeader::size() + sizeOfSprite); - - // At this stage, textSprite points to an unmovable memory block. Set - // up the frame header. - - FrameHeader frame_head; - - frame_head.compSize = 0; - frame_head.width = spriteWidth; - frame_head.height = spriteHeight; - - frame_head.write(textSprite); - - debug(4, "Text sprite size: %ux%u", spriteWidth, spriteHeight); - - // Clear the entire sprite to make it transparent. - - byte *linePtr = textSprite + FrameHeader::size(); - memset(linePtr, 0, sizeOfSprite); - - byte *charSet = _vm->_resman->openResource(fontRes); - - // Build the sprite, one line at a time - - uint16 pos = 0; - - for (i = 0; i < noOfLines; i++) { - // Center each line - byte *spritePtr = linePtr + (spriteWidth - line[i].width) / 2; - - // copy the sprite for each character in this line to the - // text sprite and inc the sprite ptr by the character's - // width minus the 'overlap' - - for (uint j = 0; j < line[i].length; j++) { - byte *charPtr = findChar(sentence[pos++], charSet); - - frame_head.read(charPtr); - - assert(frame_head.height == char_height); - copyChar(charPtr, spritePtr, spriteWidth, pen); - spritePtr += frame_head.width + _charSpacing; - } - - // Skip space at end of last word in this line - pos++; - - linePtr += (char_height + _lineSpacing) * spriteWidth; - } - - _vm->_resman->closeResource(fontRes); - - return textSprite; -} - -/** - * @param ch the ASCII code of the character - * @param fontRes the font resource id - * @return the width of the character - */ - -uint16 FontRenderer::charWidth(byte ch, uint32 fontRes) { - byte *charSet = _vm->_resman->openResource(fontRes); - - FrameHeader frame_head; - - frame_head.read(findChar(ch, charSet)); - _vm->_resman->closeResource(fontRes); - - return frame_head.width; -} - -/** - * @param fontRes the font resource id - * @return the height of a character sprite - * @note All characters in a font are assumed to have the same height, so - * there is no need to specify which one to look at. - */ - -// Returns the height of a character sprite, given the character's ASCII code -// and a pointer to the start of the character set. - -uint16 FontRenderer::charHeight(uint32 fontRes) { - byte *charSet = _vm->_resman->openResource(fontRes); - - FrameHeader frame_head; - - frame_head.read(findChar(FIRST_CHAR, charSet)); - _vm->_resman->closeResource(fontRes); - - return frame_head.height; -} - -/** - * @param ch the ASCII code of the character to find - * @param charSet pointer to the start of the character set - * @return pointer to the requested character or, if it's out of range, the - * 'dud' character (chequered flag) - */ - -byte *FontRenderer::findChar(byte ch, byte *charSet) { - if (ch < FIRST_CHAR) - ch = DUD; - return _vm->fetchFrameHeader(charSet, ch - FIRST_CHAR); -} - -/** - * Copies a character sprite to the sprite buffer. - * @param charPtr pointer to the character sprite - * @param spritePtr pointer to the sprite buffer - * @param spriteWidth the width of the character - * @param pen If zero, copy the data directly. Otherwise remap the - * sprite's colours from BORDER_COL to _borderPen and from - * LETTER_COL to pen. - */ - -void FontRenderer::copyChar(byte *charPtr, byte *spritePtr, uint16 spriteWidth, uint8 pen) { - FrameHeader frame; - - frame.read(charPtr); - - byte *source = charPtr + FrameHeader::size(); - byte *rowPtr = spritePtr; - - for (uint i = 0; i < frame.height; i++) { - byte *dest = rowPtr; - - if (pen) { - // Use the specified colours - for (uint j = 0; j < frame.width; j++) { - switch (*source++) { - case LETTER_COL: - *dest = pen; - break; - case BORDER_COL: - // Don't do a border pixel if there's - // already a bit of another character - // underneath (for overlapping!) - if (!*dest) - *dest = _borderPen; - break; - default: - // Do nothing if source pixel is zero, - // ie. transparent - break; - } - dest++; - } - } else { - // Pen is zero, so just copy character sprites - // directly into text sprite without remapping colours. - // Apparently overlapping is never considered here? - memcpy(dest, source, frame.width); - source += frame.width; - } - rowPtr += spriteWidth; - } -} - -// Distance to keep speech text from edges of screen -#define TEXT_MARGIN 12 - -/** - * Creates a text bloc in the list and returns the bloc number. The list of - * blocs is read and blitted at render time. Choose alignment type - * RDSPR_DISPLAYALIGN or 0 - */ - -uint32 FontRenderer::buildNewBloc(byte *ascii, int16 x, int16 y, uint16 width, uint8 pen, uint32 type, uint32 fontRes, uint8 justification) { - uint32 i = 0; - - while (i < MAX_text_blocs && _blocList[i].text_mem) - i++; - - assert(i < MAX_text_blocs); - - // Create and position the sprite - - _blocList[i].text_mem = makeTextSprite(ascii, width, pen, fontRes); - - // 'NO_JUSTIFICATION' means print sprite with top-left at (x,y) - // without margin checking - used for debug text - - if (justification != NO_JUSTIFICATION) { - FrameHeader frame_head; - - frame_head.read(_blocList[i].text_mem); - - switch (justification) { - case POSITION_AT_CENTRE_OF_BASE: - // This one is always used for SPEECH TEXT; possibly - // also for pointer text - x -= (frame_head.width / 2); - y -= frame_head.height; - break; - case POSITION_AT_CENTRE_OF_TOP: - x -= (frame_head.width / 2); - break; - case POSITION_AT_LEFT_OF_TOP: - // The given coords are already correct for this! - break; - case POSITION_AT_RIGHT_OF_TOP: - x -= frame_head.width; - break; - case POSITION_AT_LEFT_OF_BASE: - y -= frame_head.height; - break; - case POSITION_AT_RIGHT_OF_BASE: - x -= frame_head.width; - y -= frame_head.height; - break; - case POSITION_AT_LEFT_OF_CENTRE: - y -= (frame_head.height / 2); - break; - case POSITION_AT_RIGHT_OF_CENTRE: - x -= frame_head.width; - y -= (frame_head.height) / 2; - break; - } - - // Ensure text sprite is a few pixels inside the visible screen - // remember - it's RDSPR_DISPLAYALIGN - - uint16 text_left_margin = TEXT_MARGIN; - uint16 text_right_margin = 640 - TEXT_MARGIN - frame_head.width; - uint16 text_top_margin = TEXT_MARGIN; - uint16 text_bottom_margin = 400 - TEXT_MARGIN - frame_head.height; - - // Move if too far left or too far right - - if (x < text_left_margin) - x = text_left_margin; - else if (x > text_right_margin) - x = text_right_margin; - - // Move if too high or too low - - if (y < text_top_margin) - y = text_top_margin; - else if (y > text_bottom_margin) - y = text_bottom_margin; - } - - // The sprite is always uncompressed - _blocList[i].type = type | RDSPR_NOCOMPRESSION; - - _blocList[i].x = x; - _blocList[i].y = y; - - return i + 1; -} - -/** - * Called by buildDisplay() - */ - -void FontRenderer::printTextBlocs() { - for (uint i = 0; i < MAX_text_blocs; i++) { - if (_blocList[i].text_mem) { - FrameHeader frame_head; - SpriteInfo spriteInfo; - - frame_head.read(_blocList[i].text_mem); - - spriteInfo.x = _blocList[i].x; - spriteInfo.y = _blocList[i].y; - spriteInfo.w = frame_head.width; - spriteInfo.h = frame_head.height; - spriteInfo.scale = 0; - spriteInfo.scaledWidth = 0; - spriteInfo.scaledHeight = 0; - spriteInfo.type = _blocList[i].type; - spriteInfo.blend = 0; - spriteInfo.data = _blocList[i].text_mem + FrameHeader::size(); - spriteInfo.colourTable = 0; - - uint32 rv = _vm->_screen->drawSprite(&spriteInfo); - if (rv) - error("Driver Error %.8x in printTextBlocs", rv); - } - } -} - -void FontRenderer::killTextBloc(uint32 bloc_number) { - bloc_number--; - free(_blocList[bloc_number].text_mem); - _blocList[bloc_number].text_mem = NULL; -} - -// Resource 3258 contains text from location script for 152 (install, save & -// restore text, etc) - -#define TEXT_RES 3258 - -// Local line number of "save" (actor no. 1826) - -#define SAVE_LINE_NO 1 - -void Sword2Engine::initialiseFontResourceFlags() { - byte *textFile = _resman->openResource(TEXT_RES); - - // If language is Polish or Finnish it requires alternate fonts. - // Otherwise, use regular fonts - - // "tallenna" Finnish for "save" - // "zapisz" Polish for "save" - - // Get the text line (& skip the 2 chars containing the wavId) - char *textLine = (char *)fetchTextLine(textFile, SAVE_LINE_NO) + 2; - - if (strcmp(textLine, "tallenna") == 0) - initialiseFontResourceFlags(FINNISH_TEXT); - else if (strcmp(textLine, "zapisz") == 0) - initialiseFontResourceFlags(POLISH_TEXT); - else - initialiseFontResourceFlags(DEFAULT_TEXT); - - // Get the game name for the windows application - - // According to the GetNameFunction(), which was never called and has - // therefore been removed, the name of the game is: - // - // ENGLISH: "Broken Sword II" - // AMERICAN: "Circle of Blood II" - // GERMAN: "Baphomet's Fluch II" - // default: "Some game or other, part 86" - // - // But we get it from the text resource instead. - - if (_logic->readVar(DEMO)) - textLine = (char *)fetchTextLine(textFile, 451) + 2; - else - textLine = (char *)fetchTextLine(textFile, 54) + 2; - - _system->setWindowCaption(textLine); - _resman->closeResource(TEXT_RES); -} - -/** - * Called from initialiseFontResourceFlags(), and also from console.cpp - */ - -void Sword2Engine::initialiseFontResourceFlags(uint8 language) { - switch (language) { - case FINNISH_TEXT: - _speechFontId = FINNISH_SPEECH_FONT_ID; - _controlsFontId = FINNISH_CONTROLS_FONT_ID; - _redFontId = FINNISH_RED_FONT_ID; - break; - case POLISH_TEXT: - _speechFontId = POLISH_SPEECH_FONT_ID; - _controlsFontId = POLISH_CONTROLS_FONT_ID; - _redFontId = POLISH_RED_FONT_ID; - break; - default: - _speechFontId = ENGLISH_SPEECH_FONT_ID; - _controlsFontId = ENGLISH_CONTROLS_FONT_ID; - _redFontId = ENGLISH_RED_FONT_ID; - break; - } -} - -} // End of namespace Sword2 diff --git a/sword2/maketext.h b/sword2/maketext.h deleted file mode 100644 index 364a412857..0000000000 --- a/sword2/maketext.h +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef _MAKETEXT_H -#define _MAKETEXT_H - -#include "sword2/debug.h" - -namespace Sword2 { - -// Output colour for character border - should be be black but note that we -// have to use a different pen number during sequences - -#define BORDER_PEN 194 - -// Usually the only texts on screen are the subtitles and the mouse-over text, -// but there can also be a considerable number of debugging messages... - -#define MAX_text_blocs MAX_DEBUG_TEXTS + 1 - -enum { - // Doesn't keep the text inside the screen - only for debug text! - NO_JUSTIFICATION = 0, - - // These all force text inside the screen edge margin when necessary - POSITION_AT_CENTRE_OF_BASE = 1, - POSITION_AT_CENTRE_OF_TOP = 2, - POSITION_AT_LEFT_OF_TOP = 3, - POSITION_AT_RIGHT_OF_TOP = 4, - POSITION_AT_LEFT_OF_BASE = 5, - POSITION_AT_RIGHT_OF_BASE = 6, - POSITION_AT_LEFT_OF_CENTRE = 7, - POSITION_AT_RIGHT_OF_CENTRE = 8 -}; - -enum { - DEFAULT_TEXT = 0, - FINNISH_TEXT = 1, - POLISH_TEXT = 2 -}; - -// Info about the text, used to create the SpriteInfo struct - - struct TextBloc { - int16 x; - int16 y; - uint16 type; - byte *text_mem; -}; - -// Info for each line of words in the output text sprite - -struct LineInfo { - uint16 width; // Width in pixels - uint16 length; // Length in characters -}; - -class FontRenderer { -private: - Sword2Engine *_vm; - TextBloc _blocList[MAX_text_blocs]; - - // Layout variables - these used to be defines, but now we're dealing - // with three character sets - - int8 _lineSpacing; // no. of pixels to separate lines of - // characters in the output sprite - negative - // for overlap - int8 _charSpacing; // no. of pixels to separate characters along - // each line - negative for overlap - uint8 _borderPen; // output pen colour of character borders - - uint16 analyseSentence(byte *sentence, uint16 maxWidth, uint32 fontRes, LineInfo *line); - byte *buildTextSprite(byte *sentence, uint32 fontRes, uint8 pen, LineInfo *line, uint16 noOfLines); - uint16 charWidth(byte ch, uint32 fontRes); - uint16 charHeight(uint32 fontRes); - byte *findChar(byte ch, byte *charSet); - void copyChar(byte *charPtr, byte *spritePtr, uint16 spriteWidth, uint8 pen); - -public: - FontRenderer(Sword2Engine *vm) : _vm(vm) { - for (int i = 0; i < MAX_text_blocs; i++) - _blocList[i].text_mem = NULL; - } - - ~FontRenderer() { - for (int i = 0; i < MAX_text_blocs; i++) - free(_blocList[i].text_mem); - } - - byte *makeTextSprite(byte *sentence, uint16 maxWidth, uint8 pen, uint32 fontRes, uint8 border = BORDER_PEN); - - void killTextBloc(uint32 bloc_number); - void printTextBlocs(); - - uint32 buildNewBloc(byte *ascii, int16 x, int16 y, uint16 width, uint8 pen, uint32 type, uint32 fontRes, uint8 justification); -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/memory.cpp b/sword2/memory.cpp deleted file mode 100644 index 7da4e86b51..0000000000 --- a/sword2/memory.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -// The new memory manager, now only used by the resource manager. The original -// one would allocated a 12 MB memory pool at startup, which may have been -// appropriate for the original Playstation version but didn't work very well -// with our PocketPC version. -// -// There is one thing that prevents us from replacing the whole memory manager -// with the standard memory allocation functions: Broken Sword 2 absolutely, -// positively needs to be able to encode pointers as 32-bit integers. The -// original engine did this simply by casting between pointers and integers, -// but as far as I know that's not a very portable thing to do. -// -// If it had only used pointers as opcode parameters it would have been -// possible, albeit messy, to extend the stack data type. However, there is -// code in walker.cpp that obviously violates that assumption, and there are -// probably other cases as well. -// -// Instead, we take advantage of the fact that the original memory manager -// could only handle up to 999 blocks of memory. That means we can encode a -// pointer as a 10-bit id and a 22-bit offset into the block. Judging by early -// testing, both should be plenty. -// -// The number zero is used to represent the NULL pointer. - -#include "common/stdafx.h" -#include "sword2/sword2.h" -#include "sword2/memory.h" - -namespace Sword2 { - -MemoryManager::MemoryManager(Sword2Engine *vm) : _vm(vm) { - // The id stack contains all the possible ids for the memory blocks. - // We use this to ensure that no two blocks ever have the same id. - - // The memory blocks are stored in an array, indexed on the block's - // id. This means that given a block id we can find the pointer with a - // simple array lookup. - - // The memory block index is an array of pointers to the memory block - // array, sorted on the memory block's pointer. This means that given - // a pointer into a memory block we can find its id with binary - // searching. - // - // A balanced tree might have been more efficient - the index has to - // be re-sorted every time a block is allocated or freed - but such - // beasts are tricky to implement. Anyway, it wouldn't have made - // encoding or decoding pointers any faster, and these are by far the - // most common operations. - - _idStack = (int16 *)malloc(MAX_MEMORY_BLOCKS * sizeof(int16)); - _memBlocks = (MemBlock *)malloc(MAX_MEMORY_BLOCKS * sizeof(MemBlock)); - _memBlockIndex = (MemBlock **)malloc(MAX_MEMORY_BLOCKS * sizeof(MemBlock *)); - - _totAlloc = 0; - _numBlocks = 0; - - for (int i = 0; i < MAX_MEMORY_BLOCKS; i++) { - _idStack[i] = MAX_MEMORY_BLOCKS - i - 1; - _memBlocks[i].ptr = NULL; - _memBlockIndex[i] = NULL; - } - - _idStackPtr = MAX_MEMORY_BLOCKS; -} - -MemoryManager::~MemoryManager() { - for (int i = 0; i < MAX_MEMORY_BLOCKS; i++) - free(_memBlocks[i].ptr); - free(_memBlocks); - free(_memBlockIndex); - free(_idStack); -} - -int32 MemoryManager::encodePtr(byte *ptr) { - if (ptr == NULL) - return 0; - - int idx = findPointerInIndex(ptr); - - assert(idx != -1); - - uint32 id = _memBlockIndex[idx]->id; - uint32 offset = ptr - _memBlocks[id].ptr; - - assert(id < 0x03ff); - assert(offset <= 0x003fffff); - assert(offset < _memBlocks[id].size); - - return ((id + 1) << 22) | (ptr - _memBlocks[id].ptr); -} - -byte *MemoryManager::decodePtr(int32 n) { - if (n == 0) - return NULL; - - uint32 id = ((n & 0xffc00000) >> 22) - 1; - uint32 offset = n & 0x003fffff; - - assert(_memBlocks[id].ptr); - assert(offset < _memBlocks[id].size); - - return _memBlocks[id].ptr + offset; -} - -int16 MemoryManager::findExactPointerInIndex(byte *ptr) { - int left = 0; - int right = _numBlocks - 1; - - while (right >= left) { - int n = (left + right) / 2; - - if (_memBlockIndex[n]->ptr == ptr) - return n; - - if (_memBlockIndex[n]->ptr > ptr) - right = n - 1; - else - left = n + 1; - } - - return -1; -} - -int16 MemoryManager::findPointerInIndex(byte *ptr) { - int left = 0; - int right = _numBlocks - 1; - - while (right >= left) { - int n = (left + right) / 2; - - if (_memBlockIndex[n]->ptr <= ptr && _memBlockIndex[n]->ptr + _memBlockIndex[n]->size > ptr) - return n; - - if (_memBlockIndex[n]->ptr > ptr) - right = n - 1; - else - left = n + 1; - } - - return -1; -} - -int16 MemoryManager::findInsertionPointInIndex(byte *ptr) { - if (_numBlocks == 0) - return 0; - - int left = 0; - int right = _numBlocks - 1; - int n = 0; - - while (right >= left) { - n = (left + right) / 2; - - if (_memBlockIndex[n]->ptr == ptr) - return -1; - - if (_memBlockIndex[n]->ptr > ptr) - right = n - 1; - else - left = n + 1; - } - - if (_memBlockIndex[n]->ptr < ptr) - n++; - - return n; -} - -byte *MemoryManager::memAlloc(uint32 size, int16 uid) { - assert(_idStackPtr > 0); - - // Get the new block's id from the stack. - int16 id = _idStack[--_idStackPtr]; - - // Allocate the new memory block - byte *ptr = (byte *)malloc(size); - - assert(ptr); - - _memBlocks[id].id = id; - _memBlocks[id].uid = uid; - _memBlocks[id].ptr = ptr; - _memBlocks[id].size = size; - - // Update the memory block index. - int16 idx = findInsertionPointInIndex(ptr); - - assert(idx != -1); - - for (int i = _numBlocks; i > idx; i--) - _memBlockIndex[i] = _memBlockIndex[i - 1]; - - _memBlockIndex[idx] = &_memBlocks[id]; - _numBlocks++; - _totAlloc += size; - - return _memBlocks[id].ptr; -} - -void MemoryManager::memFree(byte *ptr) { - int16 idx = findExactPointerInIndex(ptr); - - if (idx == -1) { - warning("Freeing non-allocated pointer %p", ptr); - return; - } - - // Put back the id on the stack - _idStack[_idStackPtr++] = _memBlockIndex[idx]->id; - - // Release the memory block - free(_memBlockIndex[idx]->ptr); - _memBlockIndex[idx]->ptr = NULL; - - _totAlloc -= _memBlockIndex[idx]->size; - - // Remove the memory block from the index - _numBlocks--; - - for (int i = idx; i < _numBlocks; i++) - _memBlockIndex[i] = _memBlockIndex[i + 1]; -} - -} // End of namespace Sword2 diff --git a/sword2/memory.h b/sword2/memory.h deleted file mode 100644 index 3154842cd9..0000000000 --- a/sword2/memory.h +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef MEMORY_H -#define MEMORY_H - -#define MAX_MEMORY_BLOCKS 999 - -namespace Sword2 { - -struct MemBlock { - int16 id; - int16 uid; - byte *ptr; - uint32 size; -}; - -class MemoryManager { -private: - Sword2Engine *_vm; - - MemBlock *_memBlocks; - MemBlock **_memBlockIndex; - int16 _numBlocks; - - uint32 _totAlloc; - - int16 *_idStack; - int16 _idStackPtr; - - int16 findExactPointerInIndex(byte *ptr); - int16 findPointerInIndex(byte *ptr); - int16 findInsertionPointInIndex(byte *ptr); - -public: - MemoryManager(Sword2Engine *vm); - ~MemoryManager(); - - int16 getNumBlocks() { return _numBlocks; } - uint32 getTotAlloc() { return _totAlloc; } - MemBlock *getMemBlocks() { return _memBlocks; } - - int32 encodePtr(byte *ptr); - byte *decodePtr(int32 n); - - byte *memAlloc(uint32 size, int16 uid); - void memFree(byte *ptr); -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/menu.cpp b/sword2/menu.cpp deleted file mode 100644 index 07e00accb6..0000000000 --- a/sword2/menu.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" - -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/mouse.h" - -namespace Sword2 { - -#define MENUDEEP 40 -#define MAXMENUANIMS 8 - -void Mouse::clearIconArea(int menu, int pocket, Common::Rect *r) { - byte *buf = _vm->_screen->getScreen(); - int16 screenWide = _vm->_screen->getScreenWide(); - - r->top = menu * (RENDERDEEP + MENUDEEP) + (MENUDEEP - RDMENU_ICONDEEP) / 2; - r->bottom = r->top + RDMENU_ICONDEEP; - r->left = RDMENU_ICONSTART + pocket * (RDMENU_ICONWIDE + RDMENU_ICONSPACING); - r->right = r->left + RDMENU_ICONWIDE; - - byte *dst = buf + r->top * screenWide + r->left; - - for (int i = 0; i < RDMENU_ICONDEEP; i++) { - memset(dst, 0, RDMENU_ICONWIDE); - dst += screenWide; - } -} - -/** - * This function should be called regularly to process the menubar system. The - * rate at which this function is called will dictate how smooth the menu - * system is. - */ - -void Mouse::processMenu() { - uint8 menu; - uint8 i, j; - uint8 frameCount; - Common::Rect r1, r2; - static int32 lastTime = 0; - - byte *buf = _vm->_screen->getScreen(); - int16 screenWide = _vm->_screen->getScreenWide(); - - if (lastTime == 0) { - lastTime = _vm->getMillis(); - frameCount = 1; - } else { - int32 delta = _vm->getMillis() - lastTime; - - if (delta > 250) { - lastTime += delta; - delta = 250; - frameCount = 1; - } else { - frameCount = (uint8) ((_iconCount + 8) * delta / 750); - lastTime += frameCount * 750 / (_iconCount + 8); - } - } - - // Note: The "almost hidden" menu state exists only so that the menu - // will be redrawn one last time before it's completely hidden. We do - // not need a corresponding "almost shown" state because the menu will - // always be redrawn while it's shown anyway. (We may want to change - // this later.) - - while (frameCount-- > 0) { - for (menu = RDMENU_TOP; menu <= RDMENU_BOTTOM; menu++) { - if (_menuStatus[menu] == RDMENU_HIDDEN || _menuStatus[menu] == RDMENU_ALMOST_HIDDEN || _menuStatus[menu] == RDMENU_SHOWN) - continue; - - int target, direction, nextState; - - if (_menuStatus[menu] == RDMENU_OPENING) { - target = MAXMENUANIMS; - direction = 1; - nextState = RDMENU_SHOWN; - } else { - target = 0; - direction = -1; - nextState = RDMENU_ALMOST_HIDDEN; - } - - bool complete = true; - - // Propagate animation from the first icon... - for (i = RDMENU_MAXPOCKETS - 1; i > 0; i--) { - _pocketStatus[menu][i] = _pocketStatus[menu][i - 1]; - - if (_pocketStatus[menu][i] != target) - complete = false; - } - - if (_pocketStatus[menu][i] != target) - complete = false; - - // ...and animate the first icon - if (_pocketStatus[menu][0] != target) - _pocketStatus[menu][0] += direction; - - if (complete) - _menuStatus[menu] = nextState; - } - } - - for (menu = RDMENU_TOP; menu <= RDMENU_BOTTOM; menu++) { - if (_menuStatus[menu] == RDMENU_HIDDEN) - continue; - - if (_menuStatus[menu] == RDMENU_ALMOST_HIDDEN) - _menuStatus[menu] = RDMENU_HIDDEN; - - // Draw the menu here. - int32 curx = RDMENU_ICONSTART + RDMENU_ICONWIDE / 2; - int32 cury = (MENUDEEP / 2) + (RENDERDEEP + MENUDEEP) * menu; - - for (i = 0; i < RDMENU_MAXPOCKETS; i++) { - if (_icons[menu][i]) { - int32 xoff, yoff; - - // Since we no longer clear the screen after - // each frame we need to clear the icon area. - - clearIconArea(menu, i, &r1); - - if (_pocketStatus[menu][i] == MAXMENUANIMS) { - xoff = (RDMENU_ICONWIDE / 2); - r2.left = curx - xoff; - r2.right = r2.left + RDMENU_ICONWIDE; - yoff = (RDMENU_ICONDEEP / 2); - r2.top = cury - yoff; - r2.bottom = r2.top + RDMENU_ICONDEEP; - } else { - xoff = (RDMENU_ICONWIDE / 2) * _pocketStatus[menu][i] / MAXMENUANIMS; - r2.left = curx - xoff; - r2.right = curx + xoff; - yoff = (RDMENU_ICONDEEP / 2) * _pocketStatus[menu][i] / MAXMENUANIMS; - r2.top = cury - yoff; - r2.bottom = cury + yoff; - } - - if (xoff != 0 && yoff != 0) { - byte *dst = buf + r2.top * screenWide + r2.left; - byte *src = _icons[menu][i]; - - if (_pocketStatus[menu][i] != MAXMENUANIMS) { - _vm->_screen->scaleImageFast( - dst, screenWide, r2.right - r2.left, r2.bottom - r2.top, - src, RDMENU_ICONWIDE, RDMENU_ICONWIDE, RDMENU_ICONDEEP); - } else { - for (j = 0; j < RDMENU_ICONDEEP; j++) { - memcpy(dst, src, RDMENU_ICONWIDE); - src += RDMENU_ICONWIDE; - dst += screenWide; - } - } - } - _vm->_screen->updateRect(&r1); - } - curx += (RDMENU_ICONSPACING + RDMENU_ICONWIDE); - } - } -} - -/** - * This function brings a specified menu into view. - * @param menu RDMENU_TOP or RDMENU_BOTTOM, depending on which menu to show - * @return RD_OK, or an error code - */ - -int32 Mouse::showMenu(uint8 menu) { - // Check for invalid menu parameter - if (menu > RDMENU_BOTTOM) - return RDERR_INVALIDMENU; - - // Check that the menu is not currently shown, or in the process of - // being shown. - if (_menuStatus[menu] == RDMENU_SHOWN || _menuStatus[menu] == RDMENU_OPENING) - return RDERR_INVALIDCOMMAND; - - _menuStatus[menu] = RDMENU_OPENING; - return RD_OK; -} - -/** - * This function hides a specified menu. - * @param menu RDMENU_TOP or RDMENU_BOTTOM depending on which menu to hide - * @return RD_OK, or an error code - */ - -int32 Mouse::hideMenu(uint8 menu) { - // Check for invalid menu parameter - if (menu > RDMENU_BOTTOM) - return RDERR_INVALIDMENU; - - // Check that the menu is not currently hidden, or in the process of - // being hidden. - if (_menuStatus[menu] == RDMENU_HIDDEN || _menuStatus[menu] == RDMENU_CLOSING) - return RDERR_INVALIDCOMMAND; - - _menuStatus[menu] = RDMENU_CLOSING; - return RD_OK; -} - -/** - * This function hides both menus immediately. - */ - -void Mouse::closeMenuImmediately() { - Common::Rect r; - int i; - - _menuStatus[RDMENU_TOP] = RDMENU_HIDDEN; - _menuStatus[RDMENU_BOTTOM] = RDMENU_HIDDEN; - - for (i = 0; i < RDMENU_MAXPOCKETS; i++) { - if (_icons[RDMENU_TOP][i]) { - clearIconArea(RDMENU_TOP, i, &r); - _vm->_screen->updateRect(&r); - } - if (_icons[RDMENU_BOTTOM][i]) { - clearIconArea(RDMENU_BOTTOM, i, &r); - _vm->_screen->updateRect(&r); - } - } - - memset(_pocketStatus, 0, sizeof(uint8) * 2 * RDMENU_MAXPOCKETS); -} - -/** - * This function sets a menubar icon. - * @param menu RDMENU_TOP or RDMENU_BOTTOM, depending on which menu to change - * @param pocket the menu pocket to change - * @param icon icon data, or NULL to clear the icon - * @return RD_OK, or an error code - */ - -int32 Mouse::setMenuIcon(uint8 menu, uint8 pocket, byte *icon) { - Common::Rect r; - - // Check for invalid menu parameter. - if (menu > RDMENU_BOTTOM) - return RDERR_INVALIDMENU; - - // Check for invalid pocket parameter - if (pocket >= RDMENU_MAXPOCKETS) - return RDERR_INVALIDPOCKET; - - // If there is an icon in the requested menu/pocket, clear it out. - if (_icons[menu][pocket]) { - _iconCount--; - free(_icons[menu][pocket]); - _icons[menu][pocket] = NULL; - clearIconArea(menu, pocket, &r); - _vm->_screen->updateRect(&r); - } - - // Only put the icon in the pocket if it is not NULL - if (icon != NULL) { - _iconCount++; - _icons[menu][pocket] = (byte *)malloc(RDMENU_ICONWIDE * RDMENU_ICONDEEP); - if (_icons[menu][pocket] == NULL) - return RDERR_OUTOFMEMORY; - memcpy(_icons[menu][pocket], icon, RDMENU_ICONWIDE * RDMENU_ICONDEEP); - } - - return RD_OK; -} - -} // End of namespace Sword2 diff --git a/sword2/module.mk b/sword2/module.mk deleted file mode 100644 index fb020ba633..0000000000 --- a/sword2/module.mk +++ /dev/null @@ -1,48 +0,0 @@ -MODULE := sword2 - -MODULE_OBJS := \ - sword2/_mouse.o \ - sword2/animation.o \ - sword2/anims.o \ - sword2/build_display.o \ - sword2/console.o \ - sword2/controls.o \ - sword2/d_draw.o \ - sword2/debug.o \ - sword2/events.o \ - sword2/function.o \ - sword2/icons.o \ - sword2/interpreter.o \ - sword2/layers.o \ - sword2/logic.o \ - sword2/maketext.o \ - sword2/memory.o \ - sword2/menu.o \ - sword2/mouse.o \ - sword2/music.o \ - sword2/palette.o \ - sword2/protocol.o \ - sword2/rdwin.o \ - sword2/render.o \ - sword2/resman.o \ - sword2/router.o \ - sword2/save_rest.o \ - sword2/scroll.o \ - sword2/sound.o \ - sword2/speech.o \ - sword2/sprite.o \ - sword2/startup.o \ - sword2/sword2.o \ - sword2/sync.o \ - sword2/walker.o - -MODULE_DIRS += \ - sword2 - -# This module can be built as a plugin -ifdef BUILD_PLUGINS -PLUGIN := 1 -endif - -# Include common rules -include $(srcdir)/common.rules diff --git a/sword2/mouse.cpp b/sword2/mouse.cpp deleted file mode 100644 index f8c315a47f..0000000000 --- a/sword2/mouse.cpp +++ /dev/null @@ -1,1437 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "sword2/sword2.h" -#include "sword2/console.h" -#include "sword2/controls.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/maketext.h" -#include "sword2/mouse.h" -#include "sword2/resman.h" -#include "sword2/sound.h" - -namespace Sword2 { - -// Pointer resource id's - -enum { - CROSHAIR = 18, - EXIT0 = 788, - EXIT1 = 789, - EXIT2 = 790, - EXIT3 = 791, - EXIT4 = 792, - EXIT5 = 793, - EXIT6 = 794, - EXIT7 = 795, - EXITDOWN = 796, - EXITUP = 797, - MOUTH = 787, - NORMAL = 17, - PICKUP = 3099, - SCROLL_L = 1440, - SCROLL_R = 1441, - USE = 3100 -}; - -Mouse::Mouse(Sword2Engine *vm) { - _vm = vm; - - setPos(0, 0); - resetMouseList(); - - _mouseTouching = 0; - _oldMouseTouching = 0; - _menuSelectedPos = 0; - _examiningMenuIcon = false; - _mousePointerRes = 0; - _mouseMode = 0; - _mouseStatus = false; - _mouseModeLocked = false; - _currentLuggageResource = 0; - _oldButton = 0; - _buttonClick = 0; - _pointerTextBlocNo = 0; - _playerActivityDelay = 0; - _realLuggageItem = 0; - - _mouseAnim.data = NULL; - _luggageAnim.data = NULL; - - // For the menus - _totalTemp = 0; - memset(_tempList, 0, sizeof(_tempList)); - - _totalMasters = 0; - memset(_masterMenuList, 0, sizeof(_masterMenuList)); - memset(_mouseList, 0, sizeof(_mouseList)); - memset(_subjectList, 0, sizeof(_subjectList)); - - _defaultResponseId = 0; - _choosing = false; - - _iconCount = 0; - - for (int i = 0; i < 2; i++) { - for (int j = 0; j < RDMENU_MAXPOCKETS; j++) { - _icons[i][j] = NULL; - _pocketStatus[i][j] = 0; - } - - _menuStatus[i] = RDMENU_HIDDEN; - } -} - -Mouse::~Mouse() { - free(_mouseAnim.data); - free(_luggageAnim.data); - for (int i = 0; i < 2; i++) - for (int j = 0; j < RDMENU_MAXPOCKETS; j++) - free(_icons[i][j]); -} - -void Mouse::getPos(int &x, int &y) { - x = _pos.x; - y = _pos.y; -} - -void Mouse::setPos(int x, int y) { - _pos.x = x; - _pos.y = y; -} - -/** - * Call at beginning of game loop - */ - -void Mouse::resetMouseList() { - _curMouse = 0; -} - -void Mouse::registerMouse(byte *ob_mouse, BuildUnit *build_unit) { - assert(_curMouse < TOTAL_mouse_list); - - ObjectMouse mouse; - - mouse.read(ob_mouse); - - if (!mouse.pointer) - return; - - if (build_unit) { - _mouseList[_curMouse].rect.left = build_unit->x; - _mouseList[_curMouse].rect.top = build_unit->y; - _mouseList[_curMouse].rect.right = 1 + build_unit->x + build_unit->scaled_width; - _mouseList[_curMouse].rect.bottom = 1 + build_unit->y + build_unit->scaled_height; - } else { - _mouseList[_curMouse].rect.left = mouse.x1; - _mouseList[_curMouse].rect.top = mouse.y1; - _mouseList[_curMouse].rect.right = 1 + mouse.x2; - _mouseList[_curMouse].rect.bottom = 1 + mouse.y2; - } - - _mouseList[_curMouse].priority = mouse.priority; - _mouseList[_curMouse].pointer = mouse.pointer; - - // Change all COGS pointers to CROSHAIR. I'm guessing that this was a - // design decision made in mid-development and they didn't want to go - // back and re-generate the resource files. - - if (_mouseList[_curMouse].pointer == USE) - _mouseList[_curMouse].pointer = CROSHAIR; - - // Check if pointer text field is set due to previous object using this - // slot (ie. not correct for this one) - - // If 'pointer_text' field is set, but the 'id' field isn't same is - // current id then we don't want this "left over" pointer text - - if (_mouseList[_curMouse].pointer_text && _mouseList[_curMouse].id != (int32)_vm->_logic->readVar(ID)) - _mouseList[_curMouse].pointer_text = 0; - - // Get id from system variable 'id' which is correct for current object - _mouseList[_curMouse].id = _vm->_logic->readVar(ID); - - _curMouse++; -} - -void Mouse::registerPointerText(int32 text_id) { - assert(_curMouse < TOTAL_mouse_list); - - // current object id - used for checking pointer_text when mouse area - // registered (in fnRegisterMouse and fnRegisterFrame) - - _mouseList[_curMouse].id = _vm->_logic->readVar(ID); - _mouseList[_curMouse].pointer_text = text_id; -} - -/** - * This function is called every game cycle. - */ - -void Mouse::mouseEngine() { - monitorPlayerActivity(); - clearPointerText(); - - // If George is dead, the system menu is visible all the time, and is - // the only thing that can be used. - - if (_vm->_logic->readVar(DEAD)) { - if (_mouseMode != MOUSE_system_menu) { - _mouseMode = MOUSE_system_menu; - - if (_mouseTouching) { - _oldMouseTouching = 0; - _mouseTouching = 0; - } - - setMouse(NORMAL_MOUSE_ID); - buildSystemMenu(); - } - systemMenuMouse(); - return; - } - - // If the mouse is not visible, do nothing - - if (_mouseStatus) - return; - - switch (_mouseMode) { - case MOUSE_normal: - normalMouse(); - break; - case MOUSE_menu: - menuMouse(); - break; - case MOUSE_drag: - dragMouse(); - break; - case MOUSE_system_menu: - systemMenuMouse(); - break; - case MOUSE_holding: - if (_pos.y < 400) { - _mouseMode = MOUSE_normal; - debug(5, " releasing"); - } - break; - default: - break; - } -} - -#if RIGHT_CLICK_CLEARS_LUGGAGE -bool Mouse::heldIsInInventory() { - int32 object_held = (int32)_vm->_logic->readVar(OBJECT_HELD); - - for (uint i = 0; i < _totalMasters; i++) { - if (_masterMenuList[i].icon_resource == object_held) - return true; - } - return false; -} -#endif - -int Mouse::menuClick(int menu_items) { - if (_pos.x < RDMENU_ICONSTART) - return -1; - - if (_pos.x > RDMENU_ICONSTART + menu_items * (RDMENU_ICONWIDE + RDMENU_ICONSPACING) - RDMENU_ICONSPACING) - return -1; - - return (_pos.x - RDMENU_ICONSTART) / (RDMENU_ICONWIDE + RDMENU_ICONSPACING); -} - -void Mouse::systemMenuMouse() { - uint32 safe_looping_music_id; - MouseEvent *me; - int hit; - byte *icon; - int32 pars[2]; - uint32 icon_list[5] = { - OPTIONS_ICON, - QUIT_ICON, - SAVE_ICON, - RESTORE_ICON, - RESTART_ICON - }; - - // If the mouse is moved off the menu, close it. Unless the player is - // dead, in which case the menu should always be visible. - - if (_pos.y > 0 && !_vm->_logic->readVar(DEAD)) { - _mouseMode = MOUSE_normal; - hideMenu(RDMENU_TOP); - return; - } - - // Check if the user left-clicks anywhere in the menu area. - - me = _vm->mouseEvent(); - - if (!me || !(me->buttons & RD_LEFTBUTTONDOWN)) - return; - - if (_pos.y > 0) - return; - - hit = menuClick(ARRAYSIZE(icon_list)); - - if (hit < 0) - return; - - // No save when dead - - if (icon_list[hit] == SAVE_ICON && _vm->_logic->readVar(DEAD)) - return; - - // Gray out all he icons, except the one that was clicked - - for (int i = 0; i < ARRAYSIZE(icon_list); i++) { - if (i != hit) { - icon = _vm->_resman->openResource(icon_list[i]) + ResHeader::size(); - setMenuIcon(RDMENU_TOP, i, icon); - _vm->_resman->closeResource(icon_list[i]); - } - } - - _vm->_sound->pauseFx(); - - // NB. Need to keep a safe copy of '_loopingMusicId' for savegame & for - // playing when returning from control panels because control panel - // music will overwrite it! - - safe_looping_music_id = _vm->_sound->getLoopingMusicId(); - - pars[0] = 221; - pars[1] = FX_LOOP; - _vm->_logic->fnPlayMusic(pars); - - // HACK: Restore proper looping_music_id - _vm->_sound->setLoopingMusicId(safe_looping_music_id); - - processMenu(); - - // call the relevant screen - - switch (hit) { - case 0: - { - OptionsDialog dialog(_vm); - dialog.runModal(); - } - break; - case 1: - { - QuitDialog dialog(_vm); - dialog.runModal(); - } - break; - case 2: - { - SaveDialog dialog(_vm); - dialog.runModal(); - } - break; - case 3: - { - RestoreDialog dialog(_vm); - dialog.runModal(); - } - break; - case 4: - { - RestartDialog dialog(_vm); - dialog.runModal(); - } - break; - } - - // Menu stays open on death screen. Otherwise it's closed. - - if (!_vm->_logic->readVar(DEAD)) { - _mouseMode = MOUSE_normal; - hideMenu(RDMENU_TOP); - } else { - setMouse(NORMAL_MOUSE_ID); - buildSystemMenu(); - } - - // Back to the game again - - processMenu(); - - // Reset game palette, but not after a successful restore or restart! - // See RestoreFromBuffer() in save_rest.cpp - - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - if (screenInfo->new_palette != 99) { - // 0 means put back game screen palette; see build_display.cpp - _vm->_screen->setFullPalette(0); - - // Stop the engine fading in the restored screens palette - screenInfo->new_palette = 0; - } else - screenInfo->new_palette = 1; - - _vm->_sound->unpauseFx(); - - // If there was looping music before coming into the control panels - // then restart it! NB. If a game has been restored the music will be - // restarted twice, but this shouldn't cause any harm. - - if (_vm->_sound->getLoopingMusicId()) { - pars[0] = _vm->_sound->getLoopingMusicId(); - pars[1] = FX_LOOP; - _vm->_logic->fnPlayMusic(pars); - } else - _vm->_logic->fnStopMusic(NULL); -} - -void Mouse::dragMouse() { - byte buf1[NAME_LEN], buf2[NAME_LEN]; - MouseEvent *me; - int hit; - - // We can use dragged object both on other inventory objects, or on - // objects in the scene, so if the mouse moves off the inventory menu, - // then close it. - - if (_pos.y < 400) { - _mouseMode = MOUSE_normal; - hideMenu(RDMENU_BOTTOM); - return; - } - - // Handles cursors and the luggage on/off according to type - - mouseOnOff(); - - // Now do the normal click stuff - - me = _vm->mouseEvent(); - - if (!me) - return; - -#if RIGHT_CLICK_CLEARS_LUGGAGE - if ((me->buttons & RD_RIGHTBUTTONDOWN) && heldIsInInventory()) { - _vm->_logic->writeVar(OBJECT_HELD, 0); - _menuSelectedPos = 0; - _mouseMode = MOUSE_menu; - setLuggage(0); - buildMenu(); - return; - } -#endif - - if (!(me->buttons & RD_LEFTBUTTONDOWN)) - return; - - // there's a mouse event to be processed - - // could be clicking on an on screen object or on the menu - // which is currently displayed - - if (_mouseTouching) { - // mouse is over an on screen object - and we have luggage - - // Depending on type we'll maybe kill the object_held - like - // for exits - - // Set global script variable 'button'. We know that it was the - // left button, not the right one. - - _vm->_logic->writeVar(LEFT_BUTTON, 1); - _vm->_logic->writeVar(RIGHT_BUTTON, 0); - - // These might be required by the action script about to be run - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - _vm->_logic->writeVar(MOUSE_X, _pos.x + screenInfo->scroll_offset_x); - _vm->_logic->writeVar(MOUSE_Y, _pos.y + screenInfo->scroll_offset_y); - - // For scripts to know what's been clicked. First used for - // 'room_13_turning_script' in object 'biscuits_13' - - _vm->_logic->writeVar(CLICKED_ID, _mouseTouching); - - _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, _mouseTouching); - - debug(2, "Used \"%s\" on \"%s\"", - _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf1), - _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID), buf2)); - - // Hide menu - back to normal menu mode - - hideMenu(RDMENU_BOTTOM); - _mouseMode = MOUSE_normal; - - return; - } - - // Better check for combine/cancel. Cancel puts us back in MOUSE_menu - // mode - - hit = menuClick(TOTAL_engine_pockets); - - if (hit < 0 || !_masterMenuList[hit].icon_resource) - return; - - // Always back into menu mode. Remove the luggage as well. - - _mouseMode = MOUSE_menu; - setLuggage(0); - - if ((uint)hit == _menuSelectedPos) { - // If we clicked on the same icon again, reset the first icon - - _vm->_logic->writeVar(OBJECT_HELD, 0); - _menuSelectedPos = 0; - } else { - // Otherwise, combine the two icons - - _vm->_logic->writeVar(COMBINE_BASE, _masterMenuList[hit].icon_resource); - _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, MENU_MASTER_OBJECT); - - // Turn off mouse now, to prevent player trying to click - // elsewhere BUT leave the bottom menu open - - hideMouse(); - - debug(2, "Used \"%s\" on \"%s\"", - _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf1), - _vm->_resman->fetchName(_vm->_logic->readVar(COMBINE_BASE), buf2)); - } - - // Refresh the menu - - buildMenu(); -} - -void Mouse::menuMouse() { - byte buf[NAME_LEN]; - MouseEvent *me; - int hit; - - // If the mouse is moved off the menu, close it. - - if (_pos.y < 400) { - _mouseMode = MOUSE_normal; - hideMenu(RDMENU_BOTTOM); - return; - } - - me = _vm->mouseEvent(); - - if (!me) - return; - - hit = menuClick(TOTAL_engine_pockets); - - // Check if we clicked on an actual icon. - - if (hit < 0 || !_masterMenuList[hit].icon_resource) - return; - - if (me->buttons & RD_RIGHTBUTTONDOWN) { - // Right button - examine an object, identified by its icon - // resource id. - - _examiningMenuIcon = true; - _vm->_logic->writeVar(OBJECT_HELD, _masterMenuList[hit].icon_resource); - - // Must clear this so next click on exit becomes 1st click - // again - - _vm->_logic->writeVar(EXIT_CLICK_ID, 0); - - _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, MENU_MASTER_OBJECT); - - // Refresh the menu - - buildMenu(); - - // Turn off mouse now, to prevent player trying to click - // elsewhere BUT leave the bottom menu open - - hideMouse(); - - debug(2, "Right-click on \"%s\" icon", - _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf)); - - return; - } - - if (me->buttons & RD_LEFTBUTTONDOWN) { - // Left button - bung us into drag luggage mode. The object is - // identified by its icon resource id. We need the luggage - // resource id for mouseOnOff - - _mouseMode = MOUSE_drag; - - _menuSelectedPos = hit; - _vm->_logic->writeVar(OBJECT_HELD, _masterMenuList[hit].icon_resource); - _currentLuggageResource = _masterMenuList[hit].luggage_resource; - - // Must clear this so next click on exit becomes 1st click - // again - - _vm->_logic->writeVar(EXIT_CLICK_ID, 0); - - // Refresh the menu - - buildMenu(); - - setLuggage(_masterMenuList[hit].luggage_resource); - - debug(2, "Left-clicked on \"%s\" icon - switch to drag mode", - _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf)); - } -} - -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 - - MouseEvent *me; - - // Check if the cursor has moved onto the system menu area. No save in - // big-object menu lock situation, of if the player is dragging an - // object. - - if (_pos.y < 0 && !_mouseModeLocked && !_vm->_logic->readVar(OBJECT_HELD)) { - _mouseMode = MOUSE_system_menu; - - if (_mouseTouching) { - // We were on something, but not anymore - _oldMouseTouching = 0; - _mouseTouching = 0; - } - - // Reset mouse cursor - in case we're between mice - - setMouse(NORMAL_MOUSE_ID); - buildSystemMenu(); - return; - } - - // Check if the cursor has moved onto the inventory menu area. No - // inventory in big-object menu lock situation, - - if (_pos.y > 399 && !_mouseModeLocked) { - // If an object is being held, i.e. if the mouse cursor has a - // luggage, go to drag mode instead of menu mode, but the menu - // is still opened. - // - // That way, we can still use an object on another inventory - // object, even if the inventory menu was closed after the - // first object was selected. - - if (!_vm->_logic->readVar(OBJECT_HELD)) - _mouseMode = MOUSE_menu; - else - _mouseMode = MOUSE_drag; - - // If mouse is moving off an object and onto the menu then do a - // standard get-off - - if (_mouseTouching) { - _oldMouseTouching = 0; - _mouseTouching = 0; - } - - // Reset mouse cursor - - setMouse(NORMAL_MOUSE_ID); - buildMenu(); - return; - } - - // Check for moving the mouse on or off things - - mouseOnOff(); - - me = _vm->mouseEvent(); - - if (!me) - return; - - bool button_down = (me->buttons & (RD_LEFTBUTTONDOWN | RD_RIGHTBUTTONDOWN)) != 0; - - // For debugging. We can draw a rectangle on the screen and see its - // coordinates. This was probably used to help defining hit areas. - - if (_vm->_debugger->_definingRectangles) { - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - if (_vm->_debugger->_draggingRectangle == 0) { - // Not yet dragging a rectangle, so need click to start - - if (button_down) { - // set both (x1,y1) and (x2,y2) to this point - _vm->_debugger->_rectX1 = _vm->_debugger->_rectX2 = (uint32)_pos.x + screenInfo->scroll_offset_x; - _vm->_debugger->_rectY1 = _vm->_debugger->_rectY2 = (uint32)_pos.y + screenInfo->scroll_offset_y; - _vm->_debugger->_draggingRectangle = 1; - } - } else if (_vm->_debugger->_draggingRectangle == 1) { - // currently dragging a rectangle - click means reset - - if (button_down) { - // lock rectangle, so you can let go of mouse - // to type in the coords - _vm->_debugger->_draggingRectangle = 2; - } else { - // drag rectangle - _vm->_debugger->_rectX2 = (uint32)_pos.x + screenInfo->scroll_offset_x; - _vm->_debugger->_rectY2 = (uint32)_pos.y + screenInfo->scroll_offset_y; - } - } else { - // currently locked to avoid knocking out of place - // while reading off the coords - - if (button_down) { - // click means reset - back to start again - _vm->_debugger->_draggingRectangle = 0; - } - } - - return; - } - -#if RIGHT_CLICK_CLEARS_LUGGAGE - if (_vm->_logic->readVar(OBJECT_HELD) && (me->buttons & RD_RIGHTBUTTONDOWN) && heldIsInInventory()) { - _vm->_logic->writeVar(OBJECT_HELD, 0); - _menuSelectedPos = 0; - setLuggage(0); - return; - } -#endif - - // Now do the normal click stuff - - // We only care about down clicks when the mouse is over an object. - - if (!_mouseTouching || !button_down) - return; - - // There's a mouse event to be processed and the mouse is on something. - // Notice that the floor itself is considered an object. - - // There are no menus about so its nice and simple. This is as close to - // the old advisor_188 script as we get, I'm sorry to say. - - // If player is walking or relaxing then those need to terminate - // correctly. Otherwise set player run the targets action script or, do - // a special walk if clicking on the scroll-more icon - - // PLAYER_ACTION script variable - whatever catches this must reset to - // 0 again - // _vm->_logic->writeVar(PLAYER_ACTION, _mouseTouching); - - // Idle or router-anim will catch it - - // Set global script variable 'button' - - if (me->buttons & RD_LEFTBUTTONDOWN) { - _vm->_logic->writeVar(LEFT_BUTTON, 1); - _vm->_logic->writeVar(RIGHT_BUTTON, 0); - _buttonClick = 0; // for re-click - } else { - _vm->_logic->writeVar(LEFT_BUTTON, 0); - _vm->_logic->writeVar(RIGHT_BUTTON, 1); - _buttonClick = 1; // for re-click - } - - // These might be required by the action script about to be run - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - _vm->_logic->writeVar(MOUSE_X, _pos.x + screenInfo->scroll_offset_x); - _vm->_logic->writeVar(MOUSE_Y, _pos.y + screenInfo->scroll_offset_y); - - if (_mouseTouching == _vm->_logic->readVar(EXIT_CLICK_ID) && (me->buttons & RD_LEFTBUTTONDOWN)) { - // It's the exit double click situation. Let the existing - // interaction continue and start fading down. Switch the human - // off too - - noHuman(); - _vm->_logic->fnFadeDown(NULL); - - // Tell the walker - - _vm->_logic->writeVar(EXIT_FADING, 1); - } else if (_oldButton == _buttonClick && _mouseTouching == _vm->_logic->readVar(CLICKED_ID) && _mousePointerRes != NORMAL_MOUSE_ID) { - // Re-click. Do nothing, except on floors - } else { - // For re-click - - _oldButton = _buttonClick; - - // For scripts to know what's been clicked. First used for - // 'room_13_turning_script' in object 'biscuits_13' - - _vm->_logic->writeVar(CLICKED_ID, _mouseTouching); - - // Must clear these two double-click control flags - do it here - // so reclicks after exit clicks are cleared up - - _vm->_logic->writeVar(EXIT_CLICK_ID, 0); - _vm->_logic->writeVar(EXIT_FADING, 0); - - _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, _mouseTouching); - - byte buf1[NAME_LEN], buf2[NAME_LEN]; - - if (_vm->_logic->readVar(OBJECT_HELD)) - debug(2, "Used \"%s\" on \"%s\"", - _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf1), - _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID), buf2)); - else if (_vm->_logic->readVar(LEFT_BUTTON)) - debug(2, "Left-clicked on \"%s\"", - _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID), buf1)); - else // RIGHT BUTTON - debug(2, "Right-clicked on \"%s\"", - _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID), buf1)); - } -} - -uint32 Mouse::chooseMouse() { - // Unlike the other mouse "engines", this one is called directly by the - // fnChoose() opcode. - - uint i; - - _vm->_logic->writeVar(AUTO_SELECTED, 0); - - uint32 in_subject = _vm->_logic->readVar(IN_SUBJECT); - uint32 object_held = _vm->_logic->readVar(OBJECT_HELD); - - if (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 < in_subject; i++) { - if (_subjectList[i].res == object_held) { - response = _subjectList[i].ref; - break; - } - } - - // The user won't be holding the object any more, and the - // conversation menu will be closed. - - _vm->_logic->writeVar(OBJECT_HELD, 0); - _vm->_logic->writeVar(IN_SUBJECT, 0); - return response; - } - - if (_vm->_logic->readVar(CHOOSER_COUNT_FLAG) == 0 && 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. - - _vm->_logic->writeVar(AUTO_SELECTED, 1); - _vm->_logic->writeVar(IN_SUBJECT, 0); - return _subjectList[0].ref; - } - - byte *icon; - - if (!_choosing) { - // This is a new conversation menu. - - if (!in_subject) - error("fnChoose with no subjects"); - - for (i = 0; i < in_subject; i++) { - icon = _vm->_resman->openResource(_subjectList[i].res) + ResHeader::size() + 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(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 < in_subject; i++) { - if ((int)i != hit) { - icon = _vm->_resman->openResource(_subjectList[i].res) + ResHeader::size(); - _vm->_mouse->setMenuIcon(RDMENU_BOTTOM, i, icon); - _vm->_resman->closeResource(_subjectList[i].res); - } - } - - // For non-speech scripts that manually call the chooser - _vm->_logic->writeVar(RESULT, _subjectList[hit].res); - - // The conversation menu will be closed - - _choosing = false; - _vm->_logic->writeVar(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 - - uint32 pointer_type; - static uint8 mouse_flicked_off = 0; - - _oldMouseTouching = _mouseTouching; - - // don't detect objects that are hidden behind the menu bars (ie. in - // the scrolled-off areas of the screen) - - if (_pos.y < 0 || _pos.y > 399) { - pointer_type = 0; - _mouseTouching = 0; - } else { - // set '_mouseTouching' & return pointer_type - pointer_type = checkMouseList(); - } - - // same as previous cycle? - if (!mouse_flicked_off && _oldMouseTouching == _mouseTouching) { - // yes, so nothing to do - // BUT CARRY ON IF MOUSE WAS FLICKED OFF! - return; - } - - // can reset this now - mouse_flicked_off = 0; - - //the cursor has moved onto something - if (!_oldMouseTouching && _mouseTouching) { - // make a copy of the object we've moved onto because one day - // we'll move back off again! (but the list positioning could - // theoretically have changed) - - // we can only move onto something from being on nothing - we - // stop the system going from one to another when objects - // overlap - - _oldMouseTouching = _mouseTouching; - - // run get on - - if (pointer_type) { - // 'pointer_type' holds the resource id of the - // pointer anim - - setMouse(pointer_type); - - // setup luggage icon - if (_vm->_logic->readVar(OBJECT_HELD)) { - setLuggage(_currentLuggageResource); - } - } else { - byte buf[NAME_LEN]; - - error("ERROR: mouse.pointer==0 for object %d (%s) - update logic script!", _mouseTouching, _vm->_resman->fetchName(_mouseTouching, buf)); - } - } else if (_oldMouseTouching && !_mouseTouching) { - // the cursor has moved off something - reset cursor to - // normal pointer - - _oldMouseTouching = 0; - setMouse(NORMAL_MOUSE_ID); - - // reset luggage only when necessary - } else if (_oldMouseTouching && _mouseTouching) { - // The cursor has moved off something and onto something - // else. Flip to a blank cursor for a cycle. - - // ignore the new id this cycle - should hit next cycle - _mouseTouching = 0; - _oldMouseTouching = 0; - setMouse(0); - - // so we know to set the mouse pointer back to normal if 2nd - // hot-spot doesn't register because mouse pulled away - // quickly (onto nothing) - - mouse_flicked_off = 1; - - // reset luggage only when necessary - } else { - // Mouse was flicked off for one cycle, but then moved onto - // nothing before 2nd hot-spot registered - - // both '_oldMouseTouching' & '_mouseTouching' will be zero - // reset cursor to normal pointer - - setMouse(NORMAL_MOUSE_ID); - } - - // possible check for edge of screen more-to-scroll here on large - // screens -} - -void Mouse::setMouse(uint32 res) { - // high level - whats the mouse - for the engine - _mousePointerRes = res; - - if (res) { - byte *icon = _vm->_resman->openResource(res) + ResHeader::size(); - uint32 len = _vm->_resman->fetchLen(res) - ResHeader::size(); - - // don't pulse the normal pointer - just do the regular anim - // loop - - if (res == NORMAL_MOUSE_ID) - setMouseAnim(icon, len, RDMOUSE_NOFLASH); - else - setMouseAnim(icon, len, RDMOUSE_FLASH); - - _vm->_resman->closeResource(res); - } else { - // blank cursor - setMouseAnim(NULL, 0, 0); - } -} - -void Mouse::setLuggage(uint32 res) { - _realLuggageItem = res; - - if (res) { - byte *icon = _vm->_resman->openResource(res) + ResHeader::size(); - uint32 len = _vm->_resman->fetchLen(res) - ResHeader::size(); - - setLuggageAnim(icon, len); - _vm->_resman->closeResource(res); - } else - setLuggageAnim(NULL, 0); -} - -void Mouse::setObjectHeld(uint32 res) { - setLuggage(res); - - _vm->_logic->writeVar(OBJECT_HELD, res); - _currentLuggageResource = res; - - // mode locked - no menu available - _mouseModeLocked = true; -} - -uint32 Mouse::checkMouseList() { - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - Common::Point mousePos(_pos.x + screenInfo->scroll_offset_x, _pos.y + screenInfo->scroll_offset_y); - - // Number of priorities subject to implementation needs - for (int priority = 0; priority < 10; priority++) { - for (uint i = 0; i < _curMouse; i++) { - // If the mouse pointer is over this - // mouse-detection-box - - if (_mouseList[i].priority == priority && _mouseList[i].rect.contains(mousePos)) { - // Record id - _mouseTouching = _mouseList[i].id; - - createPointerText(_mouseList[i].pointer_text, _mouseList[i].pointer); - - // Return pointer type - return _mouseList[i].pointer; - } - } - } - - // Touching nothing; no pointer to return - _mouseTouching = 0; - return 0; -} - -#define POINTER_TEXT_WIDTH 640 // just in case! -#define POINTER_TEXT_PEN 184 // white - -void Mouse::createPointerText(uint32 text_id, uint32 pointer_res) { - uint32 local_text; - uint32 text_res; - byte *text; - // offsets for pointer text sprite from pointer position - int16 xOffset, yOffset; - uint8 justification; - - if (!_objectLabels || !text_id) - return; - - // Check what the pointer is, to set offsets correctly for text - // position - - switch (pointer_res) { - case CROSHAIR: - yOffset = -7; - xOffset = +10; - break; - case EXIT0: - yOffset = +15; - xOffset = +20; - break; - case EXIT1: - yOffset = +16; - xOffset = -10; - break; - case EXIT2: - yOffset = +10; - xOffset = -22; - break; - case EXIT3: - yOffset = -16; - xOffset = -10; - break; - case EXIT4: - yOffset = -15; - xOffset = +15; - break; - case EXIT5: - yOffset = -12; - xOffset = +10; - break; - case EXIT6: - yOffset = +10; - xOffset = +25; - break; - case EXIT7: - yOffset = +16; - xOffset = +20; - break; - case EXITDOWN: - yOffset = -20; - xOffset = -10; - break; - case EXITUP: - yOffset = +20; - xOffset = +20; - break; - case MOUTH: - yOffset = -10; - xOffset = +15; - break; - case NORMAL: - yOffset = -10; - xOffset = +15; - break; - case PICKUP: - yOffset = -40; - xOffset = +10; - break; - case SCROLL_L: - yOffset = -20; - xOffset = +20; - break; - case SCROLL_R: - yOffset = -20; - xOffset = -20; - break; - case USE: - yOffset = -8; - xOffset = +20; - break; - default: - // Shouldn't happen if we cover all the different mouse - // pointers above - yOffset = -10; - xOffset = +10; - break; - } - - // Set up justification for text sprite, based on its offsets from the - // pointer position - - if (yOffset < 0) { - // Above pointer - if (xOffset < 0) { - // Above left - justification = POSITION_AT_RIGHT_OF_BASE; - } else if (xOffset > 0) { - // Above right - justification = POSITION_AT_LEFT_OF_BASE; - } else { - // Above centre - justification = POSITION_AT_CENTRE_OF_BASE; - } - } else if (yOffset > 0) { - // Below pointer - if (xOffset < 0) { - // Below left - justification = POSITION_AT_RIGHT_OF_TOP; - } else if (xOffset > 0) { - // Below right - justification = POSITION_AT_LEFT_OF_TOP; - } else { - // Below centre - justification = POSITION_AT_CENTRE_OF_TOP; - } - } else { - // Same y-coord as pointer - if (xOffset < 0) { - // Centre left - justification = POSITION_AT_RIGHT_OF_CENTRE; - } else if (xOffset > 0) { - // Centre right - justification = POSITION_AT_LEFT_OF_CENTRE; - } else { - // Centre centre - shouldn't happen anyway! - justification = POSITION_AT_LEFT_OF_CENTRE; - } - } - - // Text resource number, and line number within the resource - - text_res = text_id / SIZE; - local_text = text_id & 0xffff; - - // open text file & get the line - text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text); - - // 'text+2' to skip the first 2 bytes which form the - // line reference number - - _pointerTextBlocNo = _vm->_fontRenderer->buildNewBloc( - text + 2, _pos.x + xOffset, - _pos.y + yOffset, - POINTER_TEXT_WIDTH, POINTER_TEXT_PEN, - RDSPR_TRANS | RDSPR_DISPLAYALIGN, - _vm->_speechFontId, justification); - - // now ok to close the text file - _vm->_resman->closeResource(text_res); -} - -void Mouse::clearPointerText() { - if (_pointerTextBlocNo) { - _vm->_fontRenderer->killTextBloc(_pointerTextBlocNo); - _pointerTextBlocNo = 0; - } -} - -void Mouse::hideMouse() { - // leaves the menus open - // used by the system when clicking right on a menu item to examine - // it and when combining objects - - // for logic scripts - _vm->_logic->writeVar(MOUSE_AVAILABLE, 0); - - // human/mouse off - _mouseStatus = true; - - setMouse(0); - setLuggage(0); -} - -void Mouse::noHuman() { - hideMouse(); - clearPointerText(); - - // Must be normal mouse situation or a largely neutral situation - - // special menus use hideMouse() - - // Don't hide menu in conversations - if (_vm->_logic->readVar(TALK_FLAG) == 0) - hideMenu(RDMENU_BOTTOM); - - if (_mouseMode == MOUSE_system_menu) { - // Close menu - _mouseMode = MOUSE_normal; - hideMenu(RDMENU_TOP); - } -} - -void Mouse::addHuman() { - // For logic scripts - _vm->_logic->writeVar(MOUSE_AVAILABLE, 1); - - if (_mouseStatus) { - // Force engine to choose a cursor - _mouseStatus = false; - _mouseTouching = 1; - } - - // Clear this to reset no-second-click system - _vm->_logic->writeVar(CLICKED_ID, 0); - - // This is now done outside the OBJECT_HELD check in case it's set to - // zero before now! - - // Unlock the mouse from possible large object lock situtations - see - // syphon in rm 3 - - _mouseModeLocked = false; - - if (_vm->_logic->readVar(OBJECT_HELD)) { - // Was dragging something around - need to clear this again - _vm->_logic->writeVar(OBJECT_HELD, 0); - - // And these may also need clearing, just in case - _examiningMenuIcon = false; - _vm->_logic->writeVar(COMBINE_BASE, 0); - - setLuggage(0); - } - - // If mouse is over menu area - if (_pos.y > 399) { - if (_mouseMode != MOUSE_holding) { - // VITAL - reset things & rebuild the menu - _mouseMode = MOUSE_normal; - } - setMouse(NORMAL_MOUSE_ID); - } - - // Enabled/disabled from console; status printed with on-screen debug - // info - - if (_vm->_debugger->_testingSnR) { - uint8 black[4] = { 0, 0, 0, 0 }; - uint8 white[4] = { 255, 255, 255, 0 }; - - // Testing logic scripts by simulating instant Save & Restore - - _vm->_screen->setPalette(0, 1, white, RDPAL_INSTANT); - - // Stops all fx & clears the queue - eg. when leaving a room - _vm->_sound->clearFxQueue(); - - // Trash all object resources so they load in fresh & restart - // their logic scripts - - _vm->_resman->killAllObjects(false); - - _vm->_screen->setPalette(0, 1, black, RDPAL_INSTANT); - } -} - -void Mouse::refreshInventory() { - // Can reset this now - _vm->_logic->writeVar(COMBINE_BASE, 0); - - // Cause 'object_held' icon to be greyed. The rest are coloured. - _examiningMenuIcon = true; - buildMenu(); - _examiningMenuIcon = false; -} - -void Mouse::startConversation() { - if (_vm->_logic->readVar(TALK_FLAG) == 0) { - // See fnChooser & speech scripts - _vm->_logic->writeVar(CHOOSER_COUNT_FLAG, 0); - } - - noHuman(); -} - -void Mouse::endConversation() { - hideMenu(RDMENU_BOTTOM); - - if (_pos.y > 399) { - // Will wait for cursor to move off the bottom menu - _mouseMode = MOUSE_holding; - } - - // In case DC forgets - _vm->_logic->writeVar(TALK_FLAG, 0); -} - -void Mouse::monitorPlayerActivity() { - // if there is at least one mouse event outstanding - if (_vm->checkForMouseEvents()) { - // reset activity delay counter - _playerActivityDelay = 0; - } else { - // no. of game cycles since mouse event queue last empty - _playerActivityDelay++; - } -} - -void Mouse::checkPlayerActivity(uint32 seconds) { - // Convert seconds to game cycles - uint32 threshold = seconds * 12; - - // If the actual delay is at or above the given threshold, reset the - // activity delay counter now that we've got a positive check. - - if (_playerActivityDelay >= threshold) { - _playerActivityDelay = 0; - _vm->_logic->writeVar(RESULT, 1); - } else - _vm->_logic->writeVar(RESULT, 0); -} - -void Mouse::pauseGame() { - // Make the mouse cursor normal. This is the only place where we are - // allowed to clear the luggage this way. - - clearPointerText(); - setLuggageAnim(NULL, 0); - setMouse(0); - setMouseTouching(1); -} - -void Mouse::unpauseGame() { - if (_vm->_logic->readVar(OBJECT_HELD) && _realLuggageItem) - setLuggage(_realLuggageItem); -} - -} // End of namespace Sword2 diff --git a/sword2/mouse.h b/sword2/mouse.h deleted file mode 100644 index bed5e032ba..0000000000 --- a/sword2/mouse.h +++ /dev/null @@ -1,257 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef MOUSE_H -#define MOUSE_H - -#define MAX_SUBJECT_LIST 30 // is that enough? - -#define TOTAL_mouse_list 50 - -namespace Sword2 { - -struct BuildUnit; - -// Menubar defines. - -#define RDMENU_TOP 0 -#define RDMENU_BOTTOM 1 - -enum { - MOUSE_normal = 0, // normal in game - MOUSE_menu = 1, // menu chooser - MOUSE_drag = 2, // dragging luggage - MOUSE_system_menu = 3, // system menu chooser - MOUSE_holding = 4 // special -}; - -enum { - RDMOUSE_NOFLASH, - RDMOUSE_FLASH -}; - -enum { - RDMENU_HIDDEN, - RDMENU_SHOWN, - RDMENU_OPENING, - RDMENU_CLOSING, - RDMENU_ALMOST_HIDDEN -}; - -#define RDMENU_ICONWIDE 35 -#define RDMENU_ICONDEEP 30 -#define RDMENU_ICONSTART 24 -#define RDMENU_ICONSPACING 5 -#define RDMENU_MAXPOCKETS 15 - -#define MOUSE_ANIM_HEADER_SIZE 6 - -struct MouseAnim { - uint8 runTimeComp; // type of runtime compression used for the - // frame data - uint8 noAnimFrames; // number of frames in the anim - int8 xHotSpot; - int8 yHotSpot; - uint8 mousew; - uint8 mouseh; - - byte *data; -}; - -// The MOUSE_holding mode is entered when the conversation menu is closed, and -// exited when the mouse cursor moves off that menu area. I don't know why yet. - -// mouse unit - like ObjectMouse, but with anim resource & pc (needed if -// sprite is to act as mouse detection mask) - -struct MouseUnit { - // Basically the same information as in ObjectMouse, except the - // coordinates are adjusted to conform to standard ScummVM usage. - - Common::Rect rect; - int32 priority; - int32 pointer; - - // In addition, we need an id when checking the mouse list, and a - // text id for mouse-overs. - - int32 id; - int32 pointer_text; -}; - -// Array of these for subject menu build up - - struct SubjectUnit { - uint32 res; - uint32 ref; -}; - -class Mouse { -private: - Sword2Engine *_vm; - - Common::Point _pos; - - MouseUnit _mouseList[TOTAL_mouse_list]; - uint32 _curMouse; - - MenuObject _tempList[TOTAL_engine_pockets]; - uint32 _totalTemp; - - 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]; - - uint8 _iconCount; - - // If it's NORMAL_MOUSE_ID (ie. normal pointer) then it's over a floor - // area (or hidden hot-zone) - - uint32 _mousePointerRes; - - MouseAnim _mouseAnim; - MouseAnim _luggageAnim; - - uint8 _mouseFrame; - - uint32 _mouseMode; - - bool _mouseStatus; // Human 0 on/1 off - bool _mouseModeLocked; // 0 not !0 mode cannot be changed from - // normal mouse to top menu (i.e. when - // carrying big objects) - uint32 _realLuggageItem; // Last minute for pause mode - uint32 _currentLuggageResource; - uint32 _oldButton; // For the re-click stuff - must be - // the same button you see - uint32 _buttonClick; - uint32 _pointerTextBlocNo; - uint32 _playerActivityDelay; // Player activity delay counter - - bool _examiningMenuIcon; - - // Set by checkMouseList() - uint32 _mouseTouching; - uint32 _oldMouseTouching; - - bool _objectLabels; - - uint32 _menuSelectedPos; - - void decompressMouse(byte *decomp, byte *comp, uint8 frame, int width, int height, int pitch, int xOff = 0, int yOff = 0); - - int32 setMouseAnim(byte *ma, int32 size, int32 mouseFlash); - int32 setLuggageAnim(byte *la, int32 size); - - void clearIconArea(int menu, int pocket, Common::Rect *r); - -public: - Mouse(Sword2Engine *vm); - ~Mouse(); - - void getPos(int &x, int &y); - void setPos(int x, int y); - - bool getObjectLabels() { return _objectLabels; } - void setObjectLabels(bool b) { _objectLabels = b; } - - bool getMouseStatus() { return _mouseStatus; } - uint32 getMouseTouching() { return _mouseTouching; } - void setMouseTouching(uint32 touching) { _mouseTouching = touching; } - - void pauseGame(); - void unpauseGame(); - - void setMouse(uint32 res); - void setLuggage(uint32 res); - - void setObjectHeld(uint32 res); - - void resetMouseList(); - - void registerMouse(byte *ob_mouse, BuildUnit *build_unit); - void registerPointerText(int32 text_id); - - void createPointerText(uint32 text_id, uint32 pointer_res); - void clearPointerText(); - - void drawMouse(); - int32 animateMouse(); - - void processMenu(); - - void addMenuObject(byte *ptr); - void addSubject(int32 id, int32 ref); - - void buildMenu(); - void buildSystemMenu(); - - int32 showMenu(uint8 menu); - int32 hideMenu(uint8 menu); - int32 setMenuIcon(uint8 menu, uint8 pocket, byte *icon); - - void closeMenuImmediately(); - - void refreshInventory(); - - void startConversation(); - void endConversation(); - - void hideMouse(); - void noHuman(); - void addHuman(); - - void resetPlayerActivityDelay() { _playerActivityDelay = 0; } - void monitorPlayerActivity(); - void checkPlayerActivity(uint32 seconds); - - void mouseOnOff(); - uint32 checkMouseList(); - void mouseEngine(); - - void normalMouse(); - void menuMouse(); - void dragMouse(); - void systemMenuMouse(); - - bool isChoosing() { return _choosing; } - uint32 chooseMouse(); - - int menuClick(int menu_items); -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/music.cpp b/sword2/music.cpp deleted file mode 100644 index 847f4808cf..0000000000 --- a/sword2/music.cpp +++ /dev/null @@ -1,856 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -// One feature still missing is the original's DipMusic() function which, as -// far as I can understand, softened the music volume when someone was -// speaking, but only (?) if the music was playing loudly at the time. -// -// All things considered, I think this is more bother than it's worth. - -#include "common/stdafx.h" -#include "common/file.h" -#include "common/system.h" -#include "sound/mp3.h" -#include "sound/vorbis.h" -#include "sound/flac.h" -#include "sound/rate.h" -#include "sound/wave.h" - -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/resman.h" -#include "sword2/sound.h" - -namespace Sword2 { - -static AudioStream *makeCLUStream(Common::File *fp, int size); - -static AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, int cd, uint32 id, uint32 *numSamples) { - debug(3, "Playing %s from CD %d", base, cd); - - if (!fh->file.isOpen()) { - struct { - const char *ext; - int mode; - } file_types[] = { - #ifdef USE_MAD - { "cl3", kMP3Mode }, - #endif - #ifdef USE_VORBIS - { "clg", kVorbisMode }, - #endif - #ifdef USE_FLAC - { "clf", kFlacMode }, - #endif - { "clu", kCLUMode } - }; - - int soundMode = 0; - char filename[20]; - - for (int i = 0; i < ARRAYSIZE(file_types); i++) { - Common::File f; - - sprintf(filename, "%s%d.%s", base, cd, file_types[i].ext); - if (f.open(filename)) { - soundMode = file_types[i].mode; - break; - } - - sprintf(filename, "%s.%s", base, file_types[i].ext); - if (f.open(filename)) { - soundMode = file_types[i].mode; - break; - } - } - - if (soundMode == 0) - return NULL; - - fh->file.open(filename); - fh->fileType = soundMode; - if (!fh->file.isOpen()) { - warning("Very strange fopen error"); - return NULL; - } - if (fh->fileSize != fh->file.size()) { - if (fh->idxTab) { - free(fh->idxTab); - fh->idxTab = NULL; - } - } - } - - uint32 entrySize = (fh->fileType == kCLUMode) ? 2 : 3; - - if (!fh->idxTab) { - fh->file.seek(0); - fh->idxLen = fh->file.readUint32LE(); - fh->file.seek(entrySize * 4); - - fh->idxTab = (uint32*)malloc(fh->idxLen * 3 * sizeof(uint32)); - for (uint32 cnt = 0; cnt < fh->idxLen; cnt++) { - fh->idxTab[cnt * 3 + 0] = fh->file.readUint32LE(); - fh->idxTab[cnt * 3 + 1] = fh->file.readUint32LE(); - if (fh->fileType == kCLUMode) { - fh->idxTab[cnt * 3 + 2] = fh->idxTab[cnt * 3 + 1]; - fh->idxTab[cnt * 3 + 1]--; - } else - fh->idxTab[cnt * 3 + 2] = fh->file.readUint32LE(); - } - } - - uint32 pos = fh->idxTab[id * 3 + 0]; - uint32 len = fh->idxTab[id * 3 + 1]; - uint32 enc_len = fh->idxTab[id * 3 + 2]; - - if (numSamples) - *numSamples = len; - - if (!pos || !len) { - fh->file.close(); - return NULL; - } - - fh->file.seek(pos, SEEK_SET); - - switch (fh->fileType) { - case kCLUMode: - return makeCLUStream(&fh->file, enc_len); -#ifdef USE_MAD - case kMP3Mode: - return makeMP3Stream(&fh->file, enc_len); -#endif -#ifdef USE_VORBIS - case kVorbisMode: - return makeVorbisStream(&fh->file, enc_len); -#endif -#ifdef USE_FLAC - case kFlacMode: - return makeFlacStream(&fh->file, enc_len); -#endif - default: - return NULL; - } -} - -// ---------------------------------------------------------------------------- -// Custom AudioStream class to handle Broken Sword 2's audio compression. -// ---------------------------------------------------------------------------- - -#define GetCompressedShift(n) ((n) >> 4) -#define GetCompressedSign(n) (((n) >> 3) & 1) -#define GetCompressedAmplitude(n) ((n) & 7) - -CLUInputStream::CLUInputStream(Common::File *file, int size) - : _file(file), _firstTime(true), _bufferEnd(_outbuf + BUFFER_SIZE) { - - _file->incRef(); - - // Determine the end position. - _file_pos = _file->pos(); - _end_pos = _file_pos + size; - - // Read in initial data - refill(); -} - -CLUInputStream::~CLUInputStream() { - _file->decRef(); -} - -int CLUInputStream::readBuffer(int16 *buffer, const int numSamples) { - int samples = 0; - while (samples < numSamples && !eosIntern()) { - const int len = MIN(numSamples - samples, (int)(_bufferEnd - _pos)); - memcpy(buffer, _pos, len * 2); - buffer += len; - _pos += len; - samples += len; - if (_pos >= _bufferEnd) { - refill(); - } - } - return samples; -} - -void CLUInputStream::refill() { - byte *in = _inbuf; - int16 *out = _outbuf; - - _file->seek(_file_pos, SEEK_SET); - - uint len_left = _file->read(in, MIN((uint32)BUFFER_SIZE, _end_pos - _file->pos())); - - _file_pos = _file->pos(); - - while (len_left > 0) { - uint16 sample; - - if (_firstTime) { - _firstTime = false; - _prev = READ_LE_UINT16(in); - sample = _prev; - len_left -= 2; - in += 2; - } else { - uint16 delta = GetCompressedAmplitude(*in) << GetCompressedShift(*in); - if (GetCompressedSign(*in)) - sample = _prev - delta; - else - sample = _prev + delta; - - _prev = sample; - len_left--; - in++; - } - - *out++ = sample; - } - - _pos = _outbuf; - _bufferEnd = out; -} - -AudioStream *makeCLUStream(Common::File *file, int size) { - return new CLUInputStream(file, size); -} - -// ---------------------------------------------------------------------------- -// Another custom AudioStream class, to wrap around the various AudioStream -// classes used for music decompression, and to add looping, fading, etc. -// ---------------------------------------------------------------------------- - -// The length of a fade-in/out, in milliseconds. -#define FADE_LENGTH 3000 - -MusicInputStream::MusicInputStream(int cd, SoundFileHandle *fh, uint32 musicId, bool looping) { - _cd = cd; - _fh = fh; - _musicId = musicId; - _looping = looping; - - _bufferEnd = _buffer + BUFFER_SIZE; - _remove = false; - _fading = 0; - - _decoder = getAudioStream(_fh, "music", _cd, _musicId, &_numSamples); - if (_decoder) { - _samplesLeft = _numSamples; - _fadeSamples = (getRate() * FADE_LENGTH) / 1000; - fadeUp(); - - // Read in initial data - refill(); - } -} - -MusicInputStream::~MusicInputStream() { - delete _decoder; -} - -int MusicInputStream::readBuffer(int16 *buffer, const int numSamples) { - if (!_decoder) - return 0; - - int samples = 0; - while (samples < numSamples && !eosIntern()) { - const int len = MIN(numSamples - samples, (int)(_bufferEnd - _pos)); - memcpy(buffer, _pos, len * 2); - buffer += len; - _pos += len; - samples += len; - if (_pos >= _bufferEnd) { - refill(); - } - } - return samples; -} - -void MusicInputStream::refill() { - int16 *buf = _buffer; - uint32 numSamples = 0; - uint32 len_left; - bool endFade = false; - - len_left = BUFFER_SIZE; - - if (_fading > 0 && (uint32)_fading < len_left) - len_left = _fading; - - if (_samplesLeft < len_left) - len_left = _samplesLeft; - - if (!_looping) { - // Non-looping music is faded out at the end. If this fade - // out would have started somewhere within the len_left samples - // to read, we only read up to that point. This way, we can - // treat this fade as any other. - - if (!_fading) { - uint32 currentlyAt = _numSamples - _samplesLeft; - uint32 fadeOutAt = _numSamples - _fadeSamples; - uint32 readTo = currentlyAt + len_left; - - if (fadeOutAt == currentlyAt) - fadeDown(); - else if (fadeOutAt > currentlyAt && fadeOutAt <= readTo) { - len_left = fadeOutAt - currentlyAt; - endFade = true; - } - } - } - - int desired = len_left - numSamples; - int len = _decoder->readBuffer(buf, desired); - - // Shouldn't happen, but if it does it could cause an infinite loop. - // Of course there were bugs that caused it to happen several times - // during development. :-) - - if (len < desired) { - warning("Expected %d samples, but got %d", desired, len); - _samplesLeft = len; - } - - buf += len; - numSamples += len; - len_left -= len; - _samplesLeft -= len; - - int16 *ptr; - - if (_fading > 0) { - // Fade down - for (ptr = _buffer; ptr < buf; ptr++) { - if (_fading > 0) { - _fading--; - *ptr = (*ptr * _fading) / _fadeSamples; - } - if (_fading == 0) { - _looping = false; - _remove = true; - *ptr = 0; - } - } - } else if (_fading < 0) { - // Fade up - for (ptr = _buffer; ptr < buf; ptr++) { - _fading--; - *ptr = -(*ptr * _fading) / _fadeSamples; - if (_fading <= -_fadeSamples) { - _fading = 0; - break; - } - } - } - - if (endFade) - fadeDown(); - - if (!_samplesLeft) { - if (_looping) { - delete _decoder; - _decoder = getAudioStream(_fh, "music", _cd, _musicId, &_numSamples); - _samplesLeft = _numSamples; - } else - _remove = true; - } - - _pos = _buffer; - _bufferEnd = buf; -} - -void MusicInputStream::fadeUp() { - if (_fading > 0) - _fading = -_fading; - else if (_fading == 0) - _fading = -1; -} - -void MusicInputStream::fadeDown() { - if (_fading < 0) - _fading = -_fading; - else if (_fading == 0) - _fading = _fadeSamples; -} - -bool MusicInputStream::readyToRemove() { - return _remove; -} - -int32 MusicInputStream::getTimeRemaining() { - // This is far from exact, but it doesn't have to be. - return (_samplesLeft + BUFFER_SIZE) / getRate(); -} - -// ---------------------------------------------------------------------------- -// Main sound class -// ---------------------------------------------------------------------------- - -// AudioStream API - -int Sound::readBuffer(int16 *buffer, const int numSamples) { - Common::StackLock lock(_mutex); - int i; - - if (_musicPaused) - return 0; - - for (i = 0; i < MAXMUS; i++) { - if (_music[i] && _music[i]->readyToRemove()) { - delete _music[i]; - _music[i] = NULL; - } - } - - memset(buffer, 0, 2 * numSamples); - - if (!_mixBuffer || numSamples > _mixBufferLen) { - if (_mixBuffer) - _mixBuffer = (int16 *)realloc(_mixBuffer, 2 * numSamples); - else - _mixBuffer = (int16 *)malloc(2 * numSamples); - - _mixBufferLen = numSamples; - } - - if (!_mixBuffer) - return 0; - - for (i = 0; i < MAXMUS; i++) { - if (!_music[i]) - continue; - - int len = _music[i]->readBuffer(_mixBuffer, numSamples); - - if (!_musicMuted) { - for (int j = 0; j < len; j++) { - Audio::clampedAdd(buffer[j], _mixBuffer[j]); - } - } - } - - bool inUse[MAXMUS]; - - for (i = 0; i < MAXMUS; i++) - inUse[i] = false; - - for (i = 0; i < MAXMUS; i++) { - if (_music[i]) { - if (_music[i]->getCD() == 1) - inUse[0] = true; - else - inUse[1] = true; - } - } - - for (i = 0; i < MAXMUS; i++) { - if (!inUse[i] && !_musicFile[i].inUse && _musicFile[i].file.isOpen()) - _musicFile[i].file.close(); - } - - return numSamples; -} - -bool Sound::endOfData() const { - for (int i = 0; i < MAXMUS; i++) { - if (_musicFile[i].file.isOpen()) - return false; - } - - return true; -} - -// ---------------------------------------------------------------------------- -// MUSIC -// ---------------------------------------------------------------------------- - -/** - * Stops the music dead in its tracks. Any music that is currently being - * streamed is paused. - */ - -void Sound::pauseMusic() { - Common::StackLock lock(_mutex); - - _musicPaused = true; -} - -/** - * Restarts the music from where it was stopped. - */ - -void Sound::unpauseMusic() { - Common::StackLock lock(_mutex); - - _musicPaused = false; -} - -/** - * Fades out and stops the music. - */ - -void Sound::stopMusic(bool immediately) { - Common::StackLock lock(_mutex); - - _loopingMusicId = 0; - - for (int i = 0; i < MAXMUS; i++) { - if (_music[i]) { - if (immediately) { - delete _music[i]; - _music[i] = NULL; - } else - _music[i]->fadeDown(); - } - } -} - -/** - * Streams music from a cluster file. - * @param musicId the id of the music to stream - * @param loop true if the music is to loop back to the start - * @return RD_OK or an error code - */ -int32 Sound::streamCompMusic(uint32 musicId, bool loop) { - //Common::StackLock lock(_mutex); - - _mutex.lock(); - int cd = _vm->_resman->getCD(); - - if (loop) - _loopingMusicId = musicId; - else - _loopingMusicId = 0; - - int primary = -1; - int secondary = -1; - - // If both music streams are active, one of them will have to go. - - if (_music[0] && _music[1]) { - int32 fade0 = _music[0]->isFading(); - int32 fade1 = _music[1]->isFading(); - - if (!fade0 && !fade1) { - // Neither is fading. This shouldn't happen, so just - // pick one and be done with it. - primary = 0; - } else if (fade0 && !fade1) { - // Stream 0 is fading, so pick that one. - primary = 0; - } else if (!fade0 && fade1) { - // Stream 1 is fading, so pick that one. - primary = 1; - } else { - // Both streams are fading. Pick the one that is - // closest to silent. - if (ABS(fade0) < ABS(fade1)) - primary = 0; - else - primary = 1; - } - - delete _music[primary]; - _music[primary] = NULL; - } - - // Pick the available music stream. If no music is playing it doesn't - // matter which we use. - - if (_music[0] || _music[1]) { - if (_music[0]) { - primary = 1; - secondary = 0; - } else { - primary = 0; - secondary = 1; - } - } else - primary = 0; - - // Don't start streaming if the volume is off. - if (isMusicMute()) { - _mutex.unlock(); - return RD_OK; - } - - if (secondary != -1) - _music[secondary]->fadeDown(); - SoundFileHandle *fh = (cd == 1) ? &_musicFile[0] : &_musicFile[1]; - fh->inUse = true; - _mutex.unlock(); - - MusicInputStream *tmp = new MusicInputStream(cd, fh, musicId, loop); - - if (tmp->isReady()) { - _mutex.lock(); - _music[primary] = tmp; - fh->inUse = false; - _mutex.unlock(); - return RD_OK; - } else { - _mutex.lock(); - fh->inUse = false; - _mutex.unlock(); - delete tmp; - return RDERR_INVALIDFILENAME; - } -} - -/** - * @return the time left for the current music, in seconds. - */ - -int32 Sound::musicTimeRemaining() { - Common::StackLock lock(_mutex); - - for (int i = 0; i < MAXMUS; i++) { - if (_music[i] && _music[i]->isFading() <= 0) - return _music[i]->getTimeRemaining(); - } - - return 0; -} - -// ---------------------------------------------------------------------------- -// SPEECH -// ---------------------------------------------------------------------------- - -/** - * Mutes/Unmutes the speech. - * @param mute If mute is false, restore the volume to the last set master - * level. Otherwise the speech is muted (volume 0). - */ - -void Sound::muteSpeech(bool mute) { - _speechMuted = mute; - - if (_vm->_mixer->isSoundHandleActive(_soundHandleSpeech)) { - uint volume = mute ? 0 : Audio::Mixer::kMaxChannelVolume; - - _vm->_mixer->setChannelVolume(_soundHandleSpeech, volume); - } -} - -/** - * Stops the speech dead in its tracks. - */ - -void Sound::pauseSpeech() { - _speechPaused = true; - _vm->_mixer->pauseHandle(_soundHandleSpeech, true); -} - -/** - * Restarts the speech from where it was stopped. - */ - -void Sound::unpauseSpeech() { - _speechPaused = false; - _vm->_mixer->pauseHandle(_soundHandleSpeech, false); -} - -/** - * Stops the speech from playing. - */ - -int32 Sound::stopSpeech() { - if (_vm->_mixer->isSoundHandleActive(_soundHandleSpeech)) { - _vm->_mixer->stopHandle(_soundHandleSpeech); - return RD_OK; - } - - return RDERR_SPEECHNOTPLAYING; -} - -/** - * @return Either RDSE_SAMPLEPLAYING or RDSE_SAMPLEFINISHED - */ - -int32 Sound::getSpeechStatus() { - return _vm->_mixer->isSoundHandleActive(_soundHandleSpeech) ? RDSE_SAMPLEPLAYING : RDSE_SAMPLEFINISHED; -} - -/** - * Returns either RDSE_QUIET or RDSE_SPEAKING - */ - -int32 Sound::amISpeaking() { - if (!_speechMuted && !_speechPaused && _vm->_mixer->isSoundHandleActive(_soundHandleSpeech)) - return RDSE_SPEAKING; - - return RDSE_QUIET; -} - -/** - * This function loads and decompresses a list of speech from a cluster, but - * does not play it. This is used for cutscene voice-overs, presumably to - * avoid having to read from more than one file on the CD during playback. - * @param speechId the text line id used to reference the speech - * @param buf a pointer to the buffer that will be allocated for the sound - */ - -uint32 Sound::preFetchCompSpeech(uint32 speechId, uint16 **buf) { - int cd = _vm->_resman->getCD(); - uint32 numSamples; - - SoundFileHandle *fh = (cd == 1) ? &_speechFile[0] : &_speechFile[1]; - - AudioStream *input = getAudioStream(fh, "speech", cd, speechId, &numSamples); - - if (!input) - return 0; - - *buf = NULL; - - // Decompress data into speech buffer. - - uint32 bufferSize = 2 * numSamples; - - *buf = (uint16 *)malloc(bufferSize); - if (!*buf) { - delete input; - fh->file.close(); - return 0; - } - - uint32 readSamples = input->readBuffer((int16 *)*buf, numSamples); - - fh->file.close(); - delete input; - - return 2 * readSamples; -} - -/** - * This function loads, decompresses and plays a line of speech. An error - * occurs if speech is already playing. - * @param speechId the text line id used to reference the speech - * @param vol volume, 0 (minimum) to 16 (maximum) - * @param pan panning, -16 (full left) to 16 (full right) - */ - -int32 Sound::playCompSpeech(uint32 speechId, uint8 vol, int8 pan) { - if (_speechMuted) - return RD_OK; - - if (getSpeechStatus() == RDERR_SPEECHPLAYING) - return RDERR_SPEECHPLAYING; - - int cd = _vm->_resman->getCD(); - SoundFileHandle *fh = (cd == 1) ? &_speechFile[0] : &_speechFile[1]; - - AudioStream *input = getAudioStream(fh, "speech", cd, speechId, NULL); - - if (!input) - return RDERR_INVALIDID; - - // Modify the volume according to the master volume - - byte volume = _speechMuted ? 0 : vol * Audio::Mixer::kMaxChannelVolume / 16; - int8 p = (pan * 127) / 16; - - if (isReverseStereo()) - p = -p; - - // Start the speech playing - _vm->_mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_soundHandleSpeech, input, -1, volume, p); - return RD_OK; -} - -// ---------------------------------------------------------------------------- -// SOUND EFFECTS -// ---------------------------------------------------------------------------- - -/** - * Mutes/Unmutes the sound effects. - * @param mute If mute is false, restore the volume to the last set master - * level. Otherwise the sound effects are muted (volume 0). - */ - -void Sound::muteFx(bool mute) { - _fxMuted = mute; - - // Now update the volume of any fxs playing - for (int i = 0; i < FXQ_LENGTH; i++) { - if (_fxQueue[i].resource) { - _vm->_mixer->setChannelVolume(_fxQueue[i].handle, mute ? 0 : _fxQueue[i].volume); - } - } -} - -/** - * Sets the volume and pan of the sample which is currently playing - * @param id the id of the sample - * @param vol volume - * @param pan panning - */ - -int32 Sound::setFxIdVolumePan(int32 id, int vol, int pan) { - if (!_fxQueue[id].resource) - return RDERR_FXNOTOPEN; - - if (vol > 16) - vol = 16; - - _fxQueue[id].volume = (vol * Audio::Mixer::kMaxChannelVolume) / 16; - - if (pan != 255) { - if (isReverseStereo()) - pan = -pan; - _fxQueue[id].pan = (pan * 127) / 16; - } - - if (!_fxMuted && _vm->_mixer->isSoundHandleActive(_fxQueue[id].handle)) { - _vm->_mixer->setChannelVolume(_fxQueue[id].handle, _fxQueue[id].volume); - if (pan != -1) - _vm->_mixer->setChannelBalance(_fxQueue[id].handle, _fxQueue[id].pan); - } - - return RD_OK; -} - -void Sound::pauseFx() { - if (_fxPaused) - return; - - for (int i = 0; i < FXQ_LENGTH; i++) { - if (_fxQueue[i].resource) - _vm->_mixer->pauseHandle(_fxQueue[i].handle, true); - } - - _fxPaused = true; -} - -void Sound::unpauseFx() { - if (!_fxPaused) - return; - - for (int i = 0; i < FXQ_LENGTH; i++) - if (_fxQueue[i].resource) - _vm->_mixer->pauseHandle(_fxQueue[i].handle, false); - - _fxPaused = false; -} - -} // End of namespace Sword2 diff --git a/sword2/object.h b/sword2/object.h deleted file mode 100644 index 1fd434f8a0..0000000000 --- a/sword2/object.h +++ /dev/null @@ -1,342 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef _SCRIPT_STRUCTURES -#define _SCRIPT_STRUCTURES - -#include "common/stream.h" - -namespace Sword2 { - -// these structures represent the broken up compact components -// these here declared to the system must be the same as those declared to -// LINC (or it wont work) - -// mouse structure - defines mouse detection area, detection priority & -// 'type' flag - -struct ObjectMouse { - int32 x1; // Top-left and bottom-right of mouse - int32 y1; // area. (These coords are inclusive.) - int32 x2; - int32 y2; - int32 priority; - int32 pointer; // type (or resource id?) of pointer used over this area - - static const int size() { - return 24; - } - - void read(byte *addr) { - Common::MemoryReadStream readS(addr, size()); - - x1 = readS.readSint32LE(); - y1 = readS.readSint32LE(); - x2 = readS.readSint32LE(); - y2 = readS.readSint32LE(); - priority = readS.readSint32LE(); - pointer = readS.readSint32LE(); - } - - void write(byte *addr) { - Common::MemoryWriteStream writeS(addr, size()); - - writeS.writeSint32LE(x1); - writeS.writeSint32LE(y1); - writeS.writeSint32LE(x2); - writeS.writeSint32LE(y2); - writeS.writeSint32LE(priority); - writeS.writeSint32LE(pointer); - } -}; - -// logic structure - contains fields used in logic script processing - -class ObjectLogic { - // int32 looping; // 0 when first calling fn<function>; - // 1 when calling subsequent times in - // same loop - // int32 pause; // pause count, used by fnPause() - -private: - byte *_addr; - -public: - ObjectLogic(byte *addr) { - _addr = addr; - } - - static const int size() { - return 8; - } - - byte *data() { - return _addr; - } - - int32 getLooping() { return READ_LE_UINT32(_addr); } - int32 getPause() { return READ_LE_UINT32(_addr + 4); } - - void setLooping(int32 x) { WRITE_LE_UINT32(_addr, x); } - void setPause(int32 x) { WRITE_LE_UINT32(_addr + 4, x); } -}; - -// status bits for 'type' field of ObjectGraphic) - -// in low word: - -#define NO_SPRITE 0x00000000 // don't print -#define BGP0_SPRITE 0x00000001 // fixed to background parallax[0] -#define BGP1_SPRITE 0x00000002 // fixed to background parallax[1] -#define BACK_SPRITE 0x00000004 // 'background' sprite, fixed to main background -#define SORT_SPRITE 0x00000008 // 'sorted' sprite, fixed to main background -#define FORE_SPRITE 0x00000010 // 'foreground' sprite, fixed to main background -#define FGP0_SPRITE 0x00000020 // fixed to foreground parallax[0] -#define FGP1_SPRITE 0x00000040 // fixed to foreground parallax[0] - -// in high word: - -#define UNSHADED_SPRITE 0x00000000 // not to be shaded -#define SHADED_SPRITE 0x00010000 // to be shaded, based on shading mask - -// graphic structure - contains fields appropriate to sprite output - -class ObjectGraphic { - // int32 type; // see above - // int32 anim_resource; // resource id of animation file - // int32 anim_pc; // current frame number of animation - -private: - byte *_addr; - -public: - ObjectGraphic(byte *addr) { - _addr = addr; - } - - static const int size() { - return 12; - } - - byte *data() { - return _addr; - } - - int32 getType() { return READ_LE_UINT32(_addr); } - int32 getAnimResource() { return READ_LE_UINT32(_addr + 4); } - int32 getAnimPc() { return READ_LE_UINT32(_addr + 8); } - - void setType(int32 x) { WRITE_LE_UINT32(_addr, x); } - void setAnimResource(int32 x) { WRITE_LE_UINT32(_addr + 4, x); } - void setAnimPc(int32 x) { WRITE_LE_UINT32(_addr + 8, x); } -}; - -// speech structure - contains fields used by speech scripts & text output - -class ObjectSpeech { - // int32 pen; // colour to use for body of characters - // int32 width; // max width of text sprite - // int32 command; // speech script command id - // int32 ins1; // speech script instruction parameters - // int32 ins2; - // int32 ins3; - // int32 ins4; - // int32 ins5; - // int32 wait_state; // 0 not waiting, - // 1 waiting for next speech command - -private: - byte *_addr; - -public: - ObjectSpeech(byte *addr) { - _addr = addr; - } - - static const int size() { - return 36; - } - - byte *data() { - return _addr; - } - - int32 getPen() { return READ_LE_UINT32(_addr); } - int32 getWidth() { return READ_LE_UINT32(_addr + 4); } - int32 getCommand() { return READ_LE_UINT32(_addr + 8); } - int32 getIns1() { return READ_LE_UINT32(_addr + 12); } - int32 getIns2() { return READ_LE_UINT32(_addr + 16); } - int32 getIns3() { return READ_LE_UINT32(_addr + 20); } - int32 getIns4() { return READ_LE_UINT32(_addr + 24); } - int32 getIns5() { return READ_LE_UINT32(_addr + 28); } - int32 getWaitState() { return READ_LE_UINT32(_addr + 32); } - - void setPen(int32 x) { WRITE_LE_UINT32(_addr, x); } - void setWidth(int32 x) { WRITE_LE_UINT32(_addr + 4, x); } - void setCommand(int32 x) { WRITE_LE_UINT32(_addr + 8, x); } - void setIns1(int32 x) { WRITE_LE_UINT32(_addr + 12, x); } - void setIns2(int32 x) { WRITE_LE_UINT32(_addr + 16, x); } - void setIns3(int32 x) { WRITE_LE_UINT32(_addr + 20, x); } - void setIns4(int32 x) { WRITE_LE_UINT32(_addr + 24, x); } - void setIns5(int32 x) { WRITE_LE_UINT32(_addr + 28, x); } - void setWaitState(int32 x) { WRITE_LE_UINT32(_addr + 32, x); } -}; - -// mega structure - contains fields used for mega-character & mega-set -// processing - -class ObjectMega { - // int32 NOT_USED_1; // only free roaming megas need to - // check this before registering their - // graphics for drawing - // int32 NOT_USED_2; // id of floor on which we are standing - // int32 NOT_USED_3; // id of object which we are getting to - // int32 NOT_USED_4; // pixel distance to stand from player - // character when in conversation - // int32 currently_walking; // number given us by the auto router - // int32 walk_pc; // current frame number of walk-anim - // int32 scale_a; // current scale factors, taken from - // int32 scale_b; // floor data - // int32 feet_x; // mega feet coords - frame-offsets are - // int32 feet_y; // added to these position mega frames - // int32 current_dir; // current dirction faced by mega; used - // by autorouter to determine turns - // required - // int32 NOT_USED_5; // means were currently avoiding a - // collision (see fnWalk) - // int32 megaset_res; // resource id of mega-set file - // int32 NOT_USED_6; // NOT USED - -private: - byte *_addr; - -public: - ObjectMega(byte *addr) { - _addr = addr; - } - - static const int size() { - return 56; - } - - byte *data() { - return _addr; - } - - int32 getIsWalking() { return READ_LE_UINT32(_addr + 16); } - int32 getWalkPc() { return READ_LE_UINT32(_addr + 20); } - int32 getScaleA() { return READ_LE_UINT32(_addr + 24); } - int32 getScaleB() { return READ_LE_UINT32(_addr + 28); } - int32 getFeetX() { return READ_LE_UINT32(_addr + 32); } - int32 getFeetY() { return READ_LE_UINT32(_addr + 36); } - int32 getCurDir() { return READ_LE_UINT32(_addr + 40); } - int32 getMegasetRes() { return READ_LE_UINT32(_addr + 48); } - - void setIsWalking(int32 x) { WRITE_LE_UINT32(_addr + 16, x); } - void setWalkPc(int32 x) { WRITE_LE_UINT32(_addr + 20, x); } - void setScaleA(int32 x) { WRITE_LE_UINT32(_addr + 24, x); } - void setScaleB(int32 x) { WRITE_LE_UINT32(_addr + 28, x); } - void setFeetX(int32 x) { WRITE_LE_UINT32(_addr + 32, x); } - void setFeetY(int32 x) { WRITE_LE_UINT32(_addr + 36, x); } - void setCurDir(int32 x) { WRITE_LE_UINT32(_addr + 40, x); } - void setMegasetRes(int32 x) { WRITE_LE_UINT32(_addr + 48, x); } - - int32 calcScale() { - // Calc scale at which to print the sprite, based on feet - // y-coord & scaling constants (NB. 'scale' is actually - // 256 * true_scale, to maintain accuracy) - - // Ay+B gives 256 * scale ie. 256 * 256 * true_scale for even - // better accuracy, ie. scale = (Ay + B) / 256 - return (getScaleA() * getFeetY() + getScaleB()) / 256; - } -}; - -// walk-data structure - contains details of layout of frames in the -// mega-set, and how they are to be used - -struct ObjectWalkdata { - int32 nWalkFrames; // no. of frames per walk-cycle - int32 usingStandingTurnFrames; // 0 = no 1 = yes - int32 usingWalkingTurnFrames; // 0 = no 1 = yes - int32 usingSlowInFrames; // 0 = no 1 = yes - int32 usingSlowOutFrames; // 0 = no !0 = number of slow-out frames in each direction - int32 nSlowInFrames[8]; // no. of slow-in frames in each direction - int32 leadingLeg[8]; // leading leg for walk in each direction (0 = left 1 = right) - int32 dx[8 * (12 + 1)]; // walk step distances in x direction - int32 dy[8 * (12 + 1)]; // walk step distances in y direction - - static const int size() { - return 916; - } - - void read(byte *addr) { - Common::MemoryReadStream readS(addr, size()); - - nWalkFrames = readS.readUint32LE(); - usingStandingTurnFrames = readS.readUint32LE(); - usingWalkingTurnFrames = readS.readUint32LE(); - usingSlowInFrames = readS.readUint32LE(); - usingSlowOutFrames = readS.readUint32LE(); - - int i; - - for (i = 0; i < ARRAYSIZE(nSlowInFrames); i++) - nSlowInFrames[i] = readS.readUint32LE(); - - for (i = 0; i < ARRAYSIZE(leadingLeg); i++) - leadingLeg[i] = readS.readUint32LE(); - - for (i = 0; i < ARRAYSIZE(dx); i++) - dx[i] = readS.readUint32LE(); - - for (i = 0; i < ARRAYSIZE(dy); i++) - dy[i] = readS.readUint32LE(); - } - - void write(byte *addr) { - Common::MemoryWriteStream writeS(addr, size()); - - writeS.writeUint32LE(nWalkFrames); - writeS.writeUint32LE(usingStandingTurnFrames); - writeS.writeUint32LE(usingWalkingTurnFrames); - writeS.writeUint32LE(usingSlowInFrames); - writeS.writeUint32LE(usingSlowOutFrames); - - int i; - - for (i = 0; i < ARRAYSIZE(nSlowInFrames); i++) - writeS.writeUint32LE(nSlowInFrames[i]); - - for (i = 0; i < ARRAYSIZE(leadingLeg); i++) - writeS.writeUint32LE(leadingLeg[i]); - - for (i = 0; i < ARRAYSIZE(dx); i++) - writeS.writeUint32LE(dx[i]); - - for (i = 0; i < ARRAYSIZE(dy); i++) - writeS.writeUint32LE(dy[i]); - } -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/palette.cpp b/sword2/palette.cpp deleted file mode 100644 index 0b6b7a8ca2..0000000000 --- a/sword2/palette.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "common/system.h" -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/resman.h" - -namespace Sword2 { - -/** - * Start layer palette fading up - */ - -void Screen::startNewPalette() { - // If the screen is still fading down then wait for black - could - // happen when everythings cached into a large memory model - waitForFade(); - - byte *screenFile = _vm->_resman->openResource(_thisScreen.background_layer_id); - - memcpy(_paletteMatch, _vm->fetchPaletteMatchTable(screenFile), PALTABLESIZE); - setPalette(0, 256, _vm->fetchPalette(screenFile), RDPAL_FADE); - - // Indicating that it's a screen palette - _lastPaletteRes = 0; - - _vm->_resman->closeResource(_thisScreen.background_layer_id); - fadeUp(); - _thisScreen.new_palette = 0; -} - -void Screen::setFullPalette(int32 palRes) { - // fudge for hut interior - // - unpausing should restore last palette as normal (could be screen - // palette or 'dark_palette_13') - // - but restoring the screen palette after 'dark_palette_13' should - // now work properly too! - - // "Hut interior" refers to the watchman's hut in Marseille, and this - // is apparently needed for the palette to be restored properly when - // you turn the light off. (I didn't even notice the light switch!) - - if (_vm->_logic->readVar(LOCATION) == 13) { - // unpausing - if (palRes == -1) { - // restore whatever palette was last set (screen - // palette or 'dark_palette_13') - palRes = _lastPaletteRes; - } - } else { - // check if we're just restoring the current screen palette - // because we might actually need to use a separate palette - // file anyway eg. for pausing & unpausing during the eclipse - - // unpausing (fudged for location 13) - if (palRes == -1) { - // we really meant '0' - palRes = 0; - } - - if (palRes == 0 && _lastPaletteRes) - palRes = _lastPaletteRes; - } - - // If non-zero, set palette to this separate palette file. Otherwise, - // set palette to current screen palette. - - if (palRes) { - byte *pal = _vm->_resman->openResource(palRes); - - assert(_vm->_resman->fetchType(pal) == PALETTE_FILE); - - pal += ResHeader::size(); - - // always set colour 0 to black because most background screen - // palettes have a bright colour 0 although it should come out - // as black in the game! - - pal[0] = 0; - pal[1] = 0; - pal[2] = 0; - pal[3] = 0; - - setPalette(0, 256, pal, RDPAL_INSTANT); - _vm->_resman->closeResource(palRes); - } else { - if (_thisScreen.background_layer_id) { - byte *data = _vm->_resman->openResource(_thisScreen.background_layer_id); - memcpy(_paletteMatch, _vm->fetchPaletteMatchTable(data), PALTABLESIZE); - setPalette(0, 256, _vm->fetchPalette(data), RDPAL_INSTANT); - _vm->_resman->closeResource(_thisScreen.background_layer_id); - } else - error("setFullPalette(0) called, but no current screen available!"); - } - - if (palRes != CONTROL_PANEL_PALETTE) - _lastPaletteRes = palRes; -} - -/** - * Matches a colour triplet to a palette index. - * @param r red colour component - * @param g green colour component - * @param b blue colour component - * @return the palette index of the closest matching colour in the palette - */ - -// FIXME: This used to be inlined - probably a good idea - but the -// linker complained when I tried to use it in sprite.cpp. - -uint8 Screen::quickMatch(uint8 r, uint8 g, uint8 b) { - return _paletteMatch[((int32)(r >> 2) << 12) + ((int32)(g >> 2) << 6) + (b >> 2)]; -} - -/** - * Sets the palette. - * @param startEntry the first colour entry to set - * @param noEntries the number of colour entries to set - * @param colourTable the new colour entries - * @param fadeNow whether to perform the change immediately or delayed - */ - -void Screen::setPalette(int16 startEntry, int16 noEntries, byte *colourTable, uint8 fadeNow) { - assert(noEntries > 0); - - memcpy(&_palette[4 * startEntry], colourTable, noEntries * 4); - - if (fadeNow == RDPAL_INSTANT) { - _vm->_system->setPalette(_palette, startEntry, noEntries); - setNeedFullRedraw(); - } -} - -void Screen::dimPalette() { - byte *p = _palette; - - for (int i = 0; i < 256; i++) { - p[i * 4 + 0] /= 2; - p[i * 4 + 1] /= 2; - p[i * 4 + 2] /= 2; - } - - _vm->_system->setPalette(p, 0, 256); - setNeedFullRedraw(); -} - -/** - * Fades the palette up from black to the current palette. - * @param time the time it will take the palette to fade up - */ - -int32 Screen::fadeUp(float time) { - if (getFadeStatus() != RDFADE_BLACK && getFadeStatus() != RDFADE_NONE) - return RDERR_FADEINCOMPLETE; - - _fadeTotalTime = (int32)(time * 1000); - _fadeStatus = RDFADE_UP; - _fadeStartTime = _vm->_system->getMillis(); - - return RD_OK; -} - -/** - * Fades the palette down to black from the current palette. - * @param time the time it will take the palette to fade down - */ - -int32 Screen::fadeDown(float time) { - if (getFadeStatus() != RDFADE_BLACK && getFadeStatus() != RDFADE_NONE) - return RDERR_FADEINCOMPLETE; - - _fadeTotalTime = (int32)(time * 1000); - _fadeStatus = RDFADE_DOWN; - _fadeStartTime = _vm->_system->getMillis(); - - return RD_OK; -} - -/** - * Get the current fade status - * @return RDFADE_UP (fading up), RDFADE_DOWN (fading down), RDFADE_NONE - * (not faded), or RDFADE_BLACK (completely faded down) - */ - -uint8 Screen::getFadeStatus() { - return _fadeStatus; -} - -void Screen::waitForFade() { - while (getFadeStatus() != RDFADE_NONE && getFadeStatus() != RDFADE_BLACK && !_vm->_quit) { - updateDisplay(); - _vm->_system->delayMillis(20); - } -} - -void Screen::fadeServer() { - static int32 previousTime = 0; - byte fadePalette[256 * 4]; - byte *newPalette = fadePalette; - int32 currentTime; - int16 fadeMultiplier; - int16 i; - - // If we're not in the process of fading, do nothing. - if (getFadeStatus() != RDFADE_UP && getFadeStatus() != RDFADE_DOWN) - return; - - // I don't know if this is necessary, but let's limit how often the - // palette is updated, just to be safe. - currentTime = _vm->_system->getMillis(); - if (currentTime - previousTime <= 25) - return; - - previousTime = currentTime; - - if (getFadeStatus() == RDFADE_UP) { - if (currentTime >= _fadeStartTime + _fadeTotalTime) { - _fadeStatus = RDFADE_NONE; - newPalette = _palette; - } else { - fadeMultiplier = (int16)(((int32)(currentTime - _fadeStartTime) * 256) / _fadeTotalTime); - for (i = 0; i < 256; i++) { - newPalette[i * 4 + 0] = (_palette[i * 4 + 0] * fadeMultiplier) >> 8; - newPalette[i * 4 + 1] = (_palette[i * 4 + 1] * fadeMultiplier) >> 8; - newPalette[i * 4 + 2] = (_palette[i * 4 + 2] * fadeMultiplier) >> 8; - } - } - } else { - if (currentTime >= _fadeStartTime + _fadeTotalTime) { - _fadeStatus = RDFADE_BLACK; - memset(newPalette, 0, sizeof(fadePalette)); - } else { - fadeMultiplier = (int16)(((int32)(_fadeTotalTime - (currentTime - _fadeStartTime)) * 256) / _fadeTotalTime); - for (i = 0; i < 256; i++) { - newPalette[i * 4 + 0] = (_palette[i * 4 + 0] * fadeMultiplier) >> 8; - newPalette[i * 4 + 1] = (_palette[i * 4 + 1] * fadeMultiplier) >> 8; - newPalette[i * 4 + 2] = (_palette[i * 4 + 2] * fadeMultiplier) >> 8; - } - } - } - - _vm->_system->setPalette(newPalette, 0, 256); - setNeedFullRedraw(); -} - -} // End of namespace Sword2 diff --git a/sword2/protocol.cpp b/sword2/protocol.cpp deleted file mode 100644 index 23010e27a9..0000000000 --- a/sword2/protocol.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "sword2/sword2.h" -#include "sword2/resman.h" - -namespace Sword2 { - -/** - * Returns a pointer to the first palette entry, given the pointer to the start - * of the screen file. - */ - -byte *Sword2Engine::fetchPalette(byte *screenFile) { - MultiScreenHeader mscreenHeader; - - mscreenHeader.read(screenFile + ResHeader::size()); - - byte *palette = screenFile + ResHeader::size() + mscreenHeader.palette; - - // Always set colour 0 to black, because while most background screen - // palettes have a bright colour 0 it should come out as black in the - // game. - - palette[0] = 0; - palette[1] = 0; - palette[2] = 0; - palette[3] = 0; - - return palette; -} - -/** - * Returns a pointer to the start of the palette match table, given the pointer - * to the start of the screen file. - */ - -byte *Sword2Engine::fetchPaletteMatchTable(byte *screenFile) { - MultiScreenHeader mscreenHeader; - - mscreenHeader.read(screenFile + ResHeader::size()); - - return screenFile + ResHeader::size() + mscreenHeader.paletteTable; -} - -/** - * Returns a pointer to the screen header, given the pointer to the start of - * the screen file. - */ - -byte *Sword2Engine::fetchScreenHeader(byte *screenFile) { - MultiScreenHeader mscreenHeader; - - mscreenHeader.read(screenFile + ResHeader::size()); - - return screenFile + ResHeader::size() + mscreenHeader.screen; -} - -/** - * Returns a pointer to the requested layer header, given the pointer to the - * start of the screen file. Drops out if the requested layer number exceeds - * the number of layers on this screen. - */ - -byte *Sword2Engine::fetchLayerHeader(byte *screenFile, uint16 layerNo) { -#ifdef SWORD2_DEBUG - ScreenHeader screenHead; - - screenHead.read(fetchScreenHeader(screenFile)); - assert(layerNo < screenHead.noLayers); -#endif - - MultiScreenHeader mscreenHeader; - - mscreenHeader.read(screenFile + ResHeader::size()); - - return screenFile + ResHeader::size() + mscreenHeader.layers + layerNo * LayerHeader::size(); -} - -/** - * Returns a pointer to the start of the shading mask, given the pointer to the - * start of the screen file. - */ - -byte *Sword2Engine::fetchShadingMask(byte *screenFile) { - MultiScreenHeader mscreenHeader; - - mscreenHeader.read(screenFile + ResHeader::size()); - - return screenFile + ResHeader::size() + mscreenHeader.maskOffset; -} - -/** - * Returns a pointer to the anim header, given the pointer to the start of the - * anim file. - */ - -byte *Sword2Engine::fetchAnimHeader(byte *animFile) { - return animFile + ResHeader::size(); -} - -/** - * Returns a pointer to the requested frame number's cdtEntry, given the - * pointer to the start of the anim file. Drops out if the requested frame - * number exceeds the number of frames in this anim. - */ - -byte *Sword2Engine::fetchCdtEntry(byte *animFile, uint16 frameNo) { -#ifdef SWORD2_DEBUG - AnimHeader animHead; - - animHead.read(fetchAnimHeader(animFile)); - - if (frameNo > animHead->noAnimFrames - 1) - error("fetchCdtEntry(animFile,%d) - anim only %d frames", frameNo, animHead.noAnimFrames); -#endif - - return fetchAnimHeader(animFile) + AnimHeader::size() + frameNo * CdtEntry::size(); -} - -/** - * Returns a pointer to the requested frame number's header, given the pointer - * to the start of the anim file. Drops out if the requested frame number - * exceeds the number of frames in this anim - */ - -byte *Sword2Engine::fetchFrameHeader(byte *animFile, uint16 frameNo) { - // required address = (address of the start of the anim header) + frameOffset - CdtEntry cdt; - - cdt.read(fetchCdtEntry(animFile, frameNo)); - - return animFile + ResHeader::size() + cdt.frameOffset; -} - -/** - * Returns a pointer to the requested parallax layer data. - */ - -byte *Sword2Engine::fetchBackgroundParallaxLayer(byte *screenFile, int layer) { - MultiScreenHeader mscreenHeader; - - mscreenHeader.read(screenFile + ResHeader::size()); - assert(mscreenHeader.bg_parallax[layer]); - - return screenFile + ResHeader::size() + mscreenHeader.bg_parallax[layer]; -} - -byte *Sword2Engine::fetchBackgroundLayer(byte *screenFile) { - MultiScreenHeader mscreenHeader; - - mscreenHeader.read(screenFile + ResHeader::size()); - assert(mscreenHeader.screen); - - return screenFile + ResHeader::size() + mscreenHeader.screen + ScreenHeader::size(); -} - -byte *Sword2Engine::fetchForegroundParallaxLayer(byte *screenFile, int layer) { - MultiScreenHeader mscreenHeader; - - mscreenHeader.read(screenFile + ResHeader::size()); - assert(mscreenHeader.fg_parallax[layer]); - - return screenFile + ResHeader::size() + mscreenHeader.fg_parallax[layer]; -} - -byte *Sword2Engine::fetchTextLine(byte *file, uint32 text_line) { - TextHeader text_header; - static byte errorLine[128]; - - text_header.read(file + ResHeader::size()); - - if (text_line >= text_header.noOfLines) { - sprintf((char *)errorLine, "xxMissing line %d of %s (only 0..%d)", text_line, _resman->fetchName(file), text_header.noOfLines - 1); - - // first 2 chars are NULL so that actor-number comes out as '0' - errorLine[0] = 0; - errorLine[1] = 0; - return errorLine; - } - - // The "number of lines" field is followed by a lookup table - - return file + READ_LE_UINT32(file + ResHeader::size() + 4 + 4 * text_line); -} - -// Used for testing text & speech (see fnISpeak in speech.cpp) - -bool Sword2Engine::checkTextLine(byte *file, uint32 text_line) { - TextHeader text_header; - - text_header.read(file + ResHeader::size()); - - return text_line < text_header.noOfLines; -} - -} // End of namespace Sword2 diff --git a/sword2/rdwin.cpp b/sword2/rdwin.cpp deleted file mode 100644 index 310b66abf7..0000000000 --- a/sword2/rdwin.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "common/system.h" -#include "sword2/sword2.h" - -namespace Sword2 { - -/** - * Tell updateDisplay() that the scene needs to be completely updated. - */ - -void Screen::setNeedFullRedraw() { - _needFullRedraw = true; -} - -/** - * Mark an area of the screen as dirty, first generation. - */ - -void Screen::markAsDirty(int16 x0, int16 y0, int16 x1, int16 y1) { - int16 gridX0 = x0 / CELLWIDE; - int16 gridY0 = y0 / CELLDEEP; - int16 gridX1 = x1 / CELLWIDE; - int16 gridY1 = y1 / CELLDEEP; - - for (int16 i = gridY0; i <= gridY1; i++) - for (int16 j = gridX0; j <= gridX1; j++) - _dirtyGrid[i * _gridWide + j] = 2; -} - -/** - * This function has two purposes: It redraws the scene, and it handles input - * events, palette fading, etc. It should be called at a high rate (> 20 per - * second), but the scene is usually only redrawn about 12 times per second, - * except when then screen is scrolling. - * - * @param redrawScene If true, redraw the scene. - */ - -void Screen::updateDisplay(bool redrawScene) { - _vm->parseInputEvents(); - fadeServer(); - - if (redrawScene) { - int i; - - // Note that the entire scene is always rendered, which is less - // than optimal, but at least we can try to be intelligent - // about updating the screen afterwards. - - if (_needFullRedraw) { - // Update the entire screen. This is necessary when - // scrolling, fading, etc. - - _vm->_system->copyRectToScreen(_buffer + MENUDEEP * _screenWide, _screenWide, 0, MENUDEEP, _screenWide, _screenDeep - 2 * MENUDEEP); - _needFullRedraw = false; - } else { - // Update only the dirty areas of the screen - - int j, x, y; - int stripWide; - - for (i = 0; i < _gridDeep; i++) { - stripWide = 0; - - for (j = 0; j < _gridWide; j++) { - if (_dirtyGrid[i * _gridWide + j]) { - stripWide++; - } else if (stripWide) { - x = CELLWIDE * (j - stripWide); - y = CELLDEEP * i; - _vm->_system->copyRectToScreen(_buffer + y * _screenWide + x, _screenWide, x, y, stripWide * CELLWIDE, CELLDEEP); - stripWide = 0; - } - } - - if (stripWide) { - x = CELLWIDE * (j - stripWide); - y = CELLDEEP * i; - _vm->_system->copyRectToScreen(_buffer + y * _screenWide + x, _screenWide, x, y, stripWide * CELLWIDE, CELLDEEP); - stripWide = 0; - } - } - } - - // Age the dirty cells one generation. This way we keep track - // of both the cells that were updated this time, and the ones - // that were updated the last time. - - for (i = 0; i < _gridWide * _gridDeep; i++) - _dirtyGrid[i] >>= 1; - } - - // We always need to update because of fades, menu animations, etc. - _vm->_system->updateScreen(); -} - -} // End of namespace Sword2 diff --git a/sword2/render.cpp b/sword2/render.cpp deleted file mode 100644 index da60ecd6d9..0000000000 --- a/sword2/render.cpp +++ /dev/null @@ -1,584 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "common/system.h" - -#include "graphics/primitives.h" - -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/build_display.h" - -#ifdef BACKEND_8BIT -#include "sword2/animation.h" -#endif - -namespace Sword2 { - -#define MILLISECSPERCYCLE 83 -#define RENDERAVERAGETOTAL 4 - -void Screen::updateRect(Common::Rect *r) { - _vm->_system->copyRectToScreen(_buffer + r->top * _screenWide + r->left, - _screenWide, r->left, r->top, r->right - r->left, - r->bottom - r->top); -} - -void Screen::blitBlockSurface(BlockSurface *s, Common::Rect *r, Common::Rect *clipRect) { - if (!r->intersects(*clipRect)) - return; - - byte *src = s->data; - - if (r->top < clipRect->top) { - src -= BLOCKWIDTH * (r->top - clipRect->top); - r->top = clipRect->top; - } - if (r->left < clipRect->left) { - src -= (r->left - clipRect->left); - r->left = clipRect->left; - } - if (r->bottom > clipRect->bottom) - r->bottom = clipRect->bottom; - if (r->right > clipRect->right) - r->right = clipRect->right; - - byte *dst = _buffer + r->top * _screenWide + r->left; - int i; - - if (s->transparent) { - for (i = 0; i < r->bottom - r->top; i++) { - for (int j = 0; j < r->right - r->left; j++) { - if (src[j]) - dst[j] = src[j]; - } - src += BLOCKWIDTH; - dst += _screenWide; - } - } else { - for (i = 0; i < r->bottom - r->top; i++) { - memcpy(dst, src, r->right - r->left); - src += BLOCKWIDTH; - dst += _screenWide; - } - } -} - -// There are two different separate functions for scaling the image - one fast -// and one good. Or at least that's the theory. I'm sure there are better ways -// to scale an image than this. The latter is used at the highest graphics -// quality setting. Note that the "good" scaler takes an extra parameter, a -// pointer to the area of the screen where the sprite will be drawn. -// -// This code isn't quite like the original DrawSprite(), but should be close -// enough. - -void Screen::scaleImageFast(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight) { - int x, y; - - for (x = 0; x < dstWidth; x++) - _xScale[x] = (x * srcWidth) / dstWidth; - - for (y = 0; y < dstHeight; y++) - _yScale[y] = (y * srcHeight) / dstHeight; - - for (y = 0; y < dstHeight; y++) { - for (x = 0; x < dstWidth; x++) { - dst[x] = src[_yScale[y] * srcPitch + _xScale[x]]; - } - dst += dstPitch; - } -} - -void Screen::scaleImageGood(byte *dst, uint16 dstPitch, uint16 dstWidth, uint16 dstHeight, byte *src, uint16 srcPitch, uint16 srcWidth, uint16 srcHeight, byte *backbuf) { - for (int y = 0; y < dstHeight; y++) { - for (int x = 0; x < dstWidth; x++) { - uint8 c1, c2, c3, c4; - - uint32 xPos = (x * srcWidth) / dstWidth; - uint32 yPos = (y * srcHeight) / dstHeight; - uint32 xFrac = dstWidth - (x * srcWidth) % dstWidth; - uint32 yFrac = dstHeight - (y * srcHeight) % dstHeight; - - byte *srcPtr = src + yPos * srcPitch + xPos; - byte *backPtr = backbuf + y * _screenWide + x; - - bool transparent = true; - - if (*srcPtr) { - c1 = *srcPtr; - transparent = false; - } else - c1 = *backPtr; - - if (x < dstWidth - 1) { - if (*(srcPtr + 1)) { - c2 = *(srcPtr + 1); - transparent = false; - } else - c2 = *(backPtr + 1); - } else - c2 = c1; - - if (y < dstHeight - 1) { - if (*(srcPtr + srcPitch)) { - c3 = *(srcPtr + srcPitch); - transparent = false; - } else - c3 = *(backPtr + _screenWide); - } else - c3 = c1; - - if (x < dstWidth - 1 && y < dstHeight - 1) { - if (*(srcPtr + srcPitch + 1)) { - c4 = *(srcPtr + srcPitch + 1); - transparent = false; - } else - c4 = *(backPtr + _screenWide + 1); - } else - c4 = c3; - - if (!transparent) { - uint32 r1 = _palette[c1 * 4 + 0]; - uint32 g1 = _palette[c1 * 4 + 1]; - uint32 b1 = _palette[c1 * 4 + 2]; - - uint32 r2 = _palette[c2 * 4 + 0]; - uint32 g2 = _palette[c2 * 4 + 1]; - uint32 b2 = _palette[c2 * 4 + 2]; - - uint32 r3 = _palette[c3 * 4 + 0]; - uint32 g3 = _palette[c3 * 4 + 1]; - uint32 b3 = _palette[c3 * 4 + 2]; - - uint32 r4 = _palette[c4 * 4 + 0]; - uint32 g4 = _palette[c4 * 4 + 1]; - uint32 b4 = _palette[c4 * 4 + 2]; - - uint32 r5 = (r1 * xFrac + r2 * (dstWidth - xFrac)) / dstWidth; - uint32 g5 = (g1 * xFrac + g2 * (dstWidth - xFrac)) / dstWidth; - uint32 b5 = (b1 * xFrac + b2 * (dstWidth - xFrac)) / dstWidth; - - uint32 r6 = (r3 * xFrac + r4 * (dstWidth - xFrac)) / dstWidth; - uint32 g6 = (g3 * xFrac + g4 * (dstWidth - xFrac)) / dstWidth; - uint32 b6 = (b3 * xFrac + b4 * (dstWidth - xFrac)) / dstWidth; - - uint32 r = (r5 * yFrac + r6 * (dstHeight - yFrac)) / dstHeight; - uint32 g = (g5 * yFrac + g6 * (dstHeight - yFrac)) / dstHeight; - uint32 b = (b5 * yFrac + b6 * (dstHeight - yFrac)) / dstHeight; - - dst[y * dstWidth + x] = quickMatch(r, g, b); - } else - dst[y * dstWidth + x] = 0; - } - } -} - -/** - * Plots a point relative to the top left corner of the screen. This is only - * used for debugging. - * @param x x-coordinate of the point - * @param y y-coordinate of the point - * @param colour colour of the point - */ - -void Screen::plotPoint(int x, int y, uint8 colour) { - byte *buf = _buffer + MENUDEEP * RENDERWIDE; - - x -= _scrollX; - y -= _scrollY; - - if (x >= 0 && x < RENDERWIDE && y >= 0 && y < RENDERDEEP) { - buf[y * RENDERWIDE + x] = colour; - markAsDirty(x, y + MENUDEEP, x, y + MENUDEEP); - } -} - -static void plot(int x, int y, int colour, void *data) { - Screen *screen = (Screen *)data; - screen->plotPoint(x, y, (uint8) colour); -} - -/** - * Draws a line from one point to another. This is only used for debugging. - * @param x0 x-coordinate of the start point - * @param y0 y-coordinate of the start point - * @param x1 x-coordinate of the end point - * @param y1 y-coordinate of the end point - * @param colour colour of the line - */ - -void Screen::drawLine(int x0, int y0, int x1, int y1, uint8 colour) { - Graphics::drawLine(x0, y0, x1, y1, colour, &plot, this); -} - -/** - * This function tells the driver the size of the background screen for the - * current location. - * @param w width of the current location - * @param h height of the current location - */ - -void Screen::setLocationMetrics(uint16 w, uint16 h) { - _locationWide = w; - _locationDeep = h; - setNeedFullRedraw(); -} - -/** - * Draws a parallax layer at the current position determined by the scroll. A - * parallax can be either foreground, background or the main screen. - */ - -void Screen::renderParallax(byte *ptr, int16 l) { - Parallax p; - int16 x, y; - Common::Rect r; - - p.read(ptr); - - if (_locationWide == _screenWide) - x = 0; - else - x = ((int32)((p.w - _screenWide) * _scrollX) / (int32)(_locationWide - _screenWide)); - - if (_locationDeep == _screenDeep - MENUDEEP * 2) - y = 0; - else - y = ((int32)((p.h - (_screenDeep - MENUDEEP * 2)) * _scrollY) / (int32)(_locationDeep - (_screenDeep - MENUDEEP * 2))); - - Common::Rect clipRect; - - // Leave enough space for the top and bottom menues - - clipRect.left = 0; - clipRect.right = _screenWide; - clipRect.top = MENUDEEP; - clipRect.bottom = _screenDeep - MENUDEEP; - - for (int j = 0; j < _yBlocks[l]; j++) { - for (int i = 0; i < _xBlocks[l]; i++) { - if (_blockSurfaces[l][i + j * _xBlocks[l]]) { - r.left = i * BLOCKWIDTH - x; - r.right = r.left + BLOCKWIDTH; - r.top = j * BLOCKHEIGHT - y + MENUDEEP; - r.bottom = r.top + BLOCKHEIGHT; - blitBlockSurface(_blockSurfaces[l][i + j * _xBlocks[l]], &r, &clipRect); - } - } - } - - _parallaxScrollX = _scrollX - x; - _parallaxScrollY = _scrollY - y; -} - -// Uncomment this when benchmarking the drawing routines. -#define LIMIT_FRAME_RATE - -/** - * Initialises the timers before the render loop is entered. - */ - -void Screen::initialiseRenderCycle() { - _initialTime = _vm->_system->getMillis(); - _totalTime = _initialTime + MILLISECSPERCYCLE; -} - -/** - * This function should be called when the game engine is ready to start the - * render cycle. - */ - -void Screen::startRenderCycle() { - _scrollXOld = _scrollX; - _scrollYOld = _scrollY; - - _startTime = _vm->_system->getMillis(); - - if (_startTime + _renderAverageTime >= _totalTime) { - _scrollX = _scrollXTarget; - _scrollY = _scrollYTarget; - _renderTooSlow = true; - } else { - _scrollX = (int16)(_scrollXOld + ((_scrollXTarget - _scrollXOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); - _scrollY = (int16)(_scrollYOld + ((_scrollYTarget - _scrollYOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); - _renderTooSlow = false; - } - - if (_scrollXOld != _scrollX || _scrollYOld != _scrollY) - setNeedFullRedraw(); - - _framesPerGameCycle = 0; -} - -/** - * This function should be called at the end of the render cycle. - * @return true if the render cycle is to be terminated, - * or false if it should continue - */ - -bool Screen::endRenderCycle() { - static int32 renderTimeLog[4] = { 60, 60, 60, 60 }; - static int32 renderCountIndex = 0; - int32 time; - - time = _vm->_system->getMillis(); - renderTimeLog[renderCountIndex] = time - _startTime; - _startTime = time; - _renderAverageTime = (renderTimeLog[0] + renderTimeLog[1] + renderTimeLog[2] + renderTimeLog[3]) >> 2; - - _framesPerGameCycle++; - - if (++renderCountIndex == RENDERAVERAGETOTAL) - renderCountIndex = 0; - - if (_renderTooSlow) { - initialiseRenderCycle(); - return true; - } - - if (_startTime + _renderAverageTime >= _totalTime) { - _totalTime += MILLISECSPERCYCLE; - _initialTime = time; - return true; - } - -#ifdef LIMIT_FRAME_RATE - if (_scrollXTarget == _scrollX && _scrollYTarget == _scrollY) { - // If we have already reached the scroll target sleep for the - // rest of the render cycle. - _vm->sleepUntil(_totalTime); - _initialTime = _vm->_system->getMillis(); - _totalTime += MILLISECSPERCYCLE; - return true; - } -#endif - - // This is an attempt to ensure that we always reach the scroll target. - // Otherwise the game frequently tries to pump out new interpolation - // frames without ever getting anywhere. - - if (ABS(_scrollX - _scrollXTarget) <= 1 && ABS(_scrollY - _scrollYTarget) <= 1) { - _scrollX = _scrollXTarget; - _scrollY = _scrollYTarget; - } else { - _scrollX = (int16)(_scrollXOld + ((_scrollXTarget - _scrollXOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); - _scrollY = (int16)(_scrollYOld + ((_scrollYTarget - _scrollYOld) * (_startTime - _initialTime + _renderAverageTime)) / (_totalTime - _initialTime)); - } - - if (_scrollX != _scrollXOld || _scrollY != _scrollYOld) - setNeedFullRedraw(); - -#ifdef LIMIT_FRAME_RATE - // Give the other threads some breathing space. This apparently helps - // against bug #875683, though I was never able to reproduce it for - // myself. - _vm->_system->delayMillis(10); -#endif - - return false; -} - -/** - * Reset scrolling stuff. This function is called from initBackground() - */ - -void Screen::resetRenderEngine() { - _parallaxScrollX = 0; - _parallaxScrollY = 0; - _scrollX = 0; - _scrollY = 0; -} - -/** - * This function should be called five times with either the parallax layer - * or a NULL pointer in order of background parallax to foreground parallax. - */ - -int32 Screen::initialiseBackgroundLayer(byte *parallax) { - Parallax p; - uint16 i, j, k; - byte *data; - byte *dst; - - debug(2, "initialiseBackgroundLayer"); - - assert(_layer < MAXLAYERS); - - if (!parallax) { - _layer++; - return RD_OK; - } - - p.read(parallax); - - _xBlocks[_layer] = (p.w + BLOCKWIDTH - 1) / BLOCKWIDTH; - _yBlocks[_layer] = (p.h + BLOCKHEIGHT - 1) / BLOCKHEIGHT; - - _blockSurfaces[_layer] = (BlockSurface **)calloc(_xBlocks[_layer] * _yBlocks[_layer], sizeof(BlockSurface *)); - if (!_blockSurfaces[_layer]) - return RDERR_OUTOFMEMORY; - - // Decode the parallax layer into a large chunk of memory - - byte *memchunk = (byte *)calloc(_xBlocks[_layer] * _yBlocks[_layer], BLOCKWIDTH * BLOCKHEIGHT); - if (!memchunk) - return RDERR_OUTOFMEMORY; - - for (i = 0; i < p.h; i++) { - uint32 p_offset = READ_LE_UINT32(parallax + Parallax::size() + 4 * i); - - if (!p_offset) - continue; - - byte *pLine = parallax + p_offset; - uint16 packets = READ_LE_UINT16(pLine); - uint16 offset = READ_LE_UINT16(pLine + 2); - - data = pLine + 4; - dst = memchunk + i * p.w + offset; - - if (!packets) { - memcpy(dst, data, p.w); - continue; - } - - bool zeros = false; - - for (j = 0; j < packets; j++) { - if (zeros) { - dst += *data; - offset += *data; - data++; - zeros = false; - } else if (!*data) { - data++; - zeros = true; - } else { - uint16 count = *data++; - memcpy(dst, data, count); - data += count; - dst += count; - offset += count; - zeros = true; - } - } - } - - // The large memory chunk is now divided into a number of smaller - // surfaces. For most parallax layers, we'll end up using less memory - // this way, and it will be faster to draw since completely transparent - // surfaces are discarded. - - for (i = 0; i < _xBlocks[_layer] * _yBlocks[_layer]; i++) { - bool block_has_data = false; - bool block_is_transparent = false; - - int x = BLOCKWIDTH * (i % _xBlocks[_layer]); - int y = BLOCKHEIGHT * (i / _xBlocks[_layer]); - - data = memchunk + p.w * y + x; - - for (j = 0; j < BLOCKHEIGHT; j++) { - for (k = 0; k < BLOCKWIDTH; k++) { - if (x + k < p.w && y + j < p.h) { - if (data[j * p.w + k]) - block_has_data = true; - else - block_is_transparent = true; - } - } - } - - // Only assign a surface to the block if it contains data. - - if (block_has_data) { - _blockSurfaces[_layer][i] = (BlockSurface *)malloc(sizeof(BlockSurface)); - - // Copy the data into the surfaces. - dst = _blockSurfaces[_layer][i]->data; - for (j = 0; j < BLOCKHEIGHT; j++) { - memcpy(dst, data, BLOCKWIDTH); - data += p.w; - dst += BLOCKWIDTH; - } - - _blockSurfaces[_layer][i]->transparent = block_is_transparent; - - } else - _blockSurfaces[_layer][i] = NULL; - } - - free(memchunk); - _layer++; - - return RD_OK; -} - -/** - * Should be called once after leaving the room to free up memory. - */ - -void Screen::closeBackgroundLayer() { - debug(2, "CloseBackgroundLayer"); - - for (int i = 0; i < MAXLAYERS; i++) { - if (_blockSurfaces[i]) { - for (int j = 0; j < _xBlocks[i] * _yBlocks[i]; j++) - if (_blockSurfaces[i][j]) - free(_blockSurfaces[i][j]); - free(_blockSurfaces[i]); - _blockSurfaces[i] = NULL; - } - } - - _layer = 0; -} - -#ifdef BACKEND_8BIT -void Screen::plotYUV(byte *lut, int width, int height, byte *const *dat) { - byte *buf = _buffer + ((480 - height) / 2) * RENDERWIDE + (640 - width) / 2; - - int x, y; - - int ypos = 0; - int cpos = 0; - int linepos = 0; - - for (y = 0; y < height; y += 2) { - for (x = 0; x < width; x += 2) { - int i = ((((dat[2][cpos] + ROUNDADD) >> SHIFT) * (BITDEPTH + 1)) + ((dat[1][cpos] + ROUNDADD) >> SHIFT)) * (BITDEPTH + 1); - cpos++; - - buf[linepos ] = lut[i + ((dat[0][ ypos ] + ROUNDADD) >> SHIFT)]; - buf[RENDERWIDE + linepos++] = lut[i + ((dat[0][width + ypos++] + ROUNDADD) >> SHIFT)]; - buf[linepos ] = lut[i + ((dat[0][ ypos ] + ROUNDADD) >> SHIFT)]; - buf[RENDERWIDE + linepos++] = lut[i + ((dat[0][width + ypos++] + ROUNDADD) >> SHIFT)]; - } - linepos += (2 * RENDERWIDE - width); - ypos += width; - } -} -#endif - - -} // End of namespace Sword2 diff --git a/sword2/resman.cpp b/sword2/resman.cpp deleted file mode 100644 index 7387dc8f50..0000000000 --- a/sword2/resman.cpp +++ /dev/null @@ -1,633 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "common/file.h" -#include "common/system.h" -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/console.h" -#include "sword2/logic.h" -#include "sword2/memory.h" -#include "sword2/resman.h" -#include "sword2/router.h" -#include "sword2/sound.h" - -#define Debug_Printf _vm->_debugger->DebugPrintf - -namespace Sword2 { - -// Welcome to the easy resource manager - written in simple code for easy -// maintenance -// -// The resource compiler will create two files -// -// resource.inf which is a list of ascii cluster file names -// resource.tab which is a table which tells us which cluster a resource -// is located in and the number within the cluster - -enum { - BOTH = 0x0, // Cluster is on both CDs - CD1 = 0x1, // Cluster is on CD1 only - CD2 = 0x2, // Cluster is on CD2 only - LOCAL_CACHE = 0x4, // Cluster is cached on HDD - LOCAL_PERM = 0x8 // Cluster is on HDD. -}; - -struct CdInf { - uint8 clusterName[20]; // Null terminated cluster name. - uint8 cd; // Cd cluster is on and whether it is on the local drive or not. -}; - -ResourceManager::ResourceManager(Sword2Engine *vm) { - _vm = vm; - - // Until proven differently, assume we're on CD 1. This is so the start - // dialog will be able to play any music at all. - setCD(1); - - // We read in the resource info which tells us the names of the - // resource cluster files ultimately, although there might be groups - // within the clusters at this point it makes no difference. We only - // wish to know what resource files there are and what is in each - - Common::File file; - uint32 size; - byte *temp; - - _totalClusters = 0; - _resConvTable = NULL; - - if (!file.open("resource.inf")) - error("Cannot open resource.inf"); - - size = file.size(); - - // Get some space for the incoming resource file - soon to be trashed - temp = (byte *)malloc(size); - - if (file.read(temp, size) != size) { - file.close(); - error("init cannot *READ* resource.inf"); - } - - file.close(); - - // Ok, we've loaded in the resource.inf file which contains a list of - // all the files now extract the filenames. - - // Using this method the Gode generated resource.inf must have #0d0a on - // the last entry - - uint32 i = 0; - uint32 j = 0; - - do { - // item must have an #0d0a - while (temp[i] != 13) { - _resFiles[_totalClusters].fileName[j] = temp[i]; - i++; - j++; - } - - // NULL terminate our extracted string - _resFiles[_totalClusters].fileName[j] = '\0'; - _resFiles[_totalClusters].numEntries = -1; - _resFiles[_totalClusters].entryTab = NULL; - - // Reset position in current slot between entries, skip the - // 0x0a in the source and increase the number of clusters. - - j = 0; - i += 2; - _totalClusters++; - - // TODO: put overload check here - } while (i != size); - - free(temp); - - // Now load in the binary id to res conversion table - if (!file.open("resource.tab")) - error("Cannot open resource.tab"); - - // Find how many resources - size = file.size(); - - _totalResFiles = size / 4; - - // Table seems ok so malloc some space - _resConvTable = (uint16 *)malloc(size); - - for (i = 0; i < size / 2; i++) - _resConvTable[i] = file.readUint16LE(); - - if (file.ioFailed()) { - file.close(); - error("Cannot read resource.tab"); - } - - file.close(); - - if (!file.open("cd.inf")) - error("Cannot open cd.inf"); - - CdInf *cdInf = new CdInf[_totalClusters]; - - for (i = 0; i < _totalClusters; i++) { - file.read(cdInf[i].clusterName, sizeof(cdInf[i].clusterName)); - - cdInf[i].cd = file.readByte(); - - if (file.ioFailed()) - error("Cannot read cd.inf"); - - // It has been reported that there are two different versions - // of the cd.inf file: One where all clusters on CD also have - // the LOCAL_CACHE bit set. This bit is no longer used. To - // avoid future problems, let's normalize the flag once and for - // all here. - - if (cdInf[i].cd & LOCAL_PERM) - cdInf[i].cd = 0; - else if (cdInf[i].cd & CD1) - cdInf[i].cd = 1; - else if (cdInf[i].cd & CD2) - cdInf[i].cd = 2; - else - cdInf[i].cd = 0; - } - - file.close(); - - for (i = 0; i < _totalClusters; i++) { - for (j = 0; j < _totalClusters; j++) { - if (scumm_stricmp((char *)cdInf[j].clusterName, _resFiles[i].fileName) == 0) - break; - } - - if (j == _totalClusters) - error("%s is not in cd.inf", _resFiles[i].fileName); - - _resFiles[i].cd = cdInf[j].cd; - } - - delete [] cdInf; - - debug(1, "%d resources in %d cluster files", _totalResFiles, _totalClusters); - for (i = 0; i < _totalClusters; i++) - debug(2, "filename of cluster %d: -%s (%d)", i, _resFiles[i].fileName, _resFiles[i].cd); - - _resList = (Resource *)malloc(_totalResFiles * sizeof(Resource)); - - for (i = 0; i < _totalResFiles; i++) { - _resList[i].ptr = NULL; - _resList[i].size = 0; - _resList[i].refCount = 0; - _resList[i].prev = _resList[i].next = NULL; - } - _cacheStart = _cacheEnd = NULL; - _usedMem = 0; -} - -ResourceManager::~ResourceManager() { - Resource *res = _cacheStart; - while (res) { - _vm->_memory->memFree(res->ptr); - res = res->next; - } - for (uint i = 0; i < _totalClusters; i++) - free(_resFiles[i].entryTab); - free(_resList); - free(_resConvTable); -} - -/** - * Returns the address of a resource. Loads if not in memory. Retains a count. - */ - -byte *ResourceManager::openResource(uint32 res, bool dump) { - assert(res < _totalResFiles); - - // Is the resource in memory already? If not, load it. - - if (!_resList[res].ptr) { - // Fetch the correct file and read in the correct portion. - uint16 cluFileNum = _resConvTable[res * 2]; // points to the number of the ascii filename - assert(cluFileNum != 0xffff); - - // Relative resource within the file - // First we have to find the file via the _resConvTable - uint16 actual_res = _resConvTable[(res * 2) + 1]; - - debug(5, "openResource %s res %d", _resFiles[cluFileNum].fileName, res); - - // If we're loading a cluster that's only available from one - // of the CDs, remember which one so that we can play the - // correct speech and music. - - setCD(_resFiles[cluFileNum].cd); - - // Actually, as long as the file can be found we don't really - // care which CD it's on. But if we can't find it, keep asking - // for the CD until we do. - - Common::File *file = openCluFile(cluFileNum); - - if (_resFiles[cluFileNum].entryTab == NULL) { - // we didn't read from this file before, get its index table - readCluIndex(cluFileNum, file); - } - - uint32 pos = _resFiles[cluFileNum].entryTab[actual_res * 2 + 0]; - uint32 len = _resFiles[cluFileNum].entryTab[actual_res * 2 + 1]; - - file->seek(pos, SEEK_SET); - - debug(6, "res len %d", len); - - // Ok, we know the length so try and allocate the memory. - _resList[res].ptr = _vm->_memory->memAlloc(len, res); - _resList[res].size = len; - _resList[res].refCount = 0; - - file->read(_resList[res].ptr, len); - - debug(3, "Loaded resource '%s' from '%s' on CD %d (%d)", fetchName(_resList[res].ptr), _resFiles[cluFileNum].fileName, getCD(), _resFiles[cluFileNum].cd); - - if (dump) { - char buf[256]; - const char *tag; - Common::File out; - - switch (fetchType(_resList[res].ptr)) { - case ANIMATION_FILE: - tag = "anim"; - break; - case SCREEN_FILE: - tag = "layer"; - break; - case GAME_OBJECT: - tag = "object"; - break; - case WALK_GRID_FILE: - tag = "walkgrid"; - break; - case GLOBAL_VAR_FILE: - tag = "globals"; - break; - case PARALLAX_FILE_null: - tag = "parallax"; // Not used! - break; - case RUN_LIST: - tag = "runlist"; - break; - case TEXT_FILE: - tag = "text"; - break; - case SCREEN_MANAGER: - tag = "screen"; - break; - case MOUSE_FILE: - tag = "mouse"; - break; - case WAV_FILE: - tag = "wav"; - break; - case ICON_FILE: - tag = "icon"; - break; - case PALETTE_FILE: - tag = "palette"; - break; - default: - tag = "unknown"; - break; - } - -#if defined(MACOS_CARBON) - sprintf(buf, ":dumps:%s-%d.dmp", tag, res); -#else - sprintf(buf, "dumps/%s-%d.dmp", tag, res); -#endif - - if (!out.exists(buf, "")) { - if (out.open(buf, Common::File::kFileWriteMode, "")) - out.write(_resList[res].ptr, len); - } - } - - // close the cluster - file->close(); - delete file; - - _usedMem += len; - checkMemUsage(); - } else if (_resList[res].refCount == 0) - removeFromCacheList(_resList + res); - - _resList[res].refCount++; - - return _resList[res].ptr; -} - -void ResourceManager::closeResource(uint32 res) { - assert(res < _totalResFiles); - - // Don't try to close the resource if it has already been forcibly - // closed, e.g. by fnResetGlobals(). - - if (_resList[res].ptr == NULL) - return; - - assert(_resList[res].refCount > 0); - - _resList[res].refCount--; - if (_resList[res].refCount == 0) - addToCacheList(_resList + res); - - // It's tempting to free the resource immediately when refCount - // reaches zero, but that'd be a mistake. Closing a resource does not - // mean "I'm not going to use this resource any more". It means that - // "the next time I use this resource I'm going to ask for a new - // pointer to it". - // - // Since the original memory manager had to deal with memory - // fragmentation, keeping a resource open - and thus locked down to a - // specific memory address - was considered a bad thing. -} - -void ResourceManager::removeFromCacheList(Resource *res) { - if (_cacheStart == res) - _cacheStart = res->next; - - if (_cacheEnd == res) - _cacheEnd = res->prev; - - if (res->prev) - res->prev->next = res->next; - if (res->next) - res->next->prev = res->prev; - res->prev = res->next = NULL; -} - -void ResourceManager::addToCacheList(Resource *res) { - res->prev = NULL; - res->next = _cacheStart; - if (_cacheStart) - _cacheStart->prev = res; - _cacheStart = res; - if (!_cacheEnd) - _cacheEnd = res; -} - -Common::File *ResourceManager::openCluFile(uint16 fileNum) { - Common::File *file = new Common::File; - while (!file->open(_resFiles[fileNum].fileName)) { - // HACK: We have to check for this, or it'll be impossible to - // quit while the game is asking for the user to insert a CD. - // But recovering from this situation gracefully is just too - // much trouble, so quit now. - if (_vm->_quit) - g_system->quit(); - - // If the file is supposed to be on hard disk, or we're - // playing a demo, then we're in trouble if the file - // can't be found! - - if ((_vm->_features & GF_DEMO) || _resFiles[fileNum].cd == 0) - error("Could not find '%s'", _resFiles[fileNum].fileName); - - askForCD(_resFiles[fileNum].cd); - } - return file; -} - -void ResourceManager::readCluIndex(uint16 fileNum, Common::File *file) { - if (_resFiles[fileNum].entryTab == NULL) { - // we didn't read from this file before, get its index table - if (file == NULL) - file = openCluFile(fileNum); - else - file->incRef(); - - // 1st DWORD of a cluster is an offset to the look-up table - uint32 table_offset = file->readUint32LE(); - debug(6, "table offset = %d", table_offset); - uint32 tableSize = file->size() - table_offset; // the table is stored at the end of the file - file->seek(table_offset); - - assert((tableSize % 8) == 0); - _resFiles[fileNum].entryTab = (uint32*)malloc(tableSize); - _resFiles[fileNum].numEntries = tableSize / 8; - file->read(_resFiles[fileNum].entryTab, tableSize); - if (file->ioFailed()) - error("unable to read index table from file %s\n", _resFiles[fileNum].fileName); -#ifdef SCUMM_BIG_ENDIAN - for (int tabCnt = 0; tabCnt < _resFiles[fileNum].numEntries * 2; tabCnt++) - _resFiles[fileNum].entryTab[tabCnt] = FROM_LE_32(_resFiles[fileNum].entryTab[tabCnt]); -#endif - file->decRef(); - } -} - -/** - * Returns true if resource is valid, otherwise false. - */ - -bool ResourceManager::checkValid(uint32 res) { - // Resource number out of range - if (res >= _totalResFiles) - return false; - - // Points to the number of the ascii filename - uint16 parent_res_file = _resConvTable[res * 2]; - - // Null & void resource - if (parent_res_file == 0xffff) - return false; - - return true; -} - -/** - * Returns the total file length of a resource - i.e. all headers are included - * too. - */ - -uint32 ResourceManager::fetchLen(uint32 res) { - if (_resList[res].ptr) - return _resList[res].size; - - // Does this ever happen? - warning("fetchLen: Resource %u is not loaded; reading length from file", res); - - // Points to the number of the ascii filename - uint16 parent_res_file = _resConvTable[res * 2]; - - // relative resource within the file - uint16 actual_res = _resConvTable[(res * 2) + 1]; - - // first we have to find the file via the _resConvTable - // open the cluster file - - if (_resFiles[parent_res_file].entryTab == NULL) { - readCluIndex(parent_res_file); - } - return _resFiles[parent_res_file].entryTab[actual_res * 2 + 1]; -} - -void ResourceManager::checkMemUsage() { - while (_usedMem > MAX_MEM_CACHE) { - // we're using up more memory than we wanted to. free some old stuff. - // Newly loaded objects are added to the start of the list, - // we start freeing from the end, to free the oldest items first - if (_cacheEnd) { - Resource *tmp = _cacheEnd; - assert((tmp->refCount == 0) && (tmp->ptr) && (tmp->next == NULL)); - removeFromCacheList(tmp); - - _vm->_memory->memFree(tmp->ptr); - tmp->ptr = NULL; - _usedMem -= tmp->size; - } else { - warning("%d bytes of memory used, but cache list is empty!\n"); - return; - } - } -} - -void ResourceManager::remove(int res) { - if (_resList[res].ptr) { - removeFromCacheList(_resList + res); - - _vm->_memory->memFree(_resList[res].ptr); - _resList[res].ptr = NULL; - _resList[res].refCount = 0; - _usedMem -= _resList[res].size; - } -} - -/** - * Remove all res files from memory - ready for a total restart. This includes - * the player object and global variables resource. - */ - -void ResourceManager::removeAll() { - // We need to clear the FX queue, because otherwise the sound system - // will still believe that the sound resources are in memory, and that - // it's ok to close them. - - _vm->_sound->clearFxQueue(); - - for (uint i = 0; i < _totalResFiles; i++) - remove(i); -} - -/** - * Remove all resources from memory. - */ - -void ResourceManager::killAll(bool wantInfo) { - int nuked = 0; - - // We need to clear the FX queue, because otherwise the sound system - // will still believe that the sound resources are in memory, and that - // it's ok to close them. - - _vm->_sound->clearFxQueue(); - - for (uint i = 0; i < _totalResFiles; i++) { - // Don't nuke the global variables or the player object! - if (i == 1 || i == CUR_PLAYER_ID) - continue; - - if (_resList[i].ptr) { - if (wantInfo) - Debug_Printf("Nuked %5d: %s\n", i, fetchName(_resList[i].ptr)); - - remove(i); - nuked++; - } - } - - if (wantInfo) - Debug_Printf("Expelled %d resources\n", nuked); -} - -/** - * Like killAll but only kills objects (except George & the variable table of - * course) - ie. forcing them to reload & restart their scripts, which - * simulates the effect of a save & restore, thus checking that each object's - * re-entrant logic works correctly, and doesn't cause a statuette to - * disappear forever, or some plaster-filled holes in sand to crash the game & - * get James in trouble again. - */ - -void ResourceManager::killAllObjects(bool wantInfo) { - int nuked = 0; - - for (uint i = 0; i < _totalResFiles; i++) { - // Don't nuke the global variables or the player object! - if (i == 1 || i == CUR_PLAYER_ID) - continue; - - if (_resList[i].ptr) { - if (fetchType(_resList[i].ptr) == GAME_OBJECT) { - if (wantInfo) - Debug_Printf("Nuked %5d: %s\n", i, fetchName(_resList[i].ptr)); - - remove(i); - nuked++; - } - } - } - - if (wantInfo) - Debug_Printf("Expelled %d resources\n", nuked); -} - -void ResourceManager::askForCD(int cd) { - byte *textRes; - - // Stop any music from playing - so the system no longer needs the - // current CD - otherwise when we take out the CD, Windows will - // complain! - - _vm->_sound->stopMusic(true); - - textRes = openResource(2283); - _vm->_screen->displayMsg(_vm->fetchTextLine(textRes, 5 + cd) + 2, 0); - closeResource(2283); - - // The original code probably determined automagically when the correct - // CD had been inserted, but our backend doesn't support that, and - // anyway I don't know if all systems allow that sort of thing. So we - // wait for the user to press any key instead, or click the mouse. - // - // But just in case we ever try to identify the CDs by their labels, - // they should be: - // - // CD1: "RBSII1" (or "PCF76" for the PCF76 version, whatever that is) - // CD2: "RBSII2" -} - -} // End of namespace Sword2 diff --git a/sword2/resman.h b/sword2/resman.h deleted file mode 100644 index 18b5cb8765..0000000000 --- a/sword2/resman.h +++ /dev/null @@ -1,134 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef RESMAN_H -#define RESMAN_H - -namespace Common { - class File; -} - -#define MAX_MEM_CACHE (8 * 1024 * 1024) // we keep up to 8 megs of resource data files in memory -#define MAX_res_files 20 - -namespace Sword2 { - -class Sword2Engine; - -struct Resource { - byte *ptr; - uint32 size; - uint32 refCount; - Resource *next, *prev; -}; - -struct ResourceFile { - char fileName[20]; - int32 numEntries; - uint32 *entryTab; - uint8 cd; -}; - -class ResourceManager { -private: - Common::File *openCluFile(uint16 fileNum); - void readCluIndex(uint16 fileNum, Common::File *file = NULL); - void removeFromCacheList(Resource *res); - void addToCacheList(Resource *res); - void checkMemUsage(); - - Sword2Engine *_vm; - - int _curCD; - uint32 _totalResFiles; - uint32 _totalClusters; - - // Gode generated res-id to res number/rel number conversion table - - uint16 *_resConvTable; - ResourceFile _resFiles[MAX_res_files]; - Resource *_resList; - - Resource *_cacheStart, *_cacheEnd; - uint32 _usedMem; // amount of used memory in bytes - -public: - ResourceManager(Sword2Engine *vm); // read in the config file - ~ResourceManager(); - - uint32 getNumResFiles() { return _totalResFiles; } - uint32 getNumClusters() { return _totalClusters; } - ResourceFile *getResFiles() { return _resFiles; } - Resource *getResList() { return _resList; } - - byte *openResource(uint32 res, bool dump = false); - void closeResource(uint32 res); - - bool checkValid(uint32 res); - uint32 fetchLen(uint32 res); - uint8 fetchType(uint32 res) { - byte *ptr = openResource(res); - uint8 type = ptr[0]; - closeResource(res); - - return type; - } - - uint8 fetchType(byte *ptr) { - return ptr[0]; - } - - byte *fetchName(uint32 res, byte *buf) { - byte *ptr = openResource(res); - memcpy(buf, ptr + 10, NAME_LEN); - closeResource(res); - - return buf; - } - - byte *fetchName(byte *ptr) { - return ptr + 10; - } - - // Prompts the user for the specified CD. - void askForCD(int cd); - - void setCD(int cd) { - if (cd) - _curCD = cd; - } - - int getCD() { - return _curCD; - } - - void remove(int res); - void removeAll(); - - // ----console commands - - void killAll(bool wantInfo); - void killAllObjects(bool wantInfo); -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/router.cpp b/sword2/router.cpp deleted file mode 100644 index bbca609e3c..0000000000 --- a/sword2/router.cpp +++ /dev/null @@ -1,2506 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -// --------------------------------------------------------------------------- -// ROUTER.CPP by James -// -// A rehash of Jeremy's original jrouter.c, containing low-level system -// routines for calculating routes between points inside a walk-grid, and -// constructing walk animations from mega-sets. -// -// jrouter.c underwent 2 major reworks from the original: -// (1) Restructured to allow more flexibility in the mega-sets, ie. more info -// taken from the walk-data -// - the new George & Nico mega-sets & walk-data were then tested & -// tweaked in the Sword1 system -// (2) Updated for the new Sword2 system, ie. new object structures -// - now compatible with Sword2, the essential code already having been -// tested -// -// --------------------------------------------------------------------------- - -/**************************************************************************** - * JROUTER.C polygon router with modular walks - * using a tree of modules - * 21 july 94 - * 3 november 94 - * System currently works by scanning grid data and coming up with a ROUTE - * as a series of way points(nodes), the smoothest eight directional PATH - * through these nodes is then found, and a WALK created to fit the PATH. - * - * Two funtions are called by the user, RouteFinder creates a route as a - * module list, HardWalk creates an animation list from the module list. - * The split is only provided to allow the possibility of turning the - * autorouter over two game cycles. - **************************************************************************** - * - * Routine timings on osborne 486 - * - * Read floor resource (file already loaded) 112 pixels - * - * Read mega resource (file already loaded) 112 pixels - * - * - * - **************************************************************************** - * - * Modified 12 Oct 95 - * - * Target Points within 1 pixel of a line are ignored ??? - * - * Modules split into Points within 1 pixel of a line are ignored ??? - * - **************************************************************************** - * - * TOTALLY REHASHED BY JAMES FOR NEW MEGAS USING OLD SYSTEM - * THEN REINCARNATED BY JAMES FOR NEW MEGAS USING NEW SYSTEM - * - ****************************************************************************/ - -#include "common/stdafx.h" -#include "common/stream.h" -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/resman.h" -#include "sword2/router.h" - -namespace Sword2 { - -//---------------------------------------------------------- -// (4) WALK-GRID FILES -//---------------------------------------------------------- -// a walk-grid file consists of: -// -// standard file header -// walk-grid file header -// walk-grid data - -// Walk-Grid Header - taken directly from old "header.h" in STD_INC - -struct WalkGridHeader { - int32 numBars; // number of bars on the floor - int32 numNodes; // number of nodes -}; - -uint8 Router::returnSlotNo(uint32 megaId) { - if (_vm->_logic->readVar(ID) == CUR_PLAYER_ID) { - // George (8) - return 0; - } else { - // One of Nico's mega id's - return 1; - } -} - -void Router::allocateRouteMem() { - uint8 slotNo; - - // Player character always always slot 0, while the other mega - // (normally Nico) always uses slot 1 - // Better this way, so that if mega object removed from memory while - // in middle of route, the old route will be safely cleared from - // memory just before they create a new one - - slotNo = returnSlotNo(_vm->_logic->readVar(ID)); - - // if this slot is already used, then it can't be needed any more - // because this id is creating a new route! - - if (_routeSlots[slotNo]) - freeRouteMem(); - - _routeSlots[slotNo] = (WalkData *)malloc(sizeof(WalkData) * O_WALKANIM_SIZE); - - // 12000 bytes were used for this in Sword1 mega compacts, based on - // 20 bytes per 'WalkData' frame - // ie. allowing for 600 frames including end-marker - // Now 'WalkData' is 8 bytes, so 8*600 = 4800 bytes. - // Note that a 600 frame walk lasts about 48 seconds! - // (600fps / 12.5s = 48s) - - // mega keeps note of which slot contains the pointer to it's walk - // animation mem block - // +1 so that '0' can mean "not walking" - // megaObject->route_slot_id = slotNo + 1; -} - -WalkData *Router::getRouteMem() { - uint8 slotNo = returnSlotNo(_vm->_logic->readVar(ID)); - - return (WalkData *)_routeSlots[slotNo]; -} - -void Router::freeRouteMem() { - uint8 slotNo = returnSlotNo(_vm->_logic->readVar(ID)); - - free(_routeSlots[slotNo]); - _routeSlots[slotNo] = NULL; -} - -void Router::freeAllRouteMem() { - for (int i = 0; i < TOTAL_ROUTE_SLOTS; i++) { - free(_routeSlots[i]); - _routeSlots[i] = NULL; - } -} - -int32 Router::routeFinder(byte *ob_mega, byte *ob_walkdata, int32 x, int32 y, int32 dir) { - /********************************************************************* - * RouteFinder.C polygon router with modular walks - * 21 august 94 - * 3 november 94 - * routeFinder creates a list of modules that enables HardWalk to - * create an animation list. - * - * routeFinder currently works by scanning grid data and coming up - * with a ROUTE as a series of way points(nodes), the smoothest eight - * directional PATH through these nodes is then found, this - * information is made available to HardWalk for a WALK to be created - * to fit the PATH. - * - * 30 november 94 return values modified - * - * return 0 = failed to find a route - * - * 1 = found a route - * - * 2 = mega already at target - * - *********************************************************************/ - - int32 routeFlag = 0; - int32 solidFlag = 0; - WalkData *walkAnim; - - // megaId = id; - - setUpWalkGrid(ob_mega, x, y, dir); - loadWalkData(ob_walkdata); - - walkAnim = getRouteMem(); - - // All route data now loaded start finding a route - - // Check if we can get a route through the floor. changed 12 Oct95 JPS - - routeFlag = getRoute(); - - switch (routeFlag) { - case 2: - // special case for zero length route - - // if target direction specified as any - if (_targetDir > 7) - _targetDir = _startDir; - - // just a turn on the spot is required set an end module for - // the route let the animator deal with it - // modularPath is normally set by extractRoute - - _modularPath[0].dir = _startDir; - _modularPath[0].num = 0; - _modularPath[0].x = _startX; - _modularPath[0].y = _startY; - _modularPath[1].dir = _targetDir; - _modularPath[1].num = 0; - _modularPath[1].x = _startX; - _modularPath[1].y = _startY; - _modularPath[2].dir = 9; - _modularPath[2].num = ROUTE_END_FLAG; - - slidyWalkAnimator(walkAnim); - routeFlag = 2; - break; - case 1: - // A normal route. Convert the route to an exact path - smoothestPath(); - - // The Route had waypoints and direction options - - // The Path is an exact set of lines in 8 directions that - // reach the target. - - // The path is in module format, but steps taken in each - // direction are not accurate - - // if target dir = 8 then the walk isn't linked to an anim so - // we can create a route without sliding and miss the exact - // target - -#ifndef FORCE_SLIDY - if (_targetDir == 8) { - // can end facing ANY direction (ie. exact end - // position not vital) - so use SOLID walk to - // avoid sliding to exact position - - solidPath(); - solidFlag = solidWalkAnimator(walkAnim); - } -#endif - - if (!solidFlag) { - // if we failed to create a SOLID route, do a SLIDY - // one instead - - slidyPath(); - slidyWalkAnimator(walkAnim); - } - - break; - default: - // Route didn't reach target so assume point was off the floor - // routeFlag = 0; - break; - } - - return routeFlag; // send back null route -} - -int32 Router::getRoute() { - /********************************************************************* - * GetRoute.C extract a path from walk grid - * 12 october 94 - * - * GetRoute currently works by scanning grid data and coming up with - * a ROUTE as a series of way points(nodes). - * - * static routeData _route[O_ROUTE_SIZE]; - * - * return 0 = failed to find a route - * - * 1 = found a route - * - * 2 = mega already at target - * - * 3 = failed to find a route because target was on a line - * - *********************************************************************/ - - int32 routeGot = 0; - - if (_startX == _targetX && _startY == _targetY) - routeGot = 2; - else { - // 'else' added by JEL (23jan96) otherwise 'routeGot' affected - // even when already set to '2' above - causing some 'turns' - // to walk downwards on the spot - - // returns 3 if target on a line ( +- 1 pixel ) - routeGot = checkTarget(_targetX, _targetY); - } - - if (routeGot == 0) { - // still looking for a route check if target is within a pixel - // of a line - - // scan through the nodes linking each node to its nearest - // neighbour until no more nodes change - - // This is the routine that finds a route using scan() - - int32 level = 1; - - while (scan(level)) - level++; - - // Check to see if the route reached the target - - if (_node[_nNodes].dist < 9999) { - // it did so extract the route as nodes and the - // directions to go between each node - - routeGot = 1; - extractRoute(); - - // route.X,route.Y and route.Dir now hold all the - // route infomation with the target dir or route - // continuation - } - } - - return routeGot; -} - -// THE SLIDY PATH ROUTINES - -int32 Router::smoothestPath() { - // This is the second big part of the route finder and the the only - // bit that tries to be clever (the other bits are clever). - // - // This part of the autorouter creates a list of modules from a set of - // lines running across the screen. The task is complicated by two - // things: - // - // Firstly in choosing a route through the maze of nodes the routine - // tries to minimise the amount of each individual turn avoiding 90 - // degree and greater turns (where possible) and reduces the total - // number of turns (subject to two 45 degree turns being better than - // one 90 degree turn). - // - // Secondly when walking in a given direction the number of steps - // required to reach the end of that run is not calculated accurately. - // This is because I was unable to derive a function to relate number - // of steps taken between two points to the shrunken step size - - int i; - int32 steps = 0; - int32 lastDir; - int32 tempturns[4]; - int32 turns[4]; - int32 turntable[NO_DIRECTIONS] = { 0, 1, 3, 5, 7, 5, 3, 1 }; - - // route.X route.Y and route.Dir start at far end - - _smoothPath[0].x = _startX; - _smoothPath[0].y = _startY; - _smoothPath[0].dir = _startDir; - _smoothPath[0].num = 0; - - lastDir = _startDir; - - // for each section of the route - - for (int p = 0; p < _routeLength; p++) { - int32 dirS = _route[p].dirS; - int32 dirD = _route[p].dirD; - int32 nextDirS = _route[p + 1].dirS; - int32 nextDirD = _route[p + 1].dirD; - - // Check directions into and out of a pair of nodes going in - int32 dS = dirS - lastDir; - if (dS < 0) - dS = dS + NO_DIRECTIONS; - - int32 dD = dirD - lastDir; - if (dD < 0) - dD = dD + NO_DIRECTIONS; - - // coming out - int32 dSS = dirS - nextDirS; - if (dSS < 0) - dSS = dSS + NO_DIRECTIONS; - - int32 dDD = dirD - nextDirD; - if (dDD < 0) - dDD = dDD + NO_DIRECTIONS; - - int32 dSD = dirS - nextDirD; - if (dSD < 0) - dSD = dSD + NO_DIRECTIONS; - - int32 dDS = dirD - nextDirS; - if (dDS < 0) - dDS = dDS + NO_DIRECTIONS; - - // Determine the amount of turning involved in each possible - // path - - dS = turntable[dS]; - dD = turntable[dD]; - dSS = turntable[dSS]; - dDD = turntable[dDD]; - dSD = turntable[dSD]; - dDS = turntable[dDS]; - - // get the best path out ie assume next section uses best - // direction - - if (dSD < dSS) - dSS = dSD; - - if (dDS < dDD) - dDD = dDS; - - // Rate each option. Split routes look crap so weight against - // them - - int32 SS = dS + dSS + 3; - int32 SD = dS + dDD; - int32 DS = dD + dSS; - int32 DD = dD + dDD + 3; - - // set up turns as a sorted array of the turn values - - tempturns[0] = SS; - turns[0] = 0; - tempturns[1] = SD; - turns[1] = 1; - tempturns[2] = DS; - turns[2] = 2; - tempturns[3] = DD; - turns[3] = 3; - - for (i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if (tempturns[j] > tempturns[j + 1]) { - SWAP(turns[j], turns[j + 1]); - SWAP(tempturns[j], tempturns[j + 1]); - } - } - } - - // best option matched in order of the priority we would like - // to see on the screen but each option must be checked to see - // if it can be walked - - int32 options = newCheck(1, _route[p].x, _route[p].y, _route[p + 1].x, _route[p + 1].y); - - assert(options); - - i = 0; - steps = 0; - - do { - int32 opt = 1 << turns[i]; - if (options & opt) - steps = smoothCheck(turns[i], p, dirS, dirD); - i++; - } while (steps == 0 && i < 4); - - assert(steps); - - // route.X route.Y route.dir and bestTurns start at far end - } - - // best turns will end heading as near as possible to target dir rest - // is down to anim for now - - _smoothPath[steps].dir = 9; - _smoothPath[steps].num = ROUTE_END_FLAG; - return 1; -} - -int32 Router::smoothCheck(int32 best, int32 p, int32 dirS, int32 dirD) { - /********************************************************************* - * Slip sliding away - * This path checker checks to see if a walk that exactly follows the - * path would be valid. This should be inherently true for atleast one - * of the turn options. - * No longer checks the data it only creates the smoothPath array JPS - *********************************************************************/ - - static int32 k; - int32 dsx, dsy; - int32 ddx, ddy; - int32 ss0, ss1, ss2; - int32 sd0, sd1, sd2; - - if (p == 0) - k = 1; - - int32 x = _route[p].x; - int32 y = _route[p].y; - int32 x2 = _route[p + 1].x; - int32 y2 = _route[p + 1].y; - int32 ldx = x2 - x; - int32 ldy = y2 - y; - int32 dirX = 1; - int32 dirY = 1; - - if (ldx < 0) { - ldx = -ldx; - dirX = -1; - } - - if (ldy < 0) { - ldy = -ldy; - dirY = -1; - } - - // set up sd0-ss2 to reflect possible movement in each direction - - if (dirS == 0 || dirS == 4) { // vert and diag - ddx = ldx; - ddy = (ldx * _diagonaly) / _diagonalx; - dsy = ldy - ddy; - ddx = ddx * dirX; - ddy = ddy * dirY; - dsy = dsy * dirY; - dsx = 0; - - sd0 = (ddx + _modX[dirD] / 2) / _modX[dirD]; - ss0 = (dsy + _modY[dirS] / 2) / _modY[dirS]; - sd1 = sd0 / 2; - ss1 = ss0 / 2; - sd2 = sd0 - sd1; - ss2 = ss0 - ss1; - } else { - ddy = ldy; - ddx = (ldy * _diagonalx) / _diagonaly; - dsx = ldx - ddx; - ddy = ddy * dirY; - ddx = ddx * dirX; - dsx = dsx * dirX; - dsy = 0; - - sd0 = (ddy + _modY[dirD] / 2) / _modY[dirD]; - ss0 = (dsx + _modX[dirS] / 2) / _modX[dirS]; - sd1 = sd0 / 2; - ss1 = ss0 / 2; - sd2 = sd0 - sd1; - ss2 = ss0 - ss1; - } - - switch (best) { - case 0: // halfsquare, diagonal, halfsquare - _smoothPath[k].x = x + dsx / 2; - _smoothPath[k].y = y + dsy / 2; - _smoothPath[k].dir = dirS; - _smoothPath[k].num = ss1; - k++; - - _smoothPath[k].x = x + dsx / 2 + ddx; - _smoothPath[k].y = y + dsy / 2 + ddy; - _smoothPath[k].dir = dirD; - _smoothPath[k].num = sd0; - k++; - - _smoothPath[k].x = x + dsx + ddx; - _smoothPath[k].y = y + dsy + ddy; - _smoothPath[k].dir = dirS; - _smoothPath[k].num = ss2; - k++; - - break; - case 1: // square, diagonal - _smoothPath[k].x = x + dsx; - _smoothPath[k].y = y + dsy; - _smoothPath[k].dir = dirS; - _smoothPath[k].num = ss0; - k++; - - _smoothPath[k].x = x2; - _smoothPath[k].y = y2; - _smoothPath[k].dir = dirD; - _smoothPath[k].num = sd0; - k++; - - break; - case 2: // diagonal square - _smoothPath[k].x = x + ddx; - _smoothPath[k].y = y + ddy; - _smoothPath[k].dir = dirD; - _smoothPath[k].num = sd0; - k++; - - _smoothPath[k].x = x2; - _smoothPath[k].y = y2; - _smoothPath[k].dir = dirS; - _smoothPath[k].num = ss0; - k++; - - break; - default: // halfdiagonal, square, halfdiagonal - _smoothPath[k].x = x + ddx / 2; - _smoothPath[k].y = y + ddy / 2; - _smoothPath[k].dir = dirD; - _smoothPath[k].num = sd1; - k++; - - _smoothPath[k].x = x + dsx + ddx / 2; - _smoothPath[k].y = y + dsy + ddy / 2; - _smoothPath[k].dir = dirS; - _smoothPath[k].num = ss0; - k++; - - _smoothPath[k].x = x2; - _smoothPath[k].y = y2; - _smoothPath[k].dir = dirD; - _smoothPath[k].num = sd2; - k++; - - break; - } - - return k; -} - -void Router::slidyPath() { - /********************************************************************* - * slidyPath creates a path based on part steps with no sliding to get - * as near as possible to the target without any sliding this routine - * is intended for use when just clicking about. - * - * produce a module list from the line data - *********************************************************************/ - - int32 smooth = 1; - int32 slidy = 1; - - // strip out the short sections - - _modularPath[0].x = _smoothPath[0].x; - _modularPath[0].y = _smoothPath[0].y; - _modularPath[0].dir = _smoothPath[0].dir; - _modularPath[0].num = 0; - - while (_smoothPath[smooth].num < ROUTE_END_FLAG) { - int32 scale = _scaleA * _smoothPath[smooth].y + _scaleB; - int32 deltaX = _smoothPath[smooth].x - _modularPath[slidy - 1].x; - int32 deltaY = _smoothPath[smooth].y - _modularPath[slidy - 1].y; - // quarter a step minimum - int32 stepX = (scale * _modX[_smoothPath[smooth].dir]) >> 19; - int32 stepY = (scale * _modY[_smoothPath[smooth].dir]) >> 19; - - if (ABS(deltaX) >= ABS(stepX) && ABS(deltaY) >= ABS(stepY)) { - _modularPath[slidy].x = _smoothPath[smooth].x; - _modularPath[slidy].y = _smoothPath[smooth].y; - _modularPath[slidy].dir = _smoothPath[smooth].dir; - _modularPath[slidy].num = 1; - slidy++; - } - smooth++; - } - - // in case the last bit had no steps - - if (slidy > 1) { - _modularPath[slidy - 1].x = _smoothPath[smooth - 1].x; - _modularPath[slidy - 1].y = _smoothPath[smooth - 1].y; - } - - // set up the end of the walk - - _modularPath[slidy].x = _smoothPath[smooth - 1].x; - _modularPath[slidy].y = _smoothPath[smooth - 1].y; - _modularPath[slidy].dir = _targetDir; - _modularPath[slidy].num = 0; - slidy++; - - _modularPath[slidy].x = _smoothPath[smooth - 1].x; - _modularPath[slidy].y = _smoothPath[smooth - 1].y; - _modularPath[slidy].dir = 9; - _modularPath[slidy].num = ROUTE_END_FLAG; - slidy++; -} - -// SLOW IN - -bool Router::addSlowInFrames(WalkData *walkAnim) { - if (_walkData.usingSlowInFrames && _modularPath[1].num > 0) { - for (int slowInFrameNo = 0; slowInFrameNo < _walkData.nSlowInFrames[_currentDir]; slowInFrameNo++) { - walkAnim[_stepCount].frame = _firstSlowInFrame[_currentDir] + slowInFrameNo; - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = _currentDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - } - return true; - } - - return false; -} - -void Router::earlySlowOut(byte *ob_mega, byte *ob_walkdata) { - int32 slowOutFrameNo; - int32 walk_pc; - WalkData *walkAnim; - - ObjectMega obMega(ob_mega); - - debug(5, "EARLY SLOW-OUT"); - - loadWalkData(ob_walkdata); - - debug(5, "********************************"); - debug(5, "_framesPerStep = %d", _framesPerStep); - debug(5, "_numberOfSlowOutFrames = %d", _numberOfSlowOutFrames); - debug(5, "_firstWalkingTurnLeftFrame = %d", _firstWalkingTurnLeftFrame); - debug(5, "_firstWalkingTurnRightFrame = %d", _firstWalkingTurnRightFrame); - debug(5, "_firstSlowOutFrame = %d", _firstSlowOutFrame); - debug(5, "********************************"); - - walk_pc = obMega.getWalkPc(); - - walkAnim = getRouteMem(); - - // if this mega does actually have slow-out frames - if (_walkData.usingSlowOutFrames) { - // overwrite the next step (half a cycle) of the walk - // (ie .step - 0..5) - - do { - debug(5, "STEP NUMBER: walkAnim[%d].step = %d", walk_pc, walkAnim[walk_pc].step); - debug(5, "ORIGINAL FRAME: walkAnim[%d].frame = %d", walk_pc, walkAnim[walk_pc].frame); - - // map from existing walk frame across to correct - // frame number of slow-out - remember, there may be - // more slow-out frames than walk-frames! - - if (walkAnim[walk_pc].frame >= _firstWalkingTurnRightFrame) { - // if it's a walking turn-right, rather than a - // normal step, then map it to a normal step - // frame first - - walkAnim[walk_pc].frame -= _firstWalkingTurnRightFrame; - debug(5, "MAPPED TO WALK: walkAnim[%d].frame = %d (walking turn-right frame --> walk frame)", walk_pc, walkAnim[walk_pc].frame); - } else if (walkAnim[walk_pc].frame >= _firstWalkingTurnLeftFrame) { - // if it's a walking turn-left, rather than a - // normal step, then map it to a normal step - // frame first - - walkAnim[walk_pc].frame -= _firstWalkingTurnLeftFrame; - debug(5, "MAPPED TO WALK: walkAnim[%d].frame = %d (walking turn-left frame --> walk frame)", walk_pc, walkAnim[walk_pc].frame); - } - - walkAnim[walk_pc].frame += _firstSlowOutFrame + ((walkAnim[walk_pc].frame / _framesPerStep) * (_numberOfSlowOutFrames - _framesPerStep)); - walkAnim[walk_pc].step = 0; - debug(5, "SLOW-OUT FRAME: walkAnim[%d].frame = %d",walk_pc, walkAnim[walk_pc].frame); - walk_pc++; - } while (walkAnim[walk_pc].step > 0); - - // add stationary frame(s) (OPTIONAL) - - for (slowOutFrameNo = _framesPerStep; slowOutFrameNo < _numberOfSlowOutFrames; slowOutFrameNo++) { - walkAnim[walk_pc].frame = walkAnim[walk_pc - 1].frame + 1; - debug(5, "EXTRA FRAME: walkAnim[%d].frame = %d", walk_pc, walkAnim[walk_pc].frame); - walkAnim[walk_pc].step = 0; - walkAnim[walk_pc].dir = walkAnim[walk_pc - 1].dir; - walkAnim[walk_pc].x = walkAnim[walk_pc - 1].x; - walkAnim[walk_pc].y = walkAnim[walk_pc - 1].y; - walk_pc++; - } - } else { - // this mega doesn't have slow-out frames - // stand in current direction - - walkAnim[walk_pc].frame = _firstStandFrame + walkAnim[walk_pc - 1].dir; - walkAnim[walk_pc].step = 0; - walkAnim[walk_pc].dir = walkAnim[walk_pc - 1].dir; - walkAnim[walk_pc].x = walkAnim[walk_pc - 1].x; - walkAnim[walk_pc].y = walkAnim[walk_pc - 1].y; - walk_pc++; - } - - // end of sequence - walkAnim[walk_pc].frame = 512; - - // so that this doesn't happen again while 'george_walking' is still - // '2' - walkAnim[walk_pc].step = 99; -} - -// SLOW OUT - -void Router::addSlowOutFrames(WalkData *walkAnim) { - int32 slowOutFrameNo; - - // if the mega did actually walk, we overwrite the last step (half a - // cycle) with slow-out frames + add any necessary stationary frames - - if (_walkData.usingSlowOutFrames && _lastCount >= _framesPerStep) { - // place stop frames here - // slowdown at the end of the last walk - - slowOutFrameNo = _lastCount - _framesPerStep; - - debug(5, "SLOW OUT: slowOutFrameNo(%d) = _lastCount(%d) - _framesPerStep(%d)", slowOutFrameNo, _lastCount, _framesPerStep); - - // overwrite the last step (half a cycle) of the walk - - do { - // map from existing walk frame across to correct - // frame number of slow-out - remember, there may be - // more slow-out frames than walk-frames! - - walkAnim[slowOutFrameNo].frame += _firstSlowOutFrame + ((walkAnim[slowOutFrameNo].frame / _framesPerStep) * (_numberOfSlowOutFrames - _framesPerStep)); - - // because no longer a normal walk-step - walkAnim[slowOutFrameNo].step = 0; - - debug(5, "walkAnim[%d].frame = %d",slowOutFrameNo,walkAnim[slowOutFrameNo].frame); - slowOutFrameNo++; - } while (slowOutFrameNo < _lastCount); - - // add stationary frame(s) (OPTIONAL) - - for (slowOutFrameNo = _framesPerStep; slowOutFrameNo < _numberOfSlowOutFrames; slowOutFrameNo++) { - walkAnim[_stepCount].frame = walkAnim[_stepCount - 1].frame + 1; - - debug(5, "EXTRA FRAMES: walkAnim[%d].frame = %d", _stepCount, walkAnim[_stepCount].frame); - - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = walkAnim[_stepCount - 1].dir; - walkAnim[_stepCount].x = walkAnim[_stepCount - 1].x; - walkAnim[_stepCount].y = walkAnim[_stepCount - 1].y; - _stepCount++; - } - } -} - -void Router::slidyWalkAnimator(WalkData *walkAnim) { - /********************************************************************* - * Skidding every where HardWalk creates an animation that exactly - * fits the smoothPath and uses foot slipping to fit whole steps into - * the route - * - * Parameters: georgeg, mouseg - * Returns: rout - * - * produce a module list from the line data - *********************************************************************/ - - static int32 left = 0; - int32 p; - int32 lastDir; - int32 lastRealDir; - int32 turnDir; - int32 scale; - int32 step; - int32 module; - int32 moduleEnd; - int32 module16X; - int32 module16Y; - int32 stepX; - int32 stepY; - int32 errorX; - int32 errorY; - int32 lastErrorX; - int32 lastErrorY; - int32 frameCount; - int32 frames; - - p = 0; - lastDir = _modularPath[0].dir; - _currentDir = _modularPath[1].dir; - - if (_currentDir == NO_DIRECTIONS) - _currentDir = lastDir; - - _moduleX = _startX; - _moduleY = _startY; - module16X = _moduleX << 16; - module16Y = _moduleY << 16; - _stepCount = 0; - - // START THE WALK WITH THE FIRST STANDFRAME THIS MAY CAUSE A DELAY - // BUT IT STOPS THE PLAYER MOVING FOR COLLISIONS ARE DETECTED - - debug(5, "SLIDY: STARTING THE WALK"); - - module = _framesPerChar + lastDir; - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = lastDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - - // TURN TO START THE WALK - - debug(5, "SLIDY: TURNING TO START THE WALK"); - // rotate if we need to - - if (lastDir != _currentDir) { - // get the direction to turn - turnDir = _currentDir - lastDir; - if (turnDir < 0) - turnDir += NO_DIRECTIONS; - - if (turnDir > 4) - turnDir = -1; - else if (turnDir > 0) - turnDir = 1; - - // rotate to new walk direction - // for george and nico put in a head turn at the start - - if (_walkData.usingStandingTurnFrames) { - // new frames for turn frames 29oct95jps - if (turnDir < 0) - module = _firstStandingTurnLeftFrame + lastDir; - else - module = _firstStandingTurnRightFrame + lastDir; - - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = lastDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - } - - // rotate till were facing new dir then go back 45 degrees - while (lastDir != _currentDir) { - lastDir += turnDir; - - // new frames for turn frames 29oct95jps - if (turnDir < 0) { - if ( lastDir < 0) - lastDir += NO_DIRECTIONS; - module = _firstStandingTurnLeftFrame + lastDir; - } else { - if ( lastDir > 7) - lastDir -= NO_DIRECTIONS; - module = _firstStandingTurnRightFrame + lastDir; - } - - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = lastDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - } - - // the back 45 degrees bit - // step back one because new head turn for george takes us - // past the new dir - _stepCount--; - } - - // his head is in the right direction - lastRealDir = _currentDir; - - // SLIDY: THE SLOW IN - - addSlowInFrames(walkAnim); - - // THE WALK - - debug(5, "SLIDY: THE WALK"); - - // start the walk on the left or right leg, depending on how the - // slow-in frames were drawn - - // (0 = left; 1 = right) - - if (_walkData.leadingLeg[_currentDir] == 0) { - // start the walk on the left leg (ie. at beginning of the - // first step of the walk cycle) - left = 0; - } else { - // start the walk on the right leg (ie. at beginning of the - // second step of the walk cycle) - left = _framesPerStep; - } - - _lastCount = _stepCount; - - // this ensures that we don't put in turn frames for the start - lastDir = 99; - - // this ensures that we don't put in turn frames for the start - _currentDir = 99; - - do { - assert(_stepCount < O_WALKANIM_SIZE); - while (_modularPath[p].num == 0) { - p++; - if (_currentDir != 99) - lastRealDir = _currentDir; - lastDir = _currentDir; - _lastCount = _stepCount; - } - - // calculate average amount to lose in each step on the way - // to the next node - - _currentDir = _modularPath[p].dir; - - if (_currentDir < NO_DIRECTIONS) { - module = _currentDir * _framesPerStep * 2 + left; - - if (left == 0) - left = _framesPerStep; - else - left = 0; - - moduleEnd = module + _framesPerStep; - step = 0; - scale = (_scaleA * _moduleY + _scaleB); - - do { - module16X += _walkData.dx[module] * scale; - module16Y += _walkData.dy[module] * scale; - _moduleX = module16X >> 16; - _moduleY = module16Y >> 16; - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = step; // normally 0,1,2,3,4,5,0,1,2,etc - walkAnim[_stepCount].dir = _currentDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - step++; - module++; - } while (module < moduleEnd); - - stepX = _modX[_modularPath[p].dir]; - stepY = _modY[_modularPath[p].dir]; - errorX = _modularPath[p].x - _moduleX; - errorX = errorX * stepX; - errorY = _modularPath[p].y - _moduleY; - errorY = errorY * stepY; - - if (errorX < 0 || errorY < 0) { - _modularPath[p].num = 0; // the end of the path - - // okay those last steps took us past our - // target but do we want to scoot or moonwalk - - frames = _stepCount - _lastCount; - errorX = _modularPath[p].x - walkAnim[_stepCount - 1].x; - errorY = _modularPath[p].y - walkAnim[_stepCount - 1].y; - - if (frames > _framesPerStep) { - lastErrorX = _modularPath[p].x - walkAnim[_stepCount - 7].x; - lastErrorY = _modularPath[p].y - walkAnim[_stepCount - 7].y; - - if (stepX == 0) { - if (3 * ABS(lastErrorY) < ABS(errorY)) { - // the last stop was - // closest - _stepCount -= _framesPerStep; - if (left == 0) - left = _framesPerStep; - else - left = 0; - } - } else { - if (3 * ABS(lastErrorX) < ABS(errorX)) { - //the last stop was - // closest - _stepCount -= _framesPerStep; - if (left == 0) - left = _framesPerStep; - else - left = 0; - } - } - } - - errorX = _modularPath[p].x - walkAnim[_stepCount-1].x; - errorY = _modularPath[p].y - walkAnim[_stepCount-1].y; - - // okay we've reached the end but we still - // have an error - - if (errorX != 0) { - frameCount = 0; - frames = _stepCount - _lastCount; - - do { - frameCount++; - walkAnim[_lastCount + frameCount - 1].x += errorX * frameCount / frames; - } while (frameCount < frames); - } - - if (errorY != 0) { - frameCount = 0; - frames = _stepCount - _lastCount; - do { - frameCount++; - walkAnim[_lastCount + frameCount - 1].y += errorY * frameCount / frames; - } while (frameCount < frames); - } - - // Now is the time to put in the turn frames - // for the last turn - - if (frames < _framesPerStep) { - // this ensures that we don't put in - // turn frames for this walk or the - // next - _currentDir = 99; - } - - if (_currentDir != 99) - lastRealDir = _currentDir; - - // check each turn condition in turn - - // only for george - if (lastDir != 99 && _currentDir != 99 && _walkData.usingWalkingTurnFrames) { - // 1 and -7 going right -1 and 7 going - // left - lastDir = _currentDir - lastDir; - - if (lastDir == -1 || lastDir == 7 || lastDir == -2 || lastDir == 6) { - // turn at the end of the last - // walk - - _frame = _lastCount - _framesPerStep; - do { - // turning left - walkAnim[_frame].frame += _firstWalkingTurnLeftFrame; - _frame++; - } while (_frame < _lastCount); - } else if (lastDir == 1 || lastDir == -7 || lastDir == 2 || lastDir == -6) { - // turn at the end of the - // current walk - - _frame = _lastCount - _framesPerStep; - do { - // turning right - walkAnim[_frame].frame += _firstWalkingTurnRightFrame; - _frame++; - } while (_frame < _lastCount); - } - lastDir = _currentDir; - } - - // all turns checked - - _lastCount = _stepCount; - _moduleX = walkAnim[_stepCount - 1].x; - _moduleY = walkAnim[_stepCount - 1].y; - module16X = _moduleX << 16; - module16Y = _moduleY << 16; - } - } - } while (_modularPath[p].dir < NO_DIRECTIONS); - -#ifdef SWORD2_DEBUG - if (lastRealDir == 99) - error("slidyWalkAnimatorlast direction error"); -#endif - - // THE SLOW OUT - addSlowOutFrames(walkAnim); - - // TURNS TO END THE WALK ? - - // We've done the walk now put in any turns at the end - - if (_targetDir == 8) { - // ANY direction -> stand in the last direction - - module = _firstStandFrame + lastRealDir; - _targetDir = lastRealDir; - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = lastRealDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - } - - if (_targetDir == 9) { - // 'stance' was non-zero - if (_stepCount == 0) { - module = _framesPerChar + lastRealDir; - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = lastRealDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - } - } else if (_targetDir != lastRealDir) { - // rotate to target direction - turnDir = _targetDir - lastRealDir; - if ( turnDir < 0) - turnDir += NO_DIRECTIONS; - - if (turnDir > 4) - turnDir = -1; - else if (turnDir > 0) - turnDir = 1; - - // rotate to target direction - // for george and nico put in a head turn at the start - - if (_walkData.usingStandingTurnFrames) { - // new frames for turn frames 29oct95jps - if (turnDir < 0) - module = _firstStandingTurnLeftFrame + lastDir; - else - module = _firstStandingTurnRightFrame + lastDir; - - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = lastRealDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - } - - // rotate if we need to - - while (lastRealDir != _targetDir) { - lastRealDir += turnDir; - - // new frames for turn frames 29oct95jps - if (turnDir < 0) { - if (lastRealDir < 0) - lastRealDir += NO_DIRECTIONS; - module = _firstStandingTurnLeftFrame + lastRealDir; - } else { - if (lastRealDir > 7) - lastRealDir -= NO_DIRECTIONS; - module = _firstStandingTurnRightFrame + lastRealDir; - } - - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = lastRealDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - } - - module = _firstStandFrame + lastRealDir; - walkAnim[_stepCount - 1].frame = module; - } else { - // just stand at the end - module = _firstStandFrame + lastRealDir; - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = lastRealDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - } - - walkAnim[_stepCount].frame = 512; - walkAnim[_stepCount].step = 99; - _stepCount++; - - walkAnim[_stepCount].frame = 512; - walkAnim[_stepCount].step = 99; - _stepCount++; - - walkAnim[_stepCount].frame = 512; - walkAnim[_stepCount].step = 99; - - // write all the frames to "debug.txt" - debug(5, "THE WALKDATA:"); - - for (_frame = 0; _frame <= _stepCount; _frame++) - debug(5, "walkAnim[%d].frame=%d", _frame, walkAnim[_frame].frame); - - debug(5, "routeFinder RouteSize is %d", _stepCount); - return; -} - -#ifndef FORCE_SLIDY - -// THE SOLID PATH ROUTINES - -int32 Router::solidPath() { - /********************************************************************* - * SolidPath creates a path based on whole steps with no sliding to - * get as near as possible to the target without any sliding this - * routine is currently unused, but is intended for use when just - * clicking about. - * - * produce a module list from the line data - *********************************************************************/ - - int32 smooth; - int32 solid; - int32 scale; - int32 stepX; - int32 stepY; - int32 deltaX; - int32 deltaY; - - // strip out the short sections - - solid = 1; - smooth = 1; - _modularPath[0].x = _smoothPath[0].x; - _modularPath[0].y = _smoothPath[0].y; - _modularPath[0].dir = _smoothPath[0].dir; - _modularPath[0].num = 0; - - do { - scale = _scaleA * _smoothPath[smooth].y + _scaleB; - deltaX = _smoothPath[smooth].x - _modularPath[solid - 1].x; - deltaY = _smoothPath[smooth].y - _modularPath[solid - 1].y; - stepX = _modX[_smoothPath[smooth].dir]; - stepY = _modY[_smoothPath[smooth].dir]; - stepX = stepX * scale; - stepY = stepY * scale; - stepX = stepX >> 16; - stepY = stepY >> 16; - - if (ABS(deltaX) >= ABS(stepX) && ABS(deltaY) >= ABS(stepY)) { - _modularPath[solid].x = _smoothPath[smooth].x; - _modularPath[solid].y = _smoothPath[smooth].y; - _modularPath[solid].dir = _smoothPath[smooth].dir; - _modularPath[solid].num = 1; - solid++; - } - - smooth++; - } while (_smoothPath[smooth].num < ROUTE_END_FLAG); - - // in case the last bit had no steps - - if (solid == 1) { - // there were no paths so put in a dummy end - solid = 2; - _modularPath[1].dir = _smoothPath[0].dir; - _modularPath[1].num = 0; - } - - _modularPath[solid - 1].x = _smoothPath[smooth - 1].x; - _modularPath[solid - 1].y = _smoothPath[smooth - 1].y; - - // set up the end of the walk - _modularPath[solid].x = _smoothPath[smooth - 1].x; - _modularPath[solid].y = _smoothPath[smooth - 1].y; - _modularPath[solid].dir = 9; - _modularPath[solid].num = ROUTE_END_FLAG; - - return 1; -} - -int32 Router::solidWalkAnimator(WalkData *walkAnim) { - /********************************************************************* - * SolidWalk creates an animation based on whole steps with no sliding - * to get as near as possible to the target without any sliding. This - * routine is is intended for use when just clicking about. - * - * produce a module list from the line data - * - * returns 0 if solid route not found - *********************************************************************/ - - int32 left; - int32 turnDir; - int32 scale; - int32 step; - int32 errorX; - int32 errorY; - int32 moduleEnd; - bool slowStart = false; - - // start at the beginning for a change - - int32 lastDir = _modularPath[0].dir; - int32 module = _framesPerChar + lastDir; - - _currentDir = _modularPath[1].dir; - _moduleX = _startX; - _moduleY = _startY; - _stepCount = 0; - - int32 module16X = _moduleX << 16; - int32 module16Y = _moduleY << 16; - - // START THE WALK WITH THE FIRST STANDFRAME THIS MAY CAUSE A DELAY - // BUT IT STOPS THE PLAYER MOVING FOR COLLISIONS ARE DETECTED - - debug(5, "SOLID: STARTING THE WALK"); - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = lastDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - - // TURN TO START THE WALK - - debug(5, "SOLID: TURNING TO START THE WALK"); - - // rotate if we need to - - if (lastDir != _currentDir) { - // get the direction to turn - turnDir = _currentDir - lastDir; - if (turnDir < 0) - turnDir += NO_DIRECTIONS; - - if (turnDir > 4) - turnDir = -1; - else if (turnDir > 0) - turnDir = 1; - - // rotate to new walk direction - // for george and nico put in a head turn at the start - - if (_walkData.usingStandingTurnFrames) { - // new frames for turn frames 29oct95jps - if (turnDir < 0) - module = _firstStandingTurnLeftFrame + lastDir; - else - module = _firstStandingTurnRightFrame + lastDir; - - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = lastDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - } - - // rotate till were facing new dir then go back 45 degrees - - while (lastDir != _currentDir) { - lastDir += turnDir; - - // new frames for turn frames - if (turnDir < 0) { - if (lastDir < 0) - lastDir += NO_DIRECTIONS; - module = _firstStandingTurnLeftFrame + lastDir; - } else { - if (lastDir > 7) - lastDir -= NO_DIRECTIONS; - module = _firstStandingTurnRightFrame + lastDir; - } - - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = lastDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - } - - // the back 45 degrees bit - // step back one because new head turn for george takes us - // past the new dir - - _stepCount--; - } - - // THE SLOW IN - - slowStart = addSlowInFrames(walkAnim); - - // THE WALK - - debug(5, "SOLID: THE WALK"); - - // start the walk on the left or right leg, depending on how the - // slow-in frames were drawn - - // (0 = left; 1 = right) - if (_walkData.leadingLeg[_currentDir] == 0) { - // start the walk on the left leg (ie. at beginning of the - // first step of the walk cycle) - left = 0; - } else { - // start the walk on the right leg (ie. at beginning of the - // second step of the walk cycle) - left = _framesPerStep; - } - - _lastCount = _stepCount; - - // this ensures that we don't put in turn frames for the start - lastDir = 99; - - // this ensures that we don't put in turn frames for the start - _currentDir = 99; - - int32 p = 1; - - do { - while (_modularPath[p].num > 0) { - _currentDir = _modularPath[p].dir; - if (_currentDir < NO_DIRECTIONS) { - module = _currentDir * _framesPerStep * 2 + left; - - if (left == 0) - left = _framesPerStep; - else - left = 0; - - moduleEnd = module + _framesPerStep; - step = 0; - scale = (_scaleA * _moduleY + _scaleB); - - do { - module16X += _walkData.dx[module] * scale; - module16Y += _walkData.dy[module] * scale; - _moduleX = module16X >> 16; - _moduleY = module16Y >> 16; - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = step; // normally 0,1,2,3,4,5,0,1,2,etc - walkAnim[_stepCount].dir = _currentDir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - module++; - step++; - } while (module < moduleEnd); - - errorX = _modularPath[p].x - _moduleX; - errorX = errorX * _modX[_modularPath[p].dir]; - errorY = _modularPath[p].y - _moduleY; - errorY = errorY * _modY[_modularPath[p].dir]; - - if (errorX < 0 || errorY < 0) { - _modularPath[p].num = 0; - _stepCount -= _framesPerStep; - - if (left == 0) - left = _framesPerStep; - else - left = 0; - - // Okay this is the end of a section - - _moduleX = walkAnim[_stepCount - 1].x; - _moduleY = walkAnim[_stepCount - 1].y; - module16X = _moduleX << 16; - module16Y = _moduleY << 16; - _modularPath[p].x = _moduleX; - _modularPath[p].y = _moduleY; - - // Now is the time to put in the turn - // frames for the last turn - - if (_stepCount - _lastCount < _framesPerStep) { - // no step taken - - // clean up if a slow in but no - // walk - - if (slowStart) { - _stepCount -= _walkData.nSlowInFrames[_currentDir]; - _lastCount -= _walkData.nSlowInFrames[_currentDir]; - slowStart = false; - } - - // this ensures that we don't - // put in turn frames for this - // walk or the next - - _currentDir = 99; - } - - // check each turn condition in turn - if (lastDir != 99 && _currentDir != 99 && _walkData.usingWalkingTurnFrames) { - // only for george - // 1 and -7 going right -1 and - // 7 going left - - lastDir = _currentDir - lastDir; - - if (lastDir == -1 || lastDir == 7 || lastDir == -2 || lastDir == 6) { - // turn at the end of - // the last walk - - _frame = _lastCount - _framesPerStep; - - do { - // turning left - walkAnim[_frame].frame += _firstWalkingTurnLeftFrame; - _frame++; - } while (_frame < _lastCount); - } else if (lastDir == 1 || lastDir == -7 || lastDir == 2 || lastDir == -6) { - // turn at the end of - // the current walk - - _frame = _lastCount - _framesPerStep; - do { - // turning right - walkAnim[_frame].frame += _firstWalkingTurnRightFrame; - _frame++; - } while (_frame < _lastCount); - } - } - - // all turns checked - _lastCount = _stepCount; - } - } - } - p++; - lastDir = _currentDir; - - // can only be valid first time round - slowStart = false; - } while (_modularPath[p].dir < NO_DIRECTIONS); - - // THE SLOW OUT - - addSlowOutFrames(walkAnim); - - module = _framesPerChar + _modularPath[p - 1].dir; - walkAnim[_stepCount].frame = module; - walkAnim[_stepCount].step = 0; - walkAnim[_stepCount].dir = _modularPath[p - 1].dir; - walkAnim[_stepCount].x = _moduleX; - walkAnim[_stepCount].y = _moduleY; - _stepCount++; - - walkAnim[_stepCount].frame = 512; - walkAnim[_stepCount].step = 99; - _stepCount++; - - walkAnim[_stepCount].frame = 512; - walkAnim[_stepCount].step = 99; - _stepCount++; - - walkAnim[_stepCount].frame = 512; - walkAnim[_stepCount].step = 99; - - debug(5, "THE WALKDATA:"); - - for (_frame = 0; _frame <= _stepCount; _frame++) - debug(5, "walkAnim[%d].frame=%d", _frame, walkAnim[_frame].frame); - - // NO END TURNS - - debug(5, "routeFinder RouteSize is %d", _stepCount); - // now check the route - - int i = 0; - - do { - if (!check(_modularPath[i].x, _modularPath[i].y, _modularPath[i + 1].x, _modularPath[i + 1].y)) - p = 0; - i++; - } while (i < p - 1); - - if (p != 0) { - _targetDir = _modularPath[p - 1].dir; - if (checkTarget(_moduleX, _moduleY) == 3) { - // new target on a line - p = 0; - debug(5, "Solid walk target was on a line %d %d", _moduleX, _moduleY); - } - } - - return p; -} -#endif - -// THE SCAN ROUTINES - -bool Router::scan(int32 level) { - /********************************************************************* - * Called successively from routeFinder until no more changes take - * place in the grid array, ie he best path has been found - * - * Scans through every point in the node array and checks if there is - * a route between each point and if this route gives a new route. - * - * This routine could probably halve its processing time if it doubled - * up on the checks after each route check - * - *********************************************************************/ - - int32 x1, y1, x2, y2; - int32 distance; - bool changed = false; - - // For all the nodes that have new values and a distance less than - // enddist, ie dont check for new routes from a point we checked - // before or from a point that is already further away than the best - // route so far. - - for (int i = 0; i < _nNodes; i++) { - if (_node[i].dist < _node[_nNodes].dist && _node[i].level == level) { - x1 = _node[i].x; - y1 = _node[i].y; - - for (int j = _nNodes; j > 0; j--) { - if (_node[j].dist > _node[i].dist) { - x2 = _node[j].x; - y2 = _node[j].y; - - if (ABS(x2 - x1) > 4.5 * ABS(y2 - y1)) - distance = (8 * ABS(x2 - x1) + 18 * ABS(y2 - y1)) / (54 * 8) + 1; - else - distance = (6 * ABS(x2 - x1) + 36 * ABS(y2 - y1)) / (36 * 14) + 1; - - if (distance + _node[i].dist < _node[_nNodes].dist && distance + _node[i].dist < _node[j].dist) { - if (newCheck(0, x1, y1, x2, y2)) { - _node[j].level = level + 1; - _node[j].dist = distance + _node[i].dist; - _node[j].prev = i; - changed = true; - } - } - } - } - } - } - - return changed; -} - -int32 Router::newCheck(int32 status, int32 x1, int32 y1, int32 x2, int32 y2) { - /********************************************************************* - * newCheck routine checks if the route between two points can be - * achieved without crossing any of the bars in the Bars array. - * - * newCheck differs from check in that that 4 route options are - * considered corresponding to actual walked routes. - * - * Note distance doesnt take account of shrinking ??? - * - * Note Bars array must be properly calculated ie min max dx dy co - *********************************************************************/ - - int32 ldx; - int32 ldy; - int32 dlx; - int32 dly; - int32 dirX; - int32 dirY; - int32 step1; - int32 step2; - int32 step3; - int32 steps; - int32 options; - - steps = 0; - options = 0; - ldx = x2 - x1; - ldy = y2 - y1; - dirX = 1; - dirY = 1; - - if (ldx < 0) { - ldx = -ldx; - dirX = -1; - } - - if (ldy < 0) { - ldy = -ldy; - dirY = -1; - } - - // make the route options - - if (_diagonaly * ldx > _diagonalx * ldy) { - // dir = 1,2 or 2,3 or 5,6 or 6,7 - - dly = ldy; - dlx = (ldy * _diagonalx) / _diagonaly; - ldx = ldx - dlx; - dlx = dlx * dirX; - dly = dly * dirY; - ldx = ldx * dirX; - ldy = 0; - - // options are square, diagonal a code 1 route - - step1 = check(x1, y1, x1 + ldx, y1); - if (step1 != 0) { - step2 = check(x1 + ldx, y1, x2, y2); - if (step2 != 0) { - steps = step1 + step2; - options |= 2; - } - } - - // diagonal, square a code 2 route - - if (steps == 0 || status == 1) { - step1 = check(x1, y1, x1 + dlx, y1 + dly); - if (step1 != 0) { - step2 = check(x1 + dlx, y2, x2, y2); - if (step2 != 0) { - steps = step1 + step2; - options |= 4; - } - } - } - - // halfsquare, diagonal, halfsquare a code 0 route - - if (steps == 0 || status == 1) { - step1 = check(x1, y1, x1 + ldx / 2, y1); - if (step1 != 0) { - step2 = check(x1 + ldx / 2, y1, x1 + ldx / 2 + dlx, y2); - if (step2 != 0) { - step3 = check(x1 + ldx / 2 + dlx, y2, x2, y2); - if (step3 != 0) { - steps = step1 + step2 + step3; - options |= 1; - } - } - } - } - - //halfdiagonal, square, halfdiagonal a code 3 route - - if (steps == 0 || status == 1) { - step1 = check(x1, y1, x1 + dlx / 2, y1 + dly / 2); - if (step1 != 0) { - step2 = check(x1 + dlx / 2, y1 + dly / 2, x1 + ldx + dlx / 2, y1 + dly / 2); - if (step2 != 0) { - step3 = check(x1 + ldx + dlx / 2, y1 + dly / 2, x2, y2); - if (step3 != 0) { - steps = step1 + step2 + step3; - options |= 8; - } - } - } - } - } else { - // dir = 7,0 or 0,1 or 3,4 or 4,5 - - dlx = ldx; - dly = (ldx * _diagonaly) / _diagonalx; - ldy = ldy - dly; - dlx = dlx * dirX; - dly = dly * dirY; - ldy = ldy * dirY; - ldx = 0; - - // options are square, diagonal a code 1 route - - step1 = check(x1 ,y1, x1, y1 + ldy); - if (step1 != 0) { - step2 = check(x1, y1 + ldy, x2, y2); - if (step2 != 0) { - steps = step1 + step2; - options |= 2; - } - } - - // diagonal, square a code 2 route - - if (steps == 0 || status == 1) { - step1 = check(x1, y1, x2, y1 + dly); - if (step1 != 0) { - step2 = check(x2, y1 + dly, x2, y2); - if (step2 != 0) { - steps = step1 + step2; - options |= 4; - } - } - } - - // halfsquare, diagonal, halfsquare a code 0 route - - if (steps == 0 || status == 1) { - step1 = check(x1, y1, x1, y1 + ldy / 2); - if (step1 != 0) { - step2 = check(x1, y1 + ldy / 2, x2, y1 + ldy / 2 + dly); - if (step2 != 0) { - step3 = check(x2, y1 + ldy / 2 + dly, x2, y2); - if (step3 != 0) { - steps = step1 + step2 + step3; - options |= 1; - } - } - } - } - - // halfdiagonal, square, halfdiagonal a code 3 route - - if (steps == 0 || status == 1) { - step1 = check(x1, y1, x1 + dlx / 2, y1 + dly / 2); - if (step1 != 0) { - step2 = check(x1 + dlx / 2, y1 + dly / 2, x1 + dlx / 2, y1 + ldy + dly / 2); - if (step2 != 0) { - step3 = check(x1 + dlx / 2, y1 + ldy + dly / 2, x2, y2); - if (step3 != 0) { - steps = step1 + step2 + step3; - options |= 8; - } - } - } - } - } - - if (status == 0) - status = steps; - else - status = options; - - return status; -} - -// CHECK ROUTINES - -bool Router::check(int32 x1, int32 y1, int32 x2, int32 y2) { - // call the fastest line check for the given line - // returns true if line didn't cross any bars - - if (x1 == x2 && y1 == y2) - return true; - - if (x1 == x2) - return vertCheck(x1, y1, y2); - - if (y1 == y2) - return horizCheck(x1, y1, x2); - - return lineCheck(x1, y1, x2, y2); -} - -bool Router::lineCheck(int32 x1, int32 y1, int32 x2, int32 y2) { - bool linesCrossed = true; - - int32 xmin = MIN(x1, x2); - int32 xmax = MAX(x1, x2); - int32 ymin = MIN(y1, y2); - int32 ymax = MAX(y1, y2); - - // Line set to go one step in chosen direction so ignore if it hits - // anything - - int32 dirx = x2 - x1; - int32 diry = y2 - y1; - - int32 co = (y1 * dirx) - (x1 * diry); // new line equation - - for (int i = 0; i < _nBars && linesCrossed; i++) { - // skip if not on module - if (xmax >= _bars[i].xmin && xmin <= _bars[i].xmax && ymax >= _bars[i].ymin && ymin <= _bars[i].ymax) { - // Okay, it's a valid line. Calculate an intercept. Wow - // but all this arithmetic we must have loads of time - - // slope it he slope between the two lines - int32 slope = (_bars[i].dx * diry) - (_bars[i].dy *dirx); - // assuming parallel lines don't cross - if (slope != 0) { - // calculate x intercept and check its on both - // lines - int32 xc = ((_bars[i].co * dirx) - (co * _bars[i].dx)) / slope; - - // skip if not on module - if (xc >= xmin - 1 && xc <= xmax + 1) { - // skip if not on line - if (xc >= _bars[i].xmin - 1 && xc <= _bars[i].xmax + 1) { - int32 yc = ((_bars[i].co * diry) - (co * _bars[i].dy)) / slope; - - // skip if not on module - if (yc >= ymin - 1 && yc <= ymax + 1) { - // skip if not on line - if (yc >= _bars[i].ymin - 1 && yc <= _bars[i].ymax + 1) { - linesCrossed = false; - } - } - } - } - } - } - } - - return linesCrossed; -} - -bool Router::horizCheck(int32 x1, int32 y, int32 x2) { - bool linesCrossed = true; - - int32 xmin = MIN(x1, x2); - int32 xmax = MAX(x1, x2); - - // line set to go one step in chosen direction so ignore if it hits - // anything - - for (int i = 0; i < _nBars && linesCrossed; i++) { - // skip if not on module - if (xmax >= _bars[i].xmin && xmin <= _bars[i].xmax && y >= _bars[i].ymin && y <= _bars[i].ymax) { - // Okay, it's a valid line calculate an intercept. Wow - // but all this arithmetic we must have loads of time - - if (_bars[i].dy == 0) - linesCrossed = false; - else { - int32 ldy = y - _bars[i].y1; - int32 xc = _bars[i].x1 + (_bars[i].dx * ldy) / _bars[i].dy; - // skip if not on module - if (xc >= xmin - 1 && xc <= xmax + 1) - linesCrossed = false; - } - } - } - - return linesCrossed; -} - -bool Router::vertCheck(int32 x, int32 y1, int32 y2) { - bool linesCrossed = true; - - int32 ymin = MIN(y1, y2); - int32 ymax = MAX(y1, y2); - - // Line set to go one step in chosen direction so ignore if it hits - // anything - - for (int i = 0; i < _nBars && linesCrossed; i++) { - // skip if not on module - if (x >= _bars[i].xmin && x <= _bars[i].xmax && ymax >= _bars[i].ymin && ymin <= _bars[i].ymax) { - // Okay, it's a valid line calculate an intercept. Wow - // but all this arithmetic we must have loads of time - - // both lines vertical and overlap in x and y so they - // cross - - if (_bars[i].dx == 0) - linesCrossed = false; - else { - int32 ldx = x - _bars[i].x1; - int32 yc = _bars[i].y1 + (_bars[i].dy * ldx) / _bars[i].dx; - // the intercept overlaps - if (yc >= ymin - 1 && yc <= ymax + 1) - linesCrossed = false; - } - } - } - - return linesCrossed; -} - -int32 Router::checkTarget(int32 x, int32 y) { - int32 onLine = 0; - - int32 xmin = x - 1; - int32 xmax = x + 1; - int32 ymin = y - 1; - int32 ymax = y + 1; - - // check if point +- 1 is on the line - // so ignore if it hits anything - - for (int i = 0; i < _nBars && onLine == 0; i++) { - // overlapping line - if (xmax >= _bars[i].xmin && xmin <= _bars[i].xmax && ymax >= _bars[i].ymin && ymin <= _bars[i].ymax) { - int32 xc, yc; - - // okay this line overlaps the target calculate - // an y intercept for x - - // vertical line so we know it overlaps y - if (_bars[i].dx == 0) - yc = 0; - else { - int ldx = x - _bars[i].x1; - yc = _bars[i].y1 + (_bars[i].dy * ldx) / _bars[i].dx; - } - - // overlapping point for y - if (yc >= ymin && yc <= ymax) { - // target on a line so drop out - onLine = 3; - debug(5, "RouteFail due to target on a line %d %d", x, y); - } else { - // vertical line so we know it overlaps y - if (_bars[i].dy == 0) - xc = 0; - else { - int32 ldy = y - _bars[i].y1; - xc = _bars[i].x1 + (_bars[i].dx * ldy) / _bars[i].dy; - } - - // skip if not on module - if (xc >= xmin && xc <= xmax) { - // target on a line so drop out - onLine = 3; - debug(5, "RouteFail due to target on a line %d %d", x, y); - } - } - } - } - - return onLine; -} - -// THE SETUP ROUTINES - -void Router::loadWalkData(byte *ob_walkdata) { - uint16 firstFrameOfDirection; - uint16 walkFrameNo; - uint32 frameCounter = 0; // starts at frame 0 of mega set - int i; - - _walkData.read(ob_walkdata); - - // 0 = not using slow out frames; non-zero = using that many frames - // for each leading leg for each direction - - _numberOfSlowOutFrames = _walkData.usingSlowOutFrames; - - for (i = 0; i < NO_DIRECTIONS; i++) { - firstFrameOfDirection = i * _walkData.nWalkFrames; - - _modX[i] = 0; - _modY[i] = 0; - - for (walkFrameNo = firstFrameOfDirection; walkFrameNo < firstFrameOfDirection + _walkData.nWalkFrames / 2; walkFrameNo++) { - // eg. _modX[0] is the sum of the x-step sizes for the - // first half of the walk cycle for direction 0 - _modX[i] += _walkData.dx[walkFrameNo]; - _modY[i] += _walkData.dy[walkFrameNo]; - } - } - - _diagonalx = _modX[3]; - _diagonaly = _modY[3]; - - // interpret the walk data - - _framesPerStep = _walkData.nWalkFrames / 2; - _framesPerChar = _walkData.nWalkFrames * NO_DIRECTIONS; - - // offset pointers added Oct 30 95 JPS - // mega id references removed 16sep96 by JEL - - // WALK FRAMES - // start on frame 0 - - frameCounter += _framesPerChar; - - // STAND FRAMES - // stand frames come after the walk frames - // one stand frame for each direction - - _firstStandFrame = frameCounter; - frameCounter += NO_DIRECTIONS; - - // STANDING TURN FRAMES - OPTIONAL! - // standing turn-left frames come after the slow-out frames - // one for each direction - // standing turn-left frames come after the standing turn-right frames - // one for each direction - - if (_walkData.usingStandingTurnFrames) { - _firstStandingTurnLeftFrame = frameCounter; - frameCounter += NO_DIRECTIONS; - - _firstStandingTurnRightFrame = frameCounter; - frameCounter += NO_DIRECTIONS; - } else { - // refer instead to the normal stand frames - _firstStandingTurnLeftFrame = _firstStandFrame; - _firstStandingTurnRightFrame = _firstStandFrame; - } - - // WALKING TURN FRAMES - OPTIONAL! - // walking left-turn frames come after the stand frames - // walking right-turn frames come after the walking left-turn frames - - if (_walkData.usingWalkingTurnFrames) { - _firstWalkingTurnLeftFrame = frameCounter; - frameCounter += _framesPerChar; - - _firstWalkingTurnRightFrame = frameCounter; - frameCounter += _framesPerChar; - } else { - _firstWalkingTurnLeftFrame = 0; - _firstWalkingTurnRightFrame = 0; - } - - // SLOW-IN FRAMES - OPTIONAL! - // slow-in frames come after the walking right-turn frames - - if (_walkData.usingSlowInFrames) { - // Make note of frame number of first slow-in frame for each - // direction. There may be a different number of slow-in - // frames in each direction - - for (i = 0; i < NO_DIRECTIONS; i++) { - _firstSlowInFrame[i] = frameCounter; - frameCounter += _walkData.nSlowInFrames[i]; - } - } - - // SLOW-OUT FRAMES - OPTIONAL! - // slow-out frames come after the slow-in frames - - if (_walkData.usingSlowOutFrames) - _firstSlowOutFrame = frameCounter; -} - -// THE ROUTE EXTRACTOR - -void Router::extractRoute() { - /********************************************************************* - * extractRoute gets route from the node data after a full scan, route - * is written with just the basic way points and direction options for - * heading to the next point. - *********************************************************************/ - - int32 prev; - int32 prevx; - int32 prevy; - int32 last; - int32 point; - int32 p; - int32 dirx; - int32 diry; - int32 dir; - int32 ldx; - int32 ldy; - - // extract the route from the node data - - prev = _nNodes; - last = prev; - point = O_ROUTE_SIZE - 1; - _route[point].x = _node[last].x; - _route[point].y = _node[last].y; - - do { - point--; - prev = _node[last].prev; - prevx = _node[prev].x; - prevy = _node[prev].y; - _route[point].x = prevx; - _route[point].y = prevy; - last = prev; - } while (prev > 0); - - // now shuffle route down in the buffer - - _routeLength = 0; - - do { - _route[_routeLength].x = _route[point].x; - _route[_routeLength].y = _route[point].y; - point++; - _routeLength++; - } while (point < O_ROUTE_SIZE); - - _routeLength--; - - // okay the route exists as a series point now put in some directions - - p = 0; - - do { - ldx = _route[p + 1].x - _route[p].x; - ldy = _route[p + 1].y - _route[p].y; - dirx = 1; - diry = 1; - - if (ldx < 0) { - ldx = -ldx; - dirx = -1; - } - - if (ldy < 0) { - ldy = -ldy; - diry = -1; - } - - if (_diagonaly * ldx > _diagonalx * ldy) { - // dir = 1,2 or 2,3 or 5,6 or 6,7 - - // 2 or 6 - dir = 4 - 2 * dirx; - _route[p].dirS = dir; - - // 1, 3, 5 or 7 - dir = dir + diry * dirx; - _route[p].dirD = dir; - } else { - // dir = 7,0 or 0,1 or 3,4 or 4,5 - - // 0 or 4 - dir = 2 + 2 * diry; - _route[p].dirS = dir; - - // 2 or 6 - dir = 4 - 2 * dirx; - - // 1, 3, 5 or 7 - dir = dir + diry * dirx; - _route[p].dirD = dir; - } - p++; - } while (p < _routeLength); - - // set the last dir to continue previous route unless specified - - if (_targetDir == 8) { - // ANY direction - _route[p].dirS = _route[p - 1].dirS; - _route[p].dirD = _route[p - 1].dirD; - } else { - _route[p].dirS = _targetDir; - _route[p].dirD = _targetDir; - } - - return; -} - -void Router::setUpWalkGrid(byte *ob_mega, int32 x, int32 y, int32 dir) { - ObjectMega obMega(ob_mega); - - // get walk grid file + extra grid into 'bars' & 'node' arrays - loadWalkGrid(); - - // copy the mega structure into the local variables for use in all - // subroutines - - _startX = obMega.getFeetX(); - _startY = obMega.getFeetY(); - _startDir = obMega.getCurDir(); - _targetX = x; - _targetY = y; - _targetDir = dir; - - _scaleA = obMega.getScaleA(); - _scaleB = obMega.getScaleB(); - - // mega's current position goes into first node - - _node[0].x = _startX; - _node[0].y = _startY; - _node[0].level = 1; - _node[0].prev = 0; - _node[0].dist = 0; - - // reset other nodes - - for (int i = 1; i < _nNodes; i++) { - _node[i].level = 0; - _node[i].prev = 0; - _node[i].dist = 9999; - } - - // target position goes into final node - _node[_nNodes].x = _targetX; - _node[_nNodes].y = _targetY; - _node[_nNodes].level = 0; - _node[_nNodes].prev = 0; - _node[_nNodes].dist = 9999; -} - -void Router::plotWalkGrid() { - int32 i; - - // get walk grid file + extra grid into 'bars' & 'node' arrays - loadWalkGrid(); - - // lines - - for (i = 0; i < _nBars; i++) - _vm->_screen->drawLine(_bars[i].x1, _bars[i].y1, _bars[i].x2, _bars[i].y2, 254); - - // nodes - - // leave node 0 for start node - for (i = 1; i < _nNodes; i++) - plotCross(_node[i].x, _node[i].y, 184); -} - -void Router::plotCross(int16 x, int16 y, uint8 colour) { - _vm->_screen->drawLine(x - 1, y - 1, x + 1, y + 1, colour); - _vm->_screen->drawLine(x + 1, y - 1, x - 1, y + 1, colour); -} - -void Router::loadWalkGrid() { - WalkGridHeader floorHeader; - byte *fPolygrid; - uint16 fPolygridLen; - - _nBars = 0; // reset counts - _nNodes = 1; // leave node 0 for start-node - - // STATIC GRIDS (added/removed by object logics) - - // go through walkgrid list - for (int i = 0; i < MAX_WALKGRIDS; i++) { - if (_walkGridList[i]) { - int j; - - // open walk grid file - fPolygrid = _vm->_resman->openResource(_walkGridList[i]); - fPolygridLen = _vm->_resman->fetchLen(_walkGridList[i]); - - Common::MemoryReadStream readS(fPolygrid, fPolygridLen); - - readS.seek(ResHeader::size()); - - floorHeader.numBars = readS.readSint32LE(); - floorHeader.numNodes = readS.readSint32LE(); - - // check that we're not going to exceed the max - // allowed in the complete walkgrid arrays - - assert(_nBars + floorHeader.numBars < O_GRID_SIZE); - assert(_nNodes + floorHeader.numNodes < O_GRID_SIZE); - - // lines - - for (j = 0; j < floorHeader.numBars; j++) { - _bars[_nBars + j].x1 = readS.readSint16LE(); - _bars[_nBars + j].y1 = readS.readSint16LE(); - _bars[_nBars + j].x2 = readS.readSint16LE(); - _bars[_nBars + j].y2 = readS.readSint16LE(); - _bars[_nBars + j].xmin = readS.readSint16LE(); - _bars[_nBars + j].ymin = readS.readSint16LE(); - _bars[_nBars + j].xmax = readS.readSint16LE(); - _bars[_nBars + j].ymax = readS.readSint16LE(); - _bars[_nBars + j].dx = readS.readSint16LE(); - _bars[_nBars + j].dy = readS.readSint16LE(); - _bars[_nBars + j].co = readS.readSint32LE(); - } - - // nodes - - // leave node 0 for start node - for (j = 0; j < floorHeader.numNodes; j++) { - _node[_nNodes + j].x = readS.readSint16LE(); - _node[_nNodes + j].y = readS.readSint16LE(); - } - - // close walk grid file - _vm->_resman->closeResource(_walkGridList[i]); - - // increment counts of total bars & nodes in whole - // walkgrid - - _nBars += floorHeader.numBars; - _nNodes += floorHeader.numNodes; - } - } -} - -void Router::clearWalkGridList() { - memset(_walkGridList, 0, sizeof(_walkGridList)); -} - -// called from fnAddWalkGrid - -void Router::addWalkGrid(int32 gridResource) { - int i; - // First, scan the list to see if this grid is already included - - for (i = 0; i < MAX_WALKGRIDS; i++) { - if (_walkGridList[i] == gridResource) - return; - } - - // Scan the list for a free slot - - for (i = 0; i < MAX_WALKGRIDS; i++) { - if (_walkGridList[i] == 0) { - _walkGridList[i] = gridResource; - return; - } - } - - error("_walkGridList[] full"); -} - -// called from fnRemoveWalkGrid - -void Router::removeWalkGrid(int32 gridResource) { - for (int i = 0; i < MAX_WALKGRIDS; i++) { - if (_walkGridList[i] == gridResource) { - // If we've found it in the list, reset entry to zero. - // Otherwise just ignore the request. - _walkGridList[i] = 0; - break; - } - } -} - -} // End of namespace Sword2 diff --git a/sword2/router.h b/sword2/router.h deleted file mode 100644 index 45efd046bd..0000000000 --- a/sword2/router.h +++ /dev/null @@ -1,255 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef _ROUTER_H -#define _ROUTER_H - -// This used to be a variable, but it was never set. Actually, it wasn't even -// initialised! -// -// Define this to force the use of slidy router (so solid path not used when -// ending walk in ANY direction) -// -// #define FORCE_SLIDY - -#include "sword2/object.h" - -namespace Sword2 { - -struct WalkData { - uint16 frame; - int16 x; - int16 y; - uint8 step; - uint8 dir; -}; - -struct BarData { - int16 x1; - int16 y1; - int16 x2; - int16 y2; - int16 xmin; - int16 ymin; - int16 xmax; - int16 ymax; - int16 dx; // x2 - x1 - int16 dy; // y2 - y1 - int32 co; // co = (y1 * dx) - (x1 * dy) from an equation for a - // line y * dx = x * dy + co -}; - -struct NodeData { - int16 x; - int16 y; - int16 level; - int16 prev; - int16 dist; -}; - -// because we only have 2 megas in the game! -#define TOTAL_ROUTE_SLOTS 2 - -#define MAX_FRAMES_PER_CYCLE 16 -#define NO_DIRECTIONS 8 -#define MAX_FRAMES_PER_CHAR (MAX_FRAMES_PER_CYCLE * NO_DIRECTIONS) -#define ROUTE_END_FLAG 255 - -#define MAX_WALKGRIDS 10 - -#define O_WALKANIM_SIZE 600 // max number of nodes in router output -#define O_GRID_SIZE 200 // max 200 lines & 200 points -#define O_ROUTE_SIZE 50 // max number of modules in a route - -struct RouteData { - int32 x; - int32 y; - int32 dirS; - int32 dirD; -}; - -struct PathData { - int32 x; - int32 y; - int32 dir; - int32 num; -}; - -class Router { -private: - Sword2Engine *_vm; - - int16 _standbyX; // see fnSetStandbyCoords() - int16 _standbyY; - int16 _standbyDir; - - // stores pointers to mem blocks containing routes created & used by - // megas (NULL if slot not in use) - WalkData *_routeSlots[TOTAL_ROUTE_SLOTS]; - - BarData _bars[O_GRID_SIZE]; - NodeData _node[O_GRID_SIZE]; - - int32 _walkGridList[MAX_WALKGRIDS]; - - int32 _nBars; - int32 _nNodes; - - int32 _startX; - int32 _startY; - int32 _startDir; - int32 _targetX; - int32 _targetY; - int32 _targetDir; - int32 _scaleA; - int32 _scaleB; - - RouteData _route[O_ROUTE_SIZE]; - PathData _smoothPath[O_ROUTE_SIZE]; - PathData _modularPath[O_ROUTE_SIZE]; - int32 _routeLength; - - int32 _framesPerStep; - int32 _framesPerChar; - - ObjectWalkdata _walkData; - - int8 _modX[NO_DIRECTIONS]; - int8 _modY[NO_DIRECTIONS]; - int32 _diagonalx; - int32 _diagonaly; - - int32 _firstStandFrame; - - int32 _firstStandingTurnLeftFrame; - int32 _firstStandingTurnRightFrame; - - int32 _firstWalkingTurnLeftFrame; // left walking turn - int32 _firstWalkingTurnRightFrame; // right walking turn - - uint32 _firstSlowInFrame[NO_DIRECTIONS]; - - int32 _firstSlowOutFrame; - - // number of slow-out frames on for each leading-leg in each direction - // ie. total number of slow-out frames = (numberOfSlowOutFrames * 2 * - // NO_DIRECTIONS) - - int32 _numberOfSlowOutFrames; - - int32 _stepCount; - - int32 _moduleX; - int32 _moduleY; - int32 _currentDir; - int32 _lastCount; - int32 _frame; - - uint8 returnSlotNo(uint32 megaId); - - int32 getRoute(); - void extractRoute(); - void loadWalkGrid(); - void setUpWalkGrid(byte *ob_mega, int32 x, int32 y, int32 dir); - void loadWalkData(byte *ob_walkdata); - bool scan(int32 level); - - int32 newCheck(int32 status, int32 x1, int32 y1, int32 x2, int32 y2); - bool lineCheck(int32 x1, int32 x2, int32 y1, int32 y2); - bool vertCheck(int32 x, int32 y1, int32 y2); - bool horizCheck(int32 x1, int32 y, int32 x2); - bool check(int32 x1, int32 y1, int32 x2, int32 y2); - int32 checkTarget(int32 x, int32 y); - - int32 smoothestPath(); - void slidyPath(); - - int32 smoothCheck(int32 best, int32 p, int32 dirS, int32 dirD); - - bool addSlowInFrames(WalkData *walkAnim); - void addSlowOutFrames(WalkData *walkAnim); - void slidyWalkAnimator(WalkData *walkAnim); - -#ifndef FORCE_SLIDY - int32 solidPath(); - int32 solidWalkAnimator(WalkData *walkAnim); -#endif - - void plotCross(int16 x, int16 y, uint8 colour); - -public: - Router(Sword2Engine *vm) : _vm(vm), _diagonalx(0), _diagonaly(0) { - memset(_routeSlots, 0, sizeof(_routeSlots)); - memset(_bars, 0, sizeof(_bars)); - memset(_node, 0, sizeof(_node)); - memset(_walkGridList, 0, sizeof(_walkGridList)); - memset(_route, 0, sizeof(_route)); - memset(_smoothPath, 0, sizeof(_smoothPath)); - memset(_modularPath, 0, sizeof(_modularPath)); - memset(_modX, 0, sizeof(_modX)); - memset(_modY, 0, sizeof(_modY)); - memset(_firstSlowInFrame, 0, sizeof(_firstSlowInFrame)); - } - - void setStandbyCoords(int16 x, int16 y, uint8 dir); - int whatTarget(int startX, int startY, int destX, int destY); - - // Sprites - void setSpriteStatus(byte *ob_graph, uint32 type); - void setSpriteShading(byte *ob_graph, uint32 type); - - // Animation - int doAnimate(byte *ob_logic, byte *ob_graph, int32 animRes, bool reverse); - int megaTableAnimate(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *animTable, bool reverse); - - // Walking - int doWalk(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, int16 target_x, int16 target_y, uint8 target_dir); - int walkToAnim(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint32 animRes); - int walkToTalkToMega(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint32 megaId, uint32 separation); - - // Turning - int doFace(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint8 target_dir); - int faceXY(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, int16 target_x, int16 target_y); - int faceMega(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint32 megaId); - - // Standing - void standAt(byte *ob_graph, byte *ob_mega, int32 x, int32 y, int32 dir); - void standAfterAnim(byte *ob_graph, byte *ob_mega, uint32 animRes); - void standAtAnim(byte *ob_graph, byte *ob_mega, uint32 animRes); - - int32 routeFinder(byte *ob_mega, byte *ob_walkdata, int32 x, int32 y, int32 dir); - - void earlySlowOut(byte *ob_mega, byte *ob_walkdata); - - void allocateRouteMem(); - WalkData *getRouteMem(); - void freeRouteMem(); - void freeAllRouteMem(); - void addWalkGrid(int32 gridResource); - void removeWalkGrid(int32 gridResource); - void clearWalkGridList(); - - void plotWalkGrid(); -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/save_rest.cpp b/sword2/save_rest.cpp deleted file mode 100644 index df03c21be3..0000000000 --- a/sword2/save_rest.cpp +++ /dev/null @@ -1,414 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -// --------------------------------------------------------------------------- -// SAVE_REST.CPP save, restore & restart functions -// -// James 05feb97 -// -// "Jesus Saves", but could he Restore or Restart? He can now... -// -// --------------------------------------------------------------------------- - -#include "common/stdafx.h" -#include "common/savefile.h" -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/mouse.h" -#include "sword2/resman.h" -#include "sword2/sound.h" - -namespace Sword2 { - -// A savegame consists of a header and the global variables - -// Max length of a savegame filename -#define MAX_FILENAME_LEN 128 - -/** - * Calculate size of required savegame buffer - */ - -uint32 Sword2Engine::findBufferSize() { - // Size of savegame header + size of global variables - return 212 + _resman->fetchLen(1); -} - -/** - * Save the game. - */ - -uint32 Sword2Engine::saveGame(uint16 slotNo, byte *desc) { - char description[SAVE_DESCRIPTION_LEN]; - uint32 bufferSize = findBufferSize(); - byte *saveBuffer = (byte *)malloc(bufferSize); - ScreenInfo *screenInfo = _screen->getScreenInfo(); - - memset(description, 0, sizeof(description)); - strncpy(description, (char *)desc, SAVE_DESCRIPTION_LEN - 1); - - Common::MemoryWriteStream writeS(saveBuffer, bufferSize); - - byte *globalVars = _resman->openResource(1); - byte *objectHub = _resman->openResource(CUR_PLAYER_ID) + ResHeader::size(); - - // Script no. 7 - 'george_savedata_request' calls fnPassPlayerSaveData - _logic->runResScript(CUR_PLAYER_ID, 7); - - writeS.writeUint32LE(0); // Checksum - writeS.write(description, SAVE_DESCRIPTION_LEN); - writeS.writeUint32LE(_resman->fetchLen(1)); - writeS.writeUint32LE(screenInfo->background_layer_id); - writeS.writeUint32LE(_logic->getRunList()); - writeS.writeUint32LE(screenInfo->feet_x); - writeS.writeUint32LE(screenInfo->feet_y); - writeS.writeUint32LE(_sound->getLoopingMusicId()); - writeS.write(objectHub, ObjectHub::size()); - writeS.write(_logic->_saveLogic, ObjectLogic::size()); - writeS.write(_logic->_saveGraphic, ObjectGraphic::size()); - writeS.write(_logic->_saveMega, ObjectMega::size()); - writeS.write(globalVars, _resman->fetchLen(1)); - - WRITE_LE_UINT32(saveBuffer, calcChecksum(saveBuffer + 4, bufferSize - 4)); - - _resman->closeResource(CUR_PLAYER_ID); - _resman->closeResource(1); - - uint32 errorCode = saveData(slotNo, saveBuffer, bufferSize); - - free(saveBuffer); - - if (errorCode != SR_OK) { - uint32 textId; - - switch (errorCode) { - case SR_ERR_FILEOPEN: - textId = TEXT_SAVE_CANT_OPEN; - break; - default: - textId = TEXT_SAVE_FAILED; - break; - } - - _screen->displayMsg(fetchTextLine(_resman->openResource(textId / SIZE), textId & 0xffff) + 2, 0); - } - - return errorCode; -} - -uint32 Sword2Engine::saveData(uint16 slotNo, byte *buffer, uint32 bufferSize) { - char saveFileName[MAX_FILENAME_LEN]; - - sprintf(saveFileName, "%s.%.3d", _targetName.c_str(), slotNo); - - Common::OutSaveFile *out; - - if (!(out = _saveFileMan->openForSaving(saveFileName))) { - return SR_ERR_FILEOPEN; - } - - out->write(buffer, bufferSize); - out->flush(); - - if (!out->ioFailed()) { - delete out; - return SR_OK; - } - - delete out; - return SR_ERR_WRITEFAIL; -} - -/** - * Restore the game. - */ - -uint32 Sword2Engine::restoreGame(uint16 slotNo) { - uint32 bufferSize = findBufferSize(); - byte *saveBufferMem = (byte *)malloc(bufferSize); - - uint32 errorCode = restoreData(slotNo, saveBufferMem, bufferSize); - - // If it was read in successfully, then restore the game from the - // buffer & free the buffer. Note that restoreFromBuffer() frees the - // buffer in order to clear it from memory before loading in the new - // screen and runlist, so we only need to free it in case of failure. - - if (errorCode == SR_OK) - errorCode = restoreFromBuffer(saveBufferMem, bufferSize); - else - free(saveBufferMem); - - if (errorCode != SR_OK) { - uint32 textId; - - switch (errorCode) { - case SR_ERR_FILEOPEN: - textId = TEXT_RESTORE_CANT_OPEN; - break; - case SR_ERR_INCOMPATIBLE: - textId = TEXT_RESTORE_INCOMPATIBLE; - break; - default: - textId = TEXT_RESTORE_FAILED; - break; - } - - _screen->displayMsg(fetchTextLine(_resman->openResource(textId / SIZE), textId & 0xffff) + 2, 0); - } else { - // Prime system with a game cycle - - // Reset the graphic 'BuildUnit' list before a new logic list - // (see fnRegisterFrame) - _screen->resetRenderLists(); - - // Reset the mouse hot-spot list. See fnRegisterMouse() - // and fnRegisterFrame() - _mouse->resetMouseList(); - - if (_logic->processSession()) - error("restore 1st cycle failed??"); - } - - // Force the game engine to pick a cursor. This appears to be needed - // when using the -x command-line option to restore a game. - _mouse->setMouseTouching(1); - return errorCode; -} - -uint32 Sword2Engine::restoreData(uint16 slotNo, byte *buffer, uint32 bufferSize) { - char saveFileName[MAX_FILENAME_LEN]; - - sprintf(saveFileName, "%s.%.3d", _targetName.c_str(), slotNo); - - Common::InSaveFile *in; - - if (!(in = _saveFileMan->openForLoading(saveFileName))) { - // error: couldn't open file - return SR_ERR_FILEOPEN; - } - - // Read savegame into the buffer - uint32 itemsRead = in->read(buffer, bufferSize); - - delete in; - - if (itemsRead != bufferSize) { - // We didn't get all of it. At the moment we have no way of - // knowing why, so assume that it's an incompatible savegame. - - return SR_ERR_INCOMPATIBLE; - } - - return SR_OK; -} - -uint32 Sword2Engine::restoreFromBuffer(byte *buffer, uint32 size) { - Common::MemoryReadStream readS(buffer, size); - - // Calc checksum & check that aginst the value stored in the header - - if (readS.readUint32LE() != calcChecksum(buffer + 4, size - 4)) { - free(buffer); - return SR_ERR_INCOMPATIBLE; - } - - readS.seek(SAVE_DESCRIPTION_LEN, SEEK_CUR); - - // Check savegame against length of current global variables resource - // This would most probably be trapped by the checksum test anyway, - // but it doesn't do any harm to check this as well. - - // Historical note: During development, earlier savegames would often - // be shorter than the current expected length. - - if (readS.readUint32LE() != _resman->fetchLen(1)) { - free(buffer); - return SR_ERR_INCOMPATIBLE; - } - - byte *globalVars = _resman->openResource(1); - byte *objectHub = _resman->openResource(CUR_PLAYER_ID) + ResHeader::size(); - - uint32 screenId = readS.readUint32LE(); - uint32 runListId = readS.readUint32LE(); - uint32 feetX = readS.readUint32LE(); - uint32 feetY = readS.readUint32LE(); - uint32 musicId = readS.readUint32LE(); - - // Trash all resources from memory except player object & global vars - _resman->killAll(false); - _logic->resetKillList(); - - readS.read(objectHub, ObjectHub::size()); - readS.read(_logic->_saveLogic, ObjectLogic::size()); - readS.read(_logic->_saveGraphic, ObjectGraphic::size()); - readS.read(_logic->_saveMega, ObjectMega::size()); - - // Fill out the player object structures from the savegame structures. - // Also run the appropriate scripts to set up George's anim tables and - // walkdata, and Nico's anim tables. - - // Script no. 8 - 'george_savedata_return' calls fnGetPlayerSaveData - _logic->runResScript(CUR_PLAYER_ID, 8); - - // Script no. 14 - 'set_up_nico_anim_tables' - _logic->runResScript(CUR_PLAYER_ID, 14); - - // Which megaset was the player at the time of saving? - ObjectMega obMega(_logic->_saveMega); - - uint32 scriptNo = 0; - - switch (obMega.getMegasetRes()) { - case 36: // GeoMega: - scriptNo = 9; // script no.9 - 'player_is_george' - break; - case 2003: // GeoMegaB: - scriptNo = 13; // script no.13 - 'player_is_georgeB' - break; - case 1366: // NicMegaA: - scriptNo = 11; // script no.11 - 'player_is_nicoA' - break; - case 1437: // NicMegaB: - scriptNo = 12; // script no.12 - 'player_is_nicoB' - break; - case 1575: // NicMegaC: - scriptNo = 10; // script no.10 - 'player_is_nicoC' - break; - } - - _logic->runResScript(CUR_PLAYER_ID, scriptNo); - - // Copy variables from savegame buffer to memory - readS.read(globalVars, _resman->fetchLen(1)); - - _resman->closeResource(CUR_PLAYER_ID); - _resman->closeResource(1); - - free(buffer); - - int32 pars[2]; - - pars[0] = screenId; - pars[1] = 1; - _logic->fnInitBackground(pars); - - ScreenInfo *screenInfo = _screen->getScreenInfo(); - - // So palette not restored immediately after control panel - we want to - // fade up instead! - screenInfo->new_palette = 99; - - // These need setting after the defaults get set in fnInitBackground. - // Remember that these can change through the game, so need saving & - // restoring too. - - screenInfo->feet_x = feetX; - screenInfo->feet_y = feetY; - - // Start the new run list - _logic->expressChangeSession(runListId); - - // Force in the new scroll position, so unsightly scroll-catch-up does - // not occur when screen first draws after returning from restore panel - - // Set the screen record of player position - ready for setScrolling() - - screenInfo->player_feet_x = obMega.getFeetX(); - screenInfo->player_feet_y = obMega.getFeetY(); - - // if this screen is wide, recompute the scroll offsets now - if (screenInfo->scroll_flag) - _screen->setScrolling(); - - // Any music required will be started after we've returned from - // restoreControl() - see systemMenuMouse() in mouse.cpp! - - // Restart any looping music. Originally this was - and still is - done - // in systemMenuMouse(), but with ScummVM we have other ways of - // restoring savegames so it's easier to put it here as well. - - if (musicId) { - pars[0] = musicId; - pars[1] = FX_LOOP; - _logic->fnPlayMusic(pars); - } else - _logic->fnStopMusic(NULL); - - return SR_OK; -} - -/** - * Get the description of a savegame - */ - -uint32 Sword2Engine::getSaveDescription(uint16 slotNo, byte *description) { - char saveFileName[MAX_FILENAME_LEN]; - - sprintf(saveFileName, "%s.%.3d", _targetName.c_str(), slotNo); - - Common::InSaveFile *in; - - if (!(in = _saveFileMan->openForLoading(saveFileName))) { - return SR_ERR_FILEOPEN; - } - - in->readUint32LE(); - in->read(description, SAVE_DESCRIPTION_LEN); - - delete in; - return SR_OK; -} - -bool Sword2Engine::saveExists() { - for (int i = 0; i <= 99; i++) - if (saveExists(i)) - return true; - return false; -} - -bool Sword2Engine::saveExists(uint16 slotNo) { - char saveFileName[MAX_FILENAME_LEN]; - - sprintf(saveFileName, "%s.%.3d", _targetName.c_str(), slotNo); - - Common::InSaveFile *in; - - if (!(in = _saveFileMan->openForLoading(saveFileName))) { - return false; - } - - delete in; - return true; -} - -uint32 Sword2Engine::calcChecksum(byte *buffer, uint32 size) { - uint32 total = 0; - - for (uint32 pos = 0; pos < size; pos++) - total += buffer[pos]; - - return total; -} - -} // End of namespace Sword2 diff --git a/sword2/save_rest.h b/sword2/save_rest.h deleted file mode 100644 index 9463f3fd4a..0000000000 --- a/sword2/save_rest.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef SAVE_REST_H -#define SAVE_REST_H - -namespace Sword2 { - -#define SAVE_DESCRIPTION_LEN 64 - -// Save & Restore error codes - -enum { - SR_OK, // No worries - SR_ERR_FILEOPEN, // Can't open file - Couldn't create file for - // saving, or couldn't find file for loading. - SR_ERR_INCOMPATIBLE, // (Restore) Incompatible savegame data. - // Savegame file is obsolete. (Won't happen - // after development stops) - SR_ERR_READFAIL, // (Restore) Failed on reading savegame file - - // Something screwed up during the read - SR_ERR_WRITEFAIL // (Save) Failed on writing savegame file - - // Something screwed up during the write - - // could be hard-drive full..? -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/scroll.cpp b/sword2/scroll.cpp deleted file mode 100644 index 3d0a263bc6..0000000000 --- a/sword2/scroll.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/logic.h" - -namespace Sword2 { - -// Max no of pixel allowed to scroll per cycle -#define MAX_SCROLL_DISTANCE 8 - -/** - * Sets the scroll target position for the end of the game cycle. The driver - * will then automatically scroll as many times as it can to reach this - * position in the allotted time. - */ - -void Screen::setScrollTarget(int16 sx, int16 sy) { - _scrollXTarget = sx; - _scrollYTarget = sy; -} - -/** - * If the room is larger than the physical screen, this function is called - * every game cycle to update the scroll offsets. - */ - -void Screen::setScrolling() { - // Normally we aim to get George's feet at (320,250) from top left - // of screen window - // feet_x = 128 + 320 - // feet_y = 128 + 250 - - // Set scroll offsets according to the player's coords - - // If the scroll offsets are being forced in script, ensure that they - // are neither too far to the right nor too far down. - uint32 scrollX = _vm->_logic->readVar(SCROLL_X); - uint32 scrollY = _vm->_logic->readVar(SCROLL_Y); - - if (scrollX || scrollY) { - _thisScreen.scroll_offset_x = MIN((uint16)scrollX, _thisScreen.max_scroll_offset_x); - _thisScreen.scroll_offset_y = MIN((uint16)scrollY, _thisScreen.max_scroll_offset_y); - return; - } - - // George's offset from the centre - the desired position for him - - int16 offset_x = _thisScreen.player_feet_x - _thisScreen.feet_x; - int16 offset_y = _thisScreen.player_feet_y - _thisScreen.feet_y; - - // Prevent scrolling too far left/right/up/down - - if (offset_x < 0) - offset_x = 0; - else if (offset_x > _thisScreen.max_scroll_offset_x) - offset_x = _thisScreen.max_scroll_offset_x; - - if (offset_y < 0) - offset_y = 0; - else if (offset_y > _thisScreen.max_scroll_offset_y) - offset_y = _thisScreen.max_scroll_offset_y; - - // First time on this screen - need absolute scroll immediately! - - if (_thisScreen.scroll_flag == 2) { - debug(5, "init scroll"); - _thisScreen.scroll_offset_x = offset_x; - _thisScreen.scroll_offset_y = offset_y; - _thisScreen.scroll_flag = 1; - return; - } - - // Catch up with required scroll offsets - speed depending on distance - // to catch up (dx and dy) and _scrollFraction used, but limit to - // certain number of pixels per cycle (MAX_SCROLL_DISTANCE) - - int16 dx = _thisScreen.scroll_offset_x - offset_x; - int16 dy = _thisScreen.scroll_offset_y - offset_y; - - uint16 scroll_distance_x; // how much we want to scroll - uint16 scroll_distance_y; - - if (dx < 0) { - // Current scroll_offset_x is less than the required value - - // NB. I'm adding 1 to the result of dx / SCROLL_FRACTION, - // because it would otherwise not scroll at all when - // dx < SCROLL_FRACTION - - // => inc by (fraction of the differnce) NB. dx is -ve, so we - // subtract dx / SCROLL_FRACTION - - scroll_distance_x = 1 - dx / _scrollFraction; - - if (scroll_distance_x > MAX_SCROLL_DISTANCE) - scroll_distance_x = MAX_SCROLL_DISTANCE; - - _thisScreen.scroll_offset_x += scroll_distance_x; - } else if (dx > 0) { - // Current scroll_offset_x is greater than - // the required value - - // => dec by (fraction of the differnce) - - scroll_distance_x = 1 + dx / _scrollFraction; - - if (scroll_distance_x > MAX_SCROLL_DISTANCE) - scroll_distance_x = MAX_SCROLL_DISTANCE; - - _thisScreen.scroll_offset_x -= scroll_distance_x; - } - - if (dy < 0) { - scroll_distance_y = 1 - dy / _scrollFraction; - - if (scroll_distance_y > MAX_SCROLL_DISTANCE) - scroll_distance_y = MAX_SCROLL_DISTANCE; - - _thisScreen.scroll_offset_y += scroll_distance_y; - } else if (dy > 0) { - scroll_distance_y = 1 + dy / _scrollFraction; - - if (scroll_distance_y > MAX_SCROLL_DISTANCE) - scroll_distance_y = MAX_SCROLL_DISTANCE; - - _thisScreen.scroll_offset_y -= scroll_distance_y; - } -} - -} // End of namespace Sword2 diff --git a/sword2/sound.cpp b/sword2/sound.cpp deleted file mode 100644 index d855e88afb..0000000000 --- a/sword2/sound.cpp +++ /dev/null @@ -1,319 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -// --------------------------------------------------------------------------- -// BROKEN SWORD 2 -// -// SOUND.CPP Contains the sound engine, fx & music functions -// Some very 'sound' code in here ;) -// -// (16Dec96 JEL) -// -// --------------------------------------------------------------------------- - -#include "common/stdafx.h" -#include "common/file.h" -#include "common/system.h" - -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/resman.h" -#include "sword2/sound.h" - -#include "sound/wave.h" - -namespace Sword2 { - -Sound::Sound(Sword2Engine *vm) { - int i; - - _vm = vm; - - for (i = 0; i < FXQ_LENGTH; i++) - _fxQueue[i].resource = 0; - - for (i = 0; i < MAXMUS; i++) { - _music[i] = NULL; - - _musicFile[i].idxTab = NULL; - _musicFile[i].idxLen = 0; - _musicFile[i].fileSize = 0; - _musicFile[i].fileType = 0; - _musicFile[i].inUse = false; - - _speechFile[i].idxTab = NULL; - _speechFile[i].idxLen = 0; - _speechFile[i].fileSize = 0; - _speechFile[i].fileType = 0; - _speechFile[i].inUse = false; - } - - _speechPaused = false; - _musicPaused = false; - _fxPaused = false; - - _speechMuted = false; - _musicMuted = false; - _fxMuted = false; - - _reverseStereo = false; - - _loopingMusicId = 0; - - _mixBuffer = NULL; - _mixBufferLen = 0; - - _vm->_mixer->setupPremix(this, Audio::Mixer::kMusicSoundType); -} - -Sound::~Sound() { - _vm->_mixer->setupPremix(0); - - clearFxQueue(); - stopMusic(true); - stopSpeech(); - - free(_mixBuffer); - - for (int i = 0; i < MAXMUS; i++) { - if (_musicFile[i].file.isOpen()) - _musicFile[i].file.close(); - if (_speechFile[i].file.isOpen()) - _speechFile[i].file.close(); - - free(_musicFile[i].idxTab); - free(_speechFile[i].idxTab); - } -} - -void Sound::setReverseStereo(bool reverse) { - if (reverse != _reverseStereo) { - _reverseStereo = reverse; - - for (int i = 0; i < FXQ_LENGTH; i++) { - if (!_fxQueue[i].resource) - continue; - - _fxQueue[i].pan = -_fxQueue[i].pan; - _vm->_mixer->setChannelBalance(_fxQueue[i].handle, _fxQueue[i].pan); - } - } -} - -/** - * Stop all sounds, close their resources and clear the FX queue. - */ - -void Sound::clearFxQueue() { - for (int i = 0; i < FXQ_LENGTH; i++) { - if (_fxQueue[i].resource) { - stopFx(i); - } - } -} - -/** - * Process the FX queue. This function is called once every game cycle. - */ - -void Sound::processFxQueue() { - for (int i = 0; i < FXQ_LENGTH; i++) { - if (!_fxQueue[i].resource) - continue; - - switch (_fxQueue[i].type) { - case FX_RANDOM: - // 1 in 'delay' chance of this fx occurring - if (_vm->_rnd.getRandomNumber(_fxQueue[i].delay) == 0) - playFx(&_fxQueue[i]); - break; - case FX_SPOT: - if (_fxQueue[i].delay) - _fxQueue[i].delay--; - else { - playFx(&_fxQueue[i]); - _fxQueue[i].type = FX_SPOT2; - } - break; - case FX_LOOP: - playFx(&_fxQueue[i]); - _fxQueue[i].type = FX_LOOPING; - break; - case FX_SPOT2: - // Once the FX has finished remove it from the queue. - if (!_vm->_mixer->isSoundHandleActive(_fxQueue[i].handle)) { - _vm->_resman->closeResource(_fxQueue[i].resource); - _fxQueue[i].resource = 0; - } - break; - case FX_LOOPING: - // Once the looped FX has started we can ignore it, - // but we can't close it since the WAV data is in use. - break; - } - } -} - -/** - * Queue a sound effect for playing later. - * @param res the sound resource number - * @param type the type of sound effect - * @param delay when to play the sound effect - * @param volume the sound effect volume (0 through 16) - * @param pan the sound effect panning (-16 through 16) - */ - -void Sound::queueFx(int32 res, int32 type, int32 delay, int32 volume, int32 pan) { - if (_vm->_wantSfxDebug) { - const char *typeStr; - - switch (type) { - case FX_SPOT: - typeStr = "SPOT"; - break; - case FX_LOOP: - typeStr = "LOOPED"; - break; - case FX_RANDOM: - typeStr = "RANDOM"; - break; - default: - typeStr = "INVALID"; - break; - } - - byte buf[NAME_LEN]; - - debug(0, "SFX (sample=\"%s\", vol=%d, pan=%d, delay=%d, type=%s)", _vm->_resman->fetchName(res, buf), volume, pan, delay, typeStr); - } - - for (int i = 0; i < FXQ_LENGTH; i++) { - if (!_fxQueue[i].resource) { - byte *data = _vm->_resman->openResource(res); - - assert(_vm->_resman->fetchType(data) == WAV_FILE); - - uint32 len = _vm->_resman->fetchLen(res) - ResHeader::size(); - - if (type == FX_RANDOM) { - // For spot effects and loops the delay is the - // number of frames to wait. For random - // effects, however, it's the average number of - // seconds between playing the sound, so we - // have to multiply by the frame rate. - delay *= 12; - } - - volume = (volume * Audio::Mixer::kMaxChannelVolume) / 16; - pan = (pan * 127) / 16; - - if (isReverseStereo()) - pan = -pan; - - _fxQueue[i].resource = res; - _fxQueue[i].data = data + ResHeader::size(); - _fxQueue[i].len = len; - _fxQueue[i].delay = delay; - _fxQueue[i].volume = volume; - _fxQueue[i].pan = pan; - _fxQueue[i].type = type; - - // Keep track of the index in the loop so that - // fnStopFx() can be used later to kill this sound. - // Mainly for FX_LOOP and FX_RANDOM. - - _vm->_logic->writeVar(RESULT, i); - return; - } - } - - warning("No free slot in FX queue"); -} - -int32 Sound::playFx(FxQueueEntry *fx) { - return playFx(&fx->handle, fx->data, fx->len, fx->volume, fx->pan, (fx->type == FX_LOOP), Audio::Mixer::kSFXSoundType); -} - -int32 Sound::playFx(Audio::SoundHandle *handle, byte *data, uint32 len, uint8 vol, int8 pan, bool loop, Audio::Mixer::SoundType soundType) { - if (_fxMuted) - return RD_OK; - - if (_vm->_mixer->isSoundHandleActive(*handle)) - return RDERR_FXALREADYOPEN; - - Common::MemoryReadStream stream(data, len); - int rate, size; - byte flags; - - if (!loadWAVFromStream(stream, size, rate, flags)) { - warning("playFX: Not a valid WAV file"); - return RDERR_INVALIDWAV; - } - - // The resource manager must have complete control over when resources - // are freed, or reference counting will break horribly. Besides, the - // data pointer is not valid for passing to free(). Why the hell is the - // AUTOFREE flag set by default anyway? - - flags &= ~Audio::Mixer::FLAG_AUTOFREE; - - if (isReverseStereo()) - flags |= Audio::Mixer::FLAG_REVERSE_STEREO; - - if (loop) - flags |= Audio::Mixer::FLAG_LOOP; - - _vm->_mixer->playRaw(handle, data + stream.pos(), size, rate, flags, -1, vol, pan, 0, 0, soundType); - return RD_OK; -} - -/** - * This function closes a sound effect which has been previously opened for - * playing. Sound effects must be closed when they are finished with, otherwise - * you will run out of sound effect buffers. - * @param i the index of the sound to close - */ - -int32 Sound::stopFx(int32 i) { - if (!_fxQueue[i].resource) - return RDERR_FXNOTOPEN; - - _vm->_mixer->stopHandle(_fxQueue[i].handle); - - _vm->_resman->closeResource(_fxQueue[i].resource); - _fxQueue[i].resource = 0; - return RD_OK; -} - -void Sound::pauseAllSound() { - pauseMusic(); - pauseSpeech(); - pauseFx(); -} - -void Sound::unpauseAllSound() { - unpauseMusic(); - unpauseSpeech(); - unpauseFx(); -} - -} // End of namespace Sword2 diff --git a/sword2/sound.h b/sword2/sound.h deleted file mode 100644 index 7390a60bbc..0000000000 --- a/sword2/sound.h +++ /dev/null @@ -1,272 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -/***************************************************************************** - * SOUND.H Sound engine - * - * SOUND.CPP Contains the sound engine, fx & music functions - * Some very 'sound' code in here ;) - * - * (16Dec96 JEL) - * - ****************************************************************************/ - -#ifndef SOUND_H -#define SOUND_H - -#include "common/file.h" -#include "sound/audiostream.h" -#include "sound/mixer.h" - -// Max number of sound fx -#define MAXMUS 2 - -// Max number of fx in queue at once -#define FXQ_LENGTH 32 - -#define BUFFER_SIZE 4096 - -namespace Sword2 { - -enum { - kCLUMode = 1, - kMP3Mode, - kVorbisMode, - kFlacMode -}; - -enum { - // These three types correspond to types set by the scripts - FX_SPOT = 0, - FX_LOOP = 1, - FX_RANDOM = 2, - - // These are used for FX queue bookkeeping - FX_SPOT2 = 3, - FX_LOOPING = 4 -}; - -// Sound defines - -enum { - RDSE_SAMPLEFINISHED = 0, - RDSE_SAMPLEPLAYING = 1, - RDSE_FXTOCLEAR = 0, // Unused - RDSE_FXCACHED = 1, // Unused - RDSE_FXSPOT = 0, - RDSE_FXLOOP = 1, - RDSE_FXLEADIN = 2, - RDSE_FXLEADOUT = 3, - RDSE_QUIET = 1, - RDSE_SPEAKING = 0 -}; - -class CLUInputStream : public AudioStream { -private: - Common::File *_file; - bool _firstTime; - uint32 _file_pos; - uint32 _end_pos; - int16 _outbuf[BUFFER_SIZE]; - byte _inbuf[BUFFER_SIZE]; - const int16 *_bufferEnd; - const int16 *_pos; - - uint16 _prev; - - void refill(); - - inline bool eosIntern() const { - return _pos >= _bufferEnd; - } - -public: - CLUInputStream(Common::File *file, int size); - ~CLUInputStream(); - - int readBuffer(int16 *buffer, const int numSamples); - - bool endOfData() const { return eosIntern(); } - bool isStereo() const { return false; } - int getRate() const { return 22050; } -}; - -struct SoundFileHandle { - Common::File file; - uint32 *idxTab; - uint32 idxLen; - uint32 fileSize; - uint32 fileType; - volatile bool inUse; -}; - -class MusicInputStream : public AudioStream { -private: - int _cd; - SoundFileHandle *_fh; - uint32 _musicId; - AudioStream *_decoder; - int16 _buffer[BUFFER_SIZE]; - const int16 *_bufferEnd; - const int16 *_pos; - bool _remove; - uint32 _numSamples; - uint32 _samplesLeft; - bool _looping; - int32 _fading; - int32 _fadeSamples; - bool _paused; - - void refill(); - - inline bool eosIntern() const { - if (_looping) - return false; - return _remove || _pos >= _bufferEnd; - } - -public: - MusicInputStream(int cd, SoundFileHandle *fh, uint32 musicId, bool looping); - ~MusicInputStream(); - - int readBuffer(int16 *buffer, const int numSamples); - - bool endOfData() const { return eosIntern(); } - bool isStereo() const { return _decoder->isStereo(); } - int getRate() const { return _decoder->getRate(); } - - int getCD() { return _cd; } - - void fadeUp(); - void fadeDown(); - - bool isReady() { return _decoder != NULL; } - int32 isFading() { return _fading; } - - bool readyToRemove(); - int32 getTimeRemaining(); -}; - -class Sound : public AudioStream { -private: - Sword2Engine *_vm; - - Common::Mutex _mutex; - - struct FxQueueEntry { - Audio::SoundHandle handle; // sound handle - uint32 resource; // resource id of sample - byte *data; // pointer to WAV data - uint32 len; // WAV data length - uint16 delay; // cycles to wait before playing (or 'random chance' if FX_RANDOM) - uint8 volume; // sound volume - int8 pan; // sound panning - uint8 type; // FX_SPOT, FX_RANDOM, FX_LOOP - }; - - FxQueueEntry _fxQueue[FXQ_LENGTH]; - - void triggerFx(uint8 i); - - bool _reverseStereo; - - bool _speechMuted; - bool _fxMuted; - bool _musicMuted; - - bool _speechPaused; - bool _fxPaused; - bool _musicPaused; - - int32 _loopingMusicId; - - Audio::SoundHandle _soundHandleSpeech; - - MusicInputStream *_music[MAXMUS]; - SoundFileHandle _musicFile[MAXMUS]; - SoundFileHandle _speechFile[MAXMUS]; - - int16 *_mixBuffer; - int _mixBufferLen; - -public: - Sound(Sword2Engine *vm); - ~Sound(); - - // AudioStream API - - int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return false; } - bool endOfData() const; - int getRate() const { return 22050; } - - // End of AudioStream API - - void clearFxQueue(); - void processFxQueue(); - - void setReverseStereo(bool reverse); - bool isReverseStereo() const { return _reverseStereo; } - - void muteSpeech(bool mute); - bool isSpeechMute() const { return _speechMuted; } - - void muteFx(bool mute); - bool isFxMute() const { return _fxMuted; } - - void muteMusic(bool mute) { _musicMuted = mute; } - bool isMusicMute() const { return _musicMuted; } - - void setLoopingMusicId(int32 id) { _loopingMusicId = id; } - int32 getLoopingMusicId() const { return _loopingMusicId; } - - void pauseSpeech(); - void unpauseSpeech(); - - void pauseFx(); - void unpauseFx(); - - void pauseMusic(); - void unpauseMusic(); - - void pauseAllSound(); - void unpauseAllSound(); - - void queueFx(int32 res, int32 type, int32 delay, int32 volume, int32 pan); - int32 playFx(FxQueueEntry *fx); - int32 playFx(Audio::SoundHandle *handle, byte *data, uint32 len, uint8 vol, int8 pan, bool loop, Audio::Mixer::SoundType soundType); - int32 stopFx(int32 i); - int32 setFxIdVolumePan(int32 id, int vol, int pan = 255); - - int32 getSpeechStatus(); - int32 amISpeaking(); - int32 playCompSpeech(uint32 speechId, uint8 vol, int8 pan); - uint32 preFetchCompSpeech(uint32 speechId, uint16 **buf); - int32 stopSpeech(); - - int32 streamCompMusic(uint32 musicId, bool loop); - void stopMusic(bool immediately); - int32 musicTimeRemaining(); -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/speech.cpp b/sword2/speech.cpp deleted file mode 100644 index da6bd258ea..0000000000 --- a/sword2/speech.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "common/file.h" - -#include "sword2/sword2.h" -#include "sword2/console.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/maketext.h" -#include "sword2/resman.h" - -namespace Sword2 { - -// To request the status of a target, we run its 4th script, get-speech-state. -// This will cause RESULT to be set to either 1 (target is waiting) or 0 -// (target is busy). - -// Distance kept above talking sprite -#define GAP_ABOVE_HEAD 20 - -enum { - S_OB_GRAPHIC = 0, - S_OB_SPEECH = 1, - S_OB_LOGIC = 2, - S_OB_MEGA = 3, - - S_TEXT = 4, - S_WAV = 5, - S_ANIM = 6, - S_DIR_TABLE = 7, - S_ANIM_MODE = 8 -}; - -/** - * Sets _textX and _textY for position of text sprite. Note that _textX is - * also used to calculate speech pan. - */ - -void Logic::locateTalker(int32 *params) { - // params: 0 pointer to ob_graphic - // 1 pointer to ob_speech - // 2 pointer to ob_logic - // 3 pointer to ob_mega - // 4 encoded text number - // 5 wav res id - // 6 anim res id - // 7 pointer to anim table - // 8 animation mode 0 lip synced, - // 1 just straight animation - - if (!_animId) { - // There is no animation. Assume it's voice-over text, and put - // it at the bottom of the screen. - - _textX = 320; - _textY = 400; - return; - } - - byte *file = _vm->_resman->openResource(_animId); - - // '0' means 1st frame - - CdtEntry cdt_entry; - FrameHeader frame_head; - - cdt_entry.read(_vm->fetchCdtEntry(file, 0)); - frame_head.read(_vm->fetchFrameHeader(file, 0)); - - // Note: This part of the code is quite similar to registerFrame(). - - if (cdt_entry.frameType & FRAME_OFFSET) { - // The frame has offsets, i.e. it's a scalable mega frame - ObjectMega obMega(decodePtr(params[S_OB_MEGA])); - - uint16 scale = obMega.calcScale(); - - // Calc suitable centre point above the head, based on scaled - // height - - // just use 'feet_x' as centre - _textX = obMega.getFeetX(); - - // Add scaled y-offset to feet_y coord to get top of sprite - _textY = obMega.getFeetY() + (cdt_entry.y * scale) / 256; - } else { - // It's a non-scaling anim - calc suitable centre point above - // the head, based on scaled width - - // x-coord + half of width - _textX = cdt_entry.x + frame_head.width / 2; - _textY = cdt_entry.y; - } - - _vm->_resman->closeResource(_animId); - - // Leave space above their head - _textY -= GAP_ABOVE_HEAD; - - // Adjust the text coords for RDSPR_DISPLAYALIGN - - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - _textX -= screenInfo->scroll_offset_x; - _textY -= screenInfo->scroll_offset_y; -} - -/** - * This function is called the first time to build the text, if we need one. If - * If necessary it also brings in the wav and sets up the animation. - * - * If there is an animation it can be repeating lip-sync or run-once. - * - * If there is no wav, then the text comes up instead. There can be any - * combination of text/wav playing. - */ - -void Logic::formText(int32 *params) { - // params 0 pointer to ob_graphic - // 1 pointer to ob_speech - // 2 pointer to ob_logic - // 3 pointer to ob_mega - // 4 encoded text number - // 5 wav res id - // 6 anim res id - // 7 pointer to anim table - // 8 animation mode 0 lip synced, - // 1 just straight animation - - // There should always be a text line, as all text is derived from it. - // If there is none, that's bad... - - if (!params[S_TEXT]) { - warning("No text line for speech wav %d", params[S_WAV]); - return; - } - - ObjectSpeech obSpeech(decodePtr(params[S_OB_SPEECH])); - - // Establish the max width allowed for this text sprite. - uint32 textWidth = obSpeech.getWidth(); - - if (!textWidth) - textWidth = 400; - - // Pull out the text line, and make the sprite and text block - - uint32 text_res = params[S_TEXT] / SIZE; - uint32 local_text = params[S_TEXT] & 0xffff; - byte *text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text); - - // 'text + 2' to skip the first 2 bytes which form the line reference - // number - - _speechTextBlocNo = _vm->_fontRenderer->buildNewBloc( - text + 2, _textX, _textY, - textWidth, obSpeech.getPen(), - RDSPR_TRANS | RDSPR_DISPLAYALIGN, - _vm->_speechFontId, POSITION_AT_CENTRE_OF_BASE); - - _vm->_resman->closeResource(text_res); - - // Set speech duration, in case not using a wav. - _speechTime = strlen((char *)text) + 30; -} - -/** - * There are some hard-coded cases where speech is used to illustrate a sound - * effect. In this case there is no sound associated with the speech itself. - */ - -bool Logic::wantSpeechForLine(uint32 wavId) { - switch (wavId) { - case 1328: // AttendantSpeech - // SFX(Phone71); - // FX <Telephone rings> - case 2059: // PabloSpeech - // SFX (2059); - // FX <Sound of sporadic gunfire from below> - case 4082: // DuaneSpeech - // SFX (4082); - // FX <Pffffffffffft! Frp. (Unimpressive, flatulent noise.)> - case 4214: // cat_52 - // SFX (4214); - // 4214FXMeow! - case 4568: // trapdoor_13 - // SFX (4568); - // 4568fx<door slamming> - case 4913: // LobineauSpeech - // SFX (tone2); - // FX <Lobineau hangs up> - case 5120: // bush_66 - // SFX (5120); - // 5120FX<loud buzzing> - case 528: // PresidentaSpeech - // SFX (528); - // FX <Nearby Crash of Collapsing Masonry> - case 920: // Zombie Island forest maze (bird) - case 923: // Zombie Island forest maze (monkey) - case 926: // Zombie Island forest maze (zombie) - // Don't want speech for these lines! - return false; - default: - // Ok for all other lines - return true; - } -} - -} // End of namespace Sword2 diff --git a/sword2/sprite.cpp b/sword2/sprite.cpp deleted file mode 100644 index a0ba7f7189..0000000000 --- a/sword2/sprite.cpp +++ /dev/null @@ -1,655 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" - -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/build_display.h" - -namespace Sword2 { - -/** - * This function takes a sprite and creates a mirror image of it. - * @param dst destination buffer - * @param src source buffer - * @param w width of the sprite - * @param h height of the sprite - */ - -void Screen::mirrorSprite(byte *dst, byte *src, int16 w, int16 h) { - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - *dst++ = *(src + w - x - 1); - } - src += w; - } -} - -/** - * This function takes a compressed frame of a sprite with up to 256 colours - * and decompresses it. - * @param dst destination buffer - * @param src source buffer - * @param decompSize the expected size of the decompressed sprite - */ - -int32 Screen::decompressRLE256(byte *dst, byte *src, int32 decompSize) { - // PARAMETERS: - // source points to the start of the sprite data for input - // decompSize gives size of decompressed data in bytes - // dest points to start of destination buffer for decompressed - // data - - byte headerByte; // block header byte - byte *endDest = dst + decompSize; // pointer to byte after end of decomp buffer - int32 rv; - - while (1) { - // FLAT block - // read FLAT block header & increment 'scan' to first pixel - // of block - headerByte = *src++; - - // if this isn't a zero-length block - if (headerByte) { - if (dst + headerByte > endDest) { - rv = 1; - break; - } - - // set the next 'headerByte' pixels to the next colour - // at 'source' - memset(dst, *src, headerByte); - - // increment destination pointer to just after this - // block - dst += headerByte; - - // increment source pointer to just after this colour - src++; - - // if we've decompressed all of the data - if (dst == endDest) { - rv = 0; // return "OK" - break; - } - } - - // RAW block - // read RAW block header & increment 'scan' to first pixel of - // block - headerByte = *src++; - - // if this isn't a zero-length block - if (headerByte) { - if (dst + headerByte > endDest) { - rv = 1; - break; - } - - // copy the next 'headerByte' pixels from source to - // destination - memcpy(dst, src, headerByte); - - // increment destination pointer to just after this - // block - dst += headerByte; - - // increment source pointer to just after this block - src += headerByte; - - // if we've decompressed all of the data - if (dst == endDest) { - rv = 0; // return "OK" - break; - } - } - } - - return rv; -} - -/** - * Unwinds a run of 16-colour data into 256-colour palette data. - */ - -void Screen::unwindRaw16(byte *dst, byte *src, uint8 blockSize, byte *colTable) { - // for each pair of pixels - while (blockSize > 1) { - // 1st colour = number in table at position given by upper - // nibble of source byte - *dst++ = colTable[(*src) >> 4]; - - // 2nd colour = number in table at position given by lower - // nibble of source byte - *dst++ = colTable[(*src) & 0x0f]; - - // point to next source byte - src++; - - // decrement count of how many pixels left to read - blockSize -= 2; - } - - // if there's a final odd pixel - if (blockSize) { - // colour = number in table at position given by upper nibble - // of source byte - *dst++ = colTable[(*src) >> 4]; - } -} - -/** - * This function takes a compressed frame of a sprite (with up to 16 colours) - * and decompresses it. - * @param dst destination buffer - * @param src source buffer - * @param decompSize the expected size of the uncompressed sprite - * @param colTable mapping from the 16 encoded colours to the current palette - */ - -int32 Screen::decompressRLE16(byte *dst, byte *src, int32 decompSize, byte *colTable) { - byte headerByte; // block header byte - byte *endDest = dst + decompSize; // pointer to byte after end of decomp buffer - int32 rv; - - while (1) { - // FLAT block - // read FLAT block header & increment 'scan' to first pixel - // of block - headerByte = *src++; - - // if this isn't a zero-length block - if (headerByte) { - if (dst + headerByte > endDest) { - rv = 1; - break; - } - - // set the next 'headerByte' pixels to the next - // colour at 'source' - memset(dst, *src, headerByte); - - // increment destination pointer to just after this - // block - dst += headerByte; - - // increment source pointer to just after this colour - src++; - - // if we've decompressed all of the data - if (dst == endDest) { - rv = 0; // return "OK" - break; - } - } - - // RAW block - // read RAW block header & increment 'scan' to first pixel of - // block - headerByte = *src++; - - // if this isn't a zero-length block - if (headerByte) { - if (dst + headerByte > endDest) { - rv = 1; - break; - } - - // copy the next 'headerByte' pixels from source to - // destination (NB. 2 pixels per byte) - unwindRaw16(dst, src, headerByte, colTable); - - // increment destination pointer to just after this - // block - dst += headerByte; - - // increment source pointer to just after this block - // (NB. headerByte gives pixels, so /2 for bytes) - src += (headerByte + 1) / 2; - - // if we've decompressed all of the data - if (dst >= endDest) { - rv = 0; // return "OK" - break; - } - } - } - - return rv; -} - -/** - * Creates a sprite surface. Sprite surfaces are used by the in-game dialogs - * and for displaying cutscene subtitles, which makes them much easier to draw - * than standard sprites. - * @param s information about how to decode the sprite - * @param sprite the buffer that will be created to store the surface - * @return RD_OK, or an error code - */ - -int32 Screen::createSurface(SpriteInfo *s, byte **sprite) { - *sprite = (byte *)malloc(s->w * s->h); - if (!*sprite) - return RDERR_OUTOFMEMORY; - - // Surfaces are either uncompressed or RLE256-compressed. No need to - // test for anything else. - - if (s->type & RDSPR_NOCOMPRESSION) { - memcpy(*sprite, s->data, s->w * s->h); - } else if (decompressRLE256(*sprite, s->data, s->w * s->h)) { - free(*sprite); - return RDERR_DECOMPRESSION; - } - - return RD_OK; -} - -/** - * Draws the sprite surface created earlier. - * @param s information about how to place the sprite - * @param surface pointer to the surface created earlier - * @param clipRect the clipping rectangle - */ - -void Screen::drawSurface(SpriteInfo *s, byte *surface, Common::Rect *clipRect) { - Common::Rect rd, rs; - uint16 x, y; - byte *src, *dst; - - rs.left = 0; - rs.right = s->w; - rs.top = 0; - rs.bottom = s->h; - - rd.left = s->x; - rd.right = rd.left + rs.right; - rd.top = s->y; - rd.bottom = rd.top + rs.bottom; - - Common::Rect defClipRect(0, 0, _screenWide, _screenDeep); - - if (!clipRect) { - clipRect = &defClipRect; - } - - if (clipRect->left > rd.left) { - rs.left += (clipRect->left - rd.left); - rd.left = clipRect->left; - } - - if (clipRect->top > rd.top) { - rs.top += (clipRect->top - rd.top); - rd.top = clipRect->top; - } - - if (clipRect->right < rd.right) { - rd.right = clipRect->right; - } - - if (clipRect->bottom < rd.bottom) { - rd.bottom = clipRect->bottom; - } - - if (rd.width() <= 0 || rd.height() <= 0) - return; - - src = surface + rs.top * s->w + rs.left; - dst = _buffer + _screenWide * rd.top + rd.left; - - // Surfaces are always transparent. - - for (y = 0; y < rd.height(); y++) { - for (x = 0; x < rd.width(); x++) { - if (src[x]) - dst[x] = src[x]; - } - src += s->w; - dst += _screenWide; - } - - updateRect(&rd); -} - -/** - * Destroys a surface. - */ - -void Screen::deleteSurface(byte *surface) { - free(surface); -} - -/** - * Draws a sprite onto the screen. The type of the sprite can be a combination - * of the following flags, some of which are mutually exclusive: - * RDSPR_DISPLAYALIGN The sprite is drawn relative to the top left corner - * of the screen - * RDSPR_FLIP The sprite is mirrored - * RDSPR_TRANS The sprite has a transparent colour zero - * RDSPR_BLEND The sprite is translucent - * RDSPR_SHADOW The sprite is affected by the light mask. (Scaled - * sprites always are.) - * RDSPR_NOCOMPRESSION The sprite data is not compressed - * RDSPR_RLE16 The sprite data is a 16-colour compressed sprite - * RDSPR_RLE256 The sprite data is a 256-colour compressed sprite - * @param s all the information needed to draw the sprite - * @warning Sprites will only be drawn onto the background, not over menubar - * areas. - */ - -// FIXME: I'm sure this could be optimized. There's plenty of data copying and -// mallocing here. - -int32 Screen::drawSprite(SpriteInfo *s) { - byte *src, *dst; - byte *sprite, *newSprite; - uint16 scale; - int16 i, j; - uint16 srcPitch; - bool freeSprite = false; - Common::Rect rd, rs; - - // ----------------------------------------------------------------- - // Decompression and mirroring - // ----------------------------------------------------------------- - - if (s->type & RDSPR_NOCOMPRESSION) - sprite = s->data; - else { - sprite = (byte *)malloc(s->w * s->h); - freeSprite = true; - if (!sprite) - return RDERR_OUTOFMEMORY; - if ((s->type & 0xff00) == RDSPR_RLE16) { - if (decompressRLE16(sprite, s->data, s->w * s->h, s->colourTable)) { - free(sprite); - return RDERR_DECOMPRESSION; - } - } else { - if (decompressRLE256(sprite, s->data, s->w * s->h)) { - free(sprite); - return RDERR_DECOMPRESSION; - } - } - } - - if (s->type & RDSPR_FLIP) { - newSprite = (byte *)malloc(s->w * s->h); - if (newSprite == NULL) { - if (freeSprite) - free(sprite); - return RDERR_OUTOFMEMORY; - } - mirrorSprite(newSprite, sprite, s->w, s->h); - if (freeSprite) - free(sprite); - sprite = newSprite; - freeSprite = true; - } - - // ----------------------------------------------------------------- - // Positioning and clipping. - // ----------------------------------------------------------------- - - int16 spriteX = s->x; - int16 spriteY = s->y; - - if (!(s->type & RDSPR_DISPLAYALIGN)) { - spriteX += _parallaxScrollX; - spriteY += _parallaxScrollY; - } - - spriteY += MENUDEEP; - - // A scale factor 0 or 256 means don't scale. Why do they use two - // different values to mean the same thing? Normalize it here for - // convenience. - - scale = (s->scale == 0) ? 256 : s->scale; - - rs.top = 0; - rs.left = 0; - - if (scale != 256) { - rs.right = s->scaledWidth; - rs.bottom = s->scaledHeight; - srcPitch = s->scaledWidth; - } else { - rs.right = s->w; - rs.bottom = s->h; - srcPitch = s->w; - } - - rd.top = spriteY; - rd.left = spriteX; - - if (!(s->type & RDSPR_DISPLAYALIGN)) { - rd.top -= _scrollY; - rd.left -= _scrollX; - } - - rd.right = rd.left + rs.right; - rd.bottom = rd.top + rs.bottom; - - // Check if the sprite would end up completely outside the screen. - - if (rd.left > RENDERWIDE || rd.top > RENDERDEEP + MENUDEEP || rd.right < 0 || rd.bottom < MENUDEEP) { - if (freeSprite) - free(sprite); - return RD_OK; - } - - if (rd.top < MENUDEEP) { - rs.top = MENUDEEP - rd.top; - rd.top = MENUDEEP; - } - if (rd.bottom > RENDERDEEP + MENUDEEP) { - rd.bottom = RENDERDEEP + MENUDEEP; - rs.bottom = rs.top + (rd.bottom - rd.top); - } - if (rd.left < 0) { - rs.left = -rd.left; - rd.left = 0; - } - if (rd.right > RENDERWIDE) { - rd.right = RENDERWIDE; - rs.right = rs.left + (rd.right - rd.left); - } - - // ----------------------------------------------------------------- - // Scaling - // ----------------------------------------------------------------- - - if (scale != 256) { - if (s->scaledWidth > SCALE_MAXWIDTH || s->scaledHeight > SCALE_MAXHEIGHT) { - if (freeSprite) - free(sprite); - return RDERR_NOTIMPLEMENTED; - } - - newSprite = (byte *)malloc(s->scaledWidth * s->scaledHeight); - if (newSprite == NULL) { - if (freeSprite) - free(sprite); - return RDERR_OUTOFMEMORY; - } - - if (_renderCaps & RDBLTFX_EDGEBLEND) - scaleImageGood(newSprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, sprite, s->w, s->w, s->h, _buffer + _screenWide * rd.top + rd.left); - else - scaleImageFast(newSprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, sprite, s->w, s->w, s->h); - - if (freeSprite) - free(sprite); - sprite = newSprite; - freeSprite = true; - } - - // ----------------------------------------------------------------- - // Light masking - // ----------------------------------------------------------------- - - // The light mask is an optional layer that covers the entire room - // and which is used to simulate light and shadows. Scaled sprites - // (actors, presumably) are always affected. - - if ((_renderCaps & RDBLTFX_SHADOWBLEND) && _lightMask && (scale != 256 || (s->type & RDSPR_SHADOW))) { - byte *lightMap; - - // Make sure that we never apply the shadow to the original - // resource data. This could only ever happen in the - // RDSPR_NOCOMPRESSION case. - - if (!freeSprite) { - newSprite = (byte *)malloc(s->w * s->h); - memcpy(newSprite, sprite, s->w * s->h); - sprite = newSprite; - freeSprite = true; - } - - src = sprite + rs.top * srcPitch + rs.left; - lightMap = _lightMask + (rd.top + _scrollY - MENUDEEP) * _locationWide + rd.left + _scrollX; - - for (i = 0; i < rs.height(); i++) { - for (j = 0; j < rs.width(); j++) { - if (src[j] && lightMap[j]) { - uint8 r = ((32 - lightMap[j]) * _palette[src[j] * 4 + 0]) >> 5; - uint8 g = ((32 - lightMap[j]) * _palette[src[j] * 4 + 1]) >> 5; - uint8 b = ((32 - lightMap[j]) * _palette[src[j] * 4 + 2]) >> 5; - src[j] = quickMatch(r, g, b); - } - } - src += srcPitch; - lightMap += _locationWide; - } - } - - // ----------------------------------------------------------------- - // Drawing - // ----------------------------------------------------------------- - - src = sprite + rs.top * srcPitch + rs.left; - dst = _buffer + _screenWide * rd.top + rd.left; - - if (s->type & RDSPR_BLEND) { - // The original code had two different blending cases. One for - // s->blend & 0x01 and one for s->blend & 0x02. However, the - // only values that actually appear in the cluster files are - // 0, 513 and 1025 so the s->blend & 0x02 case was never used. - // Which is just as well since that code made no sense to me. - - if (!(_renderCaps & RDBLTFX_SPRITEBLEND)) { - for (i = 0; i < rs.height(); i++) { - for (j = 0; j < rs.width(); j++) { - if (src[j] && ((i & 1) == (j & 1))) - dst[j] = src[j]; - } - src += srcPitch; - dst += _screenWide; - } - } else { - uint8 n = s->blend >> 8; - - for (i = 0; i < rs.height(); i++) { - for (j = 0; j < rs.width(); j++) { - if (src[j]) { - uint8 r1 = _palette[src[j] * 4 + 0]; - uint8 g1 = _palette[src[j] * 4 + 1]; - uint8 b1 = _palette[src[j] * 4 + 2]; - uint8 r2 = _palette[dst[j] * 4 + 0]; - uint8 g2 = _palette[dst[j] * 4 + 1]; - uint8 b2 = _palette[dst[j] * 4 + 2]; - - uint8 r = (r1 * n + r2 * (8 - n)) >> 3; - uint8 g = (g1 * n + g2 * (8 - n)) >> 3; - uint8 b = (b1 * n + b2 * (8 - n)) >> 3; - dst[j] = quickMatch(r, g, b); - } - } - src += srcPitch; - dst += _screenWide; - } - } - } else { - if (s->type & RDSPR_TRANS) { - for (i = 0; i < rs.height(); i++) { - for (j = 0; j < rs.width(); j++) { - if (src[j]) - dst[j] = src[j]; - } - src += srcPitch; - dst += _screenWide; - } - } else { - for (i = 0; i < rs.height(); i++) { - memcpy(dst, src, rs.width()); - src += srcPitch; - dst += _screenWide; - } - } - } - - if (freeSprite) - free(sprite); - - markAsDirty(rd.left, rd.top, rd.right - 1, rd.bottom - 1); - return RD_OK; -} - -/** - * Opens the light masking sprite for a room. - */ - -int32 Screen::openLightMask(SpriteInfo *s) { - // FIXME: The light mask is only needed on higher graphics detail - // settings, so to save memory we could simply ignore it on lower - // settings. But then we need to figure out how to ensure that it - // is properly loaded if the user changes the settings in mid-game. - - if (_lightMask) - return RDERR_NOTCLOSED; - - _lightMask = (byte *)malloc(s->w * s->h); - if (!_lightMask) - return RDERR_OUTOFMEMORY; - - if (decompressRLE256(_lightMask, s->data, s->w * s->h)) - return RDERR_DECOMPRESSION; - - return RD_OK; -} - -/** - * Closes the light masking sprite for a room. - */ - -int32 Screen::closeLightMask() { - if (!_lightMask) - return RDERR_NOTOPEN; - - free(_lightMask); - _lightMask = NULL; - return RD_OK; -} - -} // End of namespace Sword2 diff --git a/sword2/startup.cpp b/sword2/startup.cpp deleted file mode 100644 index 2e1dd7b0ae..0000000000 --- a/sword2/startup.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "common/file.h" - -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/maketext.h" -#include "sword2/memory.h" -#include "sword2/resman.h" -#include "sword2/router.h" -#include "sword2/sound.h" - -namespace Sword2 { - -bool Sword2Engine::initStartMenu() { - // Print out a list of all the start points available. - // There should be a linc produced file called startup.txt. - // This file should contain ascii numbers of all the resource game - // objects that are screen managers. - // We query each in turn and setup an array of start structures. - // If the file doesn't exist then we say so and return a 0. - - Common::File fp; - - // ok, load in the master screen manager file - - _totalStartups = 0; - _totalScreenManagers = 0; - - if (!fp.open("startup.inf")) { - warning("Cannot open startup.inf - the debugger won't have a start menu"); - return false; - } - - // The startup.inf file which contains a list of all the files. Now - // extract the filenames - - int start_ids[MAX_starts]; - - while (1) { - bool done = false; - - start_ids[_totalScreenManagers] = 0; - - // Scan the string until the LF in CRLF - - int b; - - do { - b = fp.readByte(); - - if (fp.ioFailed()) { - done = true; - break; - } - - if (isdigit(b)) { - start_ids[_totalScreenManagers] *= 10; - start_ids[_totalScreenManagers] += (b - '0'); - } - } while (b != 10); - - if (done) - break; - - _totalScreenManagers++; - - if (_totalScreenManagers == MAX_starts) { - warning("MAX_starts exceeded"); - break; - } - } - - fp.close(); - - // Using this method the Gode generated resource.inf must have #0d0a - // on the last entry - - debug(1, "%d screen manager objects", _totalScreenManagers); - - // Open each object and make a query call. The object must fill in a - // startup structure. It may fill in several if it wishes - for - // instance a startup could be set for later in the game where - // specific vars are set - - for (uint i = 0; i < _totalScreenManagers; i++) { - _startRes = start_ids[i]; - - debug(2, "Querying screen manager %d", _startRes); - - // Open each one and run through the interpreter. Script 0 is - // the query request script - - // if the resource number is within range & it's not a null - // resource - // - need to check in case un-built sections included in - // start list - - if (_resman->checkValid(_startRes)) { - _logic->runResScript(_startRes, 0); - } else - warning("Start menu resource %d invalid", _startRes); - } - - return 1; -} - -void Sword2Engine::registerStartPoint(int32 key, char *name) { - assert(_totalStartups < MAX_starts); - - _startList[_totalStartups].start_res_id = _startRes; - _startList[_totalStartups].key = key; - - strncpy(_startList[_totalStartups].description, name, MAX_description); - _startList[_totalStartups].description[MAX_description - 1] = 0; - - _totalStartups++; -} - -void Sword2Engine::runStart(int start) { - // Restarting - stop sfx, music & speech! - - _sound->clearFxQueue(); - _logic->fnStopMusic(NULL); - _sound->unpauseSpeech(); - _sound->stopSpeech(); - - // Remove all resources from memory, including player object and global - // variables - - _resman->removeAll(); - - // Reopen global variables resource and player object - setupPersistentResources(); - - // Free all the route memory blocks from previous game - _logic->_router->freeAllRouteMem(); - - // If there was speech text, kill the text block - if (_logic->_speechTextBlocNo) { - _fontRenderer->killTextBloc(_logic->_speechTextBlocNo); - _logic->_speechTextBlocNo = 0; - } - - _logic->runResObjScript(_startList[start].start_res_id, CUR_PLAYER_ID, _startList[start].key & 0xffff); - - // Make sure there's a mouse, in case restarting while mouse not - // available - _logic->fnAddHuman(NULL); -} - -} // End of namespace Sword2 diff --git a/sword2/sword2.cpp b/sword2/sword2.cpp deleted file mode 100644 index 6056d636b7..0000000000 --- a/sword2/sword2.cpp +++ /dev/null @@ -1,689 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" - -#include "backends/fs/fs.h" - -#include "base/gameDetector.h" -#include "base/plugins.h" - -#include "common/config-manager.h" -#include "common/file.h" -#include "common/system.h" - -#include "sword2/sword2.h" -#include "sword2/console.h" -#include "sword2/controls.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/maketext.h" -#include "sword2/memory.h" -#include "sword2/mouse.h" -#include "sword2/resman.h" -#include "sword2/router.h" -#include "sword2/sound.h" - -#ifdef _WIN32_WCE -extern bool isSmartphone(); -#endif - -struct Sword2GameSettings { - const char *gameid; - const char *description; - uint32 features; - const char *detectname; - GameSettings toGameSettings() const { - GameSettings dummy = { gameid, description, features }; - return dummy; - } -}; - -static const Sword2GameSettings sword2_settings[] = { - /* Broken Sword 2 */ - {"sword2", "Broken Sword 2: The Smoking Mirror", GF_DEFAULT_TO_1X_SCALER, "players.clu" }, - {"sword2alt", "Broken Sword 2: The Smoking Mirror (alt)", GF_DEFAULT_TO_1X_SCALER, "r2ctlns.ocx" }, - {"sword2demo", "Broken Sword 2: The Smoking Mirror (Demo)", GF_DEFAULT_TO_1X_SCALER | Sword2::GF_DEMO, "players.clu" }, - {NULL, NULL, 0, NULL} -}; - -GameList Engine_SWORD2_gameList() { - const Sword2GameSettings *g = sword2_settings; - GameList games; - while (g->gameid) { - games.push_back(g->toGameSettings()); - g++; - } - return games; -} - -DetectedGameList Engine_SWORD2_detectGames(const FSList &fslist) { - DetectedGameList detectedGames; - const Sword2GameSettings *g; - - // TODO: It would be nice if we had code here which distinguishes - // between the 'sword2' and 'sword2demo' targets. The current code - // can't do that since they use the same detectname. - - for (g = sword2_settings; g->gameid; ++g) { - // Iterate over all files in the given directory - for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { - if (!file->isDirectory()) { - const char *gameName = file->displayName().c_str(); - - if (0 == scumm_stricmp(g->detectname, gameName)) { - // Match found, add to list of candidates, then abort inner loop. - detectedGames.push_back(g->toGameSettings()); - break; - } - } - } - } - return detectedGames; -} - -Engine *Engine_SWORD2_create(GameDetector *detector, OSystem *syst) { - return new Sword2::Sword2Engine(detector, syst); -} - -REGISTER_PLUGIN(SWORD2, "Broken Sword 2") - -namespace Sword2 { - -Sword2Engine::Sword2Engine(GameDetector *detector, OSystem *syst) : Engine(syst) { - // Add default file directories - Common::File::addDefaultDirectory(_gameDataPath + "CLUSTERS/"); - Common::File::addDefaultDirectory(_gameDataPath + "SWORD2/"); - Common::File::addDefaultDirectory(_gameDataPath + "VIDEO/"); - Common::File::addDefaultDirectory(_gameDataPath + "clusters/"); - Common::File::addDefaultDirectory(_gameDataPath + "sword2/"); - Common::File::addDefaultDirectory(_gameDataPath + "video/"); - - _features = detector->_game.features; - _targetName = detector->_targetName; - - _bootParam = ConfMan.getInt("boot_param"); - _saveSlot = ConfMan.getInt("save_slot"); - - _memory = NULL; - _resman = NULL; - _sound = NULL; - _screen = NULL; - _mouse = NULL; - _logic = NULL; - _fontRenderer = NULL; - _debugger = NULL; - - _keyboardEvent.pending = false; - _keyboardEvent.repeat = 0; - _mouseEvent.pending = false; - - _wantSfxDebug = false; - -#ifdef SWORD2_DEBUG - _stepOneCycle = false; - _renderSkip = false; -#endif - - _gamePaused = false; - _graphicsLevelFudged = false; - - _gameCycle = 0; - - _quit = false; -} - -Sword2Engine::~Sword2Engine() { - delete _debugger; - delete _sound; - delete _fontRenderer; - delete _screen; - delete _mouse; - delete _logic; - delete _resman; - delete _memory; -} - -void Sword2Engine::errorString(const char *buf1, char *buf2) { - strcpy(buf2, buf1); - -#ifdef _WIN32_WCE - if (isSmartphone()) - return; -#endif - - // Unless an error -originated- within the debugger, spawn the - // debugger. Otherwise exit out normally. - if (_debugger && !_debugger->isAttached()) { - // (Print it again in case debugger segfaults) - printf("%s\n", buf2); - _debugger->attach(buf2); - _debugger->onFrame(); - } -} - -void Sword2Engine::registerDefaultSettings() { - ConfMan.registerDefault("music_mute", false); - ConfMan.registerDefault("speech_mute", false); - ConfMan.registerDefault("sfx_mute", false); - ConfMan.registerDefault("gfx_details", 2); - ConfMan.registerDefault("subtitles", false); - ConfMan.registerDefault("reverse_stereo", false); -} - -void Sword2Engine::readSettings() { - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); - setSubtitles(ConfMan.getBool("subtitles")); - _sound->muteMusic(ConfMan.getBool("music_mute")); - _sound->muteSpeech(ConfMan.getBool("speech_mute")); - _sound->muteFx(ConfMan.getBool("sfx_mute")); - _sound->setReverseStereo(ConfMan.getBool("reverse_stereo")); - _mouse->setObjectLabels(ConfMan.getBool("object_labels")); - _screen->setRenderLevel(ConfMan.getInt("gfx_details")); -} - -void Sword2Engine::writeSettings() { - ConfMan.set("music_volume", _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType)); - ConfMan.set("speech_volume", _mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType)); - ConfMan.set("sfx_volume", _mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType)); - ConfMan.set("music_mute", _sound->isMusicMute()); - ConfMan.set("speech_mute", _sound->isSpeechMute()); - ConfMan.set("sfx_mute", _sound->isFxMute()); - ConfMan.set("gfx_details", _screen->getRenderLevel()); - ConfMan.set("subtitles", getSubtitles()); - ConfMan.set("object_labels", _mouse->getObjectLabels()); - ConfMan.set("reverse_stereo", _sound->isReverseStereo()); - - ConfMan.flushToDisk(); -} - -/** - * The global script variables and player object should be kept open throughout - * the game, so that they are never expelled by the resource manager. - */ - -void Sword2Engine::setupPersistentResources() { - _logic->_scriptVars = _resman->openResource(1) + ResHeader::size(); - _resman->openResource(CUR_PLAYER_ID); -} - -int Sword2Engine::init(GameDetector &detector) { - // Get some falling RAM and put it in your pocket, never let it slip - // away - - _system->beginGFXTransaction(); - initCommonGFX(detector); - _screen = new Screen(this, 640, 480); - _system->endGFXTransaction(); - - // Create the debugger as early as possible (but not before the - // screen object!) so that errors can be displayed in it. In - // particular, we want errors about missing files to be clearly - // visible to the user. - - _debugger = new Debugger(this); - - _memory = new MemoryManager(this); - _resman = new ResourceManager(this); - _logic = new Logic(this); - _fontRenderer = new FontRenderer(this); - _sound = new Sound(this); - _mouse = new Mouse(this); - - // Setup mixer - if (!_mixer->isReady()) - warning("Sound initialization failed"); - - registerDefaultSettings(); - readSettings(); - - initStartMenu(); - - // During normal gameplay, we care neither about mouse button releases - // nor the scroll wheel. - setInputEventFilter(RD_LEFTBUTTONUP | RD_RIGHTBUTTONUP | RD_WHEELUP | RD_WHEELDOWN); - - setupPersistentResources(); - initialiseFontResourceFlags(); - - if (_features & GF_DEMO) - _logic->writeVar(DEMO, 1); - else - _logic->writeVar(DEMO, 0); - - if (_saveSlot != -1) { - if (saveExists(_saveSlot)) - restoreGame(_saveSlot); - else { - RestoreDialog dialog(this); - if (!dialog.runModal()) - startGame(); - } - } else if (!_bootParam && saveExists()) { - int32 pars[2] = { 221, FX_LOOP }; - bool result; - - _mouse->setMouse(NORMAL_MOUSE_ID); - _logic->fnPlayMusic(pars); - - StartDialog dialog(this); - - result = (dialog.runModal() != 0); - - // If the game is started from the beginning, the cutscene - // player will kill the music for us. Otherwise, the restore - // will either have killed the music, or done a crossfade. - - if (_quit) - return 0; - - if (result) - startGame(); - } else - startGame(); - - _screen->initialiseRenderCycle(); - - return 0; -} - -int Sword2Engine::go() { - while (1) { - if (_debugger->isAttached()) - _debugger->onFrame(); - -#ifdef SWORD2_DEBUG - if (_stepOneCycle) { - pauseGame(); - _stepOneCycle = false; - } -#endif - - KeyboardEvent *ke = keyboardEvent(); - - if (ke) { - if ((ke->modifiers == OSystem::KBD_CTRL && ke->keycode == 'd') || ke->ascii == '#' || ke->ascii == '~') { - _debugger->attach(); - } else if (ke->modifiers == 0 || ke->modifiers == OSystem::KBD_SHIFT) { - switch (ke->keycode) { - case 'p': - if (_gamePaused) - unpauseGame(); - else - pauseGame(); - break; - case 'c': - if (!_logic->readVar(DEMO) && !_mouse->isChoosing()) { - ScreenInfo *screenInfo = _screen->getScreenInfo(); - _logic->fnPlayCredits(NULL); - screenInfo->new_palette = 99; - } - break; -#ifdef SWORD2_DEBUG - case ' ': - if (_gamePaused) { - _stepOneCycle = true; - unpauseGame(); - } - break; - case 's': - _renderSkip = !_renderSkip; - break; -#endif - default: - break; - } - } - } - - // skip GameCycle if we're paused - if (!_gamePaused) { - _gameCycle++; - gameCycle(); - } - - // We can't use this as termination condition for the loop, - // because we want the break to happen before updating the - // screen again. - - if (_quit) - break; - - // creates the debug text blocks - _debugger->buildDebugText(); - -#ifdef SWORD2_DEBUG - // if not in console & '_renderSkip' is set, only render - // display once every 4 game-cycles - - if (!_renderSkip || (_gameCycle % 4) == 0) - _screen->buildDisplay(); -#else - _screen->buildDisplay(); -#endif - } - - return 0; -} - -void Sword2Engine::closeGame() { - _quit = true; -} - -void Sword2Engine::restartGame() { - ScreenInfo *screenInfo = _screen->getScreenInfo(); - uint32 temp_demo_flag; - - _mouse->closeMenuImmediately(); - - // Restart the game. To do this, we must... - - // Stop music instantly! - _sound->stopMusic(true); - - // In case we were dead - well we're not anymore! - _logic->writeVar(DEAD, 0); - - // Restart the game. Clear all memory and reset the globals - temp_demo_flag = _logic->readVar(DEMO); - - // Remove all resources from memory, including player object and - // global variables - _resman->removeAll(); - - // Reopen global variables resource and player object - setupPersistentResources(); - - _logic->writeVar(DEMO, temp_demo_flag); - - // Free all the route memory blocks from previous game - _logic->_router->freeAllRouteMem(); - - // Call the same function that first started us up - startGame(); - - // Prime system with a game cycle - - // Reset the graphic 'BuildUnit' list before a new logic list - // (see fnRegisterFrame) - _screen->resetRenderLists(); - - // Reset the mouse hot-spot list (see fnRegisterMouse and - // fnRegisterFrame) - _mouse->resetMouseList(); - - _mouse->closeMenuImmediately(); - - // FOR THE DEMO - FORCE THE SCROLLING TO BE RESET! - // - this is taken from fnInitBackground - // switch on scrolling (2 means first time on screen) - screenInfo->scroll_flag = 2; - - if (_logic->processSession()) - error("restart 1st cycle failed??"); - - // So palette not restored immediately after control panel - we want - // to fade up instead! - screenInfo->new_palette = 99; -} - -bool Sword2Engine::checkForMouseEvents() { - return _mouseEvent.pending; -} - -MouseEvent *Sword2Engine::mouseEvent() { - if (!_mouseEvent.pending) - return NULL; - - _mouseEvent.pending = false; - return &_mouseEvent; -} - -KeyboardEvent *Sword2Engine::keyboardEvent() { - if (!_keyboardEvent.pending) - return NULL; - - _keyboardEvent.pending = false; - return &_keyboardEvent; -} - -uint32 Sword2Engine::setInputEventFilter(uint32 filter) { - uint32 oldFilter = _inputEventFilter; - - _inputEventFilter = filter; - return oldFilter; -} - -/** - * Clear the input events. This is so that we won't get any keyboard repeat - * right after using the debugging console. - */ - -void Sword2Engine::clearInputEvents() { - _keyboardEvent.pending = false; - _keyboardEvent.repeat = 0; - _mouseEvent.pending = false; -} - -/** - * OSystem Event Handler. Full of cross platform goodness and 99% fat free! - */ - -void Sword2Engine::parseInputEvents() { - OSystem::Event event; - - uint32 now = _system->getMillis(); - - while (_system->pollEvent(event)) { - switch (event.type) { - case OSystem::EVENT_KEYDOWN: - if (!(_inputEventFilter & RD_KEYDOWN)) { - _keyboardEvent.pending = true; - _keyboardEvent.repeat = now + 400; - _keyboardEvent.ascii = event.kbd.ascii; - _keyboardEvent.keycode = event.kbd.keycode; - _keyboardEvent.modifiers = event.kbd.flags; - } - break; - case OSystem::EVENT_KEYUP: - _keyboardEvent.repeat = 0; - break; - case OSystem::EVENT_MOUSEMOVE: - if (!(_inputEventFilter & RD_KEYDOWN)) { - _mouse->setPos(event.mouse.x, event.mouse.y - MENUDEEP); - } - break; - case OSystem::EVENT_LBUTTONDOWN: - if (!(_inputEventFilter & RD_LEFTBUTTONDOWN)) { - _mouseEvent.pending = true; - _mouseEvent.buttons = RD_LEFTBUTTONDOWN; - } - break; - case OSystem::EVENT_RBUTTONDOWN: - if (!(_inputEventFilter & RD_RIGHTBUTTONDOWN)) { - _mouseEvent.pending = true; - _mouseEvent.buttons = RD_RIGHTBUTTONDOWN; - } - break; - case OSystem::EVENT_LBUTTONUP: - if (!(_inputEventFilter & RD_LEFTBUTTONUP)) { - _mouseEvent.pending = true; - _mouseEvent.buttons = RD_LEFTBUTTONUP; - } - break; - case OSystem::EVENT_RBUTTONUP: - if (!(_inputEventFilter & RD_RIGHTBUTTONUP)) { - _mouseEvent.pending = true; - _mouseEvent.buttons = RD_RIGHTBUTTONUP; - } - break; - case OSystem::EVENT_WHEELUP: - if (!(_inputEventFilter & RD_WHEELUP)) { - _mouseEvent.pending = true; - _mouseEvent.buttons = RD_WHEELUP; - } - break; - case OSystem::EVENT_WHEELDOWN: - if (!(_inputEventFilter & RD_WHEELDOWN)) { - _mouseEvent.pending = true; - _mouseEvent.buttons = RD_WHEELDOWN; - } - break; - case OSystem::EVENT_QUIT: - closeGame(); - break; - default: - break; - } - } - - // Handle keyboard auto-repeat - if (!_keyboardEvent.pending && _keyboardEvent.repeat && now >= _keyboardEvent.repeat) { - _keyboardEvent.pending = true; - _keyboardEvent.repeat = now + 100; - } -} - -void Sword2Engine::gameCycle() { - // Do one game cycle, that is run the logic session until a full loop - // has been performed. - - if (_logic->getRunList()) { - do { - // Reset the 'BuildUnit' and mouse hot-spot lists - // before each new logic list. The service scripts - // will fill thrm through fnRegisterFrame() and - // fnRegisterMouse(). - - _screen->resetRenderLists(); - _mouse->resetMouseList(); - - // Keep going as long as new lists keep getting put in - // - i.e. screen changes. - } while (_logic->processSession()); - } else { - // Start the console and print the start options perhaps? - _debugger->attach("AWAITING START COMMAND: (Enter 's 1' then 'q' to start from beginning)"); - } - - // If this screen is wide, recompute the scroll offsets every cycle - ScreenInfo *screenInfo = _screen->getScreenInfo(); - - if (screenInfo->scroll_flag) - _screen->setScrolling(); - - _mouse->mouseEngine(); - _sound->processFxQueue(); -} - -void Sword2Engine::startGame() { - // Boot the game straight into a start script. It's always George's - // script #1, but with different ScreenManager objects depending on - // if it's the demo or the full game, or if we're using a boot param. - - int screen_manager_id = 0; - - debug(5, "startGame() STARTING:"); - - if (!_bootParam) { - if (_logic->readVar(DEMO)) - screen_manager_id = 19; // DOCKS SECTION START - else - screen_manager_id = 949; // INTRO & PARIS START - } else { - // FIXME this could be validated against startup.inf for valid - // numbers to stop people shooting themselves in the foot - - if (_bootParam != 0) - screen_manager_id = _bootParam; - } - - _logic->runResObjScript(screen_manager_id, CUR_PLAYER_ID, 1); -} - -// FIXME: Move this to some better place? - -void Sword2Engine::sleepUntil(uint32 time) { - while (getMillis() < time) { - // Make sure menu animations and fades don't suffer, but don't - // redraw the entire scene. - _mouse->processMenu(); - _screen->updateDisplay(false); - _system->delayMillis(10); - } -} - -void Sword2Engine::pauseGame() { - // Don't allow Pause while screen fading or while black - if (_screen->getFadeStatus() != RDFADE_NONE) - return; - - _sound->pauseAllSound(); - _mouse->pauseGame(); - - // If render level is at max, turn it down because palette-matching - // won't work when the palette is dimmed. - - if (_screen->getRenderLevel() == 3) { - _screen->setRenderLevel(2); - _graphicsLevelFudged = true; - } - -#ifdef SWORD2_DEBUG - // Don't dim it if we're single-stepping through frames - // dim the palette during the pause - - if (!_stepOneCycle) - _screen->dimPalette(); -#else - _screen->dimPalette(); -#endif - - _gamePaused = true; -} - -void Sword2Engine::unpauseGame() { - _mouse->unpauseGame(); - _sound->unpauseAllSound(); - - // Put back game screen palette; see build_display.cpp - _screen->setFullPalette(-1); - - // If graphics level at max, turn up again - if (_graphicsLevelFudged) { - _screen->setRenderLevel(3); - _graphicsLevelFudged = false; - } - - _gamePaused = false; - - // If mouse is about or we're in a chooser menu - if (!_mouse->getMouseStatus() || _mouse->isChoosing()) - _mouse->setMouse(NORMAL_MOUSE_ID); -} - -uint32 Sword2Engine::getMillis() { - return _system->getMillis(); -} - -} // End of namespace Sword2 diff --git a/sword2/sword2.h b/sword2/sword2.h deleted file mode 100644 index bcb80ec957..0000000000 --- a/sword2/sword2.h +++ /dev/null @@ -1,240 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef _SWORD2 -#define _SWORD2 - -// Enable this to make it possible to clear the mouse cursor luggage by -// right-clicking. The original didn't do this, but it feels natural to me. -// However, I'm afraid that it'll interfer badly with parts of the game, so -// for now I'll keep it disabled. - -#define RIGHT_CLICK_CLEARS_LUGGAGE 0 - -#include "base/engine.h" - -#include "common/util.h" - -#include "sword2/build_display.h" -#include "sword2/header.h" -#include "sword2/icons.h" -#include "sword2/object.h" -#include "sword2/save_rest.h" - -#define MAX_starts 100 -#define MAX_description 100 - -class GameDetector; -class OSystem; - -namespace Sword2 { - -enum { - GF_DEMO = 1 << 0 -}; - -class MemoryManager; -class ResourceManager; -class Sound; -class Screen; -class Mouse; -class Logic; -class FontRenderer; -class Gui; -class Debugger; - -enum { - RD_LEFTBUTTONDOWN = 0x01, - RD_LEFTBUTTONUP = 0x02, - RD_RIGHTBUTTONDOWN = 0x04, - RD_RIGHTBUTTONUP = 0x08, - RD_WHEELUP = 0x10, - RD_WHEELDOWN = 0x20, - RD_KEYDOWN = 0x40, - RD_MOUSEMOVE = 0x80 -}; - -struct MouseEvent { - bool pending; - uint16 buttons; -}; - -struct KeyboardEvent { - bool pending; - uint32 repeat; - uint16 ascii; - int keycode; - int modifiers; -}; - -struct StartUp { - char description[MAX_description]; - - // id of screen manager object - uint32 start_res_id; - - // Tell the manager which startup you want (if there are more than 1) - // (i.e more than 1 entrance to a screen and/or separate game boots) - uint32 key; -}; - -class Sword2Engine : public Engine { -private: - uint32 _inputEventFilter; - - // The event "buffers" - MouseEvent _mouseEvent; - KeyboardEvent _keyboardEvent; - - uint32 _bootParam; - int32 _saveSlot; - - void getPlayerStructures(); - void putPlayerStructures(); - - uint32 saveData(uint16 slotNo, byte *buffer, uint32 bufferSize); - uint32 restoreData(uint16 slotNo, byte *buffer, uint32 bufferSize); - - uint32 calcChecksum(byte *buffer, uint32 size); - - void pauseGame(); - void unpauseGame(); - - uint32 _totalStartups; - uint32 _totalScreenManagers; - uint32 _startRes; - - bool _useSubtitles; - - StartUp _startList[MAX_starts]; - -public: - Sword2Engine(GameDetector *detector, OSystem *syst); - ~Sword2Engine(); - int go(); - int init(GameDetector &detector); - - void registerDefaultSettings(); - void readSettings(); - void writeSettings(); - - void setupPersistentResources(); - - bool getSubtitles() { return _useSubtitles; } - void setSubtitles(bool b) { _useSubtitles = b; } - - bool _quit; - - uint32 _features; - Common::String _targetName; // target name for saves - - MemoryManager *_memory; - ResourceManager *_resman; - Sound *_sound; - Screen *_screen; - Mouse *_mouse; - Logic *_logic; - FontRenderer *_fontRenderer; - - Debugger *_debugger; - - Common::RandomSource _rnd; - - uint32 _speechFontId; - uint32 _controlsFontId; - uint32 _redFontId; - - uint32 setInputEventFilter(uint32 filter); - - void clearInputEvents(); - void parseInputEvents(); - - bool checkForMouseEvents(); - MouseEvent *mouseEvent(); - KeyboardEvent *keyboardEvent(); - - bool _wantSfxDebug; - - int32 _gameCycle; - -#ifdef SWORD2_DEBUG - bool _renderSkip; - bool _stepOneCycle; -#endif - -#if RIGHT_CLICK_CLEARS_LUGGAGE - bool heldIsInInventory(); -#endif - - byte *fetchPalette(byte *screenFile); - byte *fetchScreenHeader(byte *screenFile); - byte *fetchLayerHeader(byte *screenFile, uint16 layerNo); - byte *fetchShadingMask(byte *screenFile); - - byte *fetchAnimHeader(byte *animFile); - byte *fetchCdtEntry(byte *animFile, uint16 frameNo); - byte *fetchFrameHeader(byte *animFile, uint16 frameNo); - byte *fetchBackgroundParallaxLayer(byte *screenFile, int layer); - byte *fetchBackgroundLayer(byte *screenFile); - byte *fetchForegroundParallaxLayer(byte *screenFile, int layer); - byte *fetchTextLine(byte *file, uint32 text_line); - bool checkTextLine(byte *file, uint32 text_line); - byte *fetchPaletteMatchTable(byte *screenFile); - - uint32 saveGame(uint16 slotNo, byte *description); - uint32 restoreGame(uint16 slotNo); - uint32 getSaveDescription(uint16 slotNo, byte *description); - bool saveExists(); - bool saveExists(uint16 slotNo); - uint32 restoreFromBuffer(byte *buffer, uint32 size); - uint32 findBufferSize(); - - bool _gamePaused; - bool _graphicsLevelFudged; - - void startGame(); - void gameCycle(); - void closeGame(); - void restartGame(); - - void sleepUntil(uint32 time); - - void errorString(const char *buf_input, char *buf_output); - void initialiseFontResourceFlags(); - void initialiseFontResourceFlags(uint8 language); - - bool initStartMenu(); - void registerStartPoint(int32 key, char *name); - - uint32 getNumStarts() { return _totalStartups; } - uint32 getNumScreenManagers() { return _totalScreenManagers; } - StartUp *getStartList() { return _startList; } - - void runStart(int start); - - // Convenience alias for OSystem::getMillis(). - // This is a bit hackish, of course :-). - uint32 getMillis(); -}; - -} // End of namespace Sword2 - -#endif diff --git a/sword2/sync.cpp b/sword2/sync.cpp deleted file mode 100644 index 205e273873..0000000000 --- a/sword2/sync.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/logic.h" - -namespace Sword2 { - -/** - * Clear any syncs registered for this id. Call this just after the id has been - * processed. Theoretically there could be more than one sync waiting for us, - * so clear the lot. - */ - -void Logic::clearSyncs(uint32 id) { - for (int i = 0; i < ARRAYSIZE(_syncList); i++) { - if (_syncList[i].id == id) { - debug(5, "removing sync %d for %d", i, id); - _syncList[i].id = 0; - } - } -} - -void Logic::sendSync(uint32 id, uint32 sync) { - for (int i = 0; i < ARRAYSIZE(_syncList); i++) { - if (_syncList[i].id == 0) { - debug(5, "%d sends sync %d to %d", readVar(ID), sync, id); - _syncList[i].id = id; - _syncList[i].sync = sync; - return; - } - } - - // The original code didn't even check for this condition, so maybe - // it should be a fatal error? - - warning("No free sync slot"); -} - -/** - * Check for a sync waiting for this character. Called from fnAnim() to see if - * animation is to be finished. Returns an index into _syncList[], or -1. - */ - -int Logic::getSync() { - uint32 id = readVar(ID); - - for (int i = 0; i < ARRAYSIZE(_syncList); i++) { - if (_syncList[i].id == id) - return i; - } - - return -1; -} - -} // End of namespace Sword2 diff --git a/sword2/walker.cpp b/sword2/walker.cpp deleted file mode 100644 index 82ef80f65f..0000000000 --- a/sword2/walker.cpp +++ /dev/null @@ -1,454 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -// WALKER.CPP by James (14nov96) - -// Functions for moving megas about the place & also for keeping tabs on them - -#include "common/stdafx.h" -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/interpreter.h" -#include "sword2/logic.h" -#include "sword2/resman.h" -#include "sword2/router.h" - -namespace Sword2 { - -void Router::setStandbyCoords(int16 x, int16 y, uint8 dir) { - assert(dir <= 7); - - _standbyX = x; - _standbyY = y; - _standbyDir = dir; -} - -/** - * Work out direction from start to dest. - */ - -// Used in whatTarget(); not valid for all megas -#define diagonalx 36 -#define diagonaly 8 - -int Router::whatTarget(int startX, int startY, int destX, int destY) { - int deltaX = destX - startX; - int deltaY = destY - startY; - - // 7 0 1 - // 6 2 - // 5 4 3 - - // Flat route - - if (ABS(deltaY) * diagonalx < ABS(deltaX) * diagonaly / 2) - return (deltaX > 0) ? 2 : 6; - - // Vertical route - - if (ABS(deltaY) * diagonalx / 2 > ABS(deltaX) * diagonaly) - return (deltaY > 0) ? 4 : 0; - - // Diagonal route - - if (deltaX > 0) - return (deltaY > 0) ? 3 : 1; - - return (deltaY > 0) ? 5 : 7; -} - -/** - * Walk meta to (x,y,dir). Set RESULT to 0 if it succeeded. Otherwise, set - * RESULT to 1. Return true if the mega has finished walking. - */ - -int Router::doWalk(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, int16 target_x, int16 target_y, uint8 target_dir) { - ObjectLogic obLogic(ob_logic); - ObjectGraphic obGraph(ob_graph); - ObjectMega obMega(ob_mega); - - // If this is the start of the walk, calculate the route. - - if (obLogic.getLooping() == 0) { - // If we're already there, don't even bother allocating - // memory and calling the router, just quit back & continue - // the script! This avoids an embarassing mega stand frame - // appearing for one cycle when we're already in position for - // an anim eg. repeatedly clicking on same object to repeat - // an anim - no mega frame will appear in between runs of the - // anim. - - if (obMega.getFeetX() == target_x && obMega.getFeetY() == target_y && obMega.getCurDir() == target_dir) { - _vm->_logic->writeVar(RESULT, 0); - return IR_CONT; - } - - assert(target_dir <= 8); - - obMega.setWalkPc(0); - - // Set up mem for _walkData in route_slots[] & set mega's - // 'route_slot_id' accordingly - allocateRouteMem(); - - int32 route = routeFinder(ob_mega, ob_walkdata, target_x, target_y, target_dir); - - // 0 = can't make route to target - // 1 = created route - // 2 = zero route but may need to turn - - if (route != 1 && route != 2) { - freeRouteMem(); - _vm->_logic->writeVar(RESULT, 1); - return IR_CONT; - } - - // Walk is about to start - - obMega.setIsWalking(1); - obLogic.setLooping(1); - obGraph.setAnimResource(obMega.getMegasetRes()); - } else if (_vm->_logic->readVar(EXIT_FADING) && _vm->_screen->getFadeStatus() == RDFADE_BLACK) { - // Double clicked an exit, and the screen has faded down to - // black. Ok, that's it. Back to script and change screen. - - // We have to clear te EXIT_CLICK_ID variable in case there's a - // walk instruction on the new screen, or it'd be cut short. - - freeRouteMem(); - - obLogic.setLooping(0); - obMega.setIsWalking(0); - _vm->_logic->writeVar(EXIT_CLICK_ID, 0); - _vm->_logic->writeVar(RESULT, 0); - - return IR_CONT; - } - - // Get pointer to walkanim & current frame position - - WalkData *walkAnim = getRouteMem(); - int32 walk_pc = obMega.getWalkPc(); - - // If stopping the walk early, overwrite the next step with a - // slow-out, then finish - - if (_vm->_logic->checkEventWaiting() && walkAnim[walk_pc].step == 0 && walkAnim[walk_pc + 1].step == 1) { - // At the beginning of a step - earlySlowOut(ob_mega, ob_walkdata); - } - - // Get new frame of walk - - obGraph.setAnimPc(walkAnim[walk_pc].frame); - obMega.setCurDir(walkAnim[walk_pc].dir); - obMega.setFeetX(walkAnim[walk_pc].x); - obMega.setFeetY(walkAnim[walk_pc].y); - - // Is the NEXT frame is the end-marker (512) of the walk sequence? - - if (walkAnim[walk_pc + 1].frame != 512) { - // No, it wasn't. Increment the walk-anim frame number and - // come back next cycle. - obMega.setWalkPc(obMega.getWalkPc() + 1); - return IR_REPEAT; - } - - // We have reached the end-marker, which means we can return to the - // script just as the final (stand) frame of the walk is set. - - freeRouteMem(); - obLogic.setLooping(0); - obMega.setIsWalking(0); - - // If George's walk has been interrupted to run a new action script for - // instance or Nico's walk has been interrupted by player clicking on - // her to talk - - // There used to be code here for checking if two megas were colliding, - // but it had been commented out, and it was only run if a function - // that always returned zero returned non-zero. - - if (_vm->_logic->checkEventWaiting()) { - _vm->_logic->startEvent(); - _vm->_logic->writeVar(RESULT, 1); - return IR_TERMINATE; - } - - _vm->_logic->writeVar(RESULT, 0); - - // CONTINUE the script so that RESULT can be checked! Also, if an anim - // command follows the fnWalk command, the 1st frame of the anim (which - // is always a stand frame itself) can replace the final stand frame of - // the walk, to hide the slight difference between the shrinking on the - // mega frames and the pre-shrunk anim start-frame. - - return IR_CONT; -} - -/** - * Walk mega to start position of anim - */ - -int Router::walkToAnim(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint32 animRes) { - int16 target_x = 0; - int16 target_y = 0; - uint8 target_dir = 0; - - // Walkdata is needed for earlySlowOut if player clicks elsewhere - // during the walk. - - // If this is the start of the walk, read anim file to get start coords - - ObjectLogic obLogic(ob_logic); - - if (obLogic.getLooping() == 0) { - byte *anim_file = _vm->_resman->openResource(animRes); - AnimHeader anim_head; - - anim_head.read(_vm->fetchAnimHeader(anim_file)); - - target_x = anim_head.feetStartX; - target_y = anim_head.feetStartY; - target_dir = anim_head.feetStartDir; - - _vm->_resman->closeResource(animRes); - - // If start coords not yet set in anim header, use the standby - // coords (which should be set beforehand in the script). - - if (target_x == 0 && target_y == 0) { - target_x = _standbyX; - target_y = _standbyY; - target_dir = _standbyDir; - } - - assert(target_dir <= 7); - } - - return doWalk(ob_logic, ob_graph, ob_mega, ob_walkdata, target_x, target_y, target_dir); -} - -/** - * Route to the left or right hand side of target id, if possible. - */ - -int Router::walkToTalkToMega(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint32 megaId, uint32 separation) { - ObjectMega obMega(ob_mega); - - int16 target_x = 0; - int16 target_y = 0; - uint8 target_dir = 0; - - // If this is the start of the walk, calculate the route. - - ObjectLogic obLogic(ob_logic); - - if (obLogic.getLooping() == 0) { - assert(_vm->_resman->fetchType(megaId) == GAME_OBJECT); - - // Call the base script. This is the graphic/mouse service - // call, and will set _engineMega to the ObjectMega of mega we - // want to route to. - - _vm->_logic->runResScript(megaId, 3); - - ObjectMega targetMega(_vm->_logic->getEngineMega()); - - // Stand exactly beside the mega, ie. at same y-coord - target_y = targetMega.getFeetY(); - - int scale = obMega.calcScale(); - int mega_separation = (separation * scale) / 256; - - debug(4, "Target is at (%d, %d), separation %d", targetMega.getFeetX(), targetMega.getFeetY(), mega_separation); - - if (targetMega.getFeetX() < obMega.getFeetX()) { - // Target is left of us, so aim to stand to their - // right. Face down_left - - target_x = targetMega.getFeetX() + mega_separation; - target_dir = 5; - } else { - // Ok, must be right of us so aim to stand to their - // left. Face down_right. - - target_x = targetMega.getFeetX() - mega_separation; - target_dir = 3; - } - } - - return doWalk(ob_logic, ob_graph, ob_mega, ob_walkdata, target_x, target_y, target_dir); -} -/** - * Turn mega to the specified direction. Just needs to call doWalk() with - * current feet coords, so router can produce anim of turn frames. - */ - -int Router::doFace(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint8 target_dir) { - int16 target_x = 0; - int16 target_y = 0; - - // If this is the start of the turn, get the mega's current feet - // coords + the required direction - - ObjectLogic obLogic(ob_logic); - - if (obLogic.getLooping() == 0) { - assert(target_dir <= 7); - - ObjectMega obMega(ob_mega); - - target_x = obMega.getFeetX(); - target_y = obMega.getFeetY(); - } - - return doWalk(ob_logic, ob_graph, ob_mega, ob_walkdata, target_x, target_y, target_dir); -} - -/** - * Turn mega to face point (x,y) on the floor - */ - -int Router::faceXY(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, int16 target_x, int16 target_y) { - uint8 target_dir = 0; - - // If this is the start of the turn, get the mega's current feet - // coords + the required direction - - ObjectLogic obLogic(ob_logic); - - if (obLogic.getLooping() == 0) { - ObjectMega obMega(ob_mega); - - target_dir = whatTarget(obMega.getFeetX(), obMega.getFeetY(), target_x, target_y); - } - - return doFace(ob_logic, ob_graph, ob_mega, ob_walkdata, target_dir); -} - -/** - * Turn mega to face another mega. - */ - -int Router::faceMega(byte *ob_logic, byte *ob_graph, byte *ob_mega, byte *ob_walkdata, uint32 megaId) { - uint8 target_dir = 0; - - // If this is the start of the walk, decide where to walk to. - - ObjectLogic obLogic(ob_logic); - - if (obLogic.getLooping() == 0) { - assert(_vm->_resman->fetchType(megaId) == GAME_OBJECT); - - // Call the base script. This is the graphic/mouse service - // call, and will set _engineMega to the ObjectMega of mega we - // want to turn to face. - - _vm->_logic->runResScript(megaId, 3); - - ObjectMega obMega(ob_mega); - ObjectMega targetMega(_vm->_logic->getEngineMega()); - - target_dir = whatTarget(obMega.getFeetX(), obMega.getFeetY(), targetMega.getFeetX(), targetMega.getFeetY()); - } - - return doFace(ob_logic, ob_graph, ob_mega, ob_walkdata, target_dir); -} - -/** - * Stand mega at (x,y,dir) - * Sets up the graphic object, but also needs to set the new 'current_dir' in - * the mega object, so the router knows in future - */ - -void Router::standAt(byte *ob_graph, byte *ob_mega, int32 x, int32 y, int32 dir) { - assert(dir >= 0 && dir <= 7); - - ObjectGraphic obGraph(ob_graph); - ObjectMega obMega(ob_mega); - - // Set up the stand frame & set the mega's new direction - - obMega.setFeetX(x); - obMega.setFeetY(y); - obMega.setCurDir(dir); - - // Mega-set animation file - obGraph.setAnimResource(obMega.getMegasetRes()); - - // Dir + first stand frame (always frame 96) - obGraph.setAnimPc(dir + 96); -} - -/** - * Stand mega at end position of anim - */ - -void Router::standAfterAnim(byte *ob_graph, byte *ob_mega, uint32 animRes) { - byte *anim_file = _vm->_resman->openResource(animRes); - AnimHeader anim_head; - - anim_head.read(_vm->fetchAnimHeader(anim_file)); - - int32 x = anim_head.feetEndX; - int32 y = anim_head.feetEndY; - int32 dir = anim_head.feetEndDir; - - _vm->_resman->closeResource(animRes); - - // If start coords not available either use the standby coords (which - // should be set beforehand in the script) - - if (x == 0 && y == 0) { - x = _standbyX; - y = _standbyY; - dir = _standbyDir; - } - - standAt(ob_graph, ob_mega, x, y, dir); -} - -void Router::standAtAnim(byte *ob_graph, byte *ob_mega, uint32 animRes) { - byte *anim_file = _vm->_resman->openResource(animRes); - AnimHeader anim_head; - - anim_head.read(_vm->fetchAnimHeader(anim_file)); - - int32 x = anim_head.feetStartX; - int32 y = anim_head.feetStartY; - int32 dir = anim_head.feetStartDir; - - _vm->_resman->closeResource(animRes); - - // If start coords not available use the standby coords (which should - // be set beforehand in the script) - - if (x == 0 && y == 0) { - x = _standbyX; - y = _standbyY; - dir = _standbyDir; - } - - standAt(ob_graph, ob_mega, x, y, dir); -} - -} // End of namespace Sword2 |