parent
cbb2ca005c
commit
6703dc7fa1
47 changed files with 8270 additions and 0 deletions
|
@ -96,6 +96,12 @@ else
|
||||||
MODULES += gob
|
MODULES += gob
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef DISABLE_LURE
|
||||||
|
DEFINES += -DDISABLE_LURE
|
||||||
|
else
|
||||||
|
MODULES += lure
|
||||||
|
endif
|
||||||
|
|
||||||
# After the game specific modules follow the shared modules
|
# After the game specific modules follow the shared modules
|
||||||
MODULES += \
|
MODULES += \
|
||||||
gui \
|
gui \
|
||||||
|
|
|
@ -329,6 +329,9 @@ void PluginManager::loadPlugins() {
|
||||||
#ifndef DISABLE_GOB
|
#ifndef DISABLE_GOB
|
||||||
LINK_PLUGIN(GOB)
|
LINK_PLUGIN(GOB)
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef DISABLE_LURE
|
||||||
|
LINK_PLUGIN(LURE)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
13
configure
vendored
13
configure
vendored
|
@ -56,6 +56,7 @@ _build_queen=yes
|
||||||
_build_saga=yes
|
_build_saga=yes
|
||||||
_build_gob=yes
|
_build_gob=yes
|
||||||
_build_kyra=yes
|
_build_kyra=yes
|
||||||
|
_build_lure=yes
|
||||||
_need_memalign=no
|
_need_memalign=no
|
||||||
_build_plugins=no
|
_build_plugins=no
|
||||||
_nasm=auto
|
_nasm=auto
|
||||||
|
@ -301,6 +302,7 @@ Optional Features:
|
||||||
--disable-saga don't build the SAGA engine
|
--disable-saga don't build the SAGA engine
|
||||||
--disable-gob don't build the Gobli*ns engine
|
--disable-gob don't build the Gobli*ns engine
|
||||||
--disable-kyra don't build the Legend of Kyrandia engine
|
--disable-kyra don't build the Legend of Kyrandia engine
|
||||||
|
--disable-lure don't build the Lure of the Temptress engine
|
||||||
--enable-plugins build engines as loadable modules instead of
|
--enable-plugins build engines as loadable modules instead of
|
||||||
static linking them
|
static linking them
|
||||||
--disable-mt32emu don't enable the integrated MT-32 emulator
|
--disable-mt32emu don't enable the integrated MT-32 emulator
|
||||||
|
@ -366,6 +368,7 @@ for ac_option in $@; do
|
||||||
--disable-saga) _build_saga=no ;;
|
--disable-saga) _build_saga=no ;;
|
||||||
--disable-gob) _build_gob=no ;;
|
--disable-gob) _build_gob=no ;;
|
||||||
--disable-kyra) _build_kyra=no ;;
|
--disable-kyra) _build_kyra=no ;;
|
||||||
|
--disable-lure) _build_lure=no ;;
|
||||||
--disable-hq-scalers) _build_hq_scalers=no ;;
|
--disable-hq-scalers) _build_hq_scalers=no ;;
|
||||||
--disable-scalers) _build_scalers=no ;;
|
--disable-scalers) _build_scalers=no ;;
|
||||||
--enable-alsa) _alsa=yes ;;
|
--enable-alsa) _alsa=yes ;;
|
||||||
|
@ -677,6 +680,12 @@ else
|
||||||
_mak_gob='# DISABLE_GOB = 1'
|
_mak_gob='# DISABLE_GOB = 1'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "$_build_lure" = no ; then
|
||||||
|
_mak_lure='DISABLE_LURE = 1'
|
||||||
|
else
|
||||||
|
_mak_lure='# DISABLE_LURE = 1'
|
||||||
|
fi
|
||||||
|
|
||||||
if test "$_build_hq_scalers" = no ; then
|
if test "$_build_hq_scalers" = no ; then
|
||||||
_mak_hq_scalers='DISABLE_HQ_SCALERS = 1'
|
_mak_hq_scalers='DISABLE_HQ_SCALERS = 1'
|
||||||
else
|
else
|
||||||
|
@ -1242,6 +1251,9 @@ fi
|
||||||
if test "$_build_gob" = yes ; then
|
if test "$_build_gob" = yes ; then
|
||||||
echo " Gobli*ns"
|
echo " Gobli*ns"
|
||||||
fi
|
fi
|
||||||
|
if test "$_build_lure" = yes ; then
|
||||||
|
echo " Lure of the Temptress"
|
||||||
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
@ -1379,6 +1391,7 @@ $_mak_queen
|
||||||
$_mak_kyra
|
$_mak_kyra
|
||||||
$_mak_saga
|
$_mak_saga
|
||||||
$_mak_gob
|
$_mak_gob
|
||||||
|
$_mak_lure
|
||||||
$_mak_mt32emu
|
$_mak_mt32emu
|
||||||
|
|
||||||
$_mak_hq_scalers
|
$_mak_hq_scalers
|
||||||
|
|
148
lure/animseq.cpp
Normal file
148
lure/animseq.cpp
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/animseq.h"
|
||||||
|
#include "lure/palette.h"
|
||||||
|
#include "lure/decode.h"
|
||||||
|
#include "lure/events.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
// delay
|
||||||
|
// Delays for a given number of milliseconds. If it returns true, it indicates that
|
||||||
|
// Escape has been pressed, and the introduction should be aborted.
|
||||||
|
|
||||||
|
AnimAbortType AnimationSequence::delay(uint32 milliseconds) {
|
||||||
|
uint32 delayCtr = _system.getMillis() + milliseconds;
|
||||||
|
Events &events = Events::getReference();
|
||||||
|
|
||||||
|
while (_system.getMillis() < delayCtr) {
|
||||||
|
while (events.pollEvent()) {
|
||||||
|
if (events.type() == OSystem::EVENT_KEYDOWN) {
|
||||||
|
if (events.event().kbd.keycode == 27) return ABORT_END_INTRO;
|
||||||
|
else return ABORT_NEXT_SCENE;
|
||||||
|
} else if (events.type() == OSystem::EVENT_LBUTTONDOWN)
|
||||||
|
return ABORT_NEXT_SCENE;
|
||||||
|
else if (events.type() == OSystem::EVENT_QUIT)
|
||||||
|
return ABORT_END_INTRO;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 delayAmount = delayCtr - _system.getMillis();
|
||||||
|
if (delayAmount > 10) delayAmount = 10;
|
||||||
|
_system.delayMillis(delayAmount);
|
||||||
|
}
|
||||||
|
return ABORT_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeFrame
|
||||||
|
// Decodes a single frame of the animation sequence
|
||||||
|
|
||||||
|
void AnimationSequence::decodeFrame(byte *&pPixels, byte *&pLines) {
|
||||||
|
byte *screen = _screen.screen_raw();
|
||||||
|
uint16 screenPos = 0;
|
||||||
|
uint16 len;
|
||||||
|
|
||||||
|
while (screenPos < SCREEN_SIZE) {
|
||||||
|
// Get line length
|
||||||
|
len = (uint16) *pLines++;
|
||||||
|
if (len == 0) {
|
||||||
|
len = *((uint16 *) pLines);
|
||||||
|
pLines += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the splice over
|
||||||
|
memcpy(screen, pPixels, len);
|
||||||
|
screen += len;
|
||||||
|
screenPos += len;
|
||||||
|
pPixels += len;
|
||||||
|
|
||||||
|
// Get the offset inc amount
|
||||||
|
len = (uint16) *pLines++;
|
||||||
|
if (len == 0) {
|
||||||
|
len = *((uint16 *) pLines);
|
||||||
|
pLines += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
screen += len;
|
||||||
|
screenPos += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the decoded frame visible
|
||||||
|
_screen.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationSequence::AnimationSequence(Screen &screen, OSystem &system, uint16 screenId, Palette &palette,
|
||||||
|
bool fadeIn): _screen(screen), _system(system), _screenId(screenId), _palette(palette) {
|
||||||
|
PictureDecoder decoder;
|
||||||
|
Disk &d = Disk::getReference();
|
||||||
|
MemoryBlock *data = d.getEntry(_screenId);
|
||||||
|
_decodedData = decoder.decode(data, MAX_ANIM_DECODER_BUFFER_SIZE);
|
||||||
|
delete data;
|
||||||
|
|
||||||
|
_lineRefs = d.getEntry(_screenId + 1);
|
||||||
|
|
||||||
|
// Show the screen that preceeds the start of the animation data
|
||||||
|
_screen.setPaletteEmpty();
|
||||||
|
_screen.screen().data().copyFrom(_decodedData, 0, 0, FULL_SCREEN_HEIGHT * FULL_SCREEN_WIDTH);
|
||||||
|
_screen.update();
|
||||||
|
|
||||||
|
// Set the palette
|
||||||
|
if (fadeIn) _screen.paletteFadeIn(&_palette);
|
||||||
|
else _screen.setPalette(&_palette);
|
||||||
|
|
||||||
|
// Set up frame poitners
|
||||||
|
_pPixels = _decodedData->data() + SCREEN_SIZE;
|
||||||
|
_pLines = _lineRefs->data();
|
||||||
|
_pPixelsEnd = _decodedData->data() + _decodedData->size() - 1;
|
||||||
|
_pLinesEnd = _lineRefs->data() + _lineRefs->size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationSequence::~AnimationSequence() {
|
||||||
|
delete _lineRefs;
|
||||||
|
delete _decodedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// show
|
||||||
|
// Main method for displaying the animation
|
||||||
|
|
||||||
|
AnimAbortType AnimationSequence::show() {
|
||||||
|
AnimAbortType result;
|
||||||
|
|
||||||
|
// Loop through displaying the animations
|
||||||
|
while ((_pPixels < _pPixelsEnd) && (_pLines < _pLinesEnd)) {
|
||||||
|
decodeFrame(_pPixels, _pLines);
|
||||||
|
|
||||||
|
result = delay(130);
|
||||||
|
if (result != ABORT_NONE) return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ABORT_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AnimationSequence::step() {
|
||||||
|
if ((_pPixels >= _pPixelsEnd) || (_pLines >= _pLinesEnd)) return false;
|
||||||
|
decodeFrame(_pPixels, _pLines);
|
||||||
|
_screen.setPalette(&_palette);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
56
lure/animseq.h
Normal file
56
lure/animseq.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_animseq_h__
|
||||||
|
#define __lure_animseq_h__
|
||||||
|
|
||||||
|
#include "lure/screen.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
enum AnimAbortType {ABORT_NONE, ABORT_END_INTRO, ABORT_NEXT_SCENE};
|
||||||
|
|
||||||
|
class AnimationSequence {
|
||||||
|
private:
|
||||||
|
Screen &_screen;
|
||||||
|
OSystem &_system;
|
||||||
|
uint16 _screenId;
|
||||||
|
Palette &_palette;
|
||||||
|
MemoryBlock *_decodedData;
|
||||||
|
MemoryBlock *_lineRefs;
|
||||||
|
byte *_pPixels, *_pLines;
|
||||||
|
byte *_pPixelsEnd, *_pLinesEnd;
|
||||||
|
|
||||||
|
AnimAbortType delay(uint32 milliseconds);
|
||||||
|
void decodeFrame(byte *&pPixels, byte *&pLines);
|
||||||
|
public:
|
||||||
|
AnimationSequence(Screen &screen, OSystem &system, uint16 screenId, Palette &palette,
|
||||||
|
bool fadeIn);
|
||||||
|
~AnimationSequence();
|
||||||
|
|
||||||
|
AnimAbortType show();
|
||||||
|
bool step();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
133
lure/debug-input.cpp
Normal file
133
lure/debug-input.cpp
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/debug-input.h"
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/events.h"
|
||||||
|
#include "lure/surface.h"
|
||||||
|
#include "lure/screen.h"
|
||||||
|
|
||||||
|
#ifdef LURE_DEBUG
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
bool get_string(char *buffer, uint32 maxSize, bool isNumeric, uint16 x, uint16 y) {
|
||||||
|
Events &e = Events::getReference();
|
||||||
|
buffer[0] = '\0';
|
||||||
|
|
||||||
|
// Create surface for holding entered text
|
||||||
|
Surface *s = new Surface((maxSize + 1) * FONT_WIDTH, FONT_HEIGHT);
|
||||||
|
|
||||||
|
bool abortFlag = false;
|
||||||
|
bool refreshFlag = true;
|
||||||
|
|
||||||
|
while (!e.quitFlag && !abortFlag) {
|
||||||
|
// Check for refreshing display of text
|
||||||
|
if (refreshFlag) {
|
||||||
|
uint16 strWidth = Surface::textWidth(buffer);
|
||||||
|
s->empty();
|
||||||
|
s->writeString(0, 0, buffer, false, DIALOG_TEXT_COLOUR);
|
||||||
|
s->writeChar(strWidth, 0, '_', false, DIALOG_TEXT_COLOUR);
|
||||||
|
s->copyToScreen(x, y);
|
||||||
|
|
||||||
|
refreshFlag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.pollEvent()) {
|
||||||
|
if (e.type() == OSystem::EVENT_KEYDOWN) {
|
||||||
|
char ch = e.event().kbd.ascii;
|
||||||
|
uint16 keycode = e.event().kbd.keycode;
|
||||||
|
|
||||||
|
if ((ch == 13) || (keycode == 0x10f))
|
||||||
|
break;
|
||||||
|
else if (ch == 27)
|
||||||
|
abortFlag = true;
|
||||||
|
else if (ch == 8) {
|
||||||
|
if (*buffer != '\0') {
|
||||||
|
*((char *) buffer + strlen(buffer) - 1) = '\0';
|
||||||
|
refreshFlag = true;
|
||||||
|
}
|
||||||
|
} else if ((ch >= ' ') && (strlen(buffer) < maxSize)) {
|
||||||
|
if (((ch >= '0') && (ch <= '9')) || !isNumeric) {
|
||||||
|
char *p = buffer + strlen(buffer);
|
||||||
|
*p++ = ch;
|
||||||
|
*p++ = '\0';
|
||||||
|
refreshFlag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete s;
|
||||||
|
if (e.quitFlag) abortFlag = true;
|
||||||
|
return !abortFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool input_integer(Common::String desc, uint32 &value)
|
||||||
|
{
|
||||||
|
const int MAX_SIZE = 5;
|
||||||
|
char buffer[MAX_SIZE + 1];
|
||||||
|
|
||||||
|
uint16 width = DIALOG_EDGE_SIZE + Surface::textWidth(desc.c_str()) + FONT_WIDTH;
|
||||||
|
uint16 totalWidth = width + FONT_WIDTH * (MAX_SIZE + 1) + DIALOG_EDGE_SIZE;
|
||||||
|
uint16 totalHeight = FONT_HEIGHT + DIALOG_EDGE_SIZE * 2;
|
||||||
|
|
||||||
|
Surface *s = new Surface(totalWidth, totalHeight);
|
||||||
|
s->createDialog(true);
|
||||||
|
s->writeString(DIALOG_EDGE_SIZE + 3, DIALOG_EDGE_SIZE, desc, false);
|
||||||
|
|
||||||
|
uint16 xs = (FULL_SCREEN_WIDTH-totalWidth) / 2;
|
||||||
|
uint16 ys = (FULL_SCREEN_HEIGHT-totalHeight) / 2;
|
||||||
|
s->copyToScreen(xs, ys);
|
||||||
|
|
||||||
|
bool result = get_string(&buffer[0], MAX_SIZE, true, xs+width, ys+DIALOG_EDGE_SIZE);
|
||||||
|
Screen::getReference().update();
|
||||||
|
if (!result || (buffer[0] == '\0'))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
value = atoi(buffer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool input_string(Common::String desc, char *buffer, uint32 maxSize)
|
||||||
|
{
|
||||||
|
uint16 width = Surface::textWidth(desc.c_str());
|
||||||
|
if (width < FONT_WIDTH * maxSize) width = FONT_WIDTH * maxSize;
|
||||||
|
|
||||||
|
Surface *s = new Surface(width + 2 * DIALOG_EDGE_SIZE, 2 * FONT_HEIGHT + 2 * DIALOG_EDGE_SIZE);
|
||||||
|
s->createDialog();
|
||||||
|
s->writeString(DIALOG_EDGE_SIZE, DIALOG_EDGE_SIZE, desc, false, DIALOG_TEXT_COLOUR);
|
||||||
|
|
||||||
|
uint16 xs = (FULL_SCREEN_WIDTH-s->width()) / 2;
|
||||||
|
uint16 ys = (FULL_SCREEN_HEIGHT-s->height()) / 2;
|
||||||
|
|
||||||
|
s->copyToScreen(xs, ys);
|
||||||
|
bool result = get_string(buffer, maxSize, true, xs + width, ys + DIALOG_EDGE_SIZE);
|
||||||
|
|
||||||
|
Screen::getReference().update();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
42
lure/debug-input.h
Normal file
42
lure/debug-input.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef LURE_DEBUG
|
||||||
|
#ifndef __lure_input_h__
|
||||||
|
#define __lure_input_h__
|
||||||
|
|
||||||
|
#include "common/stdafx.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
#include "lure/surface.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
bool get_string(char *buffer, uint32 maxSize, bool isNumeric, uint16 x, uint16 y);
|
||||||
|
|
||||||
|
bool input_integer(Common::String desc, uint32 &value);
|
||||||
|
|
||||||
|
bool input_string(Common::String desc, char *buffer, uint32 maxSize);
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
132
lure/debug-methods.cpp
Normal file
132
lure/debug-methods.cpp
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/debug-methods.h"
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
|
||||||
|
#include "lure/events.h"
|
||||||
|
#include "lure/surface.h"
|
||||||
|
#include "lure/screen.h"
|
||||||
|
#include "lure/res.h"
|
||||||
|
#include "lure/strings.h"
|
||||||
|
#include "lure/room.h"
|
||||||
|
|
||||||
|
#ifdef LURE_DEBUG
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
void showActiveHotspots() {
|
||||||
|
char buffer[16384];
|
||||||
|
char *lines[100];
|
||||||
|
char *s = buffer;
|
||||||
|
int numLines = 0;
|
||||||
|
lines[0] = s;
|
||||||
|
*s = '\0';
|
||||||
|
|
||||||
|
Resources &resources = Resources::getReference();
|
||||||
|
Mouse &mouse = Mouse::getReference();
|
||||||
|
Events &events = Events::getReference();
|
||||||
|
Screen &screen = Screen::getReference();
|
||||||
|
|
||||||
|
HotspotList::iterator i = resources.activeHotspots().begin();
|
||||||
|
for (; i != resources.activeHotspots().end(); ++i) {
|
||||||
|
Hotspot &h = *i.operator*();
|
||||||
|
lines[numLines++] = s;
|
||||||
|
|
||||||
|
if (numLines == 16) {
|
||||||
|
strcpy(s, "..more..");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(s, "%x", h.hotspotId());
|
||||||
|
s += strlen(s);
|
||||||
|
|
||||||
|
sprintf(s, "h pos=(%d,%d,%d) size=(%d,%d) - ",
|
||||||
|
h.resource().roomNumber, h.x(), h.y(), h.width(), h.height());
|
||||||
|
s += strlen(s);
|
||||||
|
|
||||||
|
uint16 nameId = h.resource().nameId;
|
||||||
|
if (nameId != 0) {
|
||||||
|
StringData::getReference().getString(nameId, s, NULL, NULL);
|
||||||
|
s += strlen(s);
|
||||||
|
}
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Surface *surface = Surface::newDialog(300, numLines, lines);
|
||||||
|
mouse.cursorOff();
|
||||||
|
surface->copyToScreen(10, 40);
|
||||||
|
events.waitForPress();
|
||||||
|
screen.update();
|
||||||
|
mouse.cursorOn();
|
||||||
|
delete surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
void showRoomHotspots() {
|
||||||
|
char buffer[16384];
|
||||||
|
char *lines[100];
|
||||||
|
char *s = buffer;
|
||||||
|
int numLines = 0;
|
||||||
|
lines[0] = s;
|
||||||
|
*s = '\0';
|
||||||
|
|
||||||
|
Resources &resources = Resources::getReference();
|
||||||
|
Mouse &mouse = Mouse::getReference();
|
||||||
|
Events &events = Events::getReference();
|
||||||
|
Screen &screen = Screen::getReference();
|
||||||
|
uint16 roomNumber = Room::getReference().roomNumber();
|
||||||
|
|
||||||
|
HotspotDataList::iterator i = resources.hotspotData().begin();
|
||||||
|
for (; i != resources.hotspotData().end(); ++i) {
|
||||||
|
HotspotData &h = *i.operator*();
|
||||||
|
if (h.roomNumber == roomNumber) {
|
||||||
|
lines[numLines++] = s;
|
||||||
|
|
||||||
|
sprintf(s, "%x", h.hotspotId);
|
||||||
|
s += strlen(s);
|
||||||
|
|
||||||
|
sprintf(s, "h pos=(%d,%d) size=(%d,%d) - ",
|
||||||
|
h.startX, h.startY, h.width, h.height);
|
||||||
|
s += strlen(s);
|
||||||
|
|
||||||
|
uint16 nameId = h.nameId;
|
||||||
|
if (nameId != 0) {
|
||||||
|
StringData::getReference().getString(nameId, s, NULL, NULL);
|
||||||
|
s += strlen(s);
|
||||||
|
}
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Surface *surface = Surface::newDialog(300, numLines, lines);
|
||||||
|
mouse.cursorOff();
|
||||||
|
surface->copyToScreen(10, 40);
|
||||||
|
events.waitForPress();
|
||||||
|
screen.update();
|
||||||
|
mouse.cursorOn();
|
||||||
|
delete surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
39
lure/debug-methods.h
Normal file
39
lure/debug-methods.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef LURE_DEBUG
|
||||||
|
#ifndef __lure_debugprocs_h__
|
||||||
|
#define __lure_debugprocs_h__
|
||||||
|
|
||||||
|
#include "common/stdafx.h"
|
||||||
|
#include "lure/surface.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
void showActiveHotspots();
|
||||||
|
|
||||||
|
void showRoomHotspots();
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
360
lure/decode.cpp
Normal file
360
lure/decode.cpp
Normal file
|
@ -0,0 +1,360 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/decode.h"
|
||||||
|
#include "lure/memory.h"
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* PictureDecoder class */
|
||||||
|
/* */
|
||||||
|
/* Provides the functionality for decoding screens */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void PictureDecoder::writeByte(MemoryBlock *dest, byte v) {
|
||||||
|
if (outputOffset == dest->size())
|
||||||
|
error("Decoded data exceeded allocated output buffer size");
|
||||||
|
dest->data()[outputOffset++] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PictureDecoder::writeBytes(MemoryBlock *dest, byte v, uint16 numBytes) {
|
||||||
|
if (outputOffset + numBytes > dest->size())
|
||||||
|
error("Decoded data exceeded allocated output buffer size");
|
||||||
|
dest->memset(v, outputOffset, numBytes);
|
||||||
|
outputOffset += numBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte PictureDecoder::DSSI(bool incr) {
|
||||||
|
byte result = dataIn[dataPos];
|
||||||
|
if (incr) ++dataPos;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte PictureDecoder::ESBX(bool incr) {
|
||||||
|
byte result = dataIn[dataPos2];
|
||||||
|
if (incr) ++dataPos2;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PictureDecoder::decrCtr() {
|
||||||
|
--CL;
|
||||||
|
if (CL == 0) {
|
||||||
|
CH = ESBX();
|
||||||
|
CL = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PictureDecoder::shlCarry() {
|
||||||
|
bool result = (CH & 0x80) != 0;
|
||||||
|
CH <<= 1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PictureDecoder::swap(uint16 &v1, uint16 &v2) {
|
||||||
|
uint16 vTemp;
|
||||||
|
vTemp = v1;
|
||||||
|
v1 = v2;
|
||||||
|
v2 = vTemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode_data
|
||||||
|
// Takes care of decoding compressed Lure of the Temptress data
|
||||||
|
|
||||||
|
MemoryBlock *PictureDecoder::decode(MemoryBlock *src, uint32 maxOutputSize) {
|
||||||
|
MemoryBlock *dest = Memory::allocate(maxOutputSize);
|
||||||
|
|
||||||
|
// Set up initial states
|
||||||
|
dataIn = src->data();
|
||||||
|
outputOffset = 0;
|
||||||
|
dataPos = READ_LE_UINT32(dataIn + 0x400);
|
||||||
|
dataPos2 = 0x404;
|
||||||
|
|
||||||
|
CH = ESBX();
|
||||||
|
CL = 9;
|
||||||
|
|
||||||
|
Loc754:
|
||||||
|
AL = DSSI();
|
||||||
|
writeByte(dest, AL);
|
||||||
|
BP = ((uint16) AL) << 2;
|
||||||
|
|
||||||
|
Loc755:
|
||||||
|
decrCtr();
|
||||||
|
if (shlCarry()) goto Loc761;
|
||||||
|
decrCtr();
|
||||||
|
if (shlCarry()) goto Loc759;
|
||||||
|
AL = dataIn[BP];
|
||||||
|
|
||||||
|
Loc758:
|
||||||
|
writeByte(dest, AL);
|
||||||
|
BP = ((uint16) AL) << 2;
|
||||||
|
goto Loc755;
|
||||||
|
|
||||||
|
Loc759:
|
||||||
|
AL = (byte) (BP >> 2);
|
||||||
|
AH = DSSI();
|
||||||
|
if (AH == 0) goto Loc768;
|
||||||
|
|
||||||
|
writeBytes(dest, AL, AH);
|
||||||
|
goto Loc755;
|
||||||
|
|
||||||
|
Loc761:
|
||||||
|
decrCtr();
|
||||||
|
if (shlCarry()) goto Loc765;
|
||||||
|
decrCtr();
|
||||||
|
|
||||||
|
if (shlCarry()) goto Loc764;
|
||||||
|
AL = dataIn[BP+1];
|
||||||
|
goto Loc758;
|
||||||
|
|
||||||
|
Loc764:
|
||||||
|
AL = dataIn[BP+2];
|
||||||
|
goto Loc758;
|
||||||
|
|
||||||
|
Loc765:
|
||||||
|
decrCtr();
|
||||||
|
if (shlCarry()) goto Loc767;
|
||||||
|
AL = dataIn[BP+3];
|
||||||
|
goto Loc758;
|
||||||
|
|
||||||
|
Loc767:
|
||||||
|
goto Loc754;
|
||||||
|
|
||||||
|
Loc768:
|
||||||
|
AL = DSSI();
|
||||||
|
if (AL != 0) goto Loc755;
|
||||||
|
|
||||||
|
// Resize the output to be the number of outputed bytes and return it
|
||||||
|
if (outputOffset < dest->size()) dest->reallocate(outputOffset);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* AnimationDecoder class */
|
||||||
|
/* */
|
||||||
|
/* Provides the functionality for decoding animations */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// The code below is responsible for decompressing the pixel data
|
||||||
|
// for an animation. I'm not currently sure of the of the exact details
|
||||||
|
// of the compression format - for now I've simply copied the code
|
||||||
|
// from the executable
|
||||||
|
|
||||||
|
void AnimationDecoder::rcl(uint16 &value, bool &carry) {
|
||||||
|
bool result = (value & 0x8000) != 0;
|
||||||
|
value = (value << 1) + (carry ? 1 : 0);
|
||||||
|
carry = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GET_BYTE currData = (currData & 0xff00) | *pSrc++
|
||||||
|
#define BX_VAL(x) *((byte *) (dest->data() + tableOffset + x))
|
||||||
|
#define SET_HI_BYTE(x,v) x = (x & 0xff) | ((v) << 8);
|
||||||
|
#define SET_LO_BYTE(x,v) x = (x & 0xff00) | (v);
|
||||||
|
|
||||||
|
void AnimationDecoder::decode_data_2(byte *&pSrc, uint16 &currData, uint16 &bitCtr,
|
||||||
|
uint16 &dx, bool &carry) {
|
||||||
|
SET_HI_BYTE(dx, currData >> 8);
|
||||||
|
|
||||||
|
for (int v = 0; v < 8; ++v) {
|
||||||
|
rcl(currData, carry);
|
||||||
|
if (--bitCtr == 0) {
|
||||||
|
GET_BYTE;
|
||||||
|
bitCtr = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 AnimationDecoder::decode_data(MemoryBlock *src, MemoryBlock *dest, uint32 srcPos) {
|
||||||
|
byte *pSrc = src->data() + srcPos;
|
||||||
|
byte *pDest = dest->data();
|
||||||
|
byte v;
|
||||||
|
bool carry = false;
|
||||||
|
uint16 currData, bitCtr, dx;
|
||||||
|
byte tableOffset;
|
||||||
|
uint16 tempReg1, tempReg2;
|
||||||
|
|
||||||
|
// Handle splitting up 16 bytes into individual nibbles
|
||||||
|
for (int numBytes = 0; numBytes < 16; ++numBytes, ++pDest) {
|
||||||
|
// Split up next byte to pDest and pDest+0x10
|
||||||
|
currData = *pSrc++;
|
||||||
|
*(pDest + 0x10) = currData & 0xf;
|
||||||
|
*pDest = (currData >> 4) & 0xf;
|
||||||
|
|
||||||
|
// Split up next byte to pDest+0x20 and pDest+0x30
|
||||||
|
currData = *pSrc++;
|
||||||
|
*(pDest + 0x30) = currData & 0xf;
|
||||||
|
*(pDest + 0x20) = (currData >> 4) & 0xf;
|
||||||
|
}
|
||||||
|
|
||||||
|
pDest = (byte *) (dest->data() + 0x40);
|
||||||
|
currData = READ_BE_UINT16(pSrc);
|
||||||
|
pSrc += sizeof(uint16);
|
||||||
|
|
||||||
|
bitCtr = 4;
|
||||||
|
*pDest = (currData >> 8) & 0xf0;
|
||||||
|
tableOffset = currData >> 12;
|
||||||
|
currData <<= 4;
|
||||||
|
dx = 1;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
carry = false;
|
||||||
|
rcl(currData, carry);
|
||||||
|
if (--bitCtr == 0) {
|
||||||
|
GET_BYTE;
|
||||||
|
bitCtr = 8;
|
||||||
|
}
|
||||||
|
if (carry) goto loc_1441;
|
||||||
|
tableOffset = BX_VAL(0);
|
||||||
|
|
||||||
|
loc_1439:
|
||||||
|
dx ^= 1;
|
||||||
|
if ((dx & 1) != 0) {
|
||||||
|
SET_HI_BYTE(dx, tableOffset << 4);
|
||||||
|
*pDest = dx >> 8;
|
||||||
|
} else {
|
||||||
|
*pDest++ |= tableOffset;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
loc_1441:
|
||||||
|
rcl(currData, carry);
|
||||||
|
if (--bitCtr == 0) {
|
||||||
|
GET_BYTE;
|
||||||
|
bitCtr = 8;
|
||||||
|
}
|
||||||
|
if (!carry) {
|
||||||
|
rcl(currData, carry);
|
||||||
|
if (--bitCtr == 0) {
|
||||||
|
GET_BYTE;
|
||||||
|
bitCtr = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!carry) {
|
||||||
|
tableOffset = BX_VAL(0x10);
|
||||||
|
} else {
|
||||||
|
tableOffset = BX_VAL(0x20);
|
||||||
|
}
|
||||||
|
goto loc_1439;
|
||||||
|
}
|
||||||
|
|
||||||
|
rcl(currData, carry);
|
||||||
|
if (--bitCtr == 0) {
|
||||||
|
GET_BYTE;
|
||||||
|
bitCtr = 8;
|
||||||
|
}
|
||||||
|
if (!carry) {
|
||||||
|
tableOffset = BX_VAL(0x30);
|
||||||
|
goto loc_1439;
|
||||||
|
}
|
||||||
|
|
||||||
|
SET_HI_BYTE(dx, currData >> 12);
|
||||||
|
carry = false;
|
||||||
|
for (int ctr = 0; ctr < 4; ++ctr) {
|
||||||
|
rcl(currData, carry);
|
||||||
|
if (--bitCtr == 0) {
|
||||||
|
GET_BYTE;
|
||||||
|
bitCtr = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte dxHigh = dx >> 8;
|
||||||
|
if (dxHigh == BX_VAL(0)) {
|
||||||
|
tempReg1 = bitCtr;
|
||||||
|
tempReg2 = dx;
|
||||||
|
decode_data_2(pSrc, currData, bitCtr, dx, carry);
|
||||||
|
|
||||||
|
SET_LO_BYTE(dx, dx >> 8);
|
||||||
|
decode_data_2(pSrc, currData, bitCtr, dx, carry);
|
||||||
|
SET_HI_BYTE(bitCtr, dx & 0xff);
|
||||||
|
SET_LO_BYTE(bitCtr, dx >> 8);
|
||||||
|
dx = tempReg2;
|
||||||
|
|
||||||
|
if (bitCtr == 0)
|
||||||
|
// Exit out of infinite loop
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else if (dxHigh == BX_VAL(0x10)) {
|
||||||
|
tempReg1 = bitCtr;
|
||||||
|
decode_data_2(pSrc, currData, bitCtr, dx, carry);
|
||||||
|
bitCtr = dx >> 8;
|
||||||
|
|
||||||
|
} else if (dxHigh == BX_VAL(0x20)) {
|
||||||
|
SET_HI_BYTE(dx, currData >> 10);
|
||||||
|
|
||||||
|
for (v = 0; v < 6; ++v) {
|
||||||
|
rcl(currData, carry);
|
||||||
|
if (--bitCtr == 0) {
|
||||||
|
GET_BYTE;
|
||||||
|
bitCtr = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tempReg1 = bitCtr;
|
||||||
|
bitCtr = dx >> 8;
|
||||||
|
|
||||||
|
} else if (dxHigh == BX_VAL(0x30)) {
|
||||||
|
SET_HI_BYTE(dx, currData >> 11);
|
||||||
|
|
||||||
|
for (v = 0; v < 5; ++v) {
|
||||||
|
rcl(currData, carry);
|
||||||
|
if (--bitCtr == 0) {
|
||||||
|
GET_BYTE;
|
||||||
|
bitCtr = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tempReg1 = bitCtr;
|
||||||
|
bitCtr = dx >> 8;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
tableOffset = dx >> 8;
|
||||||
|
goto loc_1439;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dx & 1) == 1) {
|
||||||
|
*pDest++ |= tableOffset;
|
||||||
|
--bitCtr;
|
||||||
|
dx &= 0xfffe;
|
||||||
|
}
|
||||||
|
|
||||||
|
SET_HI_BYTE(dx, tableOffset << 4);
|
||||||
|
tableOffset |= dx >> 8;
|
||||||
|
|
||||||
|
v = bitCtr >> 1;
|
||||||
|
while (v-- > 0) *pDest++ = tableOffset;
|
||||||
|
|
||||||
|
bitCtr &= 1;
|
||||||
|
if (bitCtr != 0) {
|
||||||
|
*pDest = tableOffset & 0xf0;
|
||||||
|
dx |= 1; //dx.l
|
||||||
|
}
|
||||||
|
|
||||||
|
bitCtr = tempReg1;
|
||||||
|
tableOffset &= 0x0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return number of bytes written
|
||||||
|
return pDest - dest->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
62
lure/decode.h
Normal file
62
lure/decode.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_decode_h__
|
||||||
|
#define __lure_decode_h__
|
||||||
|
|
||||||
|
#include "common/stdafx.h"
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/memory.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
class PictureDecoder {
|
||||||
|
private:
|
||||||
|
byte *dataIn;
|
||||||
|
uint32 BP;
|
||||||
|
uint32 dataPos, dataPos2;
|
||||||
|
uint32 outputOffset;
|
||||||
|
byte AL, AH;
|
||||||
|
byte CH, CL;
|
||||||
|
|
||||||
|
void writeByte(MemoryBlock *dest, byte v);
|
||||||
|
void writeBytes(MemoryBlock *dest, byte v, uint16 numBytes);
|
||||||
|
byte DSSI(bool incr = true);
|
||||||
|
byte ESBX(bool incr = true);
|
||||||
|
void decrCtr();
|
||||||
|
bool shlCarry();
|
||||||
|
void swap(uint16 &v1, uint16 &v2);
|
||||||
|
public:
|
||||||
|
MemoryBlock *decode(MemoryBlock *src, uint32 maxOutputSize = SCREEN_SIZE);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AnimationDecoder {
|
||||||
|
public:
|
||||||
|
static void rcl(uint16 &value, bool &carry);
|
||||||
|
static uint32 decode_data(MemoryBlock *src, MemoryBlock *dest, uint32 srcPos);
|
||||||
|
static void decode_data_2(byte *&pSrc, uint16 &currData, uint16 &bitCtr,
|
||||||
|
uint16 &dx, bool &carry);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
174
lure/disk.cpp
Normal file
174
lure/disk.cpp
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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/util.h"
|
||||||
|
#include "common/scummsys.h"
|
||||||
|
|
||||||
|
#include "lure/disk.h"
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
static Disk *int_disk = NULL;
|
||||||
|
|
||||||
|
Disk &Disk::getReference() {
|
||||||
|
return *int_disk;
|
||||||
|
}
|
||||||
|
|
||||||
|
Disk::Disk(const Common::String &gameDataPath) {
|
||||||
|
_gameDataPath = gameDataPath;
|
||||||
|
_fileNum = 0xff;
|
||||||
|
_fileHandle = NULL;
|
||||||
|
int_disk = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Disk::~Disk() {
|
||||||
|
if (_fileHandle) delete _fileHandle;
|
||||||
|
int_disk = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 Disk::indexOf(uint16 id, bool suppressError) {
|
||||||
|
// Make sure the correct file is open - the upper two bits of the Id give the file number. Note
|
||||||
|
// that an extra check is done for the upper byte of the Id being 0x3f, which is the Id range
|
||||||
|
// I use for lure.dat resources, which are resources extracted from the lure.exe executable
|
||||||
|
uint8 entryFileNum = ((id>>8) == 0x3f) ? 0 : ((id >> 14) & 3) + 1;
|
||||||
|
openFile(entryFileNum);
|
||||||
|
|
||||||
|
// Find the correct entry in the list based on the Id
|
||||||
|
for (int entryIndex=0; entryIndex<NUM_ENTRIES_IN_HEADER; ++entryIndex) {
|
||||||
|
if (_entries[entryIndex].id == HEADER_ENTRY_UNUSED_ID) break;
|
||||||
|
else if (_entries[entryIndex].id == id) return entryIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suppressError) return 0xff;
|
||||||
|
error("Could not find entry Id #%d in file %sdisk%d.vga", id, _gameDataPath.c_str(), _fileNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Disk::openFile(uint8 fileNum) {
|
||||||
|
// Validate that the file number is correct
|
||||||
|
if (fileNum > 4)
|
||||||
|
error("Invalid file number specified - %d", fileNum);
|
||||||
|
|
||||||
|
// Only load up the new file if the current file number has changed
|
||||||
|
if (fileNum == _fileNum) return;
|
||||||
|
|
||||||
|
// Delete any existing open file handle
|
||||||
|
if (_fileNum != 0xff) delete _fileHandle;
|
||||||
|
_fileNum = fileNum;
|
||||||
|
|
||||||
|
// Open up the the new file
|
||||||
|
_fileHandle = new Common::File();
|
||||||
|
|
||||||
|
char sFilename[10];
|
||||||
|
if (_fileNum == 0)
|
||||||
|
strcpy(sFilename, SUPPORT_FILENAME);
|
||||||
|
else
|
||||||
|
sprintf(sFilename, "disk%d.vga", _fileNum);
|
||||||
|
|
||||||
|
_fileHandle->open(sFilename);
|
||||||
|
if (!_fileHandle->isOpen())
|
||||||
|
error("Could not open %s%s", _gameDataPath.c_str(), sFilename);
|
||||||
|
|
||||||
|
// Validate the header
|
||||||
|
char buffer[7];
|
||||||
|
uint32 bytesRead;
|
||||||
|
|
||||||
|
bytesRead = _fileHandle->read(buffer, 6);
|
||||||
|
buffer[6] = '\0';
|
||||||
|
if (strcmp(buffer, HEADER_IDENT_STRING) != 0)
|
||||||
|
error("The file %s%s was not a valid VGA file", _gameDataPath.c_str(), sFilename);
|
||||||
|
|
||||||
|
uint16 fileFileNum = _fileHandle->readUint16BE();
|
||||||
|
if (fileFileNum != _fileNum)
|
||||||
|
error("The file %s%s was not the correct file number", _gameDataPath.c_str(), sFilename);
|
||||||
|
|
||||||
|
// Read in the header entries
|
||||||
|
uint32 headerSize = sizeof(FileEntry) * NUM_ENTRIES_IN_HEADER;
|
||||||
|
if (_fileHandle->read(_entries, headerSize) != headerSize)
|
||||||
|
error("The file %s%s had a corrupted header", _gameDataPath.c_str(), sFilename);
|
||||||
|
|
||||||
|
#ifdef SCUMM_BIG_ENDIAN
|
||||||
|
// Process the read in header list to convert to big endian
|
||||||
|
for (int i = 0; i < NUM_ENTRIES_IN_HEADER; ++i) {
|
||||||
|
_entries[i].id = FROM_LE_16(_entries[i].id);
|
||||||
|
_entries[i].size = FROM_LE_16(_entries[i].size);
|
||||||
|
_entries[i].offset = FROM_LE_16(_entries[i].offset);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Disk::getEntrySize(uint16 id) {
|
||||||
|
// Get the index of the resource, if necessary opening the correct file
|
||||||
|
uint8 index = indexOf(id);
|
||||||
|
|
||||||
|
// Calculate the offset and size of the entry
|
||||||
|
uint32 size = (uint32) _entries[index].size;
|
||||||
|
if (_entries[index].sizeExtension) size += 0x10000;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock *Disk::getEntry(uint16 id)
|
||||||
|
{
|
||||||
|
// Get the index of the resource, if necessary opening the correct file
|
||||||
|
uint8 index = indexOf(id);
|
||||||
|
|
||||||
|
// Calculate the offset and size of the entry
|
||||||
|
uint32 size = (uint32) _entries[index].size;
|
||||||
|
if (_entries[index].sizeExtension) size += 0x10000;
|
||||||
|
uint32 offset = (uint32) _entries[index].offset * 0x20;
|
||||||
|
|
||||||
|
MemoryBlock *result = Memory::allocate(size);
|
||||||
|
_fileHandle->seek(offset, SEEK_SET);
|
||||||
|
_fileHandle->read(result->data(), size);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Disk::exists(uint16 id) {
|
||||||
|
// Get the index of the resource, if necessary opening the correct file
|
||||||
|
uint8 index = indexOf(id, true);
|
||||||
|
return (index != 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 Disk::numEntries() {
|
||||||
|
if (_fileNum == 0)
|
||||||
|
error("No file is currently open");
|
||||||
|
|
||||||
|
// Figure out how many entries there are by count until an unused entry is found
|
||||||
|
for (byte entryIndex = 0; entryIndex < NUM_ENTRIES_IN_HEADER; ++entryIndex)
|
||||||
|
if (_entries[entryIndex].id == HEADER_ENTRY_UNUSED_ID) return entryIndex;
|
||||||
|
|
||||||
|
return NUM_ENTRIES_IN_HEADER;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileEntry *Disk::getIndex(uint8 entryIndex) {
|
||||||
|
if (_fileNum == 0)
|
||||||
|
error("No file is currently open");
|
||||||
|
if ((entryIndex >= NUM_ENTRIES_IN_HEADER) || (_entries[entryIndex].id == HEADER_ENTRY_UNUSED_ID))
|
||||||
|
error("There is no entry at the specified index");
|
||||||
|
|
||||||
|
return &_entries[entryIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
66
lure/disk.h
Normal file
66
lure/disk.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_disk_h__
|
||||||
|
#define __lure_disk_h__
|
||||||
|
|
||||||
|
#include "common/stdafx.h"
|
||||||
|
#include "common/scummsys.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
#include "lure/memory.h"
|
||||||
|
#include "lure/res_struct.h"
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
class File;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
#define NUM_ENTRIES_IN_HEADER 0xBF
|
||||||
|
#define HEADER_IDENT_STRING "heywow"
|
||||||
|
#define HEADER_ENTRY_UNUSED_ID 0xffff
|
||||||
|
|
||||||
|
class Disk {
|
||||||
|
private:
|
||||||
|
Common::String _gameDataPath;
|
||||||
|
uint8 _fileNum;
|
||||||
|
Common::File *_fileHandle;
|
||||||
|
FileEntry _entries[NUM_ENTRIES_IN_HEADER];
|
||||||
|
|
||||||
|
uint8 indexOf(uint16 id, bool suppressError = false);
|
||||||
|
public:
|
||||||
|
Disk(const Common::String &gameDataPath);
|
||||||
|
~Disk();
|
||||||
|
static Disk &getReference();
|
||||||
|
|
||||||
|
void openFile(uint8 fileNum);
|
||||||
|
uint32 getEntrySize(uint16 id);
|
||||||
|
MemoryBlock *getEntry(uint16 id);
|
||||||
|
bool exists(uint16 id);
|
||||||
|
|
||||||
|
uint8 numEntries();
|
||||||
|
FileEntry *getIndex(uint8 entryIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
159
lure/events.cpp
Normal file
159
lure/events.cpp
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/events.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
static Mouse *int_mouse = NULL;
|
||||||
|
|
||||||
|
Mouse &Mouse::getReference() {
|
||||||
|
return *int_mouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mouse::Mouse(OSystem &system): _system(system), _cursors(Disk::getReference().getEntry(CURSOR_RESOURCE_ID)) {
|
||||||
|
int_mouse = this;
|
||||||
|
|
||||||
|
_lButton = false;
|
||||||
|
_rButton = false;
|
||||||
|
_cursorNum = 0;
|
||||||
|
setCursorNum(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Mouse::~Mouse() {
|
||||||
|
delete _cursors;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse::handleEvent(OSystem::Event event) {
|
||||||
|
_x = (int16) event.mouse.x;
|
||||||
|
_y = (int16) event.mouse.y;
|
||||||
|
|
||||||
|
switch (event.type) {
|
||||||
|
case OSystem::EVENT_LBUTTONDOWN:
|
||||||
|
_lButton = true;
|
||||||
|
break;
|
||||||
|
case OSystem::EVENT_LBUTTONUP:
|
||||||
|
_lButton = false;
|
||||||
|
break;
|
||||||
|
case OSystem::EVENT_RBUTTONDOWN:
|
||||||
|
_rButton = true;
|
||||||
|
break;
|
||||||
|
case OSystem::EVENT_RBUTTONUP:
|
||||||
|
_rButton = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mouse::cursorOn() {
|
||||||
|
_system.showMouse(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse::cursorOff() {
|
||||||
|
_system.showMouse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse::setCursorNum(uint8 cursorNum) {
|
||||||
|
int hotspotX = 7, hotspotY = 7;
|
||||||
|
if ((cursorNum == CURSOR_ARROW) || (cursorNum == CURSOR_MENUBAR)) {
|
||||||
|
hotspotX = 0;
|
||||||
|
hotspotY = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCursorNum(cursorNum, hotspotX, hotspotY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse::setCursorNum(uint8 cursorNum, int hotspotX, int hotspotY) {
|
||||||
|
_cursorNum = cursorNum;
|
||||||
|
byte *cursorAddr = _cursors->data() + (cursorNum * CURSOR_SIZE);
|
||||||
|
_system.setMouseCursor(cursorAddr, CURSOR_WIDTH, CURSOR_HEIGHT, hotspotX, hotspotY, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse::setPosition(int newX, int newY) {
|
||||||
|
_system.warpMouse(newX, newY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse::waitForRelease() {
|
||||||
|
Events &e = Events::getReference();
|
||||||
|
|
||||||
|
do {
|
||||||
|
e.pollEvent();
|
||||||
|
} while (!e.quitFlag && (lButton() || rButton()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static Events *int_events = NULL;
|
||||||
|
|
||||||
|
Events::Events(OSystem &system, Mouse &mouse): _system(system), _mouse(mouse), quitFlag(false) {
|
||||||
|
int_events = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Events &Events::getReference() {
|
||||||
|
return *int_events;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Events::pollEvent() {
|
||||||
|
if (!_system.pollEvent(_event)) return false;
|
||||||
|
|
||||||
|
// Handle keypress
|
||||||
|
switch (_event.type) {
|
||||||
|
case OSystem::EVENT_QUIT:
|
||||||
|
quitFlag = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OSystem::EVENT_LBUTTONDOWN:
|
||||||
|
case OSystem::EVENT_LBUTTONUP:
|
||||||
|
case OSystem::EVENT_RBUTTONDOWN:
|
||||||
|
case OSystem::EVENT_RBUTTONUP:
|
||||||
|
case OSystem::EVENT_MOUSEMOVE:
|
||||||
|
case OSystem::EVENT_WHEELUP:
|
||||||
|
case OSystem::EVENT_WHEELDOWN:
|
||||||
|
_mouse.handleEvent(_event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Events::waitForPress() {
|
||||||
|
bool keyButton = false;
|
||||||
|
while (!keyButton) {
|
||||||
|
if (pollEvent()) {
|
||||||
|
if (_event.type == OSystem::EVENT_QUIT) return;
|
||||||
|
else if (_event.type == OSystem::EVENT_KEYDOWN) keyButton = true;
|
||||||
|
else if ((_event.type == OSystem::EVENT_LBUTTONDOWN) ||
|
||||||
|
(_event.type == OSystem::EVENT_RBUTTONDOWN)) {
|
||||||
|
keyButton = true;
|
||||||
|
_mouse.waitForRelease();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
78
lure/events.h
Normal file
78
lure/events.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_events_h__
|
||||||
|
#define __lure_events_h__
|
||||||
|
|
||||||
|
#include "common/stdafx.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/disk.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
class Mouse {
|
||||||
|
private:
|
||||||
|
OSystem &_system;
|
||||||
|
MemoryBlock *_cursors;
|
||||||
|
uint8 _cursorNum;
|
||||||
|
int16 _x, _y;
|
||||||
|
bool _lButton, _rButton;
|
||||||
|
public:
|
||||||
|
Mouse(OSystem &system);
|
||||||
|
~Mouse();
|
||||||
|
static Mouse &getReference();
|
||||||
|
void handleEvent(OSystem::Event event);
|
||||||
|
|
||||||
|
void cursorOn();
|
||||||
|
void cursorOff();
|
||||||
|
void setCursorNum(uint8 cursorNum);
|
||||||
|
void setCursorNum(uint8 cursorNum, int hotspotX, int hotspotY);
|
||||||
|
uint8 getCursorNum() { return _cursorNum; }
|
||||||
|
void setPosition(int x, int y);
|
||||||
|
int16 x() { return _x; }
|
||||||
|
int16 y() { return _y; }
|
||||||
|
bool lButton() { return _lButton; }
|
||||||
|
bool rButton() { return _rButton; }
|
||||||
|
void waitForRelease();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Events {
|
||||||
|
private:
|
||||||
|
OSystem &_system;
|
||||||
|
Mouse &_mouse;
|
||||||
|
OSystem::Event _event;
|
||||||
|
public:
|
||||||
|
bool quitFlag;
|
||||||
|
|
||||||
|
Events(OSystem &system, Mouse &mouse);
|
||||||
|
static Events &getReference();
|
||||||
|
|
||||||
|
bool pollEvent();
|
||||||
|
void waitForPress();
|
||||||
|
OSystem::Event event() { return _event; }
|
||||||
|
OSystem::EventType type() { return _event.type; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
420
lure/game.cpp
Normal file
420
lure/game.cpp
Normal file
|
@ -0,0 +1,420 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/game.h"
|
||||||
|
#include "lure/strings.h"
|
||||||
|
#include "lure/room.h"
|
||||||
|
#include "lure/system.h"
|
||||||
|
#include "lure/debug-input.h"
|
||||||
|
#include "lure/debug-methods.h"
|
||||||
|
#include "lure/scripts.h"
|
||||||
|
#include "lure/res_struct.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
static Game *int_game = NULL;
|
||||||
|
|
||||||
|
Game &Game::getReference() {
|
||||||
|
return *int_game;
|
||||||
|
}
|
||||||
|
|
||||||
|
Game::Game() {
|
||||||
|
int_game = this;
|
||||||
|
_slowSpeedFlag = true;
|
||||||
|
_soundFlag = true;
|
||||||
|
_remoteView = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::nextFrame() {
|
||||||
|
Resources &r = Resources::getReference();
|
||||||
|
HotspotList::iterator i = r.activeHotspots().begin();
|
||||||
|
HotspotList::iterator iTemp;
|
||||||
|
|
||||||
|
// Note the somewhat more complicated loop style as a hotspot tick handler may
|
||||||
|
// unload the hotspot and accompanying record
|
||||||
|
for (; i != r.activeHotspots().end(); i = iTemp) {
|
||||||
|
iTemp = i;
|
||||||
|
++iTemp;
|
||||||
|
Hotspot &h = *i.operator*();
|
||||||
|
h.tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::execute() {
|
||||||
|
OSystem &system = System::getReference();
|
||||||
|
Room &r = Room::getReference();
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
Events &events = Events::getReference();
|
||||||
|
Mouse &mouse = Mouse::getReference();
|
||||||
|
Screen &screen = Screen::getReference();
|
||||||
|
Menu &menu = Menu::getReference();
|
||||||
|
ValueTableData &fields = res.fieldList();
|
||||||
|
|
||||||
|
uint32 timerVal = system.getMillis();
|
||||||
|
|
||||||
|
screen.empty();
|
||||||
|
//_screen.resetPalette();
|
||||||
|
screen.setPaletteEmpty();
|
||||||
|
|
||||||
|
Script::execute(STARTUP_SCRIPT);
|
||||||
|
|
||||||
|
// Load the first room
|
||||||
|
r.setRoomNumber(1);
|
||||||
|
|
||||||
|
// Set the player direction
|
||||||
|
res.getActiveHotspot(PLAYER_ID)->setDirection(UP);
|
||||||
|
|
||||||
|
r.update();
|
||||||
|
mouse.setCursorNum(CURSOR_ARROW);
|
||||||
|
mouse.cursorOn();
|
||||||
|
|
||||||
|
while (!events.quitFlag) {
|
||||||
|
// If time for next frame, allow everything to update
|
||||||
|
if (system.getMillis() > timerVal + GAME_FRAME_DELAY) {
|
||||||
|
timerVal = system.getMillis();
|
||||||
|
nextFrame();
|
||||||
|
}
|
||||||
|
res.delayList().tick();
|
||||||
|
r.update();
|
||||||
|
|
||||||
|
if (events.pollEvent()) {
|
||||||
|
if (events.type() == OSystem::EVENT_KEYDOWN) {
|
||||||
|
uint16 roomNum = r.roomNumber();
|
||||||
|
|
||||||
|
#ifdef LURE_DEBUG
|
||||||
|
if (events.event().kbd.keycode == 282) {
|
||||||
|
doDebugMenu();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (events.event().kbd.ascii) {
|
||||||
|
case 27:
|
||||||
|
events.quitFlag = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef LURE_DEBUG
|
||||||
|
case '+':
|
||||||
|
while (++roomNum <= 51)
|
||||||
|
if (res.getRoom(roomNum) != NULL) break;
|
||||||
|
if (roomNum == 52) roomNum = 1;
|
||||||
|
|
||||||
|
r.leaveRoom();
|
||||||
|
r.setRoomNumber(roomNum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
if (roomNum == 1) roomNum = 55;
|
||||||
|
while (res.getRoom(--roomNum) == NULL) ;
|
||||||
|
|
||||||
|
r.leaveRoom();
|
||||||
|
r.setRoomNumber(roomNum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '*':
|
||||||
|
res.getActiveHotspot(PLAYER_ID)->setRoomNumber(
|
||||||
|
r.roomNumber());
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouse.y() < MENUBAR_Y_SIZE)
|
||||||
|
{
|
||||||
|
if (mouse.getCursorNum() != CURSOR_MENUBAR) mouse.setCursorNum(CURSOR_MENUBAR);
|
||||||
|
if ((mouse.getCursorNum() == CURSOR_MENUBAR) && mouse.lButton())
|
||||||
|
{
|
||||||
|
uint8 responseId = menu.execute();
|
||||||
|
mouse.setCursorNum((mouse.y() < MENUBAR_Y_SIZE) ? CURSOR_MENUBAR : CURSOR_ARROW);
|
||||||
|
if (responseId != MENUITEM_NONE)
|
||||||
|
handleMenuResponse(responseId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mouse.getCursorNum() == CURSOR_MENUBAR) mouse.setCursorNum(CURSOR_ARROW);
|
||||||
|
|
||||||
|
if (events.type() == OSystem::EVENT_MOUSEMOVE)
|
||||||
|
r.cursorMoved();
|
||||||
|
|
||||||
|
if (mouse.rButton()) handleRightClickMenu();
|
||||||
|
else if (mouse.lButton()) handleLeftClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 destRoom = fields.getField(NEW_ROOM_NUMBER);
|
||||||
|
if (_remoteView && (destRoom != 0)) {
|
||||||
|
// Show a remote view of the specified room
|
||||||
|
uint16 currentRoom = r.roomNumber();
|
||||||
|
r.setRoomNumber(destRoom, true);
|
||||||
|
|
||||||
|
// This code eventually needs to be moved into the main loop so that,
|
||||||
|
// amongst other things, the tick handlers controlling animation can work
|
||||||
|
while (!events.quitFlag && !mouse.lButton() && !mouse.rButton()) {
|
||||||
|
if (events.pollEvent()) {
|
||||||
|
if ((events.type() == OSystem::EVENT_KEYDOWN) &&
|
||||||
|
(events.event().kbd.ascii == 27))
|
||||||
|
events.quitFlag = true;
|
||||||
|
if (events.type() == OSystem::EVENT_MOUSEMOVE)
|
||||||
|
r.cursorMoved();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (system.getMillis() > timerVal + GAME_FRAME_DELAY) {
|
||||||
|
timerVal = system.getMillis();
|
||||||
|
nextFrame();
|
||||||
|
}
|
||||||
|
res.delayList().tick();
|
||||||
|
r.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
fields.setField(NEW_ROOM_NUMBER, 0);
|
||||||
|
Hotspot *player = res.getActiveHotspot(PLAYER_ID);
|
||||||
|
player->setTickProc(0x5e44); // reattach player handler
|
||||||
|
_remoteView = false;
|
||||||
|
r.setRoomNumber(currentRoom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.leaveRoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LURE_DEBUG
|
||||||
|
|
||||||
|
#define NUM_DEBUG_ITEMS 4
|
||||||
|
const char *debugItems[NUM_DEBUG_ITEMS] =
|
||||||
|
{"Toggle Info", "Set Room", "Show Active HS", "Show Room HS"};
|
||||||
|
|
||||||
|
void Game::doDebugMenu() {
|
||||||
|
uint16 index = PopupMenu::Show(NUM_DEBUG_ITEMS, debugItems);
|
||||||
|
Room &r = Room::getReference();
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
// Toggle co-ordinates
|
||||||
|
r.setShowInfo(!r.showInfo());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// Set room number:
|
||||||
|
uint32 roomNumber;
|
||||||
|
if (!input_integer("Enter room number:", roomNumber)) return;
|
||||||
|
if (res.getRoom(roomNumber))
|
||||||
|
r.setRoomNumber(roomNumber);
|
||||||
|
else
|
||||||
|
Dialog::show("The room does not exist");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// Show active hotspots
|
||||||
|
showActiveHotspots();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
// Show hotspots in room
|
||||||
|
showRoomHotspots();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Game::handleMenuResponse(uint8 selection) {
|
||||||
|
switch (selection) {
|
||||||
|
case MENUITEM_CREDITS:
|
||||||
|
doShowCredits();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENUITEM_RESTART_GAME:
|
||||||
|
case MENUITEM_SAVE_GAME:
|
||||||
|
case MENUITEM_RESTORE_GAME:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENUITEM_QUIT:
|
||||||
|
doQuit();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENUITEM_TEXT_SPEED:
|
||||||
|
doTextSpeed();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENUITEM_SOUND:
|
||||||
|
doSound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::handleRightClickMenu() {
|
||||||
|
Room &r = Room::getReference();
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
ValueTableData &fields = Resources::getReference().fieldList();
|
||||||
|
Hotspot *player = res.getActiveHotspot(PLAYER_ID);
|
||||||
|
HotspotData *hotspot;
|
||||||
|
Action action;
|
||||||
|
uint32 actions;
|
||||||
|
uint16 itemId;
|
||||||
|
|
||||||
|
if (r.hotspotId() != 0) {
|
||||||
|
// Get hotspot actions
|
||||||
|
actions = r.hotspotActions();
|
||||||
|
} else {
|
||||||
|
// Standard actions - drink, examine, look, status
|
||||||
|
actions = 0x1184000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no inventory items remove entries that require them
|
||||||
|
if (res.numInventoryItems() == 0)
|
||||||
|
actions &= 0xFEF3F9FD;
|
||||||
|
|
||||||
|
action = NONE;
|
||||||
|
hotspot = NULL;
|
||||||
|
|
||||||
|
bool breakFlag = false;
|
||||||
|
while (!breakFlag) {
|
||||||
|
action = PopupMenu::Show(actions);
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case LOOK:
|
||||||
|
case STATUS:
|
||||||
|
breakFlag = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GIVE:
|
||||||
|
case USE:
|
||||||
|
case EXAMINE:
|
||||||
|
case DRINK:
|
||||||
|
if (action != DRINK)
|
||||||
|
hotspot = res.getHotspot(r.hotspotId());
|
||||||
|
itemId = PopupMenu::ShowInventory();
|
||||||
|
breakFlag = (itemId != 0xffff);
|
||||||
|
if (breakFlag)
|
||||||
|
fields.setField(USE_HOTSPOT_ID, itemId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
hotspot = res.getHotspot(r.hotspotId());
|
||||||
|
breakFlag = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set fields used by the script interpreter
|
||||||
|
fields.setField(CHARACTER_HOTSPOT_ID, PLAYER_ID);
|
||||||
|
if (hotspot) {
|
||||||
|
fields.setField(ACTIVE_HOTSPOT_ID, hotspot->hotspotId);
|
||||||
|
if ((action != USE) && (action != GIVE)) {
|
||||||
|
fields.setField(USE_HOTSPOT_ID, hotspot->hotspotId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action != NONE)
|
||||||
|
player->doAction(action, hotspot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::handleLeftClick() {
|
||||||
|
Room &room = Room::getReference();
|
||||||
|
Mouse &mouse = Mouse::getReference();
|
||||||
|
Resources &resources = Resources::getReference();
|
||||||
|
|
||||||
|
if (room.hotspotId()) {
|
||||||
|
// Handle look at hotspot
|
||||||
|
HotspotData *hs = resources.getHotspot(room.hotspotId());
|
||||||
|
Hotspot *player = resources.getActiveHotspot(PLAYER_ID);
|
||||||
|
room.setAction(LOOK_AT);
|
||||||
|
room.update();
|
||||||
|
player->doAction(LOOK_AT, hs);
|
||||||
|
room.setAction(NONE);
|
||||||
|
} else {
|
||||||
|
// Walk to mouse click. TODO: still need to recognise other actions,
|
||||||
|
// such as to room exits or closing an on-screen floating dialog
|
||||||
|
Hotspot *hs = resources.getActiveHotspot(PLAYER_ID);
|
||||||
|
hs->walkTo(mouse.x(), mouse.y(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::doShowCredits() {
|
||||||
|
Events &events = Events::getReference();
|
||||||
|
Mouse &mouse = Mouse::getReference();
|
||||||
|
Screen &screen = Screen::getReference();
|
||||||
|
|
||||||
|
mouse.cursorOff();
|
||||||
|
Palette p(CREDITS_RESOURCE_ID - 1);
|
||||||
|
Surface *s = Surface::getScreen(CREDITS_RESOURCE_ID);
|
||||||
|
screen.setPalette(&p);
|
||||||
|
s->copyToScreen(0, 0);
|
||||||
|
delete s;
|
||||||
|
|
||||||
|
events.waitForPress();
|
||||||
|
|
||||||
|
screen.resetPalette();
|
||||||
|
screen.update();
|
||||||
|
mouse.cursorOn();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::doQuit() {
|
||||||
|
Mouse &mouse = Mouse::getReference();
|
||||||
|
Events &events = Events::getReference();
|
||||||
|
Screen &screen = Screen::getReference();
|
||||||
|
|
||||||
|
mouse.cursorOff();
|
||||||
|
Surface *s = Surface::newDialog(190, "Are you sure (y/n)?");
|
||||||
|
s->centerOnScreen();
|
||||||
|
delete s;
|
||||||
|
|
||||||
|
char key = '\0';
|
||||||
|
do {
|
||||||
|
if (events.pollEvent()) {
|
||||||
|
if (events.event().type == OSystem::EVENT_KEYDOWN) {
|
||||||
|
key = events.event().kbd.ascii;
|
||||||
|
if ((key >= 'A') && (key <= 'Z')) key += 'a' - 'A';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (((uint8) key != 27) && (key != 'y') && (key != 'n'));
|
||||||
|
|
||||||
|
events.quitFlag = key == 'y';
|
||||||
|
if (!events.quitFlag) {
|
||||||
|
screen.update();
|
||||||
|
mouse.cursorOn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::doTextSpeed() {
|
||||||
|
Menu &menu = Menu::getReference();
|
||||||
|
|
||||||
|
_slowSpeedFlag = !_slowSpeedFlag;
|
||||||
|
const char *pSrc = _slowSpeedFlag ? "Slow" : "Fast";
|
||||||
|
char *pDest = menu.getMenu(2).getEntry(1);
|
||||||
|
memcpy(pDest, pSrc, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::doSound() {
|
||||||
|
Menu &menu = Menu::getReference();
|
||||||
|
|
||||||
|
_soundFlag = !_soundFlag;
|
||||||
|
const char *pSrc = _soundFlag ? "on " : "off";
|
||||||
|
char *pDest = menu.getMenu(2).getEntry(2) + 6;
|
||||||
|
memcpy(pDest, pSrc, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
64
lure/game.h
Normal file
64
lure/game.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_game_h__
|
||||||
|
#define __lure_game_h__
|
||||||
|
|
||||||
|
#include "common/stdafx.h"
|
||||||
|
#include "base/engine.h"
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/menu.h"
|
||||||
|
#include "lure/palette.h"
|
||||||
|
#include "lure/disk.h"
|
||||||
|
#include "lure/memory.h"
|
||||||
|
#include "lure/screen.h"
|
||||||
|
#include "lure/events.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
class Game {
|
||||||
|
private:
|
||||||
|
bool _slowSpeedFlag, _soundFlag;
|
||||||
|
bool _remoteView;
|
||||||
|
|
||||||
|
void handleMenuResponse(uint8 selection);
|
||||||
|
void handleRightClickMenu();
|
||||||
|
void handleLeftClick();
|
||||||
|
public:
|
||||||
|
Game();
|
||||||
|
static Game &getReference();
|
||||||
|
|
||||||
|
void nextFrame();
|
||||||
|
void execute();
|
||||||
|
void setRemoteView() { _remoteView = true; }
|
||||||
|
|
||||||
|
// Menu item support methods
|
||||||
|
void doDebugMenu();
|
||||||
|
void doShowCredits();
|
||||||
|
void doQuit();
|
||||||
|
void doTextSpeed();
|
||||||
|
void doSound();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
806
lure/hotspots.cpp
Normal file
806
lure/hotspots.cpp
Normal file
|
@ -0,0 +1,806 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/hotspots.h"
|
||||||
|
#include "lure/decode.h"
|
||||||
|
#include "lure/palette.h"
|
||||||
|
#include "lure/disk.h"
|
||||||
|
#include "lure/res.h"
|
||||||
|
#include "lure/scripts.h"
|
||||||
|
#include "lure/room.h"
|
||||||
|
#include "lure/strings.h"
|
||||||
|
#include "lure/res_struct.h"
|
||||||
|
#include "lure/events.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
Hotspot::Hotspot(HotspotData *res) {
|
||||||
|
_data = res;
|
||||||
|
_anim = NULL;
|
||||||
|
_frames = NULL;
|
||||||
|
_numFrames = 0;
|
||||||
|
_persistant = false;
|
||||||
|
|
||||||
|
_startX = res->startX;
|
||||||
|
_startY = res->startY;
|
||||||
|
_destX = res->startX;
|
||||||
|
_destY = res->startY;
|
||||||
|
_destHotspotId = 0;
|
||||||
|
_width = res->width;
|
||||||
|
_height = res->height;
|
||||||
|
_tickCtr = res->tickTimeout;
|
||||||
|
|
||||||
|
// Check for a hotspot override
|
||||||
|
HotspotOverrideData *hor = Resources::getReference().getHotspotOverride(res->hotspotId);
|
||||||
|
|
||||||
|
if (hor) {
|
||||||
|
_startX = hor->xs;
|
||||||
|
_startY = hor->ys;
|
||||||
|
if (hor->xe < hor->xs) _width = 0;
|
||||||
|
else _width = hor->xe - hor->xs + 1;
|
||||||
|
if (hor->ye < hor->ys) _height = 0;
|
||||||
|
else _height = hor->ye - hor->ys + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_data->animRecordId != 0)
|
||||||
|
setAnimation(_data->animRecordId);
|
||||||
|
|
||||||
|
_tickHandler = HotspotTickHandlers::getHandler(_data->tickProcOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
Hotspot::~Hotspot() {
|
||||||
|
if (_frames) delete _frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::setAnimation(uint16 newAnimId) {
|
||||||
|
Resources &r = Resources::getReference();
|
||||||
|
HotspotAnimData *tempAnim;
|
||||||
|
if (newAnimId == 0) tempAnim = NULL;
|
||||||
|
else tempAnim = r.getAnimation(newAnimId);
|
||||||
|
|
||||||
|
setAnimation(tempAnim);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::setAnimation(HotspotAnimData *newRecord) {
|
||||||
|
Disk &r = Disk::getReference();
|
||||||
|
if (_frames) {
|
||||||
|
delete _frames;
|
||||||
|
_frames = NULL;
|
||||||
|
}
|
||||||
|
_anim = NULL;
|
||||||
|
_numFrames = 0;
|
||||||
|
_frameNumber = 0;
|
||||||
|
if (!newRecord) return;
|
||||||
|
if (!r.exists(newRecord->animId)) return;
|
||||||
|
|
||||||
|
_anim = newRecord;
|
||||||
|
MemoryBlock *src = Disk::getReference().getEntry(_anim->animId);
|
||||||
|
|
||||||
|
uint16 *numEntries = (uint16 *) src->data();
|
||||||
|
uint16 *headerEntry = (uint16 *) (src->data() + 2);
|
||||||
|
|
||||||
|
if ((*numEntries > 99) || (*numEntries == 0)) {
|
||||||
|
// Wobbly, likely something wrong with the resoure
|
||||||
|
_width = 1;
|
||||||
|
_numFrames = 1;
|
||||||
|
_frameNumber = 0;
|
||||||
|
_frames = new Surface(1, 1);
|
||||||
|
_frames->data().memset(_data->colourOffset, 0, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate total needed size for output and create memory block to hold it
|
||||||
|
uint32 totalSize = 0;
|
||||||
|
for (uint16 ctr = 0; ctr < *numEntries; ++ctr, ++headerEntry) {
|
||||||
|
totalSize += (*headerEntry + 31) / 32;
|
||||||
|
}
|
||||||
|
totalSize = (totalSize + 0x81) << 4;
|
||||||
|
MemoryBlock *dest = Memory::allocate(totalSize);
|
||||||
|
|
||||||
|
uint32 srcStart = (*numEntries + 1) * sizeof(uint16) + 6;
|
||||||
|
AnimationDecoder::decode_data(src, dest, srcStart);
|
||||||
|
|
||||||
|
_numFrames = *numEntries;
|
||||||
|
_frameNumber = 0;
|
||||||
|
|
||||||
|
_frames = new Surface(_data->width * _numFrames, _data->height);
|
||||||
|
|
||||||
|
_frames->data().memset(_data->colourOffset, 0, _frames->data().size());
|
||||||
|
|
||||||
|
byte *pSrc = dest->data() + 0x40;
|
||||||
|
byte *pDest;
|
||||||
|
headerEntry = (uint16 *) (src->data() + 2);
|
||||||
|
MemoryBlock &mDest = _frames->data();
|
||||||
|
|
||||||
|
for (uint16 frameCtr = 0; frameCtr < _numFrames; ++frameCtr, ++headerEntry) {
|
||||||
|
|
||||||
|
// Copy over the frame, applying the colour offset to each nibble
|
||||||
|
for (uint16 yPos = 0; yPos < _data->height; ++yPos) {
|
||||||
|
pDest = mDest.data() + (yPos * _numFrames + frameCtr) * _data->width;
|
||||||
|
|
||||||
|
for (uint16 ctr = 0; ctr < _data->width / 2; ++ctr) {
|
||||||
|
*pDest++ = _data->colourOffset + (*pSrc >> 4);
|
||||||
|
*pDest++ = _data->colourOffset + (*pSrc & 0xf);
|
||||||
|
++pSrc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete src;
|
||||||
|
delete dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::copyTo(Surface *dest) {
|
||||||
|
/*
|
||||||
|
int16 xPos = x();
|
||||||
|
int16 yPos = y();
|
||||||
|
uint16 hWidth = width();
|
||||||
|
uint16 hHeight = height();
|
||||||
|
*/
|
||||||
|
int16 xPos = _data->startX;
|
||||||
|
int16 yPos = _data->startY;
|
||||||
|
uint16 hWidth = _data->width;
|
||||||
|
uint16 hHeight = _data->height;
|
||||||
|
|
||||||
|
Rect r(_frameNumber * hWidth, 0, (_frameNumber + 1) * hWidth - 1,
|
||||||
|
hHeight - 1);
|
||||||
|
|
||||||
|
if (yPos < 0) {
|
||||||
|
if (yPos + hHeight <= 0)
|
||||||
|
// Completely off screen, so don't display
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Reduce the source rectangle to only the on-screen portion
|
||||||
|
r.top = -yPos;
|
||||||
|
yPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xPos < 0) {
|
||||||
|
if (xPos + hWidth <= 0)
|
||||||
|
// Completely off screen, so don't display
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Reduce the source rectangle to only the on-screen portion
|
||||||
|
r.left = -xPos;
|
||||||
|
xPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xPos >= FULL_SCREEN_WIDTH)
|
||||||
|
return;
|
||||||
|
else if (xPos + hWidth > FULL_SCREEN_WIDTH)
|
||||||
|
r.right = (_frameNumber * hWidth) + (FULL_SCREEN_WIDTH - xPos) - 1;
|
||||||
|
if (yPos >= FULL_SCREEN_HEIGHT)
|
||||||
|
return;
|
||||||
|
else if (yPos + hHeight > FULL_SCREEN_HEIGHT)
|
||||||
|
r.bottom = FULL_SCREEN_HEIGHT - yPos - 1;
|
||||||
|
|
||||||
|
_frames->copyTo(dest, r, (uint16) xPos, (uint16) yPos, _data->colourOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::incFrameNumber() {
|
||||||
|
++_frameNumber;
|
||||||
|
if (_frameNumber >= _numFrames)
|
||||||
|
_frameNumber = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Hotspot::isActiveAnimation() {
|
||||||
|
return ((_numFrames != 0) && (_data->layer != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::setPosition(int16 newX, int16 newY) {
|
||||||
|
_startX = newX;
|
||||||
|
_startY = newY;
|
||||||
|
_data->startX = newX;
|
||||||
|
_data->startY = newY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::setSize(uint16 newWidth, uint16 newHeight) {
|
||||||
|
_width = newWidth;
|
||||||
|
_height = newHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Hotspot::executeScript() {
|
||||||
|
if (_data->sequenceOffset == 0)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return HotspotScript::execute(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::tick() {
|
||||||
|
_tickHandler(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::setTickProc(uint16 newVal) {
|
||||||
|
_data->tickProcOffset = newVal;
|
||||||
|
_tickHandler = HotspotTickHandlers::getHandler(newVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Hotspot::walkTo(int16 endPosX, int16 endPosY, uint16 destHotspot, bool immediate) {
|
||||||
|
_destX = endPosX;
|
||||||
|
_destY = endPosY - _data->height;
|
||||||
|
|
||||||
|
_destHotspotId = destHotspot;
|
||||||
|
if (immediate)
|
||||||
|
setPosition(_destX, _destY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::setDirection(Direction dir) {
|
||||||
|
switch (dir) {
|
||||||
|
case UP:
|
||||||
|
setFrameNumber(_anim->upFrame);
|
||||||
|
break;
|
||||||
|
case DOWN:
|
||||||
|
setFrameNumber(_anim->downFrame);
|
||||||
|
break;
|
||||||
|
case LEFT:
|
||||||
|
setFrameNumber(_anim->leftFrame);
|
||||||
|
break;
|
||||||
|
case RIGHT:
|
||||||
|
setFrameNumber(_anim->rightFrame);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
/* Hotspot action handling */
|
||||||
|
/* */
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
uint16 validRoomExitHotspots[] = {0x2711, 0x2712, 0x2714, 0x2715, 0x2716, 0x2717,
|
||||||
|
0x2718, 0x2719, 0x271A, 0x271E, 0x271F, 0x2720, 0x2721, 0x2722, 0x2725, 0x2726,
|
||||||
|
0x2729, 0x272A, 0x272B, 0x272C, 0x272D, 0x272E, 0x272F, 0};
|
||||||
|
|
||||||
|
bool Hotspot::isRoomExit(uint16 id) {
|
||||||
|
for (uint16 *p = &validRoomExitHotspots[0]; *p != 0; ++p)
|
||||||
|
if (*p == id) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doAction(Action action, HotspotData *hotspot) {
|
||||||
|
switch (action) {
|
||||||
|
case GET:
|
||||||
|
doGet(hotspot);
|
||||||
|
break;
|
||||||
|
case PUSH:
|
||||||
|
case PULL:
|
||||||
|
case OPERATE:
|
||||||
|
doOperate(hotspot, action);
|
||||||
|
break;
|
||||||
|
case OPEN:
|
||||||
|
doOpen(hotspot);
|
||||||
|
break;
|
||||||
|
case CLOSE:
|
||||||
|
doClose(hotspot);
|
||||||
|
break;
|
||||||
|
case LOCK:
|
||||||
|
doSimple(hotspot, LOCK);
|
||||||
|
break;
|
||||||
|
case UNLOCK:
|
||||||
|
doSimple(hotspot, UNLOCK);
|
||||||
|
break;
|
||||||
|
case USE:
|
||||||
|
doUse(hotspot);
|
||||||
|
break;
|
||||||
|
case GIVE:
|
||||||
|
doGive(hotspot);
|
||||||
|
break;
|
||||||
|
case TALK_TO:
|
||||||
|
doTalkTo(hotspot);
|
||||||
|
break;
|
||||||
|
case TELL:
|
||||||
|
doTell(hotspot);
|
||||||
|
break;
|
||||||
|
case LOOK:
|
||||||
|
doLook();
|
||||||
|
break;
|
||||||
|
case LOOK_AT:
|
||||||
|
doLookAt(hotspot);
|
||||||
|
break;
|
||||||
|
case LOOK_THROUGH:
|
||||||
|
doSimple(hotspot, LOOK_THROUGH);
|
||||||
|
break;
|
||||||
|
case ASK:
|
||||||
|
doAsk(hotspot);
|
||||||
|
break;
|
||||||
|
case DRINK:
|
||||||
|
doDrink();
|
||||||
|
break;
|
||||||
|
case STATUS:
|
||||||
|
doStatus();
|
||||||
|
break;
|
||||||
|
case BRIBE:
|
||||||
|
doBribe(hotspot);
|
||||||
|
break;
|
||||||
|
case EXAMINE:
|
||||||
|
doExamine();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
doSimple(hotspot, action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doGet(HotspotData *hotspot) {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, GET);
|
||||||
|
|
||||||
|
if (sequenceOffset >= 0x8000) {
|
||||||
|
Dialog::showMessage(sequenceOffset, hotspotId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sequenceOffset != 0) {
|
||||||
|
uint16 result = Script::execute(sequenceOffset);
|
||||||
|
|
||||||
|
if (result == 1) return;
|
||||||
|
else if (result != 0) {
|
||||||
|
Dialog::showMessage(result, hotspotId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move hotspot into characters's inventory
|
||||||
|
hotspot->roomNumber = hotspotId();
|
||||||
|
|
||||||
|
if (hotspot->hotspotId < START_NONVISUAL_HOTSPOT_ID) {
|
||||||
|
// Deactive hotspot animation
|
||||||
|
Resources::getReference().deactivateHotspot(hotspot->hotspotId);
|
||||||
|
// Remove any 'on the ground' description for the hotspot
|
||||||
|
hotspot->descId2 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doOperate(HotspotData *hotspot, Action action) {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, action);
|
||||||
|
|
||||||
|
if (sequenceOffset >= 0x8000) {
|
||||||
|
Dialog::showMessage(sequenceOffset, hotspotId());
|
||||||
|
} else if (sequenceOffset != 0) {
|
||||||
|
uint16 result = Script::execute(sequenceOffset);
|
||||||
|
if (result > 1)
|
||||||
|
Dialog::showMessage(result, hotspotId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doOpen(HotspotData *hotspot) {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
RoomExitJoinData *joinRec;
|
||||||
|
|
||||||
|
if (isRoomExit(hotspot->hotspotId)) {
|
||||||
|
joinRec = res.getExitJoin(hotspot->hotspotId);
|
||||||
|
if (!joinRec->blocked) {
|
||||||
|
// Room exit is already open
|
||||||
|
Dialog::showMessage(4, hotspotId());
|
||||||
|
// TODO: jmp loc_1102
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Call to sub_107 and checking the results, then sub_110
|
||||||
|
|
||||||
|
uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, OPEN);
|
||||||
|
if (sequenceOffset >= 0x8000) {
|
||||||
|
// Message to display
|
||||||
|
Dialog::showMessage(sequenceOffset, hotspotId());
|
||||||
|
} else if (sequenceOffset != 0) {
|
||||||
|
// Otherwise handle script
|
||||||
|
uint16 result = Script::execute(sequenceOffset);
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
joinRec = res.getExitJoin(hotspot->hotspotId);
|
||||||
|
if (joinRec->blocked) {
|
||||||
|
joinRec->blocked = 0;
|
||||||
|
|
||||||
|
if (hotspotId() != PLAYER_ID) {
|
||||||
|
// TODO: HS[44h]=3, HS[42h]W = 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (result != 1) {
|
||||||
|
// TODO: Figure out: if Hotspot-rec[60h] != 0, then set = 4
|
||||||
|
Dialog::showMessage(result, hotspotId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doClose(HotspotData *hotspot) {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
RoomExitJoinData *joinRec;
|
||||||
|
|
||||||
|
if (isRoomExit(hotspot->hotspotId)) {
|
||||||
|
joinRec = res.getExitJoin(hotspot->hotspotId);
|
||||||
|
if (joinRec->blocked) {
|
||||||
|
// Room exit is already closed/blocked
|
||||||
|
Dialog::showMessage(3, hotspotId());
|
||||||
|
// TODO: jmp sub_129
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Call to sub_107 and checking the results, then sub_110
|
||||||
|
|
||||||
|
uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, CLOSE);
|
||||||
|
|
||||||
|
if (sequenceOffset >= 0x8000) {
|
||||||
|
// Message to display
|
||||||
|
Dialog::showMessage(sequenceOffset, hotspotId());
|
||||||
|
} else if (sequenceOffset != 0) {
|
||||||
|
// Otherwise handle script
|
||||||
|
uint16 result = Script::execute(sequenceOffset);
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
Dialog::showMessage(result, hotspotId());
|
||||||
|
} else {
|
||||||
|
joinRec = res.getExitJoin(hotspot->hotspotId);
|
||||||
|
if (!joinRec->blocked) {
|
||||||
|
// Close the door
|
||||||
|
// TODO: Decode sub_183 - does check to see if door is 'jammed', but
|
||||||
|
// a cursory inspection seems to indicate that the routine is more
|
||||||
|
// concerned with checking if any character is blocking the door
|
||||||
|
// if (!sub183(joinRec->0Dh) || !sub183(joinRec->0Fh)) {
|
||||||
|
// Dialog::showMessage(2, hotspotId());
|
||||||
|
// } else {
|
||||||
|
joinRec->blocked = 1;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doUse(HotspotData *hotspot) {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
// uint16 usedId = res.fieldList().getField(USE_HOTSPOT_ID);
|
||||||
|
uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, USE);
|
||||||
|
|
||||||
|
if (sequenceOffset >= 0x8000) {
|
||||||
|
Dialog::showMessage(sequenceOffset, hotspotId());
|
||||||
|
} else if (sequenceOffset == 0) {
|
||||||
|
Dialog::showMessage(17, hotspotId());
|
||||||
|
} else {
|
||||||
|
uint16 result = Script::execute(sequenceOffset);
|
||||||
|
if (result != 0)
|
||||||
|
Dialog::showMessage(result, hotspotId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doGive(HotspotData *hotspot) {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
uint16 usedId = res.fieldList().getField(USE_HOTSPOT_ID);
|
||||||
|
uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, GIVE);
|
||||||
|
|
||||||
|
if (sequenceOffset >= 0x8000) {
|
||||||
|
Dialog::showMessage(sequenceOffset, hotspotId());
|
||||||
|
} else {
|
||||||
|
uint16 result = Script::execute(sequenceOffset);
|
||||||
|
if (result == 0x3E7) {
|
||||||
|
// TODO
|
||||||
|
} else if (result == 0) {
|
||||||
|
// Move item into character's inventory
|
||||||
|
HotspotData *usedItem = res.getHotspot(usedId);
|
||||||
|
usedItem->roomNumber = hotspotId();
|
||||||
|
} else if (result > 1) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doTalkTo(HotspotData *hotspot) {
|
||||||
|
// TODO: extra checking at start
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, TALK_TO);
|
||||||
|
|
||||||
|
if (sequenceOffset >= 0x8000) {
|
||||||
|
Dialog::showMessage(sequenceOffset, hotspotId());
|
||||||
|
} else if (sequenceOffset != 0) {
|
||||||
|
uint16 result = Script::execute(sequenceOffset);
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
// Do talking with character
|
||||||
|
// TODO
|
||||||
|
Dialog::show("Still need to figure out talking");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doTell(HotspotData *hotspot) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doLook() {
|
||||||
|
Dialog::show(Room::getReference().descId());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doLookAt(HotspotData *hotspot) {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, LOOK_AT);
|
||||||
|
|
||||||
|
if (sequenceOffset >= 0x8000) {
|
||||||
|
Dialog::showMessage(sequenceOffset, hotspotId());
|
||||||
|
} else {
|
||||||
|
if (sequenceOffset != 0)
|
||||||
|
sequenceOffset = Script::execute(sequenceOffset);
|
||||||
|
|
||||||
|
if (sequenceOffset == 0) {
|
||||||
|
uint16 descId = (hotspot->descId2 != 0) ? hotspot->descId2 : hotspot->descId;
|
||||||
|
Dialog::show(descId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doAsk(HotspotData *hotspot) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doDrink() {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
uint16 usedId = res.fieldList().getField(USE_HOTSPOT_ID);
|
||||||
|
HotspotData *hotspot = res.getHotspot(usedId);
|
||||||
|
uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, DRINK);
|
||||||
|
|
||||||
|
if (sequenceOffset >= 0x8000) {
|
||||||
|
Dialog::showMessage(sequenceOffset, hotspotId());
|
||||||
|
} else if (sequenceOffset == 0) {
|
||||||
|
Dialog::showMessage(22, hotspotId());
|
||||||
|
} else {
|
||||||
|
uint16 result = Script::execute(sequenceOffset);
|
||||||
|
if (result == 0) {
|
||||||
|
// Item has been drunk, so remove item from game
|
||||||
|
hotspot->roomNumber = 0;
|
||||||
|
} else if (result != 1) {
|
||||||
|
Dialog::showMessage(result, hotspotId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// doStatus
|
||||||
|
// Handle the status window
|
||||||
|
|
||||||
|
void Hotspot::doStatus() {
|
||||||
|
char buffer[MAX_DESC_SIZE];
|
||||||
|
uint16 numItems = 0;
|
||||||
|
StringData &strings = StringData::getReference();
|
||||||
|
Resources &resources = Resources::getReference();
|
||||||
|
Room &room = Room::getReference();
|
||||||
|
|
||||||
|
strings.getString(room.roomNumber(), buffer, NULL, NULL);
|
||||||
|
strcat(buffer, "\n\nYou are carrying ");
|
||||||
|
|
||||||
|
// Scan through the list and add in any items assigned to the player
|
||||||
|
HotspotDataList &list = resources.hotspotData();
|
||||||
|
HotspotDataList::iterator i;
|
||||||
|
for (i = list.begin(); i != list.end(); ++i) {
|
||||||
|
HotspotData *rec = *i;
|
||||||
|
|
||||||
|
if (rec->roomNumber == PLAYER_ID) {
|
||||||
|
if (numItems++ == 0) strcat(buffer, ": ");
|
||||||
|
else strcat(buffer, ", ");
|
||||||
|
strings.getString(rec->nameId, buffer + strlen(buffer), NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there were no items, add in the word 'nothing'
|
||||||
|
if (numItems == 0) strcat(buffer, "nothing.");
|
||||||
|
|
||||||
|
// If the player has money, add it in
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// Display the dialog
|
||||||
|
Screen &screen = Screen::getReference();
|
||||||
|
Mouse &mouse = Mouse::getReference();
|
||||||
|
mouse.cursorOff();
|
||||||
|
|
||||||
|
Surface *s = Surface::newDialog(INFO_DIALOG_WIDTH, buffer);
|
||||||
|
s->copyToScreen(INFO_DIALOG_X, (FULL_SCREEN_HEIGHT-s->height())/2);
|
||||||
|
|
||||||
|
Events::getReference().waitForPress();
|
||||||
|
screen.update();
|
||||||
|
mouse.cursorOn();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doBribe(HotspotData *hotspot) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doExamine() {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
uint16 usedId = res.fieldList().getField(USE_HOTSPOT_ID);
|
||||||
|
HotspotData *hotspot = res.getHotspot(usedId);
|
||||||
|
uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, EXAMINE);
|
||||||
|
|
||||||
|
if (sequenceOffset >= 0x8000) {
|
||||||
|
Dialog::showMessage(sequenceOffset, hotspotId());
|
||||||
|
} else {
|
||||||
|
if (sequenceOffset != 0)
|
||||||
|
sequenceOffset = Script::execute(sequenceOffset);
|
||||||
|
|
||||||
|
if (sequenceOffset == 0) {
|
||||||
|
Dialog::show(hotspot->descId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotspot::doSimple(HotspotData *hotspot, Action action) {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
uint16 sequenceOffset = res.getHotspotAction(hotspot->actionsOffset, action);
|
||||||
|
|
||||||
|
if (sequenceOffset >= 0x8000) {
|
||||||
|
Dialog::showMessage(sequenceOffset, hotspotId());
|
||||||
|
} else if (sequenceOffset != 0) {
|
||||||
|
Script::execute(sequenceOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
HandlerMethodPtr HotspotTickHandlers::getHandler(uint16 procOffset) {
|
||||||
|
switch (procOffset) {
|
||||||
|
case 0x7F3A:
|
||||||
|
return standardAnimHandler;
|
||||||
|
case 0x7207:
|
||||||
|
return roomExitAnimHandler;
|
||||||
|
case 0x5e44:
|
||||||
|
return playerAnimHandler;
|
||||||
|
case 0x7F69:
|
||||||
|
return droppingTorchAnimHandler;
|
||||||
|
case 0x8009:
|
||||||
|
return fireAnimHandler;
|
||||||
|
case 0x8241:
|
||||||
|
return headAnimationHandler;
|
||||||
|
default:
|
||||||
|
return defaultHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotspotTickHandlers::defaultHandler(Hotspot &h) {
|
||||||
|
// No handling done
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotspotTickHandlers::standardAnimHandler(Hotspot &h) {
|
||||||
|
if (h.tickCtr() > 0)
|
||||||
|
h.setTickCtr(h.tickCtr() - 1);
|
||||||
|
else
|
||||||
|
h.executeScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotspotTickHandlers::roomExitAnimHandler(Hotspot &h) {
|
||||||
|
RoomExitJoinData *rec = Resources::getReference().getExitJoin(h.hotspotId());
|
||||||
|
if (!rec) return;
|
||||||
|
byte *currentFrame, *destFrame;
|
||||||
|
|
||||||
|
if (rec->hotspot1Id == h.hotspotId()) {
|
||||||
|
currentFrame = &rec->h1CurrentFrame;
|
||||||
|
destFrame = &rec->h1DestFrame;
|
||||||
|
} else {
|
||||||
|
currentFrame = &rec->h2CurrentFrame;
|
||||||
|
destFrame = &rec->h2DestFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rec->blocked != 0) && (*currentFrame != *destFrame)) {
|
||||||
|
// sub_178
|
||||||
|
|
||||||
|
++*currentFrame;
|
||||||
|
if (*currentFrame != *destFrame) {
|
||||||
|
// cx=1 => sub_184
|
||||||
|
}
|
||||||
|
} else if ((rec->blocked == 0) && (*currentFrame != 0)) {
|
||||||
|
// sub_179
|
||||||
|
if (*currentFrame == *destFrame) {
|
||||||
|
// sub_184 and other stuff TODO
|
||||||
|
}
|
||||||
|
--*currentFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
h.setFrameNumber(*currentFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotspotTickHandlers::playerAnimHandler(Hotspot &h) {
|
||||||
|
int16 xPos = h.x();
|
||||||
|
int16 yPos = h.y();
|
||||||
|
if ((xPos == h.destX()) && (yPos == h.destY())) return;
|
||||||
|
HotspotAnimData &anim = h.anim();
|
||||||
|
int16 xDiff = h.destX() - h.x();
|
||||||
|
int16 yDiff = h.destY() - h.y();
|
||||||
|
|
||||||
|
int16 xChange, yChange;
|
||||||
|
uint16 nextFrame;
|
||||||
|
MovementDataList *moves;
|
||||||
|
|
||||||
|
if ((yDiff < 0) && (xDiff <= 0)) moves = &anim.upFrames;
|
||||||
|
else if (xDiff < 0) moves = &anim.leftFrames;
|
||||||
|
else if (yDiff > 0) moves = &anim.downFrames;
|
||||||
|
else moves = &anim.rightFrames;
|
||||||
|
|
||||||
|
// Get movement amount and next frame number
|
||||||
|
moves->getFrame(h.frameNumber(), xChange, yChange, nextFrame);
|
||||||
|
xPos += xChange; yPos += yChange;
|
||||||
|
|
||||||
|
// Make sure that the move amount doesn't overstep the destination X/Y
|
||||||
|
if ((yDiff < 0) && (yPos < h.destY())) yPos = h.destY();
|
||||||
|
else if ((xDiff < 0) && (xPos < h.destX())) xPos = h.destX();
|
||||||
|
else if ((yDiff > 0) && (yPos > h.destY())) yPos = h.destY();
|
||||||
|
else if ((xDiff > 0) && (xPos > h.destX())) xPos = h.destX();
|
||||||
|
|
||||||
|
// Check to see if player has entered an exit area
|
||||||
|
RoomData *roomData = Resources::getReference().getRoom(h.roomNumber());
|
||||||
|
Room &room = Room::getReference();
|
||||||
|
bool charInRoom = room.roomNumber() == h.roomNumber();
|
||||||
|
RoomExitData *exitRec = roomData->exits.checkExits(xPos, yPos + h.height());
|
||||||
|
|
||||||
|
if (!exitRec) {
|
||||||
|
h.setPosition(xPos, yPos);
|
||||||
|
h.setFrameNumber(nextFrame);
|
||||||
|
} else {
|
||||||
|
h.setRoomNumber(exitRec->roomNumber);
|
||||||
|
h.walkTo(exitRec->x, exitRec->y, 0, true);
|
||||||
|
if (exitRec->direction != NO_DIRECTION)
|
||||||
|
h.setDirection(exitRec->direction);
|
||||||
|
if (charInRoom)
|
||||||
|
room.setRoomNumber(exitRec->roomNumber, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotspotTickHandlers::droppingTorchAnimHandler(Hotspot &h) {
|
||||||
|
if (h.tickCtr() > 0)
|
||||||
|
h.setTickCtr(h.tickCtr() - 1);
|
||||||
|
else {
|
||||||
|
bool result = h.executeScript();
|
||||||
|
if (result) {
|
||||||
|
// Changeover to the fire on the straw
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
res.deactivateHotspot(h.hotspotId());
|
||||||
|
res.activateHotspot(0x41C);
|
||||||
|
|
||||||
|
// Enable the fire and activate it's animation
|
||||||
|
HotspotData *fire = res.getHotspot(0x418);
|
||||||
|
fire->flags |= 0x80;
|
||||||
|
fire->loadOffset = 0x7172;
|
||||||
|
res.activateHotspot(0x418);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotspotTickHandlers::fireAnimHandler(Hotspot &h) {
|
||||||
|
standardAnimHandler(h);
|
||||||
|
// TODO: figure out remainder of method
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotspotTickHandlers::headAnimationHandler(Hotspot &h) {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
Hotspot *character = res.getActiveHotspot(PLAYER_ID);
|
||||||
|
uint16 frameNumber = 0;
|
||||||
|
|
||||||
|
if (character->y() < 79) {
|
||||||
|
//character = res.getActiveHotspot(RATPOUCH_ID);
|
||||||
|
frameNumber = 1;
|
||||||
|
} else {
|
||||||
|
if (character->x() < 72) frameNumber = 0;
|
||||||
|
else if (character->x() < 172) frameNumber = 1;
|
||||||
|
else frameNumber = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
h.setFrameNumber(frameNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
137
lure/hotspots.h
Normal file
137
lure/hotspots.h
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_hotspots_h__
|
||||||
|
#define __lure_hotspots_h__
|
||||||
|
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/screen.h"
|
||||||
|
#include "lure/disk.h"
|
||||||
|
#include "lure/res_struct.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
class Hotspot;
|
||||||
|
|
||||||
|
typedef void(*HandlerMethodPtr)(Hotspot &h);
|
||||||
|
|
||||||
|
class HotspotTickHandlers {
|
||||||
|
private:
|
||||||
|
static void defaultHandler(Hotspot &h);
|
||||||
|
static void standardAnimHandler(Hotspot &h);
|
||||||
|
static void roomExitAnimHandler(Hotspot &h);
|
||||||
|
static void playerAnimHandler(Hotspot &h);
|
||||||
|
static void droppingTorchAnimHandler(Hotspot &h);
|
||||||
|
static void fireAnimHandler(Hotspot &h);
|
||||||
|
static void headAnimationHandler(Hotspot &h);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static HandlerMethodPtr getHandler(uint16 procOffset);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Hotspot {
|
||||||
|
private:
|
||||||
|
HotspotData *_data;
|
||||||
|
HotspotAnimData *_anim;
|
||||||
|
HandlerMethodPtr _tickHandler;
|
||||||
|
Surface *_frames;
|
||||||
|
int16 _startX, _startY;
|
||||||
|
uint16 _height, _width;
|
||||||
|
uint16 _numFrames;
|
||||||
|
uint16 _frameNumber;
|
||||||
|
uint16 _tickCtr;
|
||||||
|
bool _persistant;
|
||||||
|
|
||||||
|
int16 _destX, _destY;
|
||||||
|
uint16 _destHotspotId;
|
||||||
|
public:
|
||||||
|
Hotspot(HotspotData *res);
|
||||||
|
~Hotspot();
|
||||||
|
|
||||||
|
void setAnimation(uint16 newAnimId);
|
||||||
|
void setAnimation(HotspotAnimData *newRecord);
|
||||||
|
uint16 hotspotId() { return _data->hotspotId; }
|
||||||
|
Surface &frames() { return *_frames; }
|
||||||
|
HotspotAnimData &anim() { return *_anim; }
|
||||||
|
HotspotData &resource() { return *_data; }
|
||||||
|
uint16 numFrames() { return _numFrames; }
|
||||||
|
uint16 frameNumber() { return _frameNumber; }
|
||||||
|
void setFrameNumber(uint16 v) { _frameNumber = v; }
|
||||||
|
void incFrameNumber();
|
||||||
|
uint16 frameWidth() { return _width; }
|
||||||
|
int16 x() { return _startX; }
|
||||||
|
int16 y() { return _startY; }
|
||||||
|
int16 destX() { return _destX; }
|
||||||
|
int16 destY() { return _destY; }
|
||||||
|
uint16 destHotspotId() { return _destHotspotId; }
|
||||||
|
uint16 width() { return _width; }
|
||||||
|
uint16 height() { return _height; }
|
||||||
|
uint16 roomNumber() { return _data->roomNumber; }
|
||||||
|
uint16 script() { return _data->sequenceOffset; }
|
||||||
|
uint8 layer() { return _data->layer; }
|
||||||
|
uint16 tickCtr() { return _tickCtr; }
|
||||||
|
void setTickCtr(uint16 newVal) { _tickCtr = newVal; }
|
||||||
|
void setTickProc(uint16 newVal);
|
||||||
|
bool persistant() { return _persistant; }
|
||||||
|
void setPersistant(bool value) { _persistant = value; }
|
||||||
|
void setRoomNumber(uint16 roomNum) { _data->roomNumber = roomNum; }
|
||||||
|
bool isActiveAnimation();
|
||||||
|
void setPosition(int16 newX, int16 newY);
|
||||||
|
void setDestPosition(int16 newX, int16 newY) { _destX = newX; _destY = newY; }
|
||||||
|
void setSize(uint16 newWidth, uint16 newHeight);
|
||||||
|
void setScript(uint16 offset) { _data->sequenceOffset = offset; }
|
||||||
|
void setActions(uint32 newActions) { _data->actions = newActions; }
|
||||||
|
|
||||||
|
void copyTo(Surface *dest);
|
||||||
|
bool executeScript();
|
||||||
|
void tick();
|
||||||
|
void walkTo(int16 endPosX, int16 endPosY, uint16 destHotspot = 0, bool immediate = false);
|
||||||
|
void setDirection(Direction dir);
|
||||||
|
|
||||||
|
// Action set
|
||||||
|
void doAction(Action action, HotspotData *hotspot);
|
||||||
|
bool isRoomExit(uint16 id);
|
||||||
|
void doGet(HotspotData *hotspot);
|
||||||
|
void doOperate(HotspotData *hotspot, Action action);
|
||||||
|
void doOpen(HotspotData *hotspot);
|
||||||
|
void doClose(HotspotData *hotspot);
|
||||||
|
void doLockUnlock(HotspotData *hotspot);
|
||||||
|
void doUse(HotspotData *hotspot);
|
||||||
|
void doGive(HotspotData *hotspot);
|
||||||
|
void doTalkTo(HotspotData *hotspot);
|
||||||
|
void doTell(HotspotData *hotspot);
|
||||||
|
void doLook();
|
||||||
|
void doLookAt(HotspotData *hotspot);
|
||||||
|
void doAsk(HotspotData *hotspot);
|
||||||
|
void doDrink();
|
||||||
|
void doStatus();
|
||||||
|
void doBribe(HotspotData *hotspot);
|
||||||
|
void doExamine();
|
||||||
|
void doSimple(HotspotData *hotspot, Action action);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ManagedList<Hotspot *> HotspotList;
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
151
lure/intro.cpp
Normal file
151
lure/intro.cpp
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/intro.h"
|
||||||
|
#include "lure/animseq.h"
|
||||||
|
#include "lure/events.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
struct AnimRecord {
|
||||||
|
uint16 resourceId;
|
||||||
|
uint8 paletteIndex;
|
||||||
|
bool initialPause;
|
||||||
|
bool endingPause;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint16 start_screens[] = {0x18, 0x1A, 0x1E, 0x1C, 0};
|
||||||
|
static const AnimRecord anim_screens[] = {{0x40, 0, true, true}, {0x42, 1, false, true},
|
||||||
|
{0x44, 2, false, false}, {0x24, 3, false, true}, {0x46, 3, false, false},
|
||||||
|
{0, 0, false, false}};
|
||||||
|
|
||||||
|
// showScreen
|
||||||
|
// Shows a screen by loading it from the given resource, and then fading it in
|
||||||
|
// with a palette in the following resource. Returns true if the introduction
|
||||||
|
// should be aborted
|
||||||
|
|
||||||
|
bool Introduction::showScreen(uint16 screenId, uint16 paletteId, uint16 delaySize) {
|
||||||
|
_screen.screen().loadScreen(screenId);
|
||||||
|
_screen.update();
|
||||||
|
Palette p(paletteId);
|
||||||
|
_screen.paletteFadeIn(&p);
|
||||||
|
|
||||||
|
bool result = delay(delaySize);
|
||||||
|
if (Events::getReference().quitFlag) return true;
|
||||||
|
|
||||||
|
_screen.paletteFadeOut();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delay
|
||||||
|
// Delays for a given number of milliseconds. If it returns true, it indicates that
|
||||||
|
// Escape has been pressed, and the introduction should be aborted.
|
||||||
|
|
||||||
|
bool Introduction::delay(uint32 milliseconds) {
|
||||||
|
Events &events = Events::getReference();
|
||||||
|
uint32 delayCtr = _system.getMillis() + milliseconds;
|
||||||
|
|
||||||
|
while (_system.getMillis() < delayCtr) {
|
||||||
|
if (events.quitFlag) return true;
|
||||||
|
|
||||||
|
if (events.pollEvent()) {
|
||||||
|
if (events.type() == OSystem::EVENT_KEYDOWN)
|
||||||
|
return events.event().kbd.keycode == 27;
|
||||||
|
else if (events.type() == OSystem::EVENT_LBUTTONDOWN)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 delayAmount = delayCtr - _system.getMillis();
|
||||||
|
if (delayAmount > 10) delayAmount = 10;
|
||||||
|
_system.delayMillis(delayAmount);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// show
|
||||||
|
// Main method for the introduction sequence
|
||||||
|
|
||||||
|
bool Introduction::show() {
|
||||||
|
_screen.setPaletteEmpty();
|
||||||
|
|
||||||
|
// Initial game company and then game screen
|
||||||
|
|
||||||
|
for (int ctr = 0; start_screens[ctr]; ++ctr)
|
||||||
|
if (showScreen(start_screens[ctr], start_screens[ctr] + 1, 5000))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
AnimationSequence *anim;
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
// Animated screens
|
||||||
|
|
||||||
|
PaletteCollection coll(0x32);
|
||||||
|
const AnimRecord *curr_anim = anim_screens;
|
||||||
|
for (; curr_anim->resourceId; ++curr_anim)
|
||||||
|
{
|
||||||
|
bool fadeIn = curr_anim == anim_screens;
|
||||||
|
anim = new AnimationSequence(_screen, _system, curr_anim->resourceId,
|
||||||
|
coll.getPalette(curr_anim->paletteIndex), fadeIn);
|
||||||
|
if (curr_anim->initialPause)
|
||||||
|
if (delay(12000)) return true;
|
||||||
|
|
||||||
|
result = false;
|
||||||
|
switch (anim->show()) {
|
||||||
|
case ABORT_NONE:
|
||||||
|
if (curr_anim->endingPause) {
|
||||||
|
result = delay(12000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ABORT_END_INTRO:
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ABORT_NEXT_SCENE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
delete anim;
|
||||||
|
|
||||||
|
if (result) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show battle pictures one frame at a time
|
||||||
|
|
||||||
|
result = false;
|
||||||
|
anim = new AnimationSequence(_screen, _system, 0x48, coll.getPalette(4), false);
|
||||||
|
do {
|
||||||
|
result = delay(2000);
|
||||||
|
_screen.paletteFadeOut();
|
||||||
|
if (!result) result = delay(500);
|
||||||
|
if (result) break;
|
||||||
|
} while (anim->step());
|
||||||
|
delete anim;
|
||||||
|
if (result) return true;
|
||||||
|
|
||||||
|
// Show final introduction screen
|
||||||
|
|
||||||
|
showScreen(0x22, 0x21, 10000);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
45
lure/intro.h
Normal file
45
lure/intro.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_intro_h__
|
||||||
|
#define __lure_intro_h__
|
||||||
|
|
||||||
|
#include "lure/screen.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
class Introduction {
|
||||||
|
private:
|
||||||
|
Screen &_screen;
|
||||||
|
OSystem &_system;
|
||||||
|
|
||||||
|
bool showScreen(uint16 screenId, uint16 paletteId, uint16 delaySize);
|
||||||
|
bool delay(uint32 milliseconds);
|
||||||
|
public:
|
||||||
|
Introduction(Screen &screen, OSystem &system): _screen(screen), _system(system) {};
|
||||||
|
|
||||||
|
bool show();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
306
lure/lure.cpp
Normal file
306
lure/lure.cpp
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "common/md5.h"
|
||||||
|
|
||||||
|
#include "sound/mixer.h"
|
||||||
|
#include "sound/mididrv.h"
|
||||||
|
#include "sound/audiostream.h"
|
||||||
|
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/surface.h"
|
||||||
|
#include "lure/lure.h"
|
||||||
|
#include "lure/intro.h"
|
||||||
|
#include "lure/game.h"
|
||||||
|
#include "lure/system.h"
|
||||||
|
|
||||||
|
using namespace Lure;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
// We only compute MD5 of the first megabyte of our data files.
|
||||||
|
kMD5FileSizeLimit = 1024 * 1024
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LureGameSettings {
|
||||||
|
const char *name;
|
||||||
|
const char *description;
|
||||||
|
byte id;
|
||||||
|
uint32 features;
|
||||||
|
const char *md5sum;
|
||||||
|
const char *checkFile;
|
||||||
|
GameSettings toGameSettings() const {
|
||||||
|
GameSettings dummy = { name, description, features };
|
||||||
|
return dummy;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
static const LureGameSettings lure_games[] = {
|
||||||
|
{ "lure", "Lure of the Temptress (Floppy, English)", GI_LURE, GF_ENGLISH | GF_FLOPPY,
|
||||||
|
"e45ea5d279a268c7d3c6524c2f63a2d2", "disk1.vga" },
|
||||||
|
{ 0, 0, 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Keep list of different supported games
|
||||||
|
|
||||||
|
struct LureGameList {
|
||||||
|
const char *name;
|
||||||
|
const char *description;
|
||||||
|
uint32 features;
|
||||||
|
GameSettings toGameSettings() const {
|
||||||
|
GameSettings dummy = { name, description, features };
|
||||||
|
return dummy;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const LureGameList lure_list[] = {
|
||||||
|
{ "lure", "Lure of the Temptress", 0 },
|
||||||
|
{ 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
GameList Engine_LURE_gameList() {
|
||||||
|
GameList games;
|
||||||
|
const LureGameList *g = lure_list;
|
||||||
|
|
||||||
|
while (g->name) {
|
||||||
|
games.push_back(g->toGameSettings());
|
||||||
|
g++;
|
||||||
|
}
|
||||||
|
return games;
|
||||||
|
}
|
||||||
|
|
||||||
|
DetectedGameList Engine_LURE_detectGames(const FSList &fslist) {
|
||||||
|
DetectedGameList detectedGames;
|
||||||
|
const LureGameSettings *g;
|
||||||
|
FSList::const_iterator file;
|
||||||
|
|
||||||
|
// Iterate over all files in the given directory
|
||||||
|
bool isFound = false;
|
||||||
|
for (file = fslist.begin(); file != fslist.end(); file++) {
|
||||||
|
if (file->isDirectory())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (g = lure_games; g->name; g++) {
|
||||||
|
if (scumm_stricmp(file->displayName().c_str(), g->checkFile) == 0)
|
||||||
|
isFound = true;
|
||||||
|
}
|
||||||
|
if (isFound)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file == fslist.end())
|
||||||
|
return detectedGames;
|
||||||
|
|
||||||
|
uint8 md5sum[16];
|
||||||
|
char md5str[32 + 1];
|
||||||
|
|
||||||
|
if (Common::md5_file(file->path().c_str(), md5sum, NULL, kMD5FileSizeLimit)) {
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
sprintf(md5str + i * 2, "%02x", (int)md5sum[i]);
|
||||||
|
}
|
||||||
|
for (g = lure_games; g->name; g++) {
|
||||||
|
if (strcmp(g->md5sum, (char *)md5str) == 0) {
|
||||||
|
detectedGames.push_back(g->toGameSettings());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (detectedGames.isEmpty()) {
|
||||||
|
debug("Unknown MD5 (%s)! Please report the details (language, platform, etc.) of this game to the ScummVM team\n", md5str);
|
||||||
|
|
||||||
|
const LureGameList *g1 = lure_list;
|
||||||
|
while (g1->name) {
|
||||||
|
detectedGames.push_back(g1->toGameSettings());
|
||||||
|
g1++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return detectedGames;
|
||||||
|
}
|
||||||
|
|
||||||
|
Engine *Engine_LURE_create(GameDetector *detector, OSystem *system) {
|
||||||
|
return new LureEngine(detector, system);
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_PLUGIN(LURE, "Lure of the Temptress Engine")
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
LureEngine::LureEngine(GameDetector *detector, OSystem *system): Engine(system) {
|
||||||
|
// Setup mixer
|
||||||
|
/*
|
||||||
|
if (!_mixer->isReady()) {
|
||||||
|
warning("Sound initialization failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
|
||||||
|
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
|
||||||
|
_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
|
||||||
|
*/
|
||||||
|
_features = 0;
|
||||||
|
_game = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LureEngine::detectGame() {
|
||||||
|
// Make sure all the needed files are present
|
||||||
|
|
||||||
|
if (!Common::File::exists(SUPPORT_FILENAME))
|
||||||
|
error("Missing %s - this is a custom file containing resources from the\n"
|
||||||
|
"Lure of the Temptress executable. See the documentation for creating it.",
|
||||||
|
SUPPORT_FILENAME);
|
||||||
|
|
||||||
|
for (uint8 fileNum = 1; fileNum <= 4; ++fileNum)
|
||||||
|
{
|
||||||
|
char sFilename[10];
|
||||||
|
sprintf(sFilename, "disk%d.vga", fileNum);
|
||||||
|
|
||||||
|
if (!Common::File::exists(sFilename))
|
||||||
|
error("Missing disk%d.vga", fileNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the version of the lure.dat file
|
||||||
|
Common::File f;
|
||||||
|
if (!f.open(SUPPORT_FILENAME)) {
|
||||||
|
error("Error opening %s for validation", SUPPORT_FILENAME);
|
||||||
|
} else {
|
||||||
|
f.seek(0xbf * 8);
|
||||||
|
VersionStructure version;
|
||||||
|
f.read(&version, sizeof(VersionStructure));
|
||||||
|
f.close();
|
||||||
|
|
||||||
|
if (READ_LE_UINT16(&version.id) != 0xffff)
|
||||||
|
error("Error validating %s - file is invalid or out of date", SUPPORT_FILENAME);
|
||||||
|
else if ((version.vMajor != LURE_DAT_MAJOR) || (version.vMinor != LURE_DAT_MINOR))
|
||||||
|
error("Incorrect version of %s file - expected %d.%d but got %d.%d",
|
||||||
|
SUPPORT_FILENAME, LURE_DAT_MAJOR, LURE_DAT_MINOR,
|
||||||
|
version.vMajor, version.vMinor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do an md5 check
|
||||||
|
|
||||||
|
uint8 md5sum[16];
|
||||||
|
char md5str[32 + 1];
|
||||||
|
const LureGameSettings *g;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
*md5str = 0;
|
||||||
|
|
||||||
|
for (g = lure_games; g->name; g++) {
|
||||||
|
if (!Common::File::exists(g->checkFile))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (Common::md5_file(g->checkFile, md5sum, ConfMan.get("path").c_str(), kMD5FileSizeLimit)) {
|
||||||
|
for (int j = 0; j < 16; j++) {
|
||||||
|
sprintf(md5str + j * 2, "%02x", (int)md5sum[j]);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strcmp(g->md5sum, (char *)md5str) == 0) {
|
||||||
|
_features = g->features;
|
||||||
|
_game = g->id;
|
||||||
|
|
||||||
|
if (g->description)
|
||||||
|
g_system->setWindowCaption(g->description);
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
debug("Unknown MD5 (%s)! Please report the details (language, platform, etc.) of this game to the ScummVM team", md5str);
|
||||||
|
_features = GF_LNGUNK || GF_FLOPPY;
|
||||||
|
_game = GI_LURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int LureEngine::init(GameDetector &detector) {
|
||||||
|
_system->beginGFXTransaction();
|
||||||
|
initCommonGFX(detector);
|
||||||
|
_system->initSize(FULL_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
|
||||||
|
_system->endGFXTransaction();
|
||||||
|
|
||||||
|
detectGame();
|
||||||
|
|
||||||
|
_sys = new System(_system);
|
||||||
|
_disk = new Disk(_gameDataPath);
|
||||||
|
_resources = new Resources();
|
||||||
|
_strings = new StringData();
|
||||||
|
_screen = new Screen(*_system);
|
||||||
|
_mouse = new Mouse(*_system);
|
||||||
|
_events = new Events(*_system, *_mouse);
|
||||||
|
_menu = new Menu(*_system);
|
||||||
|
Surface::initialise();
|
||||||
|
_room = new Room();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LureEngine::~LureEngine() {
|
||||||
|
Surface::deinitialise();
|
||||||
|
delete _room;
|
||||||
|
delete _menu;
|
||||||
|
delete _events;
|
||||||
|
delete _mouse;
|
||||||
|
delete _screen;
|
||||||
|
delete _strings;
|
||||||
|
delete _resources;
|
||||||
|
delete _disk;
|
||||||
|
delete _sys;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LureEngine::go() {
|
||||||
|
// Show the introduction
|
||||||
|
Introduction *intro = new Introduction(*_screen, *_system);
|
||||||
|
intro->show();
|
||||||
|
delete intro;
|
||||||
|
|
||||||
|
// Play the game
|
||||||
|
if (!_events->quitFlag) {
|
||||||
|
// Play the game
|
||||||
|
Game *gameInstance = new Game();
|
||||||
|
gameInstance->execute();
|
||||||
|
delete gameInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
//quitGame();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LureEngine::errorString(const char *buf1, char *buf2) {
|
||||||
|
strcpy(buf2, buf1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LureEngine::quitGame() {
|
||||||
|
_system->quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
73
lure/lure.h
Normal file
73
lure/lure.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __LURE_H__
|
||||||
|
#define __LURE_H__
|
||||||
|
|
||||||
|
#include "base/engine.h"
|
||||||
|
#include "common/rect.h"
|
||||||
|
#include "sound/mixer.h"
|
||||||
|
#include "common/file.h"
|
||||||
|
|
||||||
|
#include "lure/disk.h"
|
||||||
|
#include "lure/res.h"
|
||||||
|
#include "lure/screen.h"
|
||||||
|
#include "lure/events.h"
|
||||||
|
#include "lure/menu.h"
|
||||||
|
#include "lure/system.h"
|
||||||
|
#include "lure/strings.h"
|
||||||
|
#include "lure/room.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
class LureEngine : public Engine {
|
||||||
|
private:
|
||||||
|
uint32 _features;
|
||||||
|
uint8 _game;
|
||||||
|
Disk *_disk;
|
||||||
|
Resources *_resources;
|
||||||
|
Screen *_screen;
|
||||||
|
Mouse *_mouse;
|
||||||
|
Events *_events;
|
||||||
|
Menu *_menu;
|
||||||
|
System *_sys;
|
||||||
|
StringData *_strings;
|
||||||
|
Room *_room;
|
||||||
|
|
||||||
|
void detectGame();
|
||||||
|
public:
|
||||||
|
LureEngine(GameDetector *detector, OSystem *system);
|
||||||
|
~LureEngine();
|
||||||
|
|
||||||
|
virtual int init(GameDetector &detector);
|
||||||
|
virtual int go();
|
||||||
|
virtual void errorString(const char *buf_input, char *buf_output);
|
||||||
|
void quitGame();
|
||||||
|
|
||||||
|
uint32 features() { return _features; }
|
||||||
|
uint8 game() { return _game; }
|
||||||
|
Disk &disk() { return *_disk; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
183
lure/luredefs.h
Normal file
183
lure/luredefs.h
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __luredefs_h__
|
||||||
|
#define __luredefs_h__
|
||||||
|
|
||||||
|
#include "common/stdafx.h"
|
||||||
|
#include "common/scummsys.h"
|
||||||
|
#include "common/list.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
#define LURE_DEBUG 1
|
||||||
|
|
||||||
|
#define READ_LE_INT16(x) (int16) READ_LE_UINT16(x)
|
||||||
|
#define READ_LE_INT32(x) (int32) READ_LE_UINT32(x)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
GF_FLOPPY = 1 << 0,
|
||||||
|
GF_ENGLISH = 1 << 1,
|
||||||
|
GF_LNGUNK = 1 << 15
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
GI_LURE = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Action {
|
||||||
|
GET = 1,
|
||||||
|
DROP = 0,
|
||||||
|
PUSH = 3,
|
||||||
|
PULL = 4,
|
||||||
|
OPERATE = 5,
|
||||||
|
OPEN = 6,
|
||||||
|
CLOSE = 7,
|
||||||
|
LOCK = 8,
|
||||||
|
UNLOCK = 9,
|
||||||
|
USE = 10,
|
||||||
|
GIVE = 11,
|
||||||
|
TALK_TO = 12,
|
||||||
|
TELL = 13,
|
||||||
|
BUY = 14,
|
||||||
|
LOOK = 15,
|
||||||
|
LOOK_AT = 16,
|
||||||
|
LOOK_THROUGH = 17,
|
||||||
|
ASK = 18,
|
||||||
|
EAT = 0,
|
||||||
|
DRINK = 20,
|
||||||
|
STATUS = 21,
|
||||||
|
GO_TO = 22,
|
||||||
|
RETURN = 23,
|
||||||
|
BRIBE = 24,
|
||||||
|
EXAMINE = 25,
|
||||||
|
NONE = 0xffff
|
||||||
|
};
|
||||||
|
|
||||||
|
// Basic game dimensions
|
||||||
|
#define FULL_SCREEN_WIDTH 320
|
||||||
|
#define FULL_SCREEN_HEIGHT 200
|
||||||
|
#define GAME_COLOURS 256
|
||||||
|
#define SCREEN_SIZE (FULL_SCREEN_HEIGHT * FULL_SCREEN_WIDTH)
|
||||||
|
|
||||||
|
#define SUPPORT_FILENAME "lure.dat"
|
||||||
|
#define LURE_DAT_MAJOR 1
|
||||||
|
#define LURE_DAT_MINOR 1
|
||||||
|
|
||||||
|
// Some resources include multiple packed palettes of 64 entries each
|
||||||
|
#define SUB_PALETTE_SIZE 64
|
||||||
|
// Palette resources have 220 palette entries
|
||||||
|
#define RES_PALETTE_ENTRIES 220
|
||||||
|
// Palette colour increment amouns for palette fade in/outs
|
||||||
|
#define PALETTE_FADE_INC_SIZE 4
|
||||||
|
|
||||||
|
// Specifies the maximum buffer sized allocated for decoding animation data
|
||||||
|
#define MAX_ANIM_DECODER_BUFFER_SIZE 200000
|
||||||
|
|
||||||
|
#define MAX_DESC_SIZE 1024
|
||||||
|
#define MAX_HOTSPOT_NAME_SIZE 80
|
||||||
|
#define MAX_ACTION_NAME_SIZE 15
|
||||||
|
|
||||||
|
// Menubar constants
|
||||||
|
#define MENUBAR_Y_SIZE 8
|
||||||
|
|
||||||
|
// Cursor definitions
|
||||||
|
#define CURSOR_WIDTH 16
|
||||||
|
#define CURSOR_HEIGHT 16
|
||||||
|
#define CURSOR_SIZE 256
|
||||||
|
#define CURSOR_RESOURCE_ID 1
|
||||||
|
#define CURSOR_ARROW 0
|
||||||
|
#define CURSOR_DISK 1
|
||||||
|
#define CURSOR_TIME_START 2
|
||||||
|
#define CURSOR_TIME_END 9
|
||||||
|
#define CURSOR_CROSS 10
|
||||||
|
#define CURSOR_MENUBAR 17
|
||||||
|
|
||||||
|
// Font details
|
||||||
|
#define FONT_RESOURCE_ID 4
|
||||||
|
#define NUM_CHARS_IN_FONT 122
|
||||||
|
#define FONT_WIDTH 8
|
||||||
|
#define FONT_HEIGHT 8
|
||||||
|
|
||||||
|
// Menu constants
|
||||||
|
#define MENUBAR_SELECTED_COLOUR 0xf7
|
||||||
|
#define MENU_UNSELECTED_COLOUR 0xe2
|
||||||
|
#define MENU_SELECTED_COLOUR 0xe3
|
||||||
|
#define MENUITEM_NONE 0
|
||||||
|
#define MENUITEM_CREDITS 1
|
||||||
|
#define MENUITEM_RESTART_GAME 2
|
||||||
|
#define MENUITEM_SAVE_GAME 3
|
||||||
|
#define MENUITEM_RESTORE_GAME 4
|
||||||
|
#define MENUITEM_QUIT 5
|
||||||
|
#define MENUITEM_TEXT_SPEED 6
|
||||||
|
#define MENUITEM_SOUND 7
|
||||||
|
|
||||||
|
// Mouse change needed to change an item in a popup menu
|
||||||
|
#define POPMENU_CHANGE_SENSITIVITY 5
|
||||||
|
|
||||||
|
// Dialog related defines
|
||||||
|
#define DIALOG_EDGE_SIZE 9
|
||||||
|
#define DIALOG_TEXT_COLOUR 0xe2
|
||||||
|
#define DIALOG_WHITE_COLOUR 0xe3
|
||||||
|
#define INFO_DIALOG_X 69
|
||||||
|
#define INFO_DIALOG_Y 61
|
||||||
|
#define INFO_DIALOG_WIDTH 191
|
||||||
|
|
||||||
|
// Strings defines
|
||||||
|
#define STRINGS_RESOURCE_ID 0x10
|
||||||
|
#define STRINGS_2_RESOURCE_ID 0x11
|
||||||
|
#define STRINGS_3_RESOURCE_ID 0x12
|
||||||
|
#define STRING_ID_RANGE 0x7d0
|
||||||
|
#define STRING_ID_UPPER 0xfa0
|
||||||
|
|
||||||
|
// Custom resources stored in lure.dat
|
||||||
|
#define GAME_PALETTE_RESOURCE_ID 0x3f01
|
||||||
|
#define ALT_PALETTE_RESOURCE_ID 0x3f02
|
||||||
|
#define DIALOG_RESOURCE_ID 0x3f03
|
||||||
|
#define ROOM_DATA_RESOURCE_ID 0x3f04
|
||||||
|
#define HOTSPOT_DATA_RESOURCE_ID 0x3f05
|
||||||
|
#define HOTSPOT_OVERRIDE_DATA_RESOURCE_ID 0x3f06
|
||||||
|
#define ROOM_EXITS_RESOURCE_ID 0x3f07
|
||||||
|
#define ROOM_EXIT_JOINS_RESOURCE_ID 0x3f08
|
||||||
|
#define ANIM_DATA_RESOURCE_ID 0x3f09
|
||||||
|
#define SCRIPT_DATA_RESOURCE_ID 0x3f0a
|
||||||
|
#define SCRIPT2_DATA_RESOURCE_ID 0x3f0b
|
||||||
|
#define HOTSPOT_SCRIPT_LIST_RESOURCE_ID 0x3f0c
|
||||||
|
#define MESSAGES_LIST_RESOURCE_ID 0x3f0d
|
||||||
|
#define ACTION_LIST_RESOURCE_ID 0x3f0e
|
||||||
|
|
||||||
|
// Script constants
|
||||||
|
#define STARTUP_SCRIPT 0x23FC
|
||||||
|
|
||||||
|
// Miscellaneous resources
|
||||||
|
#define CREDITS_RESOURCE_ID 0x7800
|
||||||
|
#define NAMES_RESOURCE_ID 9
|
||||||
|
#define PLAYER_ID 0x3E8
|
||||||
|
#define RATPOUCH_ID 0x3E9
|
||||||
|
#define START_NONVISUAL_HOTSPOT_ID 0x7530
|
||||||
|
|
||||||
|
// Milliseconds delay between game frames
|
||||||
|
#define GAME_FRAME_DELAY 100
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
107
lure/memory.cpp
Normal file
107
lure/memory.cpp
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/memory.h"
|
||||||
|
#include "common/file.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
MemoryBlock *Memory::allocate(uint32 size) {
|
||||||
|
MemoryBlock *block = new MemoryBlock(size);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock *Memory::duplicate(MemoryBlock *src) {
|
||||||
|
MemoryBlock *block = new MemoryBlock(src);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 *Memory::alloc(uint32 size) {
|
||||||
|
return (uint8 *) malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Memory::dealloc(uint8 *block) {
|
||||||
|
free(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
MemoryBlock::MemoryBlock(uint32 size1) {
|
||||||
|
_data = (uint8 *) malloc(size1);
|
||||||
|
if (!_data) error ("Failed allocating memory block");
|
||||||
|
_size = size1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock::MemoryBlock(MemoryBlock *src) {
|
||||||
|
_size = src->size();
|
||||||
|
_data = (uint8 *) malloc(_size);
|
||||||
|
if (!_data) error ("Failed allocating memory block");
|
||||||
|
memcpy(_data, src->data(), _size);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock::~MemoryBlock() {
|
||||||
|
free(_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::empty() {
|
||||||
|
::memset(_data, 0, _size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::memset(int c, size_t startIndex, size_t num) {
|
||||||
|
byte *p = _data + startIndex;
|
||||||
|
::memset(p, c, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::copyFrom(MemoryBlock *src) {
|
||||||
|
copyFrom(src, 0, 0, src->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::copyFrom(MemoryBlock *src, uint32 srcPos, uint32 destPos, uint32 srcLen) {
|
||||||
|
if ((srcPos + srcLen > src->size()) || (destPos + srcLen > size()))
|
||||||
|
error("Memory block overrun in block copy");
|
||||||
|
|
||||||
|
uint8 *pDest = _data + destPos;
|
||||||
|
uint8 *pSrc = src->data() + srcPos;
|
||||||
|
memcpy(pDest, pSrc, srcLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::copyFrom(const byte *src, uint32 srcPos, uint32 destPos, uint32 srcLen) {
|
||||||
|
byte *pDest = _data + destPos;
|
||||||
|
const byte *pSrc = src + srcPos;
|
||||||
|
memcpy(pDest, pSrc, srcLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::reallocate(uint32 size1) {
|
||||||
|
_size = size1;
|
||||||
|
_data = (byte *) realloc(_data, size1);
|
||||||
|
if (!_data) error ("Failed reallocating memory block");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::saveToFile(const Common::String &filename) {
|
||||||
|
Common::File *f = new Common::File();
|
||||||
|
f->open(filename.c_str(), Common::File::kFileWriteMode);
|
||||||
|
f->write(_data, _size);
|
||||||
|
f->close();
|
||||||
|
delete f;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
63
lure/memory.h
Normal file
63
lure/memory.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_memory_h__
|
||||||
|
#define __lure_memory_h__
|
||||||
|
|
||||||
|
#include "common/stdafx.h"
|
||||||
|
#include "common/system.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
class MemoryBlock {
|
||||||
|
private:
|
||||||
|
byte *_data;
|
||||||
|
uint32 _size;
|
||||||
|
public:
|
||||||
|
MemoryBlock(uint32 size);
|
||||||
|
MemoryBlock(MemoryBlock *src);
|
||||||
|
~MemoryBlock();
|
||||||
|
|
||||||
|
byte *data() { return _data; }
|
||||||
|
uint32 size() { return _size; }
|
||||||
|
|
||||||
|
void empty();
|
||||||
|
void memset(int c, size_t startIndex, size_t num);
|
||||||
|
void copyFrom(MemoryBlock *src);
|
||||||
|
void copyFrom(MemoryBlock *src, uint32 srcPos, uint32 destPos, uint32 srcLen);
|
||||||
|
void copyFrom(const byte *src, uint32 srcPos, uint32 destPos, uint32 srcLen);
|
||||||
|
void reallocate(uint32 size);
|
||||||
|
void saveToFile(const Common::String &filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Memory {
|
||||||
|
public:
|
||||||
|
static MemoryBlock *allocate(uint32 size);
|
||||||
|
static MemoryBlock *duplicate(MemoryBlock *src);
|
||||||
|
static uint8 *alloc(uint32 size);
|
||||||
|
static void dealloc(uint8 *block);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namspace Lure
|
||||||
|
|
||||||
|
#endif
|
415
lure/menu.cpp
Normal file
415
lure/menu.cpp
Normal file
|
@ -0,0 +1,415 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/menu.h"
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/decode.h"
|
||||||
|
#include "lure/surface.h"
|
||||||
|
#include "lure/system.h"
|
||||||
|
#include "lure/res_struct.h"
|
||||||
|
#include "lure/res.h"
|
||||||
|
#include "lure/strings.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
MenuRecord::MenuRecord(uint16 hsxstartVal, uint16 hsxendVal, uint16 xstartVal,
|
||||||
|
uint16 widthVal, const char *strings) {
|
||||||
|
_xstart = xstartVal; _width = widthVal;
|
||||||
|
_hsxstart = hsxstartVal; _hsxend = hsxendVal;
|
||||||
|
|
||||||
|
// Figure out the number of entries
|
||||||
|
const char *sPtr = strings;
|
||||||
|
_numEntries = 1;
|
||||||
|
while ((sPtr = strchr(sPtr, ',')) != NULL) {
|
||||||
|
++_numEntries;
|
||||||
|
++sPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up the list of entries
|
||||||
|
char *sCopy = strdup(strings);
|
||||||
|
char *s;
|
||||||
|
_entries = (char **) malloc(sizeof(char *) * _numEntries);
|
||||||
|
uint8 index = 0;
|
||||||
|
s = sCopy;
|
||||||
|
while (s != NULL) {
|
||||||
|
_entries[index++] = s;
|
||||||
|
s = strchr(s, ',');
|
||||||
|
if (s != NULL) *s++ = '\0'; // replace comma with NULL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuRecord::~MenuRecord() {
|
||||||
|
delete _entries[0]; // Delete string data for all the menu items
|
||||||
|
free(_entries); // Free the list
|
||||||
|
}
|
||||||
|
|
||||||
|
char *MenuRecord::getEntry(uint8 index) {
|
||||||
|
if (index >= _numEntries) error("Invalid menuitem index specified: %d", index);
|
||||||
|
return _entries[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static Menu *int_menu = NULL;
|
||||||
|
|
||||||
|
Menu::Menu(OSystem &system): _system(system), _screen(Screen::getReference()),
|
||||||
|
_events(Events::getReference()), _mouse(Mouse::getReference()) {
|
||||||
|
int_menu = this;
|
||||||
|
|
||||||
|
MemoryBlock *res = Disk::getReference().getEntry(5);
|
||||||
|
PictureDecoder decoder;
|
||||||
|
_menu = decoder.decode(res, SCREEN_SIZE);
|
||||||
|
delete res;
|
||||||
|
|
||||||
|
_menus[0] = new MenuRecord(40, 87, 20, 80, "Credits");
|
||||||
|
_menus[1] = new MenuRecord(127, 179, 100, 120, "Restart game,Save game,Restore game");
|
||||||
|
_menus[2] = new MenuRecord(224, 281, 210, 105, "Quit,Slow Text\x8b,Sound on ");
|
||||||
|
_selectedMenu = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Menu::~Menu() {
|
||||||
|
for (int ctr=0; ctr<NUM_MENUS; ++ctr) delete _menus[ctr];
|
||||||
|
delete _menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
Menu &Menu::getReference() {
|
||||||
|
return *int_menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 Menu::execute() {
|
||||||
|
_mouse.setCursorNum(CURSOR_ARROW);
|
||||||
|
_system.copyRectToScreen(_menu->data(), FULL_SCREEN_WIDTH, 0, 0, FULL_SCREEN_WIDTH, MENUBAR_Y_SIZE);
|
||||||
|
_system.updateScreen();
|
||||||
|
|
||||||
|
_selectedMenu = NULL;
|
||||||
|
_surfaceMenu = NULL;
|
||||||
|
_selectedIndex = 0;
|
||||||
|
|
||||||
|
while (_mouse.lButton()) {
|
||||||
|
if (_events.pollEvent()) {
|
||||||
|
// handle events
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_mouse.y() < MENUBAR_Y_SIZE)
|
||||||
|
{
|
||||||
|
MenuRecord *p = getMenuAt(_mouse.x());
|
||||||
|
|
||||||
|
if (_selectedMenu != p) {
|
||||||
|
// If necessary, remove prior menu
|
||||||
|
if (_selectedMenu) {
|
||||||
|
toggleHighlight(_selectedMenu);
|
||||||
|
_screen.updateArea(_selectedMenu->xstart(), MENUBAR_Y_SIZE,
|
||||||
|
_surfaceMenu->width(), _surfaceMenu->height());
|
||||||
|
delete _surfaceMenu;
|
||||||
|
_surfaceMenu = NULL;
|
||||||
|
_selectedIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_selectedMenu = p;
|
||||||
|
|
||||||
|
// If a new menu is selected, show it
|
||||||
|
if (_selectedMenu) {
|
||||||
|
toggleHighlight(_selectedMenu);
|
||||||
|
_surfaceMenu = Surface::newDialog(
|
||||||
|
_selectedMenu->width(), _selectedMenu->numEntries(),
|
||||||
|
_selectedMenu->entries(), false, MENU_UNSELECTED_COLOUR);
|
||||||
|
_surfaceMenu->copyToScreen(_selectedMenu->xstart(), MENUBAR_Y_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
_system.copyRectToScreen(_menu->data(), FULL_SCREEN_WIDTH, 0, 0, FULL_SCREEN_WIDTH, MENUBAR_Y_SIZE);
|
||||||
|
_system.updateScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for changing selected index
|
||||||
|
uint8 index = getIndexAt(_mouse.x(), _mouse.y());
|
||||||
|
if (index != _selectedIndex) {
|
||||||
|
if (_selectedIndex != 0) toggleHighlightItem(_selectedIndex);
|
||||||
|
_selectedIndex = index;
|
||||||
|
if (_selectedIndex != 0) toggleHighlightItem(_selectedIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_surfaceMenu) delete _surfaceMenu;
|
||||||
|
|
||||||
|
// Deselect the currently selected menu header
|
||||||
|
if (_selectedMenu)
|
||||||
|
toggleHighlight(_selectedMenu);
|
||||||
|
|
||||||
|
// Restore the previous screen
|
||||||
|
_screen.update();
|
||||||
|
|
||||||
|
if (_selectedMenu == NULL) return MENUITEM_NONE;
|
||||||
|
else if (_selectedMenu == _menus[0]) return MENUITEM_CREDITS;
|
||||||
|
else if (_selectedMenu == _menus[1]) {
|
||||||
|
switch (_selectedIndex) {
|
||||||
|
case 1: return MENUITEM_RESTART_GAME;
|
||||||
|
case 2: return MENUITEM_SAVE_GAME;
|
||||||
|
case 3: return MENUITEM_RESTORE_GAME;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (_selectedIndex) {
|
||||||
|
case 1: return MENUITEM_QUIT;
|
||||||
|
case 2: return MENUITEM_TEXT_SPEED;
|
||||||
|
case 3: return MENUITEM_SOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MENUITEM_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuRecord *Menu::getMenuAt(int x) {
|
||||||
|
for (int ctr = 0; ctr < NUM_MENUS; ++ctr)
|
||||||
|
if ((x >= _menus[ctr]->hsxstart()) && (x <= _menus[ctr]->hsxend()))
|
||||||
|
return _menus[ctr];
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 Menu::getIndexAt(uint16 x, uint16 y) {
|
||||||
|
if (!_selectedMenu) return 0;
|
||||||
|
|
||||||
|
int ys = MENUBAR_Y_SIZE + DIALOG_EDGE_SIZE + 3;
|
||||||
|
int ye = MENUBAR_Y_SIZE + _surfaceMenu->height() - DIALOG_EDGE_SIZE - 3;
|
||||||
|
if ((y < ys) || (y > ye)) return 0;
|
||||||
|
|
||||||
|
uint16 yRelative = y - ys;
|
||||||
|
uint8 index = (uint8) (yRelative / 8) + 1;
|
||||||
|
if (index > _selectedMenu->numEntries()) index = _selectedMenu->numEntries();
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::toggleHighlight(MenuRecord *menuRec) {
|
||||||
|
byte *addr = _menu->data();
|
||||||
|
|
||||||
|
for (uint16 y=0; y<MENUBAR_Y_SIZE; ++y) {
|
||||||
|
for (uint16 x=menuRec->hsxstart(); x<=menuRec->hsxend(); ++x) {
|
||||||
|
if (addr[x] == MENUBAR_SELECTED_COLOUR) addr[x] = 0;
|
||||||
|
else if (addr[x] == 0) addr[x] = MENUBAR_SELECTED_COLOUR;
|
||||||
|
}
|
||||||
|
addr += FULL_SCREEN_WIDTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::toggleHighlightItem(uint8 index) {
|
||||||
|
byte *p = _surfaceMenu->data().data() + (DIALOG_EDGE_SIZE + 3 +
|
||||||
|
((index - 1) * 8)) * _surfaceMenu->width();
|
||||||
|
uint32 numBytes = 8 * _surfaceMenu->width();
|
||||||
|
|
||||||
|
while (numBytes-- > 0) {
|
||||||
|
if (*p == MENU_UNSELECTED_COLOUR) *p = MENU_SELECTED_COLOUR;
|
||||||
|
else if (*p == MENU_SELECTED_COLOUR) *p = MENU_UNSELECTED_COLOUR;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
_surfaceMenu->copyToScreen(_selectedMenu->xstart(), MENUBAR_Y_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
uint16 PopupMenu::ShowInventory() {
|
||||||
|
Resources &rsc = Resources::getReference();
|
||||||
|
StringData &strings = StringData::getReference();
|
||||||
|
|
||||||
|
uint16 numItems = rsc.numInventoryItems();
|
||||||
|
uint16 itemCtr = 0;
|
||||||
|
char **itemNames = (char **) Memory::alloc(sizeof(char *) * numItems);
|
||||||
|
uint16 *idList = (uint16 *) Memory::alloc(sizeof(uint16) * numItems);
|
||||||
|
|
||||||
|
HotspotDataList::iterator i;
|
||||||
|
for (i = rsc.hotspotData().begin(); i != rsc.hotspotData().end(); ++i) {
|
||||||
|
HotspotData *hotspot = *i;
|
||||||
|
if (hotspot->roomNumber == PLAYER_ID) {
|
||||||
|
idList[itemCtr] = hotspot->hotspotId;
|
||||||
|
char *hotspotName = itemNames[itemCtr++] = (char *) malloc(MAX_HOTSPOT_NAME_SIZE);
|
||||||
|
strings.getString(hotspot->nameId, hotspotName, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 result = Show(numItems, (const char **) itemNames);
|
||||||
|
if (result != 0xffff) result = idList[result];
|
||||||
|
|
||||||
|
for (itemCtr = 0; itemCtr < numItems; ++itemCtr)
|
||||||
|
free(itemNames[itemCtr]);
|
||||||
|
|
||||||
|
delete itemNames;
|
||||||
|
delete idList;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Action PopupMenu::Show(uint32 actionMask) {
|
||||||
|
int numEntries = 0;
|
||||||
|
uint32 v = actionMask;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
for (index = 1; index <= EXAMINE; ++index, v >>= 1) {
|
||||||
|
if (v & 1) ++numEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char **strList = (const char **) Memory::alloc(sizeof(char *) * numEntries);
|
||||||
|
|
||||||
|
v = actionMask;
|
||||||
|
int strIndex = 0;
|
||||||
|
for (index=1; index<=EXAMINE; ++index, v >>= 1) {
|
||||||
|
if (v & 1)
|
||||||
|
strList[strIndex++] = actionList[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 result = Show(numEntries, strList);
|
||||||
|
|
||||||
|
if (result == 0xffff) return NONE;
|
||||||
|
|
||||||
|
v = actionMask;
|
||||||
|
for (index = 1; index <= EXAMINE; ++index, v >>= 1) {
|
||||||
|
if (v & 1)
|
||||||
|
if (result-- == 0) return (Action) index;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete strList;
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Action PopupMenu::Show(int numEntries, Action *actions) {
|
||||||
|
const char **strList = (const char **) Memory::alloc(sizeof(char *) * numEntries);
|
||||||
|
Action *actionPtr = actions;
|
||||||
|
for (int index = 0; index < numEntries; ++index)
|
||||||
|
strList[index] = actionList[*actionPtr++];
|
||||||
|
uint16 result = Show(numEntries, strList);
|
||||||
|
|
||||||
|
delete strList;
|
||||||
|
if (result == 0xffff) return NONE;
|
||||||
|
else return actions[result];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 PopupMenu::Show(int numEntries, const char *actions[]) {
|
||||||
|
if (numEntries == 0) return 0xffff;
|
||||||
|
Events &e = Events::getReference();
|
||||||
|
Mouse &mouse = Mouse::getReference();
|
||||||
|
OSystem &system = System::getReference();
|
||||||
|
Screen &screen = Screen::getReference();
|
||||||
|
Rect r;
|
||||||
|
|
||||||
|
mouse.cursorOff();
|
||||||
|
uint16 oldX = mouse.x();
|
||||||
|
uint16 oldY = mouse.y();
|
||||||
|
const uint16 yMiddle = FULL_SCREEN_HEIGHT / 2;
|
||||||
|
mouse.setPosition(FULL_SCREEN_WIDTH / 2, yMiddle);
|
||||||
|
|
||||||
|
// Round up number of lines in dialog to next odd number
|
||||||
|
uint16 numLines = (numEntries / 2) * 2 + 1;
|
||||||
|
if (numLines > 5) numLines = 5;
|
||||||
|
|
||||||
|
// Figure out the character width
|
||||||
|
uint16 numCols = 0;
|
||||||
|
for (int ctr = 0; ctr < numEntries; ++ctr) {
|
||||||
|
int len = strlen(actions[ctr]);
|
||||||
|
if (len > numCols)
|
||||||
|
numCols = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the dialog surface
|
||||||
|
Surface *s = new Surface(DIALOG_EDGE_SIZE * 2 + numCols * FONT_WIDTH,
|
||||||
|
DIALOG_EDGE_SIZE * 2 + numLines * FONT_HEIGHT);
|
||||||
|
s->createDialog();
|
||||||
|
|
||||||
|
int selectedIndex = 0;
|
||||||
|
bool refreshFlag = true;
|
||||||
|
r.left = DIALOG_EDGE_SIZE;
|
||||||
|
r.right = s->width() - DIALOG_EDGE_SIZE - 1;
|
||||||
|
r.top = DIALOG_EDGE_SIZE;
|
||||||
|
r.bottom = s->height() - DIALOG_EDGE_SIZE - 1;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (refreshFlag) {
|
||||||
|
// Set up the contents of the menu
|
||||||
|
s->fillRect(r, 0);
|
||||||
|
|
||||||
|
for (int index = 0; index < numLines; ++index) {
|
||||||
|
int actionIndex = selectedIndex - (numEntries / 2) + index;
|
||||||
|
if ((actionIndex >= 0) && (actionIndex < numEntries)) {
|
||||||
|
s->writeString(DIALOG_EDGE_SIZE, DIALOG_EDGE_SIZE + index * FONT_HEIGHT,
|
||||||
|
actions[actionIndex], true,
|
||||||
|
(index == (numLines / 2)) ? MENU_SELECTED_COLOUR : MENU_UNSELECTED_COLOUR,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s->copyToScreen(0, yMiddle-(s->height() / 2));
|
||||||
|
system.updateScreen();
|
||||||
|
refreshFlag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.pollEvent()) {
|
||||||
|
if (e.quitFlag) {
|
||||||
|
selectedIndex = 0xffff;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.type() == OSystem::EVENT_KEYDOWN) {
|
||||||
|
byte ch = e.event().kbd.ascii;
|
||||||
|
uint16 keycode = e.event().kbd.keycode;
|
||||||
|
|
||||||
|
if (((keycode == 0x108) || (keycode == 0x111)) && (selectedIndex > 0)) {
|
||||||
|
--selectedIndex;
|
||||||
|
refreshFlag = true;
|
||||||
|
} else if (((keycode == 0x102) || (keycode == 0x112)) &&
|
||||||
|
(selectedIndex < numEntries-1)) {
|
||||||
|
++selectedIndex;
|
||||||
|
refreshFlag = true;
|
||||||
|
} else if ((ch == '\xd') || (keycode == 0x10f)) {
|
||||||
|
break;
|
||||||
|
} else if (ch == '\x1b') {
|
||||||
|
selectedIndex = 0xffff;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (e.type() == OSystem::EVENT_MOUSEMOVE) {
|
||||||
|
if ((mouse.y() < yMiddle) && (selectedIndex > 0) &&
|
||||||
|
(yMiddle-mouse.y() >= POPMENU_CHANGE_SENSITIVITY)) {
|
||||||
|
--selectedIndex;
|
||||||
|
mouse.setPosition(FULL_SCREEN_WIDTH / 2, yMiddle);
|
||||||
|
refreshFlag = true;
|
||||||
|
} else if ((mouse.y() > yMiddle) && (selectedIndex < numEntries - 1) &&
|
||||||
|
(mouse.y()-yMiddle >= POPMENU_CHANGE_SENSITIVITY)) {
|
||||||
|
++selectedIndex;
|
||||||
|
mouse.setPosition(FULL_SCREEN_WIDTH/2, yMiddle);
|
||||||
|
refreshFlag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (e.type() == OSystem::EVENT_LBUTTONDOWN) {
|
||||||
|
mouse.waitForRelease();
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else if (e.type() == OSystem::EVENT_RBUTTONDOWN) {
|
||||||
|
mouse.waitForRelease();
|
||||||
|
selectedIndex = 0xffff;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mouse.setPosition(oldX, oldY);
|
||||||
|
mouse.cursorOn();
|
||||||
|
screen.update();
|
||||||
|
return selectedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
92
lure/menu.h
Normal file
92
lure/menu.h
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_menu_h__
|
||||||
|
#define __lure_menu_h__
|
||||||
|
|
||||||
|
#include "common/stdafx.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/disk.h"
|
||||||
|
#include "lure/screen.h"
|
||||||
|
#include "lure/surface.h"
|
||||||
|
#include "lure/events.h"
|
||||||
|
|
||||||
|
#define NUM_MENUS 3
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
class MenuRecord {
|
||||||
|
private:
|
||||||
|
uint16 _xstart, _width;
|
||||||
|
uint16 _hsxstart, _hsxend;
|
||||||
|
char **_entries;
|
||||||
|
uint8 _numEntries;
|
||||||
|
public:
|
||||||
|
MenuRecord(uint16 hsxstartVal, uint16 hsxendVal, uint16 xstartVal,
|
||||||
|
uint16 widthVal, const char *strings);
|
||||||
|
~MenuRecord();
|
||||||
|
|
||||||
|
uint16 xstart() { return _xstart; }
|
||||||
|
uint16 width() { return _width; }
|
||||||
|
uint16 hsxstart() { return _hsxstart; }
|
||||||
|
uint16 hsxend() { return _hsxend; }
|
||||||
|
uint8 numEntries() { return _numEntries; }
|
||||||
|
char **entries() { return _entries; }
|
||||||
|
char *getEntry(uint8 index);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Menu {
|
||||||
|
private:
|
||||||
|
OSystem &_system;
|
||||||
|
Screen &_screen;
|
||||||
|
Events &_events;
|
||||||
|
Mouse &_mouse;
|
||||||
|
MemoryBlock *_menu;
|
||||||
|
MenuRecord *_menus[NUM_MENUS];
|
||||||
|
MenuRecord *_selectedMenu;
|
||||||
|
Surface *_surfaceMenu;
|
||||||
|
uint8 _selectedIndex;
|
||||||
|
|
||||||
|
MenuRecord *getMenuAt(int x);
|
||||||
|
uint8 getIndexAt(uint16 x, uint16 y);
|
||||||
|
void toggleHighlight(MenuRecord *menuRec);
|
||||||
|
void toggleHighlightItem(uint8 index);
|
||||||
|
public:
|
||||||
|
Menu(OSystem &system);
|
||||||
|
~Menu();
|
||||||
|
static Menu &getReference();
|
||||||
|
uint8 execute();
|
||||||
|
MenuRecord &getMenu(uint8 index) { return *_menus[index]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class PopupMenu {
|
||||||
|
public:
|
||||||
|
static Action Show(uint32 actionMask);
|
||||||
|
static Action Show(int numEntries, Action *actions);
|
||||||
|
static uint16 Show(int numEntries, const char *actions[]);
|
||||||
|
static uint16 ShowInventory();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
36
lure/module.mk
Normal file
36
lure/module.mk
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
MODULE := lure
|
||||||
|
|
||||||
|
MODULE_OBJS := \
|
||||||
|
lure/animseq.o \
|
||||||
|
lure/debug-input.o \
|
||||||
|
lure/debug-methods.o \
|
||||||
|
lure/decode.o \
|
||||||
|
lure/disk.o \
|
||||||
|
lure/events.o \
|
||||||
|
lure/game.o \
|
||||||
|
lure/hotspots.o \
|
||||||
|
lure/intro.o \
|
||||||
|
lure/lure.o \
|
||||||
|
lure/memory.o \
|
||||||
|
lure/menu.o \
|
||||||
|
lure/palette.o \
|
||||||
|
lure/res.o \
|
||||||
|
lure/res_struct.o \
|
||||||
|
lure/room.o \
|
||||||
|
lure/screen.o \
|
||||||
|
lure/scripts.o \
|
||||||
|
lure/strings.o \
|
||||||
|
lure/surface.o \
|
||||||
|
lure/system.o
|
||||||
|
|
||||||
|
MODULE_DIRS += \
|
||||||
|
lure
|
||||||
|
|
||||||
|
# This module can be built as a plugin
|
||||||
|
ifdef BUILD_PLUGINS
|
||||||
|
PLUGIN := 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Include common rules
|
||||||
|
include $(srcdir)/common.rules
|
||||||
|
|
142
lure/palette.cpp
Normal file
142
lure/palette.cpp
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/palette.h"
|
||||||
|
#include "common/util.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
// Defaults the palette to a full 256 entry palette
|
||||||
|
|
||||||
|
Palette::Palette() {
|
||||||
|
_numEntries = GAME_COLOURS;
|
||||||
|
_palette = Memory::allocate(_numEntries * 4);
|
||||||
|
_palette->empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consructor
|
||||||
|
// Sets up a palette with the given number of entries and a copy of the passed data
|
||||||
|
|
||||||
|
Palette::Palette(uint8 numEntries1, const byte *data1, PaletteSource paletteSource) {
|
||||||
|
_numEntries = numEntries1;
|
||||||
|
_palette = Memory::allocate(_numEntries * 4);
|
||||||
|
|
||||||
|
if (data1) {
|
||||||
|
if (paletteSource == RGB64)
|
||||||
|
convertPalette(data1, _numEntries);
|
||||||
|
else
|
||||||
|
_palette->copyFrom(data1, 0, 0, _numEntries * 4);
|
||||||
|
} else {
|
||||||
|
// No data provided, set a null palette
|
||||||
|
_palette->empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
// Makes a copy of a passed palette object
|
||||||
|
|
||||||
|
Palette::Palette(Palette &src) {
|
||||||
|
_numEntries = src.numEntries();
|
||||||
|
_palette = Memory::duplicate(src._palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
// Loads a palette from a resource
|
||||||
|
|
||||||
|
Palette::Palette(uint16 resourceId) {
|
||||||
|
Disk &d = Disk::getReference();
|
||||||
|
|
||||||
|
MemoryBlock *srcData = d.getEntry(resourceId);
|
||||||
|
if (((srcData->size() % 3) != 0) || ((srcData->size() / 3) > GAME_COLOURS))
|
||||||
|
error("Specified resource %d is not a palette", resourceId);
|
||||||
|
|
||||||
|
_numEntries = srcData->size() / 3;
|
||||||
|
_palette = Memory::allocate(_numEntries * 4);
|
||||||
|
convertPalette(srcData->data(), _numEntries);
|
||||||
|
delete srcData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Palette::convertPalette(const byte *palette1, uint16 numEntries1) {
|
||||||
|
byte *pDest = _palette->data();
|
||||||
|
const byte *pSrc = palette1;
|
||||||
|
|
||||||
|
while (numEntries1-- > 0) {
|
||||||
|
*pDest++ = (pSrc[0] << 2) + (pSrc[0] >> 4);
|
||||||
|
*pDest++ = (pSrc[1] << 2) + (pSrc[1] >> 4);
|
||||||
|
*pDest++ = (pSrc[2] << 2) + (pSrc[2] >> 4);
|
||||||
|
*pDest++ = 0;
|
||||||
|
pSrc += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Palette::setEntry(uint8 index, uint32 value) {
|
||||||
|
if (index >= numEntries()) error("Invalid palette index: %d", index);
|
||||||
|
uint32 *entry = (uint32 *) (data() + index * 4);
|
||||||
|
*entry = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Palette::getEntry(uint8 index) {
|
||||||
|
if (index >= numEntries()) error("Invalid palette index: %d", index);
|
||||||
|
uint32 *entry = (uint32 *) (data() + index * 4);
|
||||||
|
return *entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Palette::copyFrom(Palette *src) {
|
||||||
|
_palette->copyFrom(src->palette());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
PaletteCollection::PaletteCollection(uint16 resourceId) {
|
||||||
|
Disk &d = Disk::getReference();
|
||||||
|
MemoryBlock *resource = d.getEntry(resourceId);
|
||||||
|
uint32 palSize;
|
||||||
|
uint8 *data = resource->data();
|
||||||
|
|
||||||
|
if (resource->size() % (SUB_PALETTE_SIZE * 3) != 0)
|
||||||
|
error("Resource #%d is not a valid palette set", resourceId);
|
||||||
|
|
||||||
|
palSize = SUB_PALETTE_SIZE * 3;
|
||||||
|
_numPalettes = resource->size() / palSize;
|
||||||
|
|
||||||
|
_palettes = (Palette **) Memory::alloc(_numPalettes * sizeof(Palette *));
|
||||||
|
for (uint8 paletteCtr = 0; paletteCtr < _numPalettes; ++paletteCtr, data += palSize)
|
||||||
|
_palettes[paletteCtr] = new Palette(SUB_PALETTE_SIZE, data, RGB64);
|
||||||
|
|
||||||
|
delete resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
PaletteCollection::~PaletteCollection() {
|
||||||
|
for (int paletteCtr = 0; paletteCtr < _numPalettes; ++paletteCtr)
|
||||||
|
delete _palettes[paletteCtr];
|
||||||
|
free(_palettes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Palette &PaletteCollection::getPalette(uint8 paletteNum) {
|
||||||
|
if (paletteNum >= _numPalettes)
|
||||||
|
error("Invalid palette index specified");
|
||||||
|
return *_palettes[paletteNum];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
68
lure/palette.h
Normal file
68
lure/palette.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_palette_h__
|
||||||
|
#define __lure_palette_h__
|
||||||
|
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/disk.h"
|
||||||
|
#include "lure/memory.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
enum PaletteSource {RGB, RGB64};
|
||||||
|
|
||||||
|
class Palette {
|
||||||
|
private:
|
||||||
|
MemoryBlock *_palette;
|
||||||
|
uint16 _numEntries;
|
||||||
|
|
||||||
|
void convertPalette(const byte *palette, uint16 numEntries);
|
||||||
|
public:
|
||||||
|
Palette();
|
||||||
|
Palette(uint8 numEntries, const byte *data, PaletteSource paletteSource);
|
||||||
|
Palette(Palette &src);
|
||||||
|
Palette(uint16 resourceId);
|
||||||
|
|
||||||
|
uint8 *data() { return _palette->data(); }
|
||||||
|
MemoryBlock *palette() { return _palette; }
|
||||||
|
uint16 numEntries() { return _palette->size() / 4; }
|
||||||
|
void setEntry(uint8 index, uint32 value);
|
||||||
|
uint32 getEntry(uint8 index);
|
||||||
|
void copyFrom(Palette *src);
|
||||||
|
};
|
||||||
|
|
||||||
|
class PaletteCollection {
|
||||||
|
private:
|
||||||
|
Palette **_palettes;
|
||||||
|
uint8 _numPalettes;
|
||||||
|
public:
|
||||||
|
PaletteCollection(uint16 resourceId);
|
||||||
|
~PaletteCollection();
|
||||||
|
|
||||||
|
uint8 numPalettes() { return _numPalettes; }
|
||||||
|
Palette &getPalette(uint8 paletteNum);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namspace Lure
|
||||||
|
|
||||||
|
#endif
|
399
lure/res.cpp
Normal file
399
lure/res.cpp
Normal file
|
@ -0,0 +1,399 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/res.h"
|
||||||
|
#include "lure/disk.h"
|
||||||
|
#include "lure/scripts.h"
|
||||||
|
#include "lure/screen.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
static Resources *int_resources = NULL;
|
||||||
|
|
||||||
|
Resources &Resources::getReference() {
|
||||||
|
return *int_resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
Resources::Resources() {
|
||||||
|
int_resources = this;
|
||||||
|
reloadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
Resources::~Resources() {
|
||||||
|
// Delete any unremoved active hotspots
|
||||||
|
freeData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resources::freeData() {
|
||||||
|
_activeHotspots.clear();
|
||||||
|
_roomData.clear();
|
||||||
|
_hotspotData.clear();
|
||||||
|
_hotspotOverrides.clear();
|
||||||
|
_animData.clear();
|
||||||
|
_exitJoins.clear();
|
||||||
|
_delayList.clear();
|
||||||
|
|
||||||
|
delete _paletteSubset;
|
||||||
|
delete _scriptData;
|
||||||
|
delete _script2Data;
|
||||||
|
delete _hotspotScriptData;
|
||||||
|
delete _messagesData;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AnimRecordTemp {
|
||||||
|
uint16 *offset;
|
||||||
|
MovementDataList *list;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Resources::reloadData() {
|
||||||
|
Disk &d = Disk::getReference();
|
||||||
|
MemoryBlock *mb;
|
||||||
|
uint16 *offset, offsetVal;
|
||||||
|
int ctr;
|
||||||
|
|
||||||
|
// Get the palette subset data
|
||||||
|
_paletteSubset = new Palette(ALT_PALETTE_RESOURCE_ID);
|
||||||
|
|
||||||
|
// Load room data
|
||||||
|
mb = d.getEntry(ROOM_DATA_RESOURCE_ID);
|
||||||
|
offset = (uint16 *) mb->data();
|
||||||
|
for (ctr = 0; READ_LE_UINT16(offset) != 0xffff; ++ctr, ++offset) {
|
||||||
|
offsetVal = READ_LE_UINT16(offset);
|
||||||
|
if (offsetVal != 0) {
|
||||||
|
// Get room resource
|
||||||
|
RoomResource *rec = (RoomResource *) (mb->data() + offsetVal);
|
||||||
|
RoomData *newEntry = new RoomData(rec);
|
||||||
|
_roomData.push_back(newEntry);
|
||||||
|
|
||||||
|
if (rec->numExits > 0) {
|
||||||
|
RoomExitResource *exitRes = (RoomExitResource *)
|
||||||
|
(mb->data() + offsetVal + sizeof(RoomResource));
|
||||||
|
|
||||||
|
for (uint16 exitCtr = 0; exitCtr < rec->numExits; ++exitCtr, ++exitRes) {
|
||||||
|
RoomExitData *exit = new RoomExitData(exitRes);
|
||||||
|
newEntry->exits.push_back(exit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete mb;
|
||||||
|
|
||||||
|
// Load room exits
|
||||||
|
mb = d.getEntry(ROOM_EXITS_RESOURCE_ID);
|
||||||
|
ctr = 0;
|
||||||
|
for (;;) {
|
||||||
|
offsetVal = READ_LE_UINT16(mb->data() + (ctr * 2));
|
||||||
|
if (offsetVal == 0xffff) break;
|
||||||
|
|
||||||
|
if (offsetVal != 0) {
|
||||||
|
RoomData *room = getRoom(ctr);
|
||||||
|
if (room) {
|
||||||
|
RoomExitHotspotRecord *re = (RoomExitHotspotRecord *)
|
||||||
|
(mb->data() + offsetVal);
|
||||||
|
while (READ_LE_UINT16(&re->hotspotId) != 0xffff) {
|
||||||
|
RoomExitHotspotData *newEntry = new RoomExitHotspotData(re);
|
||||||
|
room->exitHotspots.push_back(newEntry);
|
||||||
|
++re;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++ctr;
|
||||||
|
}
|
||||||
|
delete mb;
|
||||||
|
|
||||||
|
// Load room joins
|
||||||
|
mb = d.getEntry(ROOM_EXIT_JOINS_RESOURCE_ID);
|
||||||
|
RoomExitJoinRecord *joinRec = (RoomExitJoinRecord *) mb->data();
|
||||||
|
while (READ_LE_UINT16(&joinRec->hotspot1Id) != 0xffff) {
|
||||||
|
RoomExitJoinData *newEntry = new RoomExitJoinData(joinRec);
|
||||||
|
_exitJoins.push_back(newEntry);
|
||||||
|
++joinRec;
|
||||||
|
}
|
||||||
|
delete mb;
|
||||||
|
|
||||||
|
// Load the hotspot list
|
||||||
|
mb = d.getEntry(HOTSPOT_DATA_RESOURCE_ID);
|
||||||
|
HotspotResource *hsRec = (HotspotResource *) mb->data();
|
||||||
|
while (READ_LE_UINT16(&hsRec->hotspotId) != 0xffff) {
|
||||||
|
HotspotData *newEntry = new HotspotData(hsRec);
|
||||||
|
_hotspotData.push_back(newEntry);
|
||||||
|
++hsRec;
|
||||||
|
}
|
||||||
|
delete mb;
|
||||||
|
|
||||||
|
// Load the hotspot overrides
|
||||||
|
mb = d.getEntry(HOTSPOT_OVERRIDE_DATA_RESOURCE_ID);
|
||||||
|
HotspotOverrideResource *hsoRec = (HotspotOverrideResource *) mb->data();
|
||||||
|
while (READ_LE_UINT16(&hsoRec->hotspotId) != 0xffff) {
|
||||||
|
HotspotOverrideData *newEntry = new HotspotOverrideData(hsoRec);
|
||||||
|
_hotspotOverrides.push_back(newEntry);
|
||||||
|
++hsoRec;
|
||||||
|
}
|
||||||
|
delete mb;
|
||||||
|
|
||||||
|
// Load the animation list
|
||||||
|
mb = d.getEntry(ANIM_DATA_RESOURCE_ID);
|
||||||
|
HotspotAnimResource *animRec = (HotspotAnimResource *) mb->data();
|
||||||
|
while (READ_LE_UINT16(&animRec->animRecordId) != 0xffff) {
|
||||||
|
HotspotAnimData *newEntry = new HotspotAnimData(animRec);
|
||||||
|
_animData.push_back(newEntry);
|
||||||
|
|
||||||
|
// Handle any direction frames
|
||||||
|
AnimRecordTemp dirEntries[4] = {
|
||||||
|
{&animRec->leftOffset, &newEntry->leftFrames},
|
||||||
|
{&animRec->rightOffset, &newEntry->rightFrames},
|
||||||
|
{&animRec->upOffset, &newEntry->upFrames},
|
||||||
|
{&animRec->downOffset, &newEntry->downFrames}};
|
||||||
|
for (int dirCtr = 0; dirCtr < 4; ++dirCtr) {
|
||||||
|
offsetVal = READ_LE_UINT16(dirEntries[dirCtr].offset);
|
||||||
|
if (offsetVal != 0) {
|
||||||
|
MovementResource *moveRec = (MovementResource *)
|
||||||
|
(mb->data() + offsetVal);
|
||||||
|
while (READ_LE_UINT16(&moveRec->frameNumber) != 0xffff) {
|
||||||
|
MovementData *newMove = new MovementData(moveRec);
|
||||||
|
dirEntries[dirCtr].list->push_back(newMove);
|
||||||
|
++moveRec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++animRec;
|
||||||
|
}
|
||||||
|
delete mb;
|
||||||
|
|
||||||
|
// Hotspot scripts
|
||||||
|
mb = d.getEntry(HOTSPOT_SCRIPT_LIST_RESOURCE_ID);
|
||||||
|
uint16 numEntries = mb->size() / 2;
|
||||||
|
uint16 *srcVal = (uint16 *) mb->data();
|
||||||
|
uint16 *destVal = _hotspotScriptData = (uint16 *)
|
||||||
|
Memory::alloc(numEntries * sizeof(uint16));
|
||||||
|
for (ctr = 0; ctr < numEntries; ++ctr, ++srcVal, ++destVal) {
|
||||||
|
*destVal = READ_LE_UINT16(srcVal);
|
||||||
|
}
|
||||||
|
delete mb;
|
||||||
|
|
||||||
|
// Handle the hotspot action lists
|
||||||
|
mb = d.getEntry(ACTION_LIST_RESOURCE_ID);
|
||||||
|
uint16 *v = (uint16 *) mb->data();
|
||||||
|
uint16 recordId;
|
||||||
|
while ((recordId = READ_LE_UINT16(v)) != 0xffff) {
|
||||||
|
++v;
|
||||||
|
offsetVal = READ_LE_UINT16(v);
|
||||||
|
++v;
|
||||||
|
|
||||||
|
HotspotActionList *list = new HotspotActionList(
|
||||||
|
recordId, mb->data() + offsetVal);
|
||||||
|
_actionsList.push_back(list);
|
||||||
|
}
|
||||||
|
delete mb;
|
||||||
|
|
||||||
|
_delayList.clear();
|
||||||
|
|
||||||
|
// Load miscellaneous data
|
||||||
|
_scriptData = d.getEntry(SCRIPT_DATA_RESOURCE_ID);
|
||||||
|
_script2Data = d.getEntry(SCRIPT2_DATA_RESOURCE_ID);
|
||||||
|
_messagesData = d.getEntry(MESSAGES_LIST_RESOURCE_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomExitJoinData *Resources::getExitJoin(uint16 hotspotId) {
|
||||||
|
RoomExitJoinList::iterator i;
|
||||||
|
|
||||||
|
for (i = _exitJoins.begin(); i != _exitJoins.end(); ++i) {
|
||||||
|
RoomExitJoinData *rec = *i;
|
||||||
|
if ((rec->hotspot1Id == hotspotId) || (rec->hotspot2Id == hotspotId))
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 Resources::getHotspotScript(uint16 index) {
|
||||||
|
return _hotspotScriptData[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomData *Resources::getRoom(uint16 roomNumber) {
|
||||||
|
RoomDataList::iterator i;
|
||||||
|
|
||||||
|
for (i = _roomData.begin(); i != _roomData.end(); ++i) {
|
||||||
|
RoomData *rec = *i;
|
||||||
|
if (rec->roomNumber == roomNumber) return rec;
|
||||||
|
++rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resources::insertPaletteSubset(Palette &p) {
|
||||||
|
p.palette()->copyFrom(_paletteSubset->palette(), 0, 129*4, 60*4);
|
||||||
|
p.palette()->copyFrom(_paletteSubset->palette(), 60*4, 220*4, 8*4);
|
||||||
|
}
|
||||||
|
|
||||||
|
HotspotData *Resources::getHotspot(uint16 hotspotId) {
|
||||||
|
HotspotDataList::iterator i;
|
||||||
|
|
||||||
|
for (i = _hotspotData.begin(); i != _hotspotData.end(); ++i) {
|
||||||
|
HotspotData *rec = *i;
|
||||||
|
if (rec->hotspotId == hotspotId) return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hotspot *Resources::getActiveHotspot(uint16 hotspotId) {
|
||||||
|
HotspotList::iterator i;
|
||||||
|
|
||||||
|
for (i = _activeHotspots.begin(); i != _activeHotspots.end(); ++i) {
|
||||||
|
Hotspot *rec = *i;
|
||||||
|
if (rec->hotspotId() == hotspotId) return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HotspotOverrideData *Resources::getHotspotOverride(uint16 hotspotId) {
|
||||||
|
HotspotOverrideList::iterator i;
|
||||||
|
|
||||||
|
for (i = _hotspotOverrides.begin(); i != _hotspotOverrides.end(); ++i) {
|
||||||
|
HotspotOverrideData *rec = *i;
|
||||||
|
if (rec->hotspotId == hotspotId) return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HotspotAnimData *Resources::getAnimation(uint16 animRecordId) {
|
||||||
|
HotspotAnimList::iterator i;
|
||||||
|
|
||||||
|
for (i = _animData.begin(); i != _animData.end(); ++i) {
|
||||||
|
HotspotAnimData *rec = *i;
|
||||||
|
if (rec->animRecordId == animRecordId) return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 Resources::getHotspotAction(uint16 actionsOffset, Action action) {
|
||||||
|
HotspotActionList *list = _actionsList.getActions(actionsOffset);
|
||||||
|
if (!list) return 0;
|
||||||
|
return list->getActionOffset(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
HotspotActionList *Resources::getHotspotActions(uint16 actionsOffset) {
|
||||||
|
return _actionsList.getActions(actionsOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resources::activateHotspot(uint16 hotspotId) {
|
||||||
|
HotspotData *res = getHotspot(hotspotId);
|
||||||
|
if (!res) return;
|
||||||
|
res->roomNumber &= 0x7fff; // clear any suppression bit in room #
|
||||||
|
|
||||||
|
// Make sure that the hotspot isn't already active
|
||||||
|
HotspotList::iterator i = _activeHotspots.begin();
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
for (; i != _activeHotspots.end(); ++i) {
|
||||||
|
Hotspot &h = *i.operator*();
|
||||||
|
if (h.hotspotId() == res->hotspotId) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) return;
|
||||||
|
|
||||||
|
// Check the script load flag
|
||||||
|
if (res->scriptLoadFlag) {
|
||||||
|
// Execute a script rather than doing a standard load
|
||||||
|
Script::execute(res->loadOffset);
|
||||||
|
} else {
|
||||||
|
// Standard load
|
||||||
|
bool loadFlag = true;
|
||||||
|
|
||||||
|
switch (res->loadOffset) {
|
||||||
|
case 0x3afe:
|
||||||
|
// Copy protection check - since the game is freeware now,
|
||||||
|
// don't bother with it
|
||||||
|
loadFlag = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x41BD:
|
||||||
|
// Empty handler used to prevent loading hotspots that
|
||||||
|
// are yet to be active (such as the straw fire)
|
||||||
|
loadFlag = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x7172:
|
||||||
|
case 0x7167:
|
||||||
|
// Standard animation load
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x88ac:
|
||||||
|
// Torch in room #1
|
||||||
|
loadFlag = _fieldList.getField(TORCH_HIDE) == 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// All others simply activate the hotspot
|
||||||
|
warning("Hotspot %d uses unknown load offset proc %d",
|
||||||
|
res->hotspotId, res->loadOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loadFlag) {
|
||||||
|
Hotspot *hotspot = addHotspot(hotspotId);
|
||||||
|
// if (res->loadOffset == 0x7167) hotspot->setPersistant(true);
|
||||||
|
// DEBUG - for now only keep certain hotspots active
|
||||||
|
hotspot->setPersistant((res->hotspotId >= 0x3e8) && (res->hotspotId <= 0x3ea));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Hotspot *Resources::addHotspot(uint16 hotspotId) {
|
||||||
|
Hotspot *hotspot = new Hotspot(getHotspot(hotspotId));
|
||||||
|
_activeHotspots.push_back(hotspot);
|
||||||
|
return hotspot;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resources::deactivateHotspot(uint16 hotspotId) {
|
||||||
|
HotspotList::iterator i = _activeHotspots.begin();
|
||||||
|
|
||||||
|
while (i != _activeHotspots.end()) {
|
||||||
|
Hotspot *h = *i;
|
||||||
|
if (h->hotspotId() == hotspotId)
|
||||||
|
i = _activeHotspots.erase(i);
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 Resources::numInventoryItems() {
|
||||||
|
uint16 numItems = 0;
|
||||||
|
HotspotDataList &list = _hotspotData;
|
||||||
|
HotspotDataList::iterator i;
|
||||||
|
for (i = list.begin(); i != list.end(); ++i) {
|
||||||
|
HotspotData *rec = *i;
|
||||||
|
if (rec->roomNumber == PLAYER_ID) ++numItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
return numItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
94
lure/res.h
Normal file
94
lure/res.h
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_res_h__
|
||||||
|
#define __lure_res_h__
|
||||||
|
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/memory.h"
|
||||||
|
#include "common/list.h"
|
||||||
|
#include "lure/res_struct.h"
|
||||||
|
#include "lure/hotspots.h"
|
||||||
|
#include "lure/palette.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
class Resources {
|
||||||
|
private:
|
||||||
|
Common::RandomSource _rnd;
|
||||||
|
Palette *_paletteSubset;
|
||||||
|
RoomDataList _roomData;
|
||||||
|
HotspotDataList _hotspotData;
|
||||||
|
HotspotOverrideList _hotspotOverrides;
|
||||||
|
HotspotAnimList _animData;
|
||||||
|
MemoryBlock *_scriptData;
|
||||||
|
MemoryBlock *_script2Data;
|
||||||
|
MemoryBlock *_messagesData;
|
||||||
|
uint16 *_hotspotScriptData;
|
||||||
|
RoomExitJoinList _exitJoins;
|
||||||
|
HotspotList _activeHotspots;
|
||||||
|
ValueTableData _fieldList;
|
||||||
|
HotspotActionSet _actionsList;
|
||||||
|
SequenceDelayList _delayList;
|
||||||
|
|
||||||
|
void freeData();
|
||||||
|
public:
|
||||||
|
Resources();
|
||||||
|
~Resources();
|
||||||
|
static Resources &getReference();
|
||||||
|
void reloadData();
|
||||||
|
|
||||||
|
byte *getResource(uint16 resId);
|
||||||
|
RoomDataList &roomData() { return _roomData; }
|
||||||
|
RoomData *getRoom(uint16 roomNumber);
|
||||||
|
void insertPaletteSubset(Palette &p);
|
||||||
|
|
||||||
|
HotspotDataList &hotspotData() { return _hotspotData; }
|
||||||
|
HotspotOverrideList &hotspotOverrides() { return _hotspotOverrides; }
|
||||||
|
HotspotAnimList &animRecords() { return _animData; }
|
||||||
|
MemoryBlock *scriptData() { return _scriptData; }
|
||||||
|
MemoryBlock *hotspotScriptData() { return _script2Data; }
|
||||||
|
MemoryBlock *messagesData() { return _messagesData; }
|
||||||
|
uint16 getHotspotScript(uint16 index);
|
||||||
|
HotspotList &activeHotspots() { return _activeHotspots; }
|
||||||
|
uint16 random() { return _rnd.getRandomNumber(65536) & 0xffff; }
|
||||||
|
HotspotData *getHotspot(uint16 hotspotId);
|
||||||
|
Hotspot *getActiveHotspot(uint16 hotspotId);
|
||||||
|
HotspotOverrideData *getHotspotOverride(uint16 hotspotId);
|
||||||
|
HotspotAnimData *getAnimation(uint16 animRecordId);
|
||||||
|
RoomExitJoinList &exitJoins() { return _exitJoins; }
|
||||||
|
RoomExitJoinData *getExitJoin(uint16 hotspotId);
|
||||||
|
uint16 getHotspotAction(uint16 actionsOffset, Action action);
|
||||||
|
HotspotActionList *getHotspotActions(uint16 actionsOffset);
|
||||||
|
ValueTableData &fieldList() { return _fieldList; }
|
||||||
|
SequenceDelayList &delayList() { return _delayList; }
|
||||||
|
uint16 numInventoryItems();
|
||||||
|
|
||||||
|
void activateHotspot(uint16 hotspotId);
|
||||||
|
Hotspot *addHotspot(uint16 hotspotId);
|
||||||
|
void deactivateHotspot(uint16 hotspotId);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
309
lure/res_struct.cpp
Normal file
309
lure/res_struct.cpp
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/res.h"
|
||||||
|
#include "lure/disk.h"
|
||||||
|
#include "lure/scripts.h"
|
||||||
|
#include "lure/system.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
const char *actionList[] = {NULL, "Get", NULL, "Push", "Pull", "Operate", "Open",
|
||||||
|
"Close", "Lock", "Unlock", "Use", "Give", "Talk to", "Tell", "Buy",
|
||||||
|
"Look", "Look at", "Look through", "Ask", NULL, "Drink", "Status",
|
||||||
|
"Go to", "Return", "Bribe", "Examine"};
|
||||||
|
|
||||||
|
// Room data holding class
|
||||||
|
|
||||||
|
RoomData::RoomData(RoomResource *rec) {
|
||||||
|
roomNumber = READ_LE_UINT16(&rec->roomNumber);
|
||||||
|
descId = READ_LE_UINT16(&rec->descId);
|
||||||
|
sequenceOffset = READ_LE_UINT16(&rec->sequenceOffset);
|
||||||
|
numLayers = READ_LE_UINT16(&rec->numLayers);
|
||||||
|
|
||||||
|
for (int ctr = 0; ctr < 4; ++ctr)
|
||||||
|
layers[ctr] = READ_LE_UINT16(&rec->layers[ctr]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Room exit hotspot area holding class
|
||||||
|
|
||||||
|
RoomExitHotspotData::RoomExitHotspotData(RoomExitHotspotRecord *rec) {
|
||||||
|
hotspotId = READ_LE_UINT16(&rec->hotspotId);
|
||||||
|
xs = READ_LE_INT16(&rec->xs);
|
||||||
|
ys = READ_LE_INT16(&rec->ys);
|
||||||
|
xe = READ_LE_INT16(&rec->xe);
|
||||||
|
ye = READ_LE_INT16(&rec->ye);
|
||||||
|
cursorNum = rec->cursorNum;
|
||||||
|
destRoomNumber = READ_LE_UINT16(&rec->destRoomNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Room exit class
|
||||||
|
|
||||||
|
RoomExitData::RoomExitData(RoomExitResource *rec) {
|
||||||
|
xs = rec->xs;
|
||||||
|
ys = rec->ys;
|
||||||
|
xe = rec->xe;
|
||||||
|
ye = rec->ye;
|
||||||
|
sequenceOffset = rec->sequenceOffset;
|
||||||
|
roomNumber = rec->newRoom;
|
||||||
|
x = rec->newRoomX;
|
||||||
|
y = rec->newRoomY;
|
||||||
|
|
||||||
|
switch (rec->direction) {
|
||||||
|
case 0x80:
|
||||||
|
direction = UP;
|
||||||
|
break;
|
||||||
|
case 0x40:
|
||||||
|
direction = DOWN;
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
direction = LEFT;
|
||||||
|
break;
|
||||||
|
case 0x10:
|
||||||
|
direction = RIGHT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
direction = NO_DIRECTION;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RoomExitData::insideRect(int16 xp, int16 yp) {
|
||||||
|
return ((xp >= xs) && (xp <= xe) && (yp >= ys) && (yp <= ye));
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomExitData *RoomExitList::checkExits(int16 xp, int16 yp) {
|
||||||
|
iterator i;
|
||||||
|
for (i = begin(); i != end(); i++) {
|
||||||
|
RoomExitData *rec = *i;
|
||||||
|
if (rec->insideRect(xp, yp)) return rec;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Room exit joins class
|
||||||
|
|
||||||
|
RoomExitJoinData::RoomExitJoinData(RoomExitJoinRecord *rec) {
|
||||||
|
hotspot1Id = READ_LE_UINT16(&rec->hotspot1Id);
|
||||||
|
h1CurrentFrame = rec->h1CurrentFrame;
|
||||||
|
h1DestFrame = rec->h1DestFrame;
|
||||||
|
h1Unknown = READ_LE_UINT16(&rec->h1Unknown);
|
||||||
|
hotspot2Id = READ_LE_UINT16(&rec->hotspot2Id);
|
||||||
|
h2CurrentFrame = rec->h2CurrentFrame;
|
||||||
|
h2DestFrame = rec->h2DestFrame;
|
||||||
|
h2Unknown = READ_LE_UINT16(&rec->h2Unknown);
|
||||||
|
blocked = rec->blocked;
|
||||||
|
unknown = rec->unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hotspot action record
|
||||||
|
|
||||||
|
HotspotActionData::HotspotActionData(HotspotActionRecord *rec) {
|
||||||
|
action = (Action) rec->action;
|
||||||
|
sequenceOffset = READ_LE_UINT16(&rec->sequenceOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 HotspotActionList::getActionOffset(Action action) {
|
||||||
|
iterator i;
|
||||||
|
for (i = begin(); i != end(); ++i) {
|
||||||
|
HotspotActionData *rec = *i;
|
||||||
|
if (rec->action == action) return rec->sequenceOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Hotspot data
|
||||||
|
|
||||||
|
HotspotData::HotspotData(HotspotResource *rec) {
|
||||||
|
hotspotId = READ_LE_UINT16(&rec->hotspotId);
|
||||||
|
nameId = READ_LE_UINT16(&rec->nameId);
|
||||||
|
descId = READ_LE_UINT16(&rec->descId);
|
||||||
|
descId2 = READ_LE_UINT16(&rec->descId2);
|
||||||
|
actions = READ_LE_UINT32(&rec->actions);
|
||||||
|
actionsOffset = READ_LE_UINT16(&rec->actionsOffset);
|
||||||
|
flags = (byte) (actions >> 24) & 0xf0;
|
||||||
|
actions &= 0xfffffff;
|
||||||
|
|
||||||
|
roomNumber = READ_LE_UINT16(&rec->roomNumber);
|
||||||
|
layer = rec->layer;
|
||||||
|
scriptLoadFlag = rec->scriptLoadFlag;
|
||||||
|
loadOffset = READ_LE_UINT16(&rec->loadOffset);
|
||||||
|
startX = READ_LE_INT16(&rec->startX);
|
||||||
|
startY = READ_LE_INT16(&rec->startY);
|
||||||
|
width = READ_LE_UINT16(&rec->width);
|
||||||
|
height = READ_LE_UINT16(&rec->height);
|
||||||
|
colourOffset = READ_LE_UINT16(&rec->colourOffset);
|
||||||
|
animRecordId = READ_LE_UINT16(&rec->animRecordId);
|
||||||
|
sequenceOffset = READ_LE_UINT16(&rec->sequenceOffset);
|
||||||
|
tickProcOffset = READ_LE_UINT16(&rec->tickProcOffset);
|
||||||
|
tickTimeout = READ_LE_UINT16(&rec->tickTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hotspot override data
|
||||||
|
|
||||||
|
HotspotOverrideData::HotspotOverrideData(HotspotOverrideResource *rec) {
|
||||||
|
hotspotId = READ_LE_UINT16(&rec->hotspotId);
|
||||||
|
xs = READ_LE_INT16(&rec->xs);
|
||||||
|
ys = READ_LE_INT16(&rec->ys);
|
||||||
|
xe = READ_LE_INT16(&rec->xe);
|
||||||
|
ye = READ_LE_INT16(&rec->ye);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hotspot animation movement frame
|
||||||
|
|
||||||
|
MovementData::MovementData(MovementResource *rec) {
|
||||||
|
frameNumber = READ_LE_UINT16(&rec->frameNumber);
|
||||||
|
xChange = READ_LE_INT16(&rec->xChange);
|
||||||
|
yChange = READ_LE_INT16(&rec->yChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
// List of movement frames
|
||||||
|
|
||||||
|
bool MovementDataList::getFrame(uint16 currentFrame, int16 &xChange,
|
||||||
|
int16 &yChange, uint16 &nextFrame) {
|
||||||
|
if (isEmpty()) return false;
|
||||||
|
bool foundFlag = false;
|
||||||
|
iterator i;
|
||||||
|
|
||||||
|
for (i = begin(); i != end(); ++i) {
|
||||||
|
MovementData *rec = *i;
|
||||||
|
if (foundFlag || (i == begin())) {
|
||||||
|
xChange = rec->xChange;
|
||||||
|
yChange = rec->yChange;
|
||||||
|
nextFrame = rec->frameNumber;
|
||||||
|
if (foundFlag) return true;
|
||||||
|
}
|
||||||
|
if (rec->frameNumber == currentFrame) foundFlag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Hotspot animation data
|
||||||
|
|
||||||
|
HotspotAnimData::HotspotAnimData(HotspotAnimResource *rec) {
|
||||||
|
animRecordId = READ_LE_UINT16(&rec->animRecordId);
|
||||||
|
animId = READ_LE_UINT16(&rec->animId);
|
||||||
|
flags = READ_LE_UINT16(&rec->flags);
|
||||||
|
|
||||||
|
upFrame = rec->upFrame;
|
||||||
|
downFrame = rec->downFrame;
|
||||||
|
leftFrame = rec->leftFrame;
|
||||||
|
rightFrame = rec->rightFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hotspot action lists
|
||||||
|
|
||||||
|
HotspotActionList::HotspotActionList(uint16 id, byte *data) {
|
||||||
|
recordId = id;
|
||||||
|
uint16 numItems = READ_LE_UINT16(data);
|
||||||
|
data += 2;
|
||||||
|
|
||||||
|
HotspotActionRecord *actionRec = (HotspotActionRecord *) data;
|
||||||
|
|
||||||
|
for (int actionCtr = 0; actionCtr < numItems; ++actionCtr, ++actionRec) {
|
||||||
|
HotspotActionData *actionEntry = new HotspotActionData(actionRec);
|
||||||
|
push_back(actionEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HotspotActionList *HotspotActionSet::getActions(uint16 recordId) {
|
||||||
|
HotspotActionSet::iterator i;
|
||||||
|
for (i = begin(); i != end(); ++i) {
|
||||||
|
HotspotActionList *list = *i;
|
||||||
|
if (list->recordId == recordId) return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following classes hold any sequence offsets that are being delayed
|
||||||
|
|
||||||
|
SequenceDelayData::SequenceDelayData(uint16 delay, uint16 seqOffset) {
|
||||||
|
OSystem &system = System::getReference();
|
||||||
|
|
||||||
|
_timeoutCtr = system.getMillis() + delay;
|
||||||
|
_sequenceOffset = seqOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SequenceDelayList::addSequence(uint16 delay, uint16 seqOffset) {
|
||||||
|
SequenceDelayData *entry = new SequenceDelayData(delay, seqOffset);
|
||||||
|
push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SequenceDelayList::tick() {
|
||||||
|
uint32 currTime = System::getReference().getMillis();
|
||||||
|
SequenceDelayList::iterator i;
|
||||||
|
|
||||||
|
for (i = begin(); i != end(); i++) {
|
||||||
|
SequenceDelayData *entry = *i;
|
||||||
|
if (entry->_timeoutCtr >= currTime) {
|
||||||
|
uint16 seqOffset = entry->_sequenceOffset;
|
||||||
|
erase(i);
|
||||||
|
Script::execute(seqOffset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field list and miscellaneous variables
|
||||||
|
|
||||||
|
ValueTableData::ValueTableData() {
|
||||||
|
_numGroats = 0;
|
||||||
|
|
||||||
|
for (uint16 index = 0; index < NUM_VALUE_FIELDS; ++index)
|
||||||
|
_fieldList[index] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ValueTableData::isKnownField(uint16 fieldIndex) {
|
||||||
|
return (fieldIndex <= 8) || (fieldIndex == 10) || (fieldIndex == 15) ||
|
||||||
|
(fieldIndex == 18) || (fieldIndex == 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 ValueTableData::getField(uint16 fieldIndex) {
|
||||||
|
if (fieldIndex > NUM_VALUE_FIELDS)
|
||||||
|
error("Invalid field index specified %d", fieldIndex);
|
||||||
|
if (!isKnownField(fieldIndex))
|
||||||
|
warning("Unknown field index %d in GET_FIELD opcode", fieldIndex);
|
||||||
|
return _fieldList[fieldIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 ValueTableData::getField(FieldName fieldName) {
|
||||||
|
return getField((uint16) fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueTableData::setField(uint16 fieldIndex, uint16 value) {
|
||||||
|
if (fieldIndex > NUM_VALUE_FIELDS)
|
||||||
|
error("Invalid field index specified %d", fieldIndex);
|
||||||
|
_fieldList[fieldIndex] = value;
|
||||||
|
if (!isKnownField(fieldIndex))
|
||||||
|
warning("Unknown field index %d in SET_FIELD opcode", fieldIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueTableData::setField(FieldName fieldName, uint16 value) {
|
||||||
|
setField((uint16) fieldName, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
401
lure/res_struct.h
Normal file
401
lure/res_struct.h
Normal file
|
@ -0,0 +1,401 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_resstruct_h__
|
||||||
|
#define __lure_resstruct_h__
|
||||||
|
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "common/list.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
extern const char *actionList[];
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
/* Structure definitions */
|
||||||
|
/* */
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if !defined(__GNUC__)
|
||||||
|
#pragma START_PACK_STRUCTS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct HotspotResource {
|
||||||
|
uint16 hotspotId;
|
||||||
|
uint16 nameId;
|
||||||
|
uint16 descId;
|
||||||
|
uint16 descId2;
|
||||||
|
uint32 actions;
|
||||||
|
uint16 actionsOffset;
|
||||||
|
uint16 roomNumber;
|
||||||
|
byte layer;
|
||||||
|
byte scriptLoadFlag;
|
||||||
|
uint16 loadOffset;
|
||||||
|
int16 startX;
|
||||||
|
int16 startY;
|
||||||
|
uint16 width;
|
||||||
|
uint16 height;
|
||||||
|
uint16 colourOffset;
|
||||||
|
uint16 animRecordId;
|
||||||
|
uint16 sequenceOffset;
|
||||||
|
uint16 tickProcOffset;
|
||||||
|
uint16 tickTimeout;
|
||||||
|
} GCC_PACK;
|
||||||
|
|
||||||
|
struct HotspotAnimResource {
|
||||||
|
uint16 animRecordId;
|
||||||
|
uint16 animId;
|
||||||
|
uint16 flags;
|
||||||
|
uint16 upOffset;
|
||||||
|
uint16 downOffset;
|
||||||
|
uint16 leftOffset;
|
||||||
|
uint16 rightOffset;
|
||||||
|
uint8 upFrame;
|
||||||
|
uint8 downFrame;
|
||||||
|
uint8 leftFrame;
|
||||||
|
uint8 rightFrame;
|
||||||
|
} GCC_PACK;
|
||||||
|
|
||||||
|
struct MovementResource {
|
||||||
|
uint16 frameNumber;
|
||||||
|
int16 xChange;
|
||||||
|
int16 yChange;
|
||||||
|
} GCC_PACK;
|
||||||
|
|
||||||
|
|
||||||
|
struct RoomResource {
|
||||||
|
uint16 roomNumber;
|
||||||
|
uint16 descId;
|
||||||
|
uint16 numLayers;
|
||||||
|
uint16 layers[4];
|
||||||
|
uint16 sequenceOffset;
|
||||||
|
uint16 numExits;
|
||||||
|
} GCC_PACK;
|
||||||
|
|
||||||
|
struct RoomExitResource {
|
||||||
|
int16 xs, xe, ys, ye;
|
||||||
|
uint16 sequenceOffset;
|
||||||
|
uint8 newRoom;
|
||||||
|
uint8 direction;
|
||||||
|
int16 newRoomX, newRoomY;
|
||||||
|
} GCC_PACK;
|
||||||
|
|
||||||
|
struct HotspotOverrideResource {
|
||||||
|
uint16 hotspotId;
|
||||||
|
int16 xs, xe, ys, ye;
|
||||||
|
} GCC_PACK;
|
||||||
|
|
||||||
|
struct RoomExitHotspotRecord {
|
||||||
|
uint16 hotspotId;
|
||||||
|
int16 xs, xe;
|
||||||
|
int16 ys, ye;
|
||||||
|
uint16 cursorNum;
|
||||||
|
uint16 destRoomNumber;
|
||||||
|
} GCC_PACK;
|
||||||
|
|
||||||
|
struct RoomExitJoinRecord {
|
||||||
|
uint16 hotspot1Id;
|
||||||
|
byte h1CurrentFrame;
|
||||||
|
byte h1DestFrame;
|
||||||
|
uint16 h1Unknown;
|
||||||
|
uint16 hotspot2Id;
|
||||||
|
byte h2CurrentFrame;
|
||||||
|
byte h2DestFrame;
|
||||||
|
uint16 h2Unknown;
|
||||||
|
byte blocked;
|
||||||
|
uint32 unknown;
|
||||||
|
} GCC_PACK;
|
||||||
|
|
||||||
|
struct HotspotActionRecord {
|
||||||
|
byte action;
|
||||||
|
uint16 sequenceOffset;
|
||||||
|
} GCC_PACK;
|
||||||
|
|
||||||
|
struct FileEntry {
|
||||||
|
uint16 id;
|
||||||
|
byte unused;
|
||||||
|
byte sizeExtension;
|
||||||
|
uint16 size;
|
||||||
|
uint16 offset;
|
||||||
|
} GCC_PACK;
|
||||||
|
|
||||||
|
struct VersionStructure {
|
||||||
|
uint16 id;
|
||||||
|
byte vMajor;
|
||||||
|
byte vMinor;
|
||||||
|
} GCC_PACK;
|
||||||
|
|
||||||
|
#if !defined(__GNUC__)
|
||||||
|
#pragma END_PACK_STRUCTS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Class template for a derived list that destroys the contained
|
||||||
|
// object when the record containing it is destroyed. It's not
|
||||||
|
// perfect, since the underlying list doesn't have virtual
|
||||||
|
// methods, but it's sufficient for my usage
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class ManagedList: public Common::List<T> {
|
||||||
|
public:
|
||||||
|
~ManagedList() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
typename Common::List<T>::iterator i;
|
||||||
|
for (i = Common::List<T>::begin(); i != Common::List<T>::end(); ++i)
|
||||||
|
delete *i;
|
||||||
|
Common::List<T>::clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
typename Common::List<T>::iterator erase(typename Common::List<T>::iterator pos) {
|
||||||
|
delete *pos;
|
||||||
|
return Common::List<T>::erase(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
typename Common::List<T>::iterator erase(typename Common::List<T>::iterator first,
|
||||||
|
typename Common::List<T>::iterator last) {
|
||||||
|
typename Common::List<T>::iterator i;
|
||||||
|
for (i = first; i != last; ++i)
|
||||||
|
delete *i;
|
||||||
|
return Common::List<T>::erase(first, last);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enumeration used for direction facings
|
||||||
|
|
||||||
|
enum Direction {UP, DOWN, LEFT, RIGHT, NO_DIRECTION};
|
||||||
|
|
||||||
|
// Support classes to hold loaded resources
|
||||||
|
|
||||||
|
class RoomExitHotspotData {
|
||||||
|
public:
|
||||||
|
RoomExitHotspotData(RoomExitHotspotRecord *rec);
|
||||||
|
|
||||||
|
uint16 hotspotId;
|
||||||
|
int16 xs, xe;
|
||||||
|
int16 ys, ye;
|
||||||
|
uint16 cursorNum;
|
||||||
|
uint16 destRoomNumber;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ManagedList<RoomExitHotspotData *> RoomExitHotspotList;
|
||||||
|
|
||||||
|
class RoomExitData {
|
||||||
|
public:
|
||||||
|
RoomExitData(RoomExitResource *rec);
|
||||||
|
bool insideRect(int16 xp, int16 yp);
|
||||||
|
|
||||||
|
int16 xs, xe, ys, ye;
|
||||||
|
uint16 sequenceOffset;
|
||||||
|
Direction direction;
|
||||||
|
uint8 roomNumber;
|
||||||
|
uint16 x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RoomExitList: public ManagedList<RoomExitData *> {
|
||||||
|
public:
|
||||||
|
RoomExitData *checkExits(int16 xp, int16 yp);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_NUM_LAYERS 4
|
||||||
|
|
||||||
|
class RoomData {
|
||||||
|
public:
|
||||||
|
RoomData(RoomResource *rec);
|
||||||
|
|
||||||
|
uint16 roomNumber;
|
||||||
|
uint16 descId;
|
||||||
|
uint16 numLayers;
|
||||||
|
uint16 layers[MAX_NUM_LAYERS];
|
||||||
|
uint16 sequenceOffset;
|
||||||
|
RoomExitHotspotList exitHotspots;
|
||||||
|
RoomExitList exits;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ManagedList<RoomData *> RoomDataList;
|
||||||
|
|
||||||
|
class RoomExitJoinData {
|
||||||
|
public:
|
||||||
|
RoomExitJoinData(RoomExitJoinRecord *rec);
|
||||||
|
|
||||||
|
uint16 hotspot1Id;
|
||||||
|
byte h1CurrentFrame;
|
||||||
|
byte h1DestFrame;
|
||||||
|
uint16 h1Unknown;
|
||||||
|
uint16 hotspot2Id;
|
||||||
|
byte h2CurrentFrame;
|
||||||
|
byte h2DestFrame;
|
||||||
|
uint16 h2Unknown;
|
||||||
|
byte blocked;
|
||||||
|
uint32 unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ManagedList<RoomExitJoinData *> RoomExitJoinList;
|
||||||
|
|
||||||
|
class HotspotActionData {
|
||||||
|
public:
|
||||||
|
HotspotActionData(HotspotActionRecord *rec);
|
||||||
|
|
||||||
|
Action action;
|
||||||
|
uint16 sequenceOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HotspotActionList: public ManagedList<HotspotActionData *> {
|
||||||
|
public:
|
||||||
|
uint16 recordId;
|
||||||
|
|
||||||
|
HotspotActionList(uint16 id, byte *data);
|
||||||
|
uint16 getActionOffset(Action action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class HotspotActionSet: public ManagedList<HotspotActionList *> {
|
||||||
|
public:
|
||||||
|
HotspotActionList *getActions(uint16 recordId);
|
||||||
|
};
|
||||||
|
|
||||||
|
class HotspotData {
|
||||||
|
public:
|
||||||
|
HotspotData(HotspotResource *rec);
|
||||||
|
|
||||||
|
uint16 hotspotId;
|
||||||
|
uint16 nameId;
|
||||||
|
uint16 descId;
|
||||||
|
uint16 descId2;
|
||||||
|
uint32 actions;
|
||||||
|
uint16 actionsOffset;
|
||||||
|
byte flags;
|
||||||
|
uint16 roomNumber;
|
||||||
|
byte layer;
|
||||||
|
byte scriptLoadFlag;
|
||||||
|
uint16 loadOffset;
|
||||||
|
int16 startX;
|
||||||
|
int16 startY;
|
||||||
|
uint16 width;
|
||||||
|
uint16 height;
|
||||||
|
uint16 colourOffset;
|
||||||
|
uint16 animRecordId;
|
||||||
|
uint16 sequenceOffset;
|
||||||
|
uint16 tickProcOffset;
|
||||||
|
uint16 tickTimeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ManagedList<HotspotData *> HotspotDataList;
|
||||||
|
|
||||||
|
class HotspotOverrideData {
|
||||||
|
public:
|
||||||
|
HotspotOverrideData(HotspotOverrideResource *rec);
|
||||||
|
|
||||||
|
uint16 hotspotId;
|
||||||
|
int16 xs, xe, ys, ye;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ManagedList<HotspotOverrideData *> HotspotOverrideList;
|
||||||
|
|
||||||
|
class MovementData {
|
||||||
|
public:
|
||||||
|
MovementData(MovementResource *);
|
||||||
|
|
||||||
|
uint16 frameNumber;
|
||||||
|
int16 xChange;
|
||||||
|
int16 yChange;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MovementDataList: public ManagedList<MovementData *> {
|
||||||
|
public:
|
||||||
|
bool getFrame(uint16 currentFrame, int16 &xChange, int16 &yChange,
|
||||||
|
uint16 &nextFrame);
|
||||||
|
};
|
||||||
|
|
||||||
|
class HotspotAnimData {
|
||||||
|
public:
|
||||||
|
HotspotAnimData(HotspotAnimResource *rec);
|
||||||
|
|
||||||
|
uint16 animRecordId;
|
||||||
|
uint16 animId;
|
||||||
|
uint16 flags;
|
||||||
|
uint8 upFrame;
|
||||||
|
uint8 downFrame;
|
||||||
|
uint8 leftFrame;
|
||||||
|
uint8 rightFrame;
|
||||||
|
|
||||||
|
MovementDataList leftFrames, rightFrames;
|
||||||
|
MovementDataList upFrames, downFrames;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ManagedList<HotspotAnimData *> HotspotAnimList;
|
||||||
|
|
||||||
|
// The following classes hold any sequence offsets that are being delayed
|
||||||
|
|
||||||
|
class SequenceDelayData {
|
||||||
|
friend class SequenceDelayList;
|
||||||
|
private:
|
||||||
|
uint32 _timeoutCtr;
|
||||||
|
uint16 _sequenceOffset;
|
||||||
|
public:
|
||||||
|
SequenceDelayData(uint16 delay, uint16 seqOffset);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SequenceDelayList: public ManagedList<SequenceDelayData *> {
|
||||||
|
public:
|
||||||
|
void addSequence(uint16 delay, uint16 seqOffset);
|
||||||
|
void tick();
|
||||||
|
};
|
||||||
|
|
||||||
|
// The following class holds the field list used by the script engine as
|
||||||
|
// well as miscellaneous fields used by the game.
|
||||||
|
|
||||||
|
#define NUM_VALUE_FIELDS 85
|
||||||
|
|
||||||
|
enum FieldName {
|
||||||
|
ROOM_NUMBER = 0,
|
||||||
|
CHARACTER_HOTSPOT_ID = 1,
|
||||||
|
USE_HOTSPOT_ID = 2,
|
||||||
|
ACTIVE_HOTSPOT_ID = 3,
|
||||||
|
SEQUENCE_RESULT = 4,
|
||||||
|
GENERAL = 5,
|
||||||
|
NEW_ROOM_NUMBER = 7,
|
||||||
|
GENERAL_STATUS = 8,
|
||||||
|
TORCH_HIDE = 10,
|
||||||
|
PRISONER_DEAD = 15,
|
||||||
|
BOTTLE_FILLED = 18,
|
||||||
|
SACK_CUT = 20
|
||||||
|
};
|
||||||
|
|
||||||
|
class ValueTableData {
|
||||||
|
private:
|
||||||
|
uint16 _numGroats;
|
||||||
|
uint16 _fieldList[NUM_VALUE_FIELDS];
|
||||||
|
bool isKnownField(uint16 fieldIndex);
|
||||||
|
public:
|
||||||
|
ValueTableData();
|
||||||
|
uint16 getField(uint16 fieldIndex);
|
||||||
|
uint16 getField(FieldName fieldName);
|
||||||
|
|
||||||
|
void setField(uint16 fieldIndex, uint16 value);
|
||||||
|
void setField(FieldName fieldName, uint16 value);
|
||||||
|
uint16 &numGroats() { return _numGroats; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
485
lure/room.cpp
Normal file
485
lure/room.cpp
Normal file
|
@ -0,0 +1,485 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/room.h"
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/res.h"
|
||||||
|
#include "lure/screen.h"
|
||||||
|
#include "lure/events.h"
|
||||||
|
#include "lure/strings.h"
|
||||||
|
#include "lure/scripts.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
static Room *int_room;
|
||||||
|
|
||||||
|
RoomLayer::RoomLayer(uint16 screenId, bool backgroundLayer):
|
||||||
|
Surface(FULL_SCREEN_WIDTH, FULL_SCREEN_HEIGHT) {
|
||||||
|
loadScreen(screenId);
|
||||||
|
byte cellIndex = 0;
|
||||||
|
byte *screenData = data().data();
|
||||||
|
|
||||||
|
memset(_cells, 0xff, FULL_HORIZ_RECTS*FULL_VERT_RECTS);
|
||||||
|
|
||||||
|
// Loop through each cell of the screen
|
||||||
|
for (int cellY = 0; cellY < NUM_VERT_RECTS; ++cellY) {
|
||||||
|
for (int cellX = 0; cellX < NUM_HORIZ_RECTS; ++cellX) {
|
||||||
|
bool hasPixels = false;
|
||||||
|
|
||||||
|
if (backgroundLayer) {
|
||||||
|
hasPixels = true;
|
||||||
|
} else {
|
||||||
|
// Check the cell
|
||||||
|
for (int yP = 0; yP < RECT_SIZE; ++yP) {
|
||||||
|
if (hasPixels) break;
|
||||||
|
byte *linePos = screenData + (cellY * RECT_SIZE + yP + 8)
|
||||||
|
* FULL_SCREEN_WIDTH + (cellX * RECT_SIZE);
|
||||||
|
|
||||||
|
for (int xP = 0; xP < RECT_SIZE; ++xP) {
|
||||||
|
hasPixels = *linePos++ != 0;
|
||||||
|
if (hasPixels) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_cells[(cellY + NUM_EDGE_RECTS) * FULL_HORIZ_RECTS + NUM_EDGE_RECTS +
|
||||||
|
cellX] = !hasPixels ? 0xff : cellIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Room::Room(): _screen(Screen::getReference()) {
|
||||||
|
int_room = this;
|
||||||
|
|
||||||
|
_roomData = NULL;
|
||||||
|
_hotspotName[0] = '\0';
|
||||||
|
for (int ctr = 0; ctr < MAX_NUM_LAYERS; ++ctr) _layers[ctr] = NULL;
|
||||||
|
_numLayers = 0;
|
||||||
|
_showInfo = false;
|
||||||
|
_currentAction = NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Room::~Room() {
|
||||||
|
for (int layerNum = 0; layerNum < _numLayers; ++layerNum)
|
||||||
|
if (_layers[layerNum])
|
||||||
|
delete _layers[layerNum];
|
||||||
|
|
||||||
|
int_room = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Room &Room::getReference() {
|
||||||
|
return *int_room;
|
||||||
|
}
|
||||||
|
|
||||||
|
// leaveRoom
|
||||||
|
// Handles leaving the current room
|
||||||
|
|
||||||
|
void Room::leaveRoom() {
|
||||||
|
Resources &r = Resources::getReference();
|
||||||
|
|
||||||
|
// Deallocate graphical layers from the room
|
||||||
|
for (int layerNum = 0; layerNum < _numLayers; ++layerNum)
|
||||||
|
if (_layers[layerNum]) {
|
||||||
|
delete _layers[layerNum];
|
||||||
|
_layers[layerNum] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan through the hotspot list and remove any uneeded entries
|
||||||
|
//r.activeHotspots().clear();
|
||||||
|
HotspotList &list = r.activeHotspots();
|
||||||
|
HotspotList::iterator i = list.begin();
|
||||||
|
while (i != list.end()) {
|
||||||
|
Hotspot *h = i.operator*();
|
||||||
|
if (!h->persistant()) {
|
||||||
|
i = list.erase(i);
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Room::loadRoomHotspots() {
|
||||||
|
Resources &r = Resources::getReference();
|
||||||
|
HotspotDataList &list = r.hotspotData();
|
||||||
|
|
||||||
|
HotspotDataList::iterator i;
|
||||||
|
for (i = list.begin(); i != list.end(); ++i) {
|
||||||
|
HotspotData *rec = *i;
|
||||||
|
|
||||||
|
if ((rec->hotspotId < 0x7530) && (rec->roomNumber == _roomNumber) &&
|
||||||
|
(rec->layer != 0))
|
||||||
|
r.activateHotspot(rec->hotspotId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Room::checkRoomHotspots() {
|
||||||
|
Mouse &m = Mouse::getReference();
|
||||||
|
Resources &r = Resources::getReference();
|
||||||
|
HotspotDataList &list = r.hotspotData();
|
||||||
|
HotspotData *entry = NULL;
|
||||||
|
int16 currentX = m.x();
|
||||||
|
int16 currentY = m.y();
|
||||||
|
|
||||||
|
HotspotDataList::iterator i;
|
||||||
|
for (i = list.begin(); i != list.end(); ++i) {
|
||||||
|
entry = *i;
|
||||||
|
|
||||||
|
bool skipFlag = (entry->roomNumber != _roomNumber);
|
||||||
|
if (!skipFlag) {
|
||||||
|
skipFlag = (((entry->flags & 0x80) == 0) &&
|
||||||
|
((entry->flags & 0x40) != 0)) ||
|
||||||
|
((entry->flags & 0x20) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!skipFlag) && (entry->hotspotId < 0x409))
|
||||||
|
skipFlag = sub_112();
|
||||||
|
|
||||||
|
if (!skipFlag && (entry->hotspotId >= 0x2710) && (entry->hotspotId <= 0x27ff)) {
|
||||||
|
RoomExitJoinData *rec = r.getExitJoin(entry->hotspotId);
|
||||||
|
if ((rec) && (!rec->blocked))
|
||||||
|
// Hotspot is over a room exit, and it's not blocked, so don't
|
||||||
|
// register it as an active hotspot
|
||||||
|
skipFlag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skipFlag) {
|
||||||
|
// Check for a hotspot override
|
||||||
|
HotspotOverrideData *hsEntry = r.getHotspotOverride(entry->hotspotId);
|
||||||
|
|
||||||
|
if (hsEntry) {
|
||||||
|
// Check whether cursor is in override hotspot area
|
||||||
|
if ((currentX >= hsEntry->xs) && (currentX <= hsEntry->xe) &&
|
||||||
|
(currentY >= hsEntry->ys) && (currentY <= hsEntry->ye))
|
||||||
|
// Found to be in hotspot entry
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// Check whether cursor is in default hospot area
|
||||||
|
if ((currentX >= entry->startX) && (currentX < entry->startX + entry->width) &&
|
||||||
|
(currentY >= entry->startY) && (currentY < entry->startY + entry->height))
|
||||||
|
// Found hotspot entry
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == list.end()) {
|
||||||
|
_hotspotId = 0;
|
||||||
|
_hotspotNameId = 0;
|
||||||
|
_hotspot = NULL;
|
||||||
|
} else {
|
||||||
|
_hotspotNameId = entry->nameId;
|
||||||
|
_hotspot = entry;
|
||||||
|
_hotspotId = entry->hotspotId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 Room::checkRoomExits() {
|
||||||
|
Mouse &m = Mouse::getReference();
|
||||||
|
Resources &r = Resources::getReference();
|
||||||
|
|
||||||
|
RoomExitHotspotList &exits = _roomData->exitHotspots;
|
||||||
|
if (exits.isEmpty()) return CURSOR_ARROW;
|
||||||
|
RoomExitJoinData *join;
|
||||||
|
bool skipFlag;
|
||||||
|
|
||||||
|
RoomExitHotspotList::iterator i;
|
||||||
|
for (i = exits.begin(); i != exits.end(); ++i) {
|
||||||
|
RoomExitHotspotData *rec = *i;
|
||||||
|
skipFlag = false;
|
||||||
|
|
||||||
|
if (rec->hotspotId != 0) {
|
||||||
|
join = r.getExitJoin(rec->hotspotId);
|
||||||
|
if ((join) && (join->blocked != 0))
|
||||||
|
skipFlag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skipFlag && (m.x() >= rec->xs) && (m.x() <= rec->xe) &&
|
||||||
|
(m.y() >= rec->ys) && (m.y() <= rec->ye)) {
|
||||||
|
// Cursor is within exit area
|
||||||
|
uint8 cursorNum = rec->cursorNum;
|
||||||
|
|
||||||
|
// If it's a hotspotted exit, change arrow to the + arrow
|
||||||
|
if (rec->hotspotId != 0) cursorNum += 7;
|
||||||
|
|
||||||
|
return cursorNum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No room exits found
|
||||||
|
return CURSOR_ARROW;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Room::flagCoveredCells(Hotspot &h) {
|
||||||
|
int16 yStart = (h.y() - MENUBAR_Y_SIZE) / RECT_SIZE;
|
||||||
|
int16 yEnd = (h.y() + h.height() - 1 - MENUBAR_Y_SIZE) / RECT_SIZE;
|
||||||
|
int16 numY = yEnd - yStart + 1;
|
||||||
|
int16 xStart = h.x() / RECT_SIZE;
|
||||||
|
int16 xEnd = (h.x() + h.width() - 1) / RECT_SIZE;
|
||||||
|
int16 numX = xEnd - xStart + 1;
|
||||||
|
|
||||||
|
int index = yStart * NUM_HORIZ_RECTS + xStart;
|
||||||
|
|
||||||
|
for (int16 yP = 0; yP < numY; ++yP) {
|
||||||
|
for (int16 xP = 0; xP < numX; ++xP) {
|
||||||
|
int indexPos = index + xP;
|
||||||
|
if ((indexPos < 0) || (indexPos >= NUM_HORIZ_RECTS*NUM_VERT_RECTS))
|
||||||
|
continue;
|
||||||
|
_cells[index+xP] |= 0x81;
|
||||||
|
_cells2[index+xP] |= 1;
|
||||||
|
}
|
||||||
|
index += NUM_HORIZ_RECTS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Room::addAnimation(Hotspot &h) {
|
||||||
|
Surface &s = _screen.screen();
|
||||||
|
char buffer[10];
|
||||||
|
h.copyTo(&s);
|
||||||
|
|
||||||
|
if (_showInfo) {
|
||||||
|
int16 x = h.x();
|
||||||
|
int16 y = h.y();
|
||||||
|
if ((x >= 0) && (x <= 319) && (y >= 0) && (y <= 200)) {
|
||||||
|
sprintf(buffer, "%x", h.resource().hotspotId);
|
||||||
|
strcat(buffer, "h");
|
||||||
|
s.writeString(h.x(), h.y(), buffer, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Room::addLayers(Hotspot &h) {
|
||||||
|
int16 hsX = h.x() + (4 * RECT_SIZE);
|
||||||
|
int16 hsY = h.y() + (4 * RECT_SIZE) - MENUBAR_Y_SIZE;
|
||||||
|
|
||||||
|
int16 xStart = hsX / RECT_SIZE;
|
||||||
|
int16 xEnd = (hsX + h.width()) / RECT_SIZE;
|
||||||
|
int16 numX = xEnd - xStart + 1;
|
||||||
|
int16 yStart = hsY / RECT_SIZE;
|
||||||
|
int16 yEnd = (hsY + h.height() - 1) / RECT_SIZE;
|
||||||
|
int16 numY = yEnd - yStart + 1;
|
||||||
|
|
||||||
|
for (int16 xCtr = 0; xCtr < numX; ++xCtr, ++xStart) {
|
||||||
|
int16 xs = xStart - 4;
|
||||||
|
if (xs < 0) continue;
|
||||||
|
|
||||||
|
// Check foreground layers for an occupied one
|
||||||
|
/* DEBUG
|
||||||
|
int layerNum = 1;
|
||||||
|
while ((layerNum < _numLayers) &&
|
||||||
|
!_layers[layerNum]->isOccupied(xStart, yEnd))
|
||||||
|
++layerNum;
|
||||||
|
if (layerNum == _numLayers) continue;
|
||||||
|
*/
|
||||||
|
int layerNum = _numLayers - 1;
|
||||||
|
while ((layerNum > 0) &&
|
||||||
|
!_layers[layerNum]->isOccupied(xStart, yEnd))
|
||||||
|
--layerNum;
|
||||||
|
if (layerNum == 0) continue;
|
||||||
|
|
||||||
|
int16 ye = yEnd - 4;
|
||||||
|
for (int16 yCtr = 0; yCtr < numY; ++yCtr, --ye) {
|
||||||
|
if (ye < 0) break;
|
||||||
|
addCell(xs, ye, layerNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Room::addCell(int16 xp, int16 yp, int layerNum) {
|
||||||
|
Surface &s = _screen.screen();
|
||||||
|
|
||||||
|
while ((layerNum > 0) && !_layers[layerNum]->isOccupied(xp+4, yp+4))
|
||||||
|
--layerNum;
|
||||||
|
if (layerNum == 0) return;
|
||||||
|
/* DEBUG
|
||||||
|
while ((layerNum < _numLayers) && !_layers[layerNum]->isOccupied(xp+4, yp+4))
|
||||||
|
++layerNum;
|
||||||
|
if (layerNum == _numLayers) return;
|
||||||
|
*/
|
||||||
|
RoomLayer *layer = _layers[layerNum];
|
||||||
|
|
||||||
|
int index = ((yp * RECT_SIZE + 8) * FULL_SCREEN_WIDTH) + (xp * RECT_SIZE);
|
||||||
|
byte *srcPos = layer->data().data() + index;
|
||||||
|
byte *destPos = s.data().data() + index;
|
||||||
|
|
||||||
|
for (int yCtr = 0; yCtr < RECT_SIZE; ++yCtr) {
|
||||||
|
for (int xCtr = 0; xCtr < RECT_SIZE; ++xCtr, ++destPos) {
|
||||||
|
byte pixel = *srcPos++;
|
||||||
|
if (pixel) *destPos = pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to start of next cell line
|
||||||
|
srcPos += FULL_SCREEN_WIDTH - RECT_SIZE;
|
||||||
|
destPos += FULL_SCREEN_WIDTH - RECT_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: old version of screen layers load compresses loaded layers down to
|
||||||
|
// only a set of the non-empty rects. Since modern memory allows me to load
|
||||||
|
// all the layers completely, I'm bypassing the need to use cell index values
|
||||||
|
}
|
||||||
|
|
||||||
|
void Room::update() {
|
||||||
|
Surface &s = _screen.screen();
|
||||||
|
Resources &r = Resources::getReference();
|
||||||
|
HotspotList &hotspots = r.activeHotspots();
|
||||||
|
HotspotList::iterator i;
|
||||||
|
|
||||||
|
memset(_cells, 0x81, NUM_HORIZ_RECTS*NUM_VERT_RECTS);
|
||||||
|
memset(_cells2, 0x81, NUM_HORIZ_RECTS*NUM_VERT_RECTS);
|
||||||
|
|
||||||
|
_layers[0]->copyTo(&s);
|
||||||
|
for (int ctr = 1; ctr < _numLayers; ++ctr)
|
||||||
|
_layers[ctr]->transparentCopyTo(&s);
|
||||||
|
|
||||||
|
// Handle first layer (layer 3)
|
||||||
|
for (i = hotspots.begin(); i != hotspots.end(); ++i) {
|
||||||
|
Hotspot &h = *i.operator*();
|
||||||
|
if ((h.roomNumber() == _roomNumber) && h.isActiveAnimation() && (h.layer() == 3)) {
|
||||||
|
flagCoveredCells(h);
|
||||||
|
addAnimation(h);
|
||||||
|
addLayers(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle second layer (layer 1) - do in order of Y axis
|
||||||
|
List<Hotspot *> tempList;
|
||||||
|
List<Hotspot *>::iterator iTemp;
|
||||||
|
for (i = hotspots.begin(); i != hotspots.end(); ++i) {
|
||||||
|
Hotspot *h = i.operator*();
|
||||||
|
if ((h->roomNumber() != _roomNumber) || !h->isActiveAnimation()
|
||||||
|
|| (h->layer() != 1))
|
||||||
|
continue;
|
||||||
|
int16 endY = h->y() + h->height();
|
||||||
|
|
||||||
|
for (iTemp = tempList.begin(); iTemp != tempList.end(); ++iTemp) {
|
||||||
|
Hotspot *hTemp = iTemp.operator*();
|
||||||
|
int16 tempY = hTemp->y() + hTemp->height();
|
||||||
|
if (endY < tempY) {
|
||||||
|
if (iTemp != tempList.begin()) --iTemp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tempList.insert(iTemp, h);
|
||||||
|
}
|
||||||
|
for (iTemp = tempList.begin(); iTemp != tempList.end(); ++iTemp) {
|
||||||
|
Hotspot &h = *iTemp.operator*();
|
||||||
|
flagCoveredCells(h);
|
||||||
|
addAnimation(h);
|
||||||
|
addLayers(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle third layer (layer 2)
|
||||||
|
for (i = hotspots.begin(); i != hotspots.end(); ++i) {
|
||||||
|
Hotspot &h = *i.operator*();
|
||||||
|
if ((h.roomNumber() == _roomNumber) && h.isActiveAnimation() && (h.layer() == 2)) {
|
||||||
|
flagCoveredCells(h);
|
||||||
|
addAnimation(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle showing name of highlighted hotspot
|
||||||
|
if (_hotspotName[0] != '\0') {
|
||||||
|
if (_currentAction == NONE) {
|
||||||
|
s.writeString(0, 0, _hotspotName, false, DIALOG_TEXT_COLOUR);
|
||||||
|
} else {
|
||||||
|
char buffer[MAX_ACTION_NAME_SIZE + MAX_HOTSPOT_NAME_SIZE];
|
||||||
|
strcpy(buffer, actionList[_currentAction]);
|
||||||
|
strcat(buffer, " ");
|
||||||
|
strcat(buffer, _hotspotName);
|
||||||
|
s.writeString(0, 0, buffer, false, DIALOG_WHITE_COLOUR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If show information is turned on, show room and position
|
||||||
|
if (_showInfo) {
|
||||||
|
char buffer[64];
|
||||||
|
Mouse &m = Mouse::getReference();
|
||||||
|
sprintf(buffer, "Room %d Pos (%d,%d)", _roomNumber, m.x(), m.y());
|
||||||
|
s.writeString(FULL_SCREEN_WIDTH / 2, 0, buffer, false, DIALOG_TEXT_COLOUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
_screen.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Room::setRoomNumber(uint16 newRoomNumber, bool showOverlay) {
|
||||||
|
Resources &r = Resources::getReference();
|
||||||
|
_roomData = r.getRoom(newRoomNumber);
|
||||||
|
if (!_roomData)
|
||||||
|
error("Tried to change to non-existant room: %d", newRoomNumber);
|
||||||
|
|
||||||
|
_roomNumber = _roomData->roomNumber;
|
||||||
|
_descId = _roomData->descId;
|
||||||
|
|
||||||
|
_screen.empty();
|
||||||
|
_screen.resetPalette();
|
||||||
|
|
||||||
|
if (_layers[0]) leaveRoom();
|
||||||
|
|
||||||
|
_numLayers = _roomData->numLayers;
|
||||||
|
if (showOverlay) ++_numLayers;
|
||||||
|
|
||||||
|
uint16 paletteId = (_roomData->layers[0] & 0xffe0) - 1;
|
||||||
|
|
||||||
|
for (uint8 layerNum = 0; layerNum < _numLayers; ++layerNum)
|
||||||
|
_layers[layerNum] = new RoomLayer(_roomData->layers[layerNum],
|
||||||
|
layerNum == 0);
|
||||||
|
|
||||||
|
// Load in the palette, add in the two replacements segments, and then
|
||||||
|
// set to the system palette
|
||||||
|
Palette p(228, NULL, RGB64);
|
||||||
|
Palette tempPalette(paletteId);
|
||||||
|
p.copyFrom(&tempPalette);
|
||||||
|
r.insertPaletteSubset(p);
|
||||||
|
_screen.setPalette(&p);
|
||||||
|
|
||||||
|
if (_roomData->sequenceOffset != 0xffff)
|
||||||
|
Script::execute(_roomData->sequenceOffset);
|
||||||
|
loadRoomHotspots();
|
||||||
|
cursorMoved();
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
// cursorMoved
|
||||||
|
// Called as the cursor moves to handle any changes that must occur
|
||||||
|
|
||||||
|
void Room::cursorMoved() {
|
||||||
|
uint16 cursorNew = CURSOR_ARROW;
|
||||||
|
uint16 oldHotspotId = _hotspotId;
|
||||||
|
|
||||||
|
Mouse &m = Mouse::getReference();
|
||||||
|
checkRoomHotspots();
|
||||||
|
|
||||||
|
if (_hotspotId != 0) {
|
||||||
|
cursorNew = CURSOR_CROSS;
|
||||||
|
|
||||||
|
if (oldHotspotId != _hotspotId)
|
||||||
|
StringData::getReference().getString(_hotspotNameId, _hotspotName, NULL, NULL);
|
||||||
|
} else {
|
||||||
|
_hotspotName[0] = '\0';
|
||||||
|
cursorNew = checkRoomExits();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m.getCursorNum() != cursorNew)
|
||||||
|
m.setCursorNum(cursorNew);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
107
lure/room.h
Normal file
107
lure/room.h
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_room_h__
|
||||||
|
#define __lure_room_h__
|
||||||
|
|
||||||
|
#include "common/stdafx.h"
|
||||||
|
#include "common/scummsys.h"
|
||||||
|
#include "lure/disk.h"
|
||||||
|
#include "lure/res.h"
|
||||||
|
#include "lure/memory.h"
|
||||||
|
#include "lure/surface.h"
|
||||||
|
#include "lure/screen.h"
|
||||||
|
#include "lure/hotspots.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
#define RECT_SIZE 32
|
||||||
|
#define NUM_HORIZ_RECTS 10
|
||||||
|
#define NUM_VERT_RECTS 6
|
||||||
|
#define FULL_HORIZ_RECTS 18
|
||||||
|
#define FULL_VERT_RECTS 14
|
||||||
|
#define NUM_EDGE_RECTS 4
|
||||||
|
|
||||||
|
class RoomLayer: public Surface {
|
||||||
|
private:
|
||||||
|
byte _cells[FULL_HORIZ_RECTS*FULL_VERT_RECTS];
|
||||||
|
public:
|
||||||
|
RoomLayer(uint16 screenId, bool backgroundLayer);
|
||||||
|
byte cellVal(byte cellX, byte cellY) {
|
||||||
|
return _cells[FULL_HORIZ_RECTS*cellY + cellX];
|
||||||
|
}
|
||||||
|
bool isOccupied(byte cellX, byte cellY) {
|
||||||
|
return cellVal(cellX, cellY) != 0xff;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Room {
|
||||||
|
private:
|
||||||
|
RoomData *_roomData;
|
||||||
|
Screen &_screen;
|
||||||
|
uint16 _roomNumber;
|
||||||
|
uint16 _descId;
|
||||||
|
uint16 _hotspotId;
|
||||||
|
uint16 _hotspotNameId;
|
||||||
|
Action _currentAction;
|
||||||
|
char _hotspotName[MAX_HOTSPOT_NAME_SIZE + MAX_ACTION_NAME_SIZE];
|
||||||
|
HotspotData *_hotspot;
|
||||||
|
bool _showInfo;
|
||||||
|
uint8 _numLayers;
|
||||||
|
RoomLayer *_layers[MAX_NUM_LAYERS];
|
||||||
|
byte _cells[NUM_HORIZ_RECTS*NUM_VERT_RECTS];
|
||||||
|
byte _cells2[NUM_HORIZ_RECTS*NUM_VERT_RECTS];
|
||||||
|
|
||||||
|
void checkRoomHotspots();
|
||||||
|
uint8 checkRoomExits();
|
||||||
|
void loadRoomHotspots();
|
||||||
|
bool sub_112() { return false; } // not yet implemented
|
||||||
|
void flagCoveredCells(Hotspot &h);
|
||||||
|
void addAnimation(Hotspot &h);
|
||||||
|
void addLayers(Hotspot &h);
|
||||||
|
void addCell(int16 xp, int16 yp, int layerNum);
|
||||||
|
public:
|
||||||
|
Room();
|
||||||
|
~Room();
|
||||||
|
static Room &getReference();
|
||||||
|
|
||||||
|
void update();
|
||||||
|
void nextFrame();
|
||||||
|
void cursorMoved();
|
||||||
|
uint16 roomNumber() { return _roomNumber; }
|
||||||
|
void setRoomNumber(uint16 newRoomNumber, bool showOverlay = false);
|
||||||
|
void leaveRoom();
|
||||||
|
void setAction(Action action) { _currentAction = action; }
|
||||||
|
Action getCurrentAction() { return _currentAction; }
|
||||||
|
uint16 hotspotId() { return _hotspotId; }
|
||||||
|
uint32 hotspotActions() { return _hotspot->actions & 0x10ffffff; }
|
||||||
|
uint8 hotspotFlags() { return (_hotspot->actions >> 24) & 0xfe; }
|
||||||
|
HotspotData &hotspot() { return *_hotspot; }
|
||||||
|
uint16 descId() { return _descId; }
|
||||||
|
bool showInfo() { return _showInfo; }
|
||||||
|
void setShowInfo(bool value) { _showInfo = value; }
|
||||||
|
uint32 xyzzy() { return (uint32) _layers[3]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
152
lure/screen.cpp
Normal file
152
lure/screen.cpp
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/screen.h"
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/memory.h"
|
||||||
|
#include "lure/disk.h"
|
||||||
|
#include "lure/decode.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
static Screen *int_disk = NULL;
|
||||||
|
|
||||||
|
Screen &Screen::getReference() {
|
||||||
|
return *int_disk;
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen::Screen(OSystem &system): _system(system),
|
||||||
|
_screen(new Surface(FULL_SCREEN_WIDTH, FULL_SCREEN_HEIGHT)),
|
||||||
|
_disk(Disk::getReference()),
|
||||||
|
_palette(new Palette(GAME_PALETTE_RESOURCE_ID)) {
|
||||||
|
int_disk = this;
|
||||||
|
_screen->empty();
|
||||||
|
_system.setPalette(_palette->data(), 0, GAME_COLOURS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen::~Screen() {
|
||||||
|
delete _screen;
|
||||||
|
delete _palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setPaletteEmpty
|
||||||
|
// Defaults the palette to an empty set
|
||||||
|
|
||||||
|
void Screen::setPaletteEmpty() {
|
||||||
|
delete _palette;
|
||||||
|
_palette = new Palette();
|
||||||
|
|
||||||
|
_system.setPalette(_palette->data(), 0, GAME_COLOURS);
|
||||||
|
_system.updateScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
// setPalette
|
||||||
|
// Sets the current palette to the passed palette
|
||||||
|
|
||||||
|
void Screen::setPalette(Palette *p) {
|
||||||
|
_palette->copyFrom(p);
|
||||||
|
_system.setPalette(_palette->data(), 0, GAME_COLOURS);
|
||||||
|
_system.updateScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
// paletteFadeIn
|
||||||
|
// Fades in the palette. For proper operation, the palette should have been
|
||||||
|
// previously set to empty
|
||||||
|
|
||||||
|
void Screen::paletteFadeIn(Palette *p) {
|
||||||
|
bool changed;
|
||||||
|
byte *const pDest = p->data();
|
||||||
|
byte *const pTemp = _palette->data();
|
||||||
|
|
||||||
|
do {
|
||||||
|
changed = false;
|
||||||
|
|
||||||
|
for (int palCtr = 0; palCtr < p->numEntries() * 4; ++palCtr)
|
||||||
|
{
|
||||||
|
if (palCtr % PALETTE_FADE_INC_SIZE == (PALETTE_FADE_INC_SIZE - 1)) continue;
|
||||||
|
bool isDifferent = pTemp[palCtr] < pDest[palCtr];
|
||||||
|
if (isDifferent) {
|
||||||
|
if (pDest[palCtr] - pTemp[palCtr] < PALETTE_FADE_INC_SIZE)
|
||||||
|
pTemp[palCtr] = pDest[palCtr];
|
||||||
|
else pTemp[palCtr] += PALETTE_FADE_INC_SIZE;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
_system.setPalette(_palette->data(), 0, GAME_COLOURS);
|
||||||
|
_system.updateScreen();
|
||||||
|
_system.delayMillis(20);
|
||||||
|
}
|
||||||
|
} while (changed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// paletteFadeOut
|
||||||
|
// Fades the screen to black by gradually decreasing the palette colours
|
||||||
|
|
||||||
|
void Screen::paletteFadeOut() {
|
||||||
|
bool changed;
|
||||||
|
|
||||||
|
do {
|
||||||
|
byte *pTemp = _palette->data();
|
||||||
|
changed = false;
|
||||||
|
|
||||||
|
for (uint32 palCtr = 0; palCtr < _palette->palette()->size(); ++palCtr, ++pTemp) {
|
||||||
|
if (palCtr % PALETTE_FADE_INC_SIZE == (PALETTE_FADE_INC_SIZE - 1))
|
||||||
|
continue;
|
||||||
|
bool isDifferent = *pTemp > 0;
|
||||||
|
if (isDifferent) {
|
||||||
|
if (*pTemp < PALETTE_FADE_INC_SIZE) *pTemp = 0;
|
||||||
|
else *pTemp -= PALETTE_FADE_INC_SIZE;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
_system.setPalette(_palette->data(), 0, GAME_COLOURS);
|
||||||
|
_system.updateScreen();
|
||||||
|
_system.delayMillis(20);
|
||||||
|
}
|
||||||
|
} while (changed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::resetPalette() {
|
||||||
|
Palette p(GAME_PALETTE_RESOURCE_ID);
|
||||||
|
setPalette(&p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::empty() {
|
||||||
|
_screen->empty();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::update() {
|
||||||
|
_system.copyRectToScreen(screen_raw(), FULL_SCREEN_WIDTH, 0, 0, FULL_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
|
||||||
|
_system.updateScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::updateArea(uint16 x, uint16 y, uint16 w, uint16 h) {
|
||||||
|
_system.copyRectToScreen(screen_raw(), FULL_SCREEN_WIDTH, x, y, w, h);
|
||||||
|
_system.updateScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
64
lure/screen.h
Normal file
64
lure/screen.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_screen_h__
|
||||||
|
#define __lure_screen_h__
|
||||||
|
|
||||||
|
#include "common/stdafx.h"
|
||||||
|
#include "base/engine.h"
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/palette.h"
|
||||||
|
#include "lure/disk.h"
|
||||||
|
#include "lure/memory.h"
|
||||||
|
#include "lure/surface.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
class Screen {
|
||||||
|
private:
|
||||||
|
OSystem &_system;
|
||||||
|
Disk &_disk;
|
||||||
|
Surface *_screen;
|
||||||
|
Palette *_palette;
|
||||||
|
public:
|
||||||
|
Screen(OSystem &system);
|
||||||
|
~Screen();
|
||||||
|
static Screen &getReference();
|
||||||
|
|
||||||
|
void setPaletteEmpty();
|
||||||
|
void setPalette(Palette *p);
|
||||||
|
Palette &getPalette() { return *_palette; }
|
||||||
|
void paletteFadeIn(Palette *p);
|
||||||
|
void paletteFadeOut();
|
||||||
|
void resetPalette();
|
||||||
|
void empty();
|
||||||
|
void update();
|
||||||
|
void updateArea(uint16 x, uint16 y, uint16 w, uint16 h);
|
||||||
|
|
||||||
|
Surface &screen() { return *_screen; }
|
||||||
|
uint8 *screen_raw() { return _screen->data().data(); }
|
||||||
|
uint8 *pixel_raw(uint16 x, uint16 y) { return screen_raw() + (y * FULL_SCREEN_WIDTH) + x; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
576
lure/scripts.cpp
Normal file
576
lure/scripts.cpp
Normal file
|
@ -0,0 +1,576 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/scripts.h"
|
||||||
|
#include "lure/res.h"
|
||||||
|
#include "lure/game.h"
|
||||||
|
#include "common/stack.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/*- Script Method List -*/
|
||||||
|
/*- -*/
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// activateHotspot
|
||||||
|
// Activates a hotspot entry for active use
|
||||||
|
|
||||||
|
void Script::activateHotspot(uint16 hotspotId, uint16 v2, uint16 v3) {
|
||||||
|
Resources::getReference().activateHotspot(hotspotId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// setHotspotScript
|
||||||
|
// Sets a hotspot's animation script offset from a master table of offsets
|
||||||
|
|
||||||
|
void Script::setHotspotScript(uint16 hotspotId, uint16 scriptIndex, uint16 v3) {
|
||||||
|
Resources &r = Resources::getReference();
|
||||||
|
uint16 offset = r.getHotspotScript(scriptIndex);
|
||||||
|
HotspotData *rsc = r.getHotspot(hotspotId);
|
||||||
|
rsc->sequenceOffset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clears the sequence delay list
|
||||||
|
|
||||||
|
void Script::clearSequenceDelayList(uint16 v1, uint16 scriptIndex, uint16 v3) {
|
||||||
|
Resources::getReference().delayList().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// deactivates the specified hotspot from active animation
|
||||||
|
|
||||||
|
void Script::deactivateHotspot(uint16 hotspotId, uint16 v2, uint16 v3) {
|
||||||
|
Resources &rsc = Resources::getReference();
|
||||||
|
if (hotspotId < START_NONVISUAL_HOTSPOT_ID)
|
||||||
|
rsc.deactivateHotspot(hotspotId);
|
||||||
|
HotspotData *hs = rsc.getHotspot(hotspotId);
|
||||||
|
hs->flags |= 0x20;
|
||||||
|
if (hotspotId < START_NONVISUAL_HOTSPOT_ID)
|
||||||
|
hs->layer = 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the offset for the table of action sequence offsets for the given
|
||||||
|
// hotspot
|
||||||
|
|
||||||
|
void Script::setActionsOffset(uint16 hotspotId, uint16 offset, uint16 v3) {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
HotspotData *hotspot = res.getHotspot(hotspotId);
|
||||||
|
|
||||||
|
if (!res.getHotspotActions(offset))
|
||||||
|
warning("Hotspot %d set to invalid actions offset %d",
|
||||||
|
hotspotId, offset);
|
||||||
|
|
||||||
|
hotspot->actionsOffset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a sequence to be executed after a specified delay
|
||||||
|
|
||||||
|
void Script::addDelayedSequence(uint16 seqOffset, uint16 delay, uint16 v3) {
|
||||||
|
SequenceDelayList &list = Resources::getReference().delayList();
|
||||||
|
list.addSequence(delay, seqOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether the given character is in the specified room, and stores
|
||||||
|
// the result in the general value field
|
||||||
|
|
||||||
|
void Script::characterInRoom(uint16 characterId, uint16 roomNumber, uint16 v3) {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
uint16 result = 0;
|
||||||
|
if (characterId >= PLAYER_ID) {
|
||||||
|
HotspotData *hotspot = res.getHotspot(characterId);
|
||||||
|
if (hotspot->roomNumber == roomNumber)
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.fieldList().setField(GENERAL, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Changes the given hotspot's name to a new name
|
||||||
|
|
||||||
|
void Script::setHotspotName(uint16 hotspotId, uint16 nameId, uint16 v3) {
|
||||||
|
HotspotData *hotspot = Resources::getReference().getHotspot(hotspotId);
|
||||||
|
hotspot->nameId = nameId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Displays the given string resource Id in a dialog
|
||||||
|
|
||||||
|
void Script::displayDialog(uint16 stringId, uint16 v2, uint16 v3) {
|
||||||
|
Dialog::show(stringId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flags for remotely viewing a room
|
||||||
|
|
||||||
|
void Script::remoteRoomViewSetup(uint16 v1, uint16 v2, uint16 v3) {
|
||||||
|
Hotspot *player = Resources::getReference().getActiveHotspot(PLAYER_ID);
|
||||||
|
player->setTickProc(0); // disable player actions
|
||||||
|
Game::getReference().setRemoteView();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the current blocked state for the given door and stores it in the
|
||||||
|
// general value field
|
||||||
|
|
||||||
|
void Script::getDoorBlocked(uint16 hotspotId, uint16 v2, uint16 v3) {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
RoomExitJoinData *joinRec = res.getExitJoin(hotspotId);
|
||||||
|
res.fieldList().setField(GENERAL, joinRec->blocked);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrements the number of inventory itemst he player has
|
||||||
|
|
||||||
|
void Script::decrInventoryItems(uint16 v1, uint16 v2, uint16 v3) {
|
||||||
|
// module currently doesn't use a static counter for the number of
|
||||||
|
// inventory items, so don't do anything
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the current frame number for the given hotspot
|
||||||
|
|
||||||
|
void Script::setFrameNumber(uint16 hotspotId, uint16 frameNumber, uint16 v3) {
|
||||||
|
Hotspot *hotspot = Resources::getReference().getActiveHotspot(hotspotId);
|
||||||
|
hotspot->setFrameNumber(frameNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disables the given hotspot from being highlighted by the cursor
|
||||||
|
|
||||||
|
void Script::disableHotspot(uint16 hotspotId, uint16 v2, uint16 v3) {
|
||||||
|
HotspotData *hotspot = Resources::getReference().getHotspot(hotspotId);
|
||||||
|
hotspot->flags |= 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increase the player's number by the specified amount
|
||||||
|
|
||||||
|
void Script::increaseNumGroats(uint16 v1, uint16 numGroats, uint16 v3) {
|
||||||
|
ValueTableData &fields = Resources::getReference().fieldList();
|
||||||
|
fields.numGroats() += numGroats;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enables the flags for the given hotspot for it to be actively highlighted
|
||||||
|
|
||||||
|
void Script::enableHotspot(uint16 hotspotId, uint16 v2, uint16 v3) {
|
||||||
|
HotspotData *hotspot = Resources::getReference().getHotspot(hotspotId);
|
||||||
|
// Clear flag 0x20 and add flag 0x80
|
||||||
|
hotspot->flags = (hotspot->flags & 0xdf) | 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marks the door in room 14 for closing
|
||||||
|
|
||||||
|
void Script::room14DoorClose(uint16 v1, uint16 v2, uint16 v3) {
|
||||||
|
RoomExitJoinData *joinRec = Resources::getReference().getExitJoin(0x2719);
|
||||||
|
joinRec->blocked = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the sequence result to 1 if the given secondary description for a
|
||||||
|
// hotspot is empty (for inventory items, this gives the description before
|
||||||
|
// the item is initially picked up)
|
||||||
|
|
||||||
|
void Script::checkDroppedDesc(uint16 hotspotId, uint16 v2, uint16 v3) {
|
||||||
|
Resources &res = Resources::getReference();
|
||||||
|
HotspotData *hotspot = res.getHotspot(hotspotId);
|
||||||
|
uint16 seqResult = (hotspot->descId2 == 0) ? 1 : 0;
|
||||||
|
res.fieldList().setField(SEQUENCE_RESULT, seqResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marks the given door hotspot for closing
|
||||||
|
|
||||||
|
void Script::doorClose(uint16 hotspotId, uint16 v2, uint16 v3) {
|
||||||
|
RoomExitJoinData *joinRec = Resources::getReference().getExitJoin(hotspotId);
|
||||||
|
if (!joinRec) error("Tried to close a non-door");
|
||||||
|
joinRec->blocked = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marks the given door hotspot for opening
|
||||||
|
|
||||||
|
void Script::doorOpen(uint16 hotspotId, uint16 v2, uint16 v3) {
|
||||||
|
RoomExitJoinData *joinRec = Resources::getReference().getExitJoin(hotspotId);
|
||||||
|
if (!joinRec) error("Tried to close a non-door");
|
||||||
|
joinRec->blocked = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup the given message Id for the specified character and display in a dialog
|
||||||
|
|
||||||
|
void Script::displayMessage(uint16 messageId, uint16 characterId, uint16 unknownVal) {
|
||||||
|
Dialog::showMessage(messageId, characterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign the given hotspot item to the player's inventory
|
||||||
|
|
||||||
|
void Script::givePlayerItem(uint16 hotspotId, uint16 v2, uint16 v3) {
|
||||||
|
HotspotData *hotspot = Resources::getReference().getHotspot(hotspotId);
|
||||||
|
hotspot->roomNumber = PLAYER_ID;
|
||||||
|
hotspot->flags |= 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrease the number of graots the player has
|
||||||
|
|
||||||
|
void Script::decreaseNumGroats(uint16 characterId, uint16 numGroats, uint16 v3) {
|
||||||
|
ValueTableData &fields = Resources::getReference().fieldList();
|
||||||
|
fields.numGroats() -= numGroats;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the tick handler for the village Skorl to an alternate handler
|
||||||
|
|
||||||
|
void Script::setVillageSkorlTickProc(uint16 v1, uint16 v2, uint16 v3) {
|
||||||
|
HotspotData *hotspot = Resources::getReference().getHotspot(0x3F1);
|
||||||
|
hotspot->tickProcOffset = 0x7efa;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stores the current number of groats in the general field
|
||||||
|
|
||||||
|
void Script::getNumGroats(uint16 v1, uint16 v2, uint16 v3) {
|
||||||
|
ValueTableData fields = Resources::getReference().fieldList();
|
||||||
|
fields.setField(GENERAL, fields.numGroats());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loads the specified animation, completely bypassing the standard process
|
||||||
|
// of checking for a load proc/sequence
|
||||||
|
|
||||||
|
void Script::animationLoad(uint16 hotspotId, uint16 v2, uint16 v3) {
|
||||||
|
Resources::getReference().addHotspot(hotspotId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds the passed actions to the available actions for the given hotspot
|
||||||
|
|
||||||
|
void Script::addActions(uint16 hotspotId, uint16 actions, uint16 v3) {
|
||||||
|
HotspotData *hotspot = Resources::getReference().getHotspot(hotspotId);
|
||||||
|
hotspot->actions |= actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks the status of the cell door, and starts music depending on it's state
|
||||||
|
|
||||||
|
void Script::checkCellDoor(uint16 v1, uint16 v2, uint16 v3) {
|
||||||
|
// In the original game, this method checks to see if the cell door
|
||||||
|
// is currently open, if it is, starts a music sequence. I'll
|
||||||
|
// implement this method properly when I get around to implementing
|
||||||
|
// the in-game music
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void(*SequenceMethodPtr)(uint16, uint16, uint16);
|
||||||
|
|
||||||
|
struct SequenceMethodRecord {
|
||||||
|
uint8 methodIndex;
|
||||||
|
SequenceMethodPtr proc;
|
||||||
|
};
|
||||||
|
|
||||||
|
SequenceMethodRecord scriptMethods[] = {
|
||||||
|
{0, Script::activateHotspot},
|
||||||
|
{1, Script::setHotspotScript},
|
||||||
|
{4, Script::clearSequenceDelayList},
|
||||||
|
{6, Script::deactivateHotspot},
|
||||||
|
{8, Script::addDelayedSequence},
|
||||||
|
{10, Script::characterInRoom},
|
||||||
|
{11, Script::setActionsOffset},
|
||||||
|
{12, Script::setHotspotName},
|
||||||
|
{16, Script::displayDialog},
|
||||||
|
{18, Script::remoteRoomViewSetup},
|
||||||
|
{20, Script::checkCellDoor},
|
||||||
|
{22, Script::getDoorBlocked},
|
||||||
|
{28, Script::decrInventoryItems},
|
||||||
|
{30, Script::setFrameNumber},
|
||||||
|
{32, Script::disableHotspot},
|
||||||
|
{34, Script::increaseNumGroats},
|
||||||
|
{35, Script::enableHotspot},
|
||||||
|
{39, Script::room14DoorClose},
|
||||||
|
{40, Script::checkDroppedDesc},
|
||||||
|
{42, Script::doorClose},
|
||||||
|
{44, Script::doorOpen},
|
||||||
|
{47, Script::displayMessage},
|
||||||
|
{50, Script::givePlayerItem},
|
||||||
|
{51, Script::decreaseNumGroats},
|
||||||
|
{54, Script::setVillageSkorlTickProc},
|
||||||
|
{57, Script::getNumGroats},
|
||||||
|
{62, Script::animationLoad},
|
||||||
|
{63, Script::addActions},
|
||||||
|
{65, Script::checkCellDoor},
|
||||||
|
{0xff, NULL}};
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/*- Script Execution -*/
|
||||||
|
/*- -*/
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
uint16 Script::execute(uint16 startOffset) {
|
||||||
|
Resources &r = Resources::getReference();
|
||||||
|
ValueTableData &fields = r.fieldList();
|
||||||
|
MemoryBlock *scriptData = r.scriptData();
|
||||||
|
byte *scripts = scriptData->data();
|
||||||
|
Common::Stack<uint16> stack;
|
||||||
|
Common::Stack<uint16> methodStack;
|
||||||
|
byte opcode;
|
||||||
|
uint16 param, v1, v2;
|
||||||
|
uint16 param1, param2, param3;
|
||||||
|
uint16 fieldNum;
|
||||||
|
uint32 tempVal;
|
||||||
|
SequenceMethodPtr ptr;
|
||||||
|
SequenceMethodRecord *rec;
|
||||||
|
|
||||||
|
uint16 offset = startOffset;
|
||||||
|
bool breakFlag = false;
|
||||||
|
param = 0;
|
||||||
|
fields.setField(SEQUENCE_RESULT, 0);
|
||||||
|
|
||||||
|
while (!breakFlag) {
|
||||||
|
if (offset >= scriptData->size())
|
||||||
|
error("Script failure in script %d - invalid offset %d", startOffset, offset);
|
||||||
|
|
||||||
|
opcode = scripts[offset++];
|
||||||
|
if ((opcode & 1) != 0) {
|
||||||
|
// Flag to read next two bytes as active parameter
|
||||||
|
if (offset >= scriptData->size()-2)
|
||||||
|
error("Script failure in script %d - invalid offset %d", startOffset, offset);
|
||||||
|
|
||||||
|
param = READ_LE_UINT16(scripts + offset);
|
||||||
|
offset += 2;
|
||||||
|
}
|
||||||
|
opcode >>= 1; // Discard param bit from opcode byte
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case S_OPCODE_ABORT:
|
||||||
|
case S_OPCODE_ABORT2:
|
||||||
|
case S_OPCODE_ABORT3:
|
||||||
|
methodStack.clear();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_ADD:
|
||||||
|
stack.push(stack.pop() + stack.pop());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_SUBTRACT:
|
||||||
|
v1 = stack.pop();
|
||||||
|
v2 = stack.pop();
|
||||||
|
stack.push(v2 - v1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_MULTIPLY:
|
||||||
|
tempVal = stack.pop() * stack.pop();
|
||||||
|
stack.push(tempVal & 0xffff);
|
||||||
|
param = (uint16) (tempVal >> 16);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_DIVIDE:
|
||||||
|
v1 = stack.pop();
|
||||||
|
v2 = stack.pop();
|
||||||
|
stack.push(v2 / v1);
|
||||||
|
param = v2 % v1; // remainder
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_NOT_EQUALS:
|
||||||
|
stack.push((stack.pop() != stack.pop()) ? 0 : 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_EQUALS:
|
||||||
|
stack.push((stack.pop() == stack.pop()) ? 0 : 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_GT:
|
||||||
|
stack.push((stack.pop() > stack.pop()) ? 1 : 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_LT:
|
||||||
|
stack.push((stack.pop() < stack.pop()) ? 1 : 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_LT2:
|
||||||
|
stack.push((stack.pop() < stack.pop()) ? 1 : 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_GT2:
|
||||||
|
stack.push((stack.pop() > stack.pop()) ? 1 : 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_AND:
|
||||||
|
stack.push(stack.pop() & stack.pop());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_OR:
|
||||||
|
stack.push(stack.pop() | stack.pop());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_LOGICAL_AND:
|
||||||
|
stack.push(((stack.pop() != 0) && (stack.pop() != 0)) ? 1 : 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_LOGICAL_OR:
|
||||||
|
stack.push(((stack.pop() != 0) || (stack.pop() != 0)) ? 1 : 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_GET_FIELD:
|
||||||
|
// Opcode not yet fully implemented
|
||||||
|
fieldNum = param >> 1;
|
||||||
|
v1 = fields.getField(fieldNum);
|
||||||
|
stack.push(v1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_SET_FIELD:
|
||||||
|
// Opcode not yet fully implemented
|
||||||
|
fieldNum = param >> 1;
|
||||||
|
v1 = stack.pop();
|
||||||
|
fields.setField(fieldNum, v1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_PUSH:
|
||||||
|
stack.push(param);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_SUBROUTINE:
|
||||||
|
methodStack.push(offset);
|
||||||
|
offset = param;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_EXEC:
|
||||||
|
param1 = 0; param2 = 0; param3 = 0;
|
||||||
|
if (!stack.empty()) param1 = stack.pop();
|
||||||
|
if (!stack.empty()) param2 = stack.pop();
|
||||||
|
if (!stack.empty()) param3 = stack.pop();
|
||||||
|
|
||||||
|
rec = &scriptMethods[0];
|
||||||
|
while ((rec->methodIndex != 0xff) && (rec->methodIndex != param))
|
||||||
|
++rec;
|
||||||
|
|
||||||
|
if (rec->methodIndex == 0xff)
|
||||||
|
warning("Undefined script method %d", param);
|
||||||
|
else {
|
||||||
|
ptr = rec->proc;
|
||||||
|
ptr(param1, param2, param3);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_COND_JUMP:
|
||||||
|
v1 = stack.pop();
|
||||||
|
if (v1 == 0) offset += (int16) param;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_JUMP:
|
||||||
|
offset += (int16) param;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_RANDOM:
|
||||||
|
param = r.random() >> 8; // make number between 0 to 255
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_OPCODE_END:
|
||||||
|
// Signal to end the execution
|
||||||
|
if (!methodStack.empty())
|
||||||
|
offset = methodStack.pop();
|
||||||
|
else
|
||||||
|
breakFlag = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error("Unknown script opcode %d", opcode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields.getField(SEQUENCE_RESULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/*- Hotspot Script Handler -*/
|
||||||
|
/*- -*/
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int16 HotspotScript::nextVal(MemoryBlock *data, uint16 &offset) {
|
||||||
|
if (offset >= data->size() - 1)
|
||||||
|
error("Script failure - invalid offset");
|
||||||
|
int16 value = READ_LE_UINT16(data->data() + offset);
|
||||||
|
offset += 2;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HotspotScript::execute(Hotspot *h)
|
||||||
|
{
|
||||||
|
Resources &r = Resources::getReference();
|
||||||
|
MemoryBlock *scriptData = r.hotspotScriptData();
|
||||||
|
uint16 offset = h->script();
|
||||||
|
int16 opcode = 0;
|
||||||
|
int16 param1, param2;
|
||||||
|
bool breakFlag = false;
|
||||||
|
|
||||||
|
while (!breakFlag) {
|
||||||
|
opcode = nextVal(scriptData, offset);
|
||||||
|
switch (opcode) {
|
||||||
|
case S2_OPCODE_TIMEOUT:
|
||||||
|
param1 = nextVal(scriptData, offset);
|
||||||
|
h->setTickCtr(param1);
|
||||||
|
h->setScript(offset);
|
||||||
|
breakFlag = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S2_OPCODE_POSITION:
|
||||||
|
param1 = nextVal(scriptData, offset);
|
||||||
|
param2 = nextVal(scriptData, offset);
|
||||||
|
h->setPosition(param1 - 0x80, param2 - 0x80);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S2_OPCODE_CHANGE_POS:
|
||||||
|
param1 = nextVal(scriptData, offset);
|
||||||
|
param2 = nextVal(scriptData, offset);
|
||||||
|
h->setPosition(h->x() + param1, h->y() + param2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S2_OPCODE_UNLOAD:
|
||||||
|
breakFlag = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S2_OPCODE_DIMENSIONS:
|
||||||
|
param1 = nextVal(scriptData, offset) << 4;
|
||||||
|
param2 = nextVal(scriptData, offset);
|
||||||
|
h->setSize((uint16) param1, (uint16) param2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S2_OPCODE_JUMP:
|
||||||
|
offset = (uint16) nextVal(scriptData, offset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S2_OPCODE_ANIMATION:
|
||||||
|
param1 = nextVal(scriptData, offset);
|
||||||
|
h->setAnimation(param1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S2_OPCODE_UNKNOWN_247:
|
||||||
|
param1 = nextVal(scriptData, offset);
|
||||||
|
param2 = nextVal(scriptData, offset);
|
||||||
|
// warning("UNKNOWN_247 stub called");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S2_OPCODE_UNKNOWN_258:
|
||||||
|
param1 = nextVal(scriptData, offset);
|
||||||
|
// warning("UNKNOWN_258 stub called");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S2_OPCODE_ACTIONS:
|
||||||
|
param1 = nextVal(scriptData, offset) << 4;
|
||||||
|
param2 = nextVal(scriptData, offset);
|
||||||
|
h->setActions((uint32) param1 | ((uint32) param2 << 16));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Set the animation frame number
|
||||||
|
h->setFrameNumber(opcode);
|
||||||
|
h->setScript(offset);
|
||||||
|
breakFlag = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (opcode == S2_OPCODE_UNLOAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
117
lure/scripts.h
Normal file
117
lure/scripts.h
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_scripts_h__
|
||||||
|
#define __lure_scripts_h__
|
||||||
|
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/memory.h"
|
||||||
|
#include "lure/hotspots.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
// Opcode list
|
||||||
|
#define S_OPCODE_ABORT 0
|
||||||
|
#define S_OPCODE_ADD 1
|
||||||
|
#define S_OPCODE_SUBTRACT 2
|
||||||
|
#define S_OPCODE_MULTIPLY 3
|
||||||
|
#define S_OPCODE_DIVIDE 4
|
||||||
|
#define S_OPCODE_NOT_EQUALS 5
|
||||||
|
#define S_OPCODE_EQUALS 6
|
||||||
|
#define S_OPCODE_GT 7
|
||||||
|
#define S_OPCODE_LT 8
|
||||||
|
#define S_OPCODE_LT2 9
|
||||||
|
#define S_OPCODE_GT2 10
|
||||||
|
#define S_OPCODE_AND 11
|
||||||
|
#define S_OPCODE_OR 12
|
||||||
|
#define S_OPCODE_LOGICAL_AND 13
|
||||||
|
#define S_OPCODE_LOGICAL_OR 14
|
||||||
|
#define S_OPCODE_GET_FIELD 15
|
||||||
|
#define S_OPCODE_SET_FIELD 16
|
||||||
|
#define S_OPCODE_PUSH 17
|
||||||
|
#define S_OPCODE_SUBROUTINE 18
|
||||||
|
#define S_OPCODE_EXEC 19
|
||||||
|
#define S_OPCODE_END 20
|
||||||
|
#define S_OPCODE_COND_JUMP 21
|
||||||
|
#define S_OPCODE_JUMP 22
|
||||||
|
#define S_OPCODE_ABORT2 23
|
||||||
|
#define S_OPCODE_ABORT3 24
|
||||||
|
#define S_OPCODE_RANDOM 25
|
||||||
|
|
||||||
|
#define S2_OPCODE_TIMEOUT -1
|
||||||
|
#define S2_OPCODE_POSITION -2
|
||||||
|
#define S2_OPCODE_CHANGE_POS -3
|
||||||
|
#define S2_OPCODE_UNLOAD -4
|
||||||
|
#define S2_OPCODE_DIMENSIONS -5
|
||||||
|
#define S2_OPCODE_JUMP -6
|
||||||
|
#define S2_OPCODE_ANIMATION -7
|
||||||
|
#define S2_OPCODE_UNKNOWN_247 -8
|
||||||
|
#define S2_OPCODE_UNKNOWN_258 -9
|
||||||
|
#define S2_OPCODE_ACTIONS -10
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Script {
|
||||||
|
public:
|
||||||
|
static uint16 execute(uint16 startOffset);
|
||||||
|
|
||||||
|
static void activateHotspot(uint16 hotspotId, uint16 v2, uint16 v3);
|
||||||
|
static void setHotspotScript(uint16 hotspotId, uint16 scriptIndex, uint16 v3);
|
||||||
|
static void clearSequenceDelayList(uint16 v1, uint16 scriptIndex, uint16 v3);
|
||||||
|
static void method2(uint16 v1, uint16 v2, uint16 v3);
|
||||||
|
static void deactivateHotspot(uint16 hotspotId, uint16 v2, uint16 v3);
|
||||||
|
static void setActionsOffset(uint16 hotspotId, uint16 offset, uint16 v3);
|
||||||
|
static void addDelayedSequence(uint16 seqOffset, uint16 delay, uint16 v3);
|
||||||
|
static void characterInRoom(uint16 characterId, uint16 roomNumber, uint16 v3);
|
||||||
|
static void setHotspotName(uint16 hotspotId, uint16 nameId, uint16 v3);
|
||||||
|
static void displayDialog(uint16 stringId, uint16 v2, uint16 v3);
|
||||||
|
static void remoteRoomViewSetup(uint16 v1, uint16 v2, uint16 v3);
|
||||||
|
static void getDoorBlocked(uint16 hotspotId, uint16 v2, uint16 v3);
|
||||||
|
static void decrInventoryItems(uint16 v1, uint16 v2, uint16 v3);
|
||||||
|
static void setFrameNumber(uint16 hotspotId, uint16 offset, uint16 v3);
|
||||||
|
static void disableHotspot(uint16 hotspotId, uint16 v2, uint16 v3);
|
||||||
|
static void increaseNumGroats(uint16 characterId, uint16 numGroats, uint16 v3);
|
||||||
|
static void enableHotspot(uint16 hotspotId, uint16 v2, uint16 v3);
|
||||||
|
static void room14DoorClose(uint16 v1, uint16 v2, uint16 v3);
|
||||||
|
static void checkDroppedDesc(uint16 hotspotId, uint16 v2, uint16 v3);
|
||||||
|
static void doorClose(uint16 hotspotId, uint16 v2, uint16 v3);
|
||||||
|
static void displayMessage(uint16 messageId, uint16 characterId, uint16 unknownVal);
|
||||||
|
static void doorOpen(uint16 hotspotId, uint16 v2, uint16 v3);
|
||||||
|
static void givePlayerItem(uint16 hotspotId, uint16 v2, uint16 v3);
|
||||||
|
static void decreaseNumGroats(uint16 characterId, uint16 numGroats, uint16 v3);
|
||||||
|
static void setVillageSkorlTickProc(uint16 v1, uint16 v2, uint16 v3);
|
||||||
|
static void getNumGroats(uint16 v1, uint16 v2, uint16 v3);
|
||||||
|
static void animationLoad(uint16 hotspotId, uint16 v2, uint16 v3);
|
||||||
|
static void addActions(uint16 hotspotId, uint16 actions, uint16 v3);
|
||||||
|
static void checkCellDoor(uint16 v1, uint16 v2, uint16 v3);
|
||||||
|
};
|
||||||
|
|
||||||
|
class HotspotScript {
|
||||||
|
private:
|
||||||
|
static int16 nextVal(MemoryBlock *data, uint16 &offset);
|
||||||
|
public:
|
||||||
|
static bool execute(Hotspot *h);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
300
lure/strings.cpp
Normal file
300
lure/strings.cpp
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/strings.h"
|
||||||
|
#include "lure/disk.h"
|
||||||
|
#include "lure/room.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
StringData *int_strings = NULL;
|
||||||
|
|
||||||
|
StringData::StringData() {
|
||||||
|
int_strings = this;
|
||||||
|
|
||||||
|
for (uint8 ctr = 0; ctr < MAX_NUM_CHARS; ++ctr) _chars[ctr] = NULL;
|
||||||
|
_numChars = 0;
|
||||||
|
_names = Disk::getReference().getEntry(NAMES_RESOURCE_ID);
|
||||||
|
_strings[0] = Disk::getReference().getEntry(STRINGS_RESOURCE_ID);
|
||||||
|
_strings[1] = Disk::getReference().getEntry(STRINGS_2_RESOURCE_ID);
|
||||||
|
_strings[2] = Disk::getReference().getEntry(STRINGS_3_RESOURCE_ID);
|
||||||
|
|
||||||
|
// Add in the list of bit sequences, and what characters they represent
|
||||||
|
add("00", ' ');
|
||||||
|
add("0100", 'e');
|
||||||
|
add("0101", 'o');
|
||||||
|
add("0110", 't');
|
||||||
|
add("01110", 'a');
|
||||||
|
add("01111", 'n');
|
||||||
|
add("1000", 's');
|
||||||
|
add("1001", 'i');
|
||||||
|
add("1010", 'r');
|
||||||
|
add("10110", 'h');
|
||||||
|
add("101110", 'u');
|
||||||
|
add("1011110", 'l');
|
||||||
|
add("1011111", 'd');
|
||||||
|
add("11000", 'y');
|
||||||
|
add("110010", 'g');
|
||||||
|
add("110011", '\0');
|
||||||
|
add("110100", 'w');
|
||||||
|
add("110101", 'c');
|
||||||
|
add("110110", 'f');
|
||||||
|
add("1101110", '.');
|
||||||
|
add("1101111", 'm');
|
||||||
|
add("111000", 'p');
|
||||||
|
add("111001", 'b');
|
||||||
|
add("1110100", ',');
|
||||||
|
add("1110101", 'k');
|
||||||
|
add("1110110", '\'');
|
||||||
|
add("11101110", 'I');
|
||||||
|
add("11101111", 'v');
|
||||||
|
add("1111000", '!');
|
||||||
|
add("1111001", '\xb4');
|
||||||
|
add("11110100", 'T');
|
||||||
|
add("11110101", '\xb5');
|
||||||
|
add("11110110", '?');
|
||||||
|
add("111101110", '\xb2');
|
||||||
|
add("111101111", '\xb3');
|
||||||
|
add("11111000", 'W');
|
||||||
|
add("111110010", 'H');
|
||||||
|
add("111110011", 'A');
|
||||||
|
add("111110100", '\xb1');
|
||||||
|
add("111110101", 'S');
|
||||||
|
add("111110110", 'Y');
|
||||||
|
add("1111101110", 'G');
|
||||||
|
add("11111011110", 'M');
|
||||||
|
add("11111011111", 'N');
|
||||||
|
add("111111000", 'O');
|
||||||
|
add("1111110010", 'E');
|
||||||
|
add("1111110011", 'L');
|
||||||
|
add("1111110100", '-');
|
||||||
|
add("1111110101", 'R');
|
||||||
|
add("1111110110", 'B');
|
||||||
|
add("11111101110", 'D');
|
||||||
|
add("11111101111", '\xa6');
|
||||||
|
add("1111111000", 'C');
|
||||||
|
add("11111110010", 'x');
|
||||||
|
add("11111110011", 'j');
|
||||||
|
add("1111111010", '\xac');
|
||||||
|
add("11111110110", '\xa3');
|
||||||
|
add("111111101110", 'P');
|
||||||
|
add("111111101111", 'U');
|
||||||
|
add("11111111000", 'q');
|
||||||
|
add("11111111001", '\xad');
|
||||||
|
add("111111110100", 'F');
|
||||||
|
add("111111110101", '1');
|
||||||
|
add("111111110110", '\xaf');
|
||||||
|
add("1111111101110", ';');
|
||||||
|
add("1111111101111", 'z');
|
||||||
|
add("111111111000", '\xa5');
|
||||||
|
add("1111111110010", '2');
|
||||||
|
add("1111111110011", '\xb0');
|
||||||
|
add("111111111010", 'K');
|
||||||
|
add("1111111110110", '%');
|
||||||
|
add("11111111101110", '\xa2');
|
||||||
|
add("11111111101111", '5');
|
||||||
|
add("1111111111000", ':');
|
||||||
|
add("1111111111001", 'J');
|
||||||
|
add("1111111111010", 'V');
|
||||||
|
add("11111111110110", '6');
|
||||||
|
add("11111111110111", '3');
|
||||||
|
add("1111111111100", '\xab');
|
||||||
|
add("11111111111010", '\xae');
|
||||||
|
add("111111111110110", '0');
|
||||||
|
add("111111111110111", '4');
|
||||||
|
add("11111111111100", '7');
|
||||||
|
add("111111111111010", '9');
|
||||||
|
add("111111111111011", '"');
|
||||||
|
add("111111111111100", '8');
|
||||||
|
add("111111111111101", '\xa7');
|
||||||
|
add("1111111111111100", '/');
|
||||||
|
add("1111111111111101", 'Q');
|
||||||
|
add("11111111111111100", '\xa8');
|
||||||
|
add("11111111111111101", '(');
|
||||||
|
add("111111111111111100", ')');
|
||||||
|
add("111111111111111101", '\x99');
|
||||||
|
add("11111111111111111", '\xa9');
|
||||||
|
}
|
||||||
|
|
||||||
|
StringData::~StringData() {
|
||||||
|
int_strings = NULL;
|
||||||
|
|
||||||
|
for (uint8 ctr = 0; ctr < MAX_NUM_CHARS; ++ctr)
|
||||||
|
if (_chars[ctr]) delete _chars[ctr];
|
||||||
|
else break;
|
||||||
|
|
||||||
|
delete _names;
|
||||||
|
delete _strings[0];
|
||||||
|
delete _strings[1];
|
||||||
|
delete _strings[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
StringData &StringData::getReference() {
|
||||||
|
return *int_strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringData::add(const char *sequence, char ascii) {
|
||||||
|
uint32 value = 0;
|
||||||
|
|
||||||
|
for (uint8 index = 0; index < strlen(sequence); ++index) {
|
||||||
|
if (sequence[index] == '1')
|
||||||
|
value |= (1 << index);
|
||||||
|
else if (sequence[index] != '0')
|
||||||
|
error("Invalid character in string bit-stream sequence");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_numChars == MAX_NUM_CHARS)
|
||||||
|
error("Max characters too lower in string decoder");
|
||||||
|
_chars[_numChars++] = new CharacterEntry(strlen(sequence), value, ascii);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte StringData::readBit() {
|
||||||
|
byte result = ((*_srcPos & _bitMask) != 0) ? 1 : 0;
|
||||||
|
_bitMask >>= 1;
|
||||||
|
if (_bitMask == 0) {
|
||||||
|
_bitMask = 0x80;
|
||||||
|
++_srcPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringData::initPosition(uint16 stringId) {
|
||||||
|
uint16 roomNumber = Room::getReference().roomNumber();
|
||||||
|
byte *stringTable;
|
||||||
|
|
||||||
|
if ((roomNumber >= 0x2A) && (stringId >= STRING_ID_RANGE) && (stringId < STRING_ID_UPPER))
|
||||||
|
stringId = 0x76;
|
||||||
|
if ((roomNumber < 0x2A) && (stringId >= STRING_ID_UPPER))
|
||||||
|
stringId = 0x76;
|
||||||
|
|
||||||
|
if (stringId < STRING_ID_RANGE)
|
||||||
|
stringTable = _strings[0]->data();
|
||||||
|
else if (stringId < STRING_ID_RANGE*2) {
|
||||||
|
stringId -= STRING_ID_RANGE;
|
||||||
|
stringTable = _strings[1]->data();
|
||||||
|
} else {
|
||||||
|
stringId -= STRING_ID_RANGE * 2;
|
||||||
|
stringTable = _strings[2]->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
_srcPos = stringTable + 4;
|
||||||
|
|
||||||
|
uint32 total = 0;
|
||||||
|
int numLoops = stringId >> 5;
|
||||||
|
for (int ctr = 0; ctr < numLoops; ++ctr) {
|
||||||
|
total += READ_LE_UINT16(_srcPos);
|
||||||
|
_srcPos += sizeof(uint16);
|
||||||
|
}
|
||||||
|
|
||||||
|
numLoops = stringId & 0x1f;
|
||||||
|
if (numLoops!= 0) {
|
||||||
|
byte *tempPtr = stringTable + (stringId & 0xffe0) + READ_LE_UINT16(stringTable);
|
||||||
|
|
||||||
|
for (int ctr = 0; ctr < numLoops; ++ctr) {
|
||||||
|
byte v = *tempPtr++;
|
||||||
|
if ((v & 0x80) == 0) {
|
||||||
|
total += v;
|
||||||
|
} else {
|
||||||
|
total += (v & 0x7f) << 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_bitMask = 0x80;
|
||||||
|
|
||||||
|
if ((total & 3) != 0)
|
||||||
|
_bitMask >>= (total & 3) * 2;
|
||||||
|
|
||||||
|
_srcPos = stringTable + (total >> 2) + READ_LE_UINT16(stringTable + 2);
|
||||||
|
|
||||||
|
// Final positioning to start of string
|
||||||
|
for (;;) {
|
||||||
|
if (readBit() == 0) break;
|
||||||
|
_srcPos += 2;
|
||||||
|
}
|
||||||
|
readBit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// readCharatcer
|
||||||
|
// Reads the next character from the input bit stream
|
||||||
|
|
||||||
|
char StringData::readCharacter() {
|
||||||
|
uint32 searchValue = 0;
|
||||||
|
|
||||||
|
// Loop through an increasing number of bits
|
||||||
|
|
||||||
|
for (uint8 numBits = 1; numBits <= 18; ++numBits) {
|
||||||
|
searchValue |= readBit() << (numBits - 1);
|
||||||
|
|
||||||
|
// Scan through list for a match
|
||||||
|
for (int index = 0; _chars[index] != NULL; ++index) {
|
||||||
|
if ((_chars[index]->_numBits == numBits) &&
|
||||||
|
(_chars[index]->_sequence == searchValue))
|
||||||
|
return _chars[index]->_ascii;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error("Unknown bit sequence encountered when decoding string");
|
||||||
|
}
|
||||||
|
|
||||||
|
void StringData::getString(uint16 stringId, char *dest, const char *hotspotName,
|
||||||
|
const char *actionName) {
|
||||||
|
char ch;
|
||||||
|
char *destPos = dest;
|
||||||
|
initPosition(stringId);
|
||||||
|
|
||||||
|
ch = readCharacter();
|
||||||
|
while (ch != '\0') {
|
||||||
|
if (ch == '%') {
|
||||||
|
// Copy over hotspot or action
|
||||||
|
ch = readCharacter();
|
||||||
|
const char *p = (ch == '1') ? hotspotName : actionName;
|
||||||
|
strcpy(destPos, p);
|
||||||
|
destPos += strlen(p);
|
||||||
|
} else if ((uint8) ch >= 0xa0) {
|
||||||
|
const char *p = getName((uint8) ch - 0xa0);
|
||||||
|
strcpy(destPos, p);
|
||||||
|
destPos += strlen(p);
|
||||||
|
} else {
|
||||||
|
*destPos++ = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = readCharacter();
|
||||||
|
}
|
||||||
|
|
||||||
|
*destPos = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// getName
|
||||||
|
// Returns the name or fragment of word at the specified index in the names resource
|
||||||
|
|
||||||
|
char *StringData::getName(uint8 nameIndex) {
|
||||||
|
uint16 numNames = *((uint16 *) _names->data()) / 2;
|
||||||
|
if (nameIndex >= numNames)
|
||||||
|
error("Invalid name index was passed to getCharacterName");
|
||||||
|
|
||||||
|
uint16 nameStart = *((uint16 *) (_names->data() + (nameIndex * 2)));
|
||||||
|
return (char *) (_names->data() + nameStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Lure
|
67
lure/strings.h
Normal file
67
lure/strings.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_strings_h__
|
||||||
|
#define __lure_strings_h__
|
||||||
|
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
#include "lure/memory.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
class CharacterEntry {
|
||||||
|
public:
|
||||||
|
uint8 _numBits;
|
||||||
|
uint32 _sequence;
|
||||||
|
char _ascii;
|
||||||
|
|
||||||
|
CharacterEntry(uint8 numBits, uint32 sequence, char ascii): _numBits(numBits),
|
||||||
|
_sequence(sequence), _ascii(ascii) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_NUM_CHARS 218
|
||||||
|
|
||||||
|
class StringData {
|
||||||
|
private:
|
||||||
|
MemoryBlock *_strings[3];
|
||||||
|
MemoryBlock *_names;
|
||||||
|
CharacterEntry *_chars[MAX_NUM_CHARS];
|
||||||
|
uint8 _numChars;
|
||||||
|
byte *_srcPos;
|
||||||
|
byte _bitMask;
|
||||||
|
|
||||||
|
void add(const char *sequence, char ascii);
|
||||||
|
void initPosition(uint16 stringId);
|
||||||
|
char readCharacter();
|
||||||
|
byte readBit();
|
||||||
|
public:
|
||||||
|
StringData();
|
||||||
|
~StringData();
|
||||||
|
static StringData &getReference();
|
||||||
|
|
||||||
|
void getString(uint16 stringId, char *dest, const char *hotspotName, const char *actionName);
|
||||||
|
char *getName(uint8 nameIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Lure
|
||||||
|
|
||||||
|
#endif
|
456
lure/surface.cpp
Normal file
456
lure/surface.cpp
Normal file
|
@ -0,0 +1,456 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/surface.h"
|
||||||
|
#include "lure/decode.h"
|
||||||
|
#include "lure/system.h"
|
||||||
|
#include "lure/events.h"
|
||||||
|
#include "lure/screen.h"
|
||||||
|
#include "lure/room.h"
|
||||||
|
#include "lure/strings.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
// These variables hold resources commonly used by the Surfaces, and must be initialised and freed
|
||||||
|
// by the static Surface methods initialise and deinitailse
|
||||||
|
|
||||||
|
static MemoryBlock *int_font = NULL;
|
||||||
|
static MemoryBlock *int_dialog_frame = NULL;
|
||||||
|
static uint8 fontSize[NUM_CHARS_IN_FONT];
|
||||||
|
|
||||||
|
void Surface::initialise() {
|
||||||
|
int_font = Disk::getReference().getEntry(FONT_RESOURCE_ID);
|
||||||
|
int_dialog_frame = Disk::getReference().getEntry(DIALOG_RESOURCE_ID);
|
||||||
|
|
||||||
|
// Calculate the size of each font character
|
||||||
|
for (int ctr = 0; ctr < NUM_CHARS_IN_FONT; ++ctr) {
|
||||||
|
byte *pChar = int_font->data() + (ctr * 8);
|
||||||
|
fontSize[ctr] = 0;
|
||||||
|
|
||||||
|
for (int yp = 0; yp < FONT_HEIGHT; ++yp)
|
||||||
|
{
|
||||||
|
byte v = *pChar++;
|
||||||
|
|
||||||
|
for (int xp = 0; xp < FONT_WIDTH; ++xp) {
|
||||||
|
if ((v & 0x80) && (xp > fontSize[ctr]))
|
||||||
|
fontSize[ctr] = xp;
|
||||||
|
v = (v << 1) & 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If character is empty, like for a space, give a default size
|
||||||
|
if (fontSize[ctr] == 0) fontSize[ctr] = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Surface::deinitialise() {
|
||||||
|
delete int_font;
|
||||||
|
delete int_dialog_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
Surface::Surface(MemoryBlock *src, uint16 wdth, uint16 hght): _data(src),
|
||||||
|
_width(wdth), _height(hght) {
|
||||||
|
if ((uint32) (wdth * hght) != src->size())
|
||||||
|
error("Surface dimensions do not match size of passed data");
|
||||||
|
}
|
||||||
|
|
||||||
|
Surface::Surface(uint16 wdth, uint16 hght): _data(Memory::allocate(wdth*hght)),
|
||||||
|
_width(wdth), _height(hght) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Surface::~Surface() {
|
||||||
|
delete _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Surface::loadScreen(uint16 resourceId) {
|
||||||
|
MemoryBlock *rawData = Disk::getReference().getEntry(resourceId);
|
||||||
|
PictureDecoder decoder;
|
||||||
|
MemoryBlock *tmpScreen = decoder.decode(rawData, FULL_SCREEN_HEIGHT * FULL_SCREEN_WIDTH);
|
||||||
|
delete rawData;
|
||||||
|
empty();
|
||||||
|
copyFrom(tmpScreen, MENUBAR_Y_SIZE * FULL_SCREEN_WIDTH);
|
||||||
|
|
||||||
|
delete tmpScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Surface::writeChar(uint16 x, uint16 y, uint8 ascii, bool transparent, uint8 colour) {
|
||||||
|
byte *const addr = _data->data() + (y * _width) + x;
|
||||||
|
|
||||||
|
if ((ascii < 32) || (ascii >= 32 + NUM_CHARS_IN_FONT))
|
||||||
|
error("Invalid ascii character passed for display '%d'", ascii);
|
||||||
|
|
||||||
|
uint8 v;
|
||||||
|
byte *pFont = int_font->data() + ((ascii - 32) * 8);
|
||||||
|
byte *pDest;
|
||||||
|
uint8 charWidth = 0;
|
||||||
|
|
||||||
|
for (int y1 = 0; y1 < 8; ++y1) {
|
||||||
|
v = *pFont++;
|
||||||
|
pDest = addr + (y1 * _width);
|
||||||
|
|
||||||
|
for (int x1 = 0; x1 < 8; ++x1, ++pDest) {
|
||||||
|
if (v & 0x80) {
|
||||||
|
*pDest = colour;
|
||||||
|
if (x1+1 > charWidth) charWidth = x1 + 1;
|
||||||
|
}
|
||||||
|
else if (!transparent) *pDest = 0;
|
||||||
|
v = (v << 1) & 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Surface::writeString(uint16 x, uint16 y, Common::String line, bool transparent,
|
||||||
|
uint8 colour, bool varLength) {
|
||||||
|
const char *sPtr = line.c_str();
|
||||||
|
|
||||||
|
while (*sPtr) {
|
||||||
|
writeChar(x, y, (uint8) *sPtr, transparent, colour);
|
||||||
|
|
||||||
|
// Move to after the character in preparation for the next character
|
||||||
|
if (!varLength) x += FONT_WIDTH;
|
||||||
|
else x += fontSize[*sPtr - ' '] + 2;
|
||||||
|
|
||||||
|
++sPtr; // Move to next character
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Surface::transparentCopyTo(Surface *dest) {
|
||||||
|
if (dest->width() != _width)
|
||||||
|
error("Incompatible surface sizes for transparent copy");
|
||||||
|
|
||||||
|
byte *pSrc = _data->data();
|
||||||
|
byte *pDest = dest->data().data();
|
||||||
|
uint16 numBytes = MIN(_height,dest->height()) * FULL_SCREEN_WIDTH;
|
||||||
|
|
||||||
|
while (numBytes-- > 0) {
|
||||||
|
if (*pSrc) *pDest = *pSrc;
|
||||||
|
|
||||||
|
++pSrc;
|
||||||
|
++pDest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Surface::copyTo(Surface *dest)
|
||||||
|
{
|
||||||
|
copyTo(dest, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Surface::copyTo(Surface *dest, uint16 x, uint16 y)
|
||||||
|
{
|
||||||
|
if ((x == 0) && (dest->width() == _width)) {
|
||||||
|
// Use fast data transfer
|
||||||
|
uint32 dataSize = dest->data().size() - (y * _width);
|
||||||
|
if (dataSize > _data->size()) dataSize = _data->size();
|
||||||
|
dest->data().copyFrom(_data, 0, y * _width, dataSize);
|
||||||
|
} else {
|
||||||
|
// Use slower transfer
|
||||||
|
Rect rect;
|
||||||
|
rect.left = 0; rect.top = 0;
|
||||||
|
rect.right = _width-1; rect.bottom = _height-1;
|
||||||
|
copyTo(dest, rect, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Surface::copyTo(Surface *dest, const Rect &srcBounds,
|
||||||
|
uint16 destX, uint16 destY, int transparentColour) {
|
||||||
|
for (uint16 y=0; y<=(srcBounds.bottom-srcBounds.top); ++y) {
|
||||||
|
const uint32 srcPos = (srcBounds.top + y) * _width + srcBounds.left;
|
||||||
|
const uint32 destPos = (destY+y) * dest->width() + destX;
|
||||||
|
|
||||||
|
uint16 numBytes = srcBounds.right-srcBounds.left+1;
|
||||||
|
if (transparentColour == -1) {
|
||||||
|
// No trnnsparent colour, so copy all the bytes of the line
|
||||||
|
dest->data().copyFrom(_data, srcPos, destPos, numBytes);
|
||||||
|
} else {
|
||||||
|
byte *pSrc = _data->data() + srcPos;
|
||||||
|
byte *pDest = dest->data().data() + destPos;
|
||||||
|
|
||||||
|
while (numBytes-- > 0) {
|
||||||
|
if (*pSrc != (uint8) transparentColour)
|
||||||
|
*pDest = *pSrc;
|
||||||
|
++pSrc;
|
||||||
|
++pDest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Surface::copyFrom(MemoryBlock *src, uint32 destOffset) {
|
||||||
|
uint32 size = _data->size() - destOffset;
|
||||||
|
if (src->size() > size) size = src->size();
|
||||||
|
_data->copyFrom(src, 0, destOffset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fillRect
|
||||||
|
// Fills a rectangular area with a colour
|
||||||
|
|
||||||
|
void Surface::fillRect(const Rect &r, uint8 colour) {
|
||||||
|
for (int yp = r.top; yp <= r.bottom; ++yp) {
|
||||||
|
byte *const addr = _data->data() + (yp * _width) + r.left;
|
||||||
|
memset(addr, colour, r.width());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// createDialog
|
||||||
|
// Forms a dialog encompassing the entire surface
|
||||||
|
|
||||||
|
void copyLine(byte *pSrc, byte *pDest, uint16 leftSide, uint16 center, uint16 rightSide) {
|
||||||
|
// Left area
|
||||||
|
memcpy(pDest, pSrc, leftSide);
|
||||||
|
pSrc += leftSide; pDest += leftSide;
|
||||||
|
// Center area
|
||||||
|
memset(pDest, *pSrc, center);
|
||||||
|
++pSrc; pDest += center;
|
||||||
|
// Right side
|
||||||
|
memcpy(pDest, pSrc, rightSide);
|
||||||
|
pSrc += rightSide; pDest += rightSide;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Surface::createDialog(bool blackFlag) {
|
||||||
|
if ((_width < 20) || (_height < 20)) return;
|
||||||
|
|
||||||
|
byte *pSrc = int_dialog_frame->data();
|
||||||
|
byte *pDest = _data->data();
|
||||||
|
uint16 xCenter = _width - DIALOG_EDGE_SIZE * 2;
|
||||||
|
uint16 yCenter = _height - DIALOG_EDGE_SIZE * 2;
|
||||||
|
|
||||||
|
// Dialog top
|
||||||
|
for (int y = 0; y < 9; ++y) {
|
||||||
|
copyLine(pSrc, pDest, DIALOG_EDGE_SIZE - 2, xCenter + 2, DIALOG_EDGE_SIZE);
|
||||||
|
pSrc += (DIALOG_EDGE_SIZE - 2) + 1 + DIALOG_EDGE_SIZE;
|
||||||
|
pDest += _width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dialog sides - note that the same source data gets used for all side lines
|
||||||
|
for (int y = 0; y < yCenter; ++y) {
|
||||||
|
copyLine(pSrc, pDest, DIALOG_EDGE_SIZE, xCenter, DIALOG_EDGE_SIZE);
|
||||||
|
pDest += _width;
|
||||||
|
}
|
||||||
|
pSrc += DIALOG_EDGE_SIZE * 2 + 1;
|
||||||
|
|
||||||
|
// Dialog bottom
|
||||||
|
for (int y = 0; y < 9; ++y) {
|
||||||
|
copyLine(pSrc, pDest, DIALOG_EDGE_SIZE, xCenter + 1, DIALOG_EDGE_SIZE - 1);
|
||||||
|
pSrc += DIALOG_EDGE_SIZE + 1 + (DIALOG_EDGE_SIZE - 1);
|
||||||
|
pDest += _width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final processing - if black flag set, clear dialog inside area
|
||||||
|
if (blackFlag) {
|
||||||
|
Rect r = Rect(DIALOG_EDGE_SIZE, DIALOG_EDGE_SIZE,
|
||||||
|
_width - DIALOG_EDGE_SIZE, _height-DIALOG_EDGE_SIZE);
|
||||||
|
fillRect(r, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Surface::copyToScreen(uint16 x, uint16 y) {
|
||||||
|
OSystem &system = System::getReference();
|
||||||
|
system.copyRectToScreen(_data->data(), _width, x, y, _width, _height);
|
||||||
|
system.updateScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Surface::centerOnScreen() {
|
||||||
|
OSystem &system = System::getReference();
|
||||||
|
|
||||||
|
system.copyRectToScreen(_data->data(), _width,
|
||||||
|
(FULL_SCREEN_WIDTH - _width) / 2, (FULL_SCREEN_HEIGHT - _height) / 2,
|
||||||
|
_width, _height);
|
||||||
|
system.updateScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 Surface::textWidth(const char *s, int numChars) {
|
||||||
|
uint16 result = 0;
|
||||||
|
if (numChars == 0) numChars = strlen(s);
|
||||||
|
|
||||||
|
while (numChars-- > 0) result += fontSize[*s++ - ' '] + 2;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Surface *Surface::newDialog(uint16 width, uint8 numLines, char **lines, bool varLength, uint8 colour) {
|
||||||
|
Surface *s = new Surface(width, (DIALOG_EDGE_SIZE + 3) * 2 +
|
||||||
|
numLines * (FONT_HEIGHT - 1));
|
||||||
|
s->createDialog();
|
||||||
|
|
||||||
|
for (uint8 ctr = 0; ctr < numLines; ++ctr)
|
||||||
|
s->writeString(DIALOG_EDGE_SIZE + 3, DIALOG_EDGE_SIZE + 3 +
|
||||||
|
(ctr * (FONT_HEIGHT - 1)), lines[ctr], true, colour, varLength);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Surface *Surface::newDialog(uint16 width, const char *line, uint8 colour) {
|
||||||
|
uint8 numLines = 1;
|
||||||
|
uint16 lineWidth = 0;
|
||||||
|
char *s, *lineCopy;
|
||||||
|
bool newLine;
|
||||||
|
|
||||||
|
s = lineCopy = strdup(line);
|
||||||
|
|
||||||
|
// Scan through the text and insert NULLs to break the line into allowable widths
|
||||||
|
|
||||||
|
while (*s != '\0') {
|
||||||
|
char *wordStart = s;
|
||||||
|
while (*wordStart == ' ') ++wordStart;
|
||||||
|
char *wordEnd = strchr(wordStart, ' ');
|
||||||
|
char *wordEnd2 = strchr(wordStart, '\n');
|
||||||
|
if ((!wordEnd) || ((wordEnd2) && (wordEnd2 < wordEnd))) {
|
||||||
|
wordEnd = wordEnd2;
|
||||||
|
newLine = (wordEnd2 != NULL);
|
||||||
|
} else {
|
||||||
|
newLine = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wordEnd) --wordEnd; // move back one to end of word
|
||||||
|
else wordEnd = strchr(s, '\0') - 1;
|
||||||
|
|
||||||
|
uint16 wordSize = textWidth(s, (int) (wordEnd - s + 1));
|
||||||
|
|
||||||
|
if (lineWidth + wordSize > width - (DIALOG_EDGE_SIZE + 3) * 2) {
|
||||||
|
// Break word onto next line
|
||||||
|
*(wordStart - 1) = '\0';
|
||||||
|
++numLines;
|
||||||
|
lineWidth = textWidth(wordStart, (int) (wordEnd - wordStart + 1));
|
||||||
|
} else if (newLine) {
|
||||||
|
// Break on newline
|
||||||
|
++numLines;
|
||||||
|
++wordEnd;
|
||||||
|
*wordEnd = '\0';
|
||||||
|
lineWidth = 0;
|
||||||
|
} else {
|
||||||
|
// Add word's length to total for line
|
||||||
|
lineWidth += wordSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = wordEnd+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up a list for the start of each line
|
||||||
|
char **lines = (char **) Memory::alloc(sizeof(char *) * numLines);
|
||||||
|
lines[0] = lineCopy;
|
||||||
|
for (int ctr = 1; ctr < numLines; ++ctr)
|
||||||
|
lines[ctr] = strchr(lines[ctr-1], 0) + 1;
|
||||||
|
|
||||||
|
// Create the dialog
|
||||||
|
Surface *result = newDialog(width, numLines, lines, true, colour);
|
||||||
|
|
||||||
|
// Deallocate used resources
|
||||||
|
free(lines);
|
||||||
|
free(lineCopy);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Surface *Surface::getScreen(uint16 resourceId) {
|
||||||
|
MemoryBlock *block = Disk::getReference().getEntry(resourceId);
|
||||||
|
PictureDecoder d;
|
||||||
|
MemoryBlock *decodedData = d.decode(block);
|
||||||
|
delete block;
|
||||||
|
return new Surface(decodedData, FULL_SCREEN_WIDTH, decodedData->size() / FULL_SCREEN_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void Dialog::show(const char *text) {
|
||||||
|
Screen &screen = Screen::getReference();
|
||||||
|
Mouse &mouse = Mouse::getReference();
|
||||||
|
mouse.cursorOff();
|
||||||
|
|
||||||
|
Surface *s = Surface::newDialog(INFO_DIALOG_WIDTH, text);
|
||||||
|
s->copyToScreen(INFO_DIALOG_X, INFO_DIALOG_Y);
|
||||||
|
|
||||||
|
// Wait for a keypress or mouse button
|
||||||
|
Events::getReference().waitForPress();
|
||||||
|
|
||||||
|
screen.update();
|
||||||
|
mouse.cursorOn();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dialog::show(uint16 stringId) {
|
||||||
|
char buffer[MAX_DESC_SIZE];
|
||||||
|
Room &r = Room::getReference();
|
||||||
|
StringData &sl = StringData::getReference();
|
||||||
|
|
||||||
|
Action action = r.getCurrentAction();
|
||||||
|
|
||||||
|
const char *actionName = (action == NONE) ? NULL : actionList[action];
|
||||||
|
char hotspotName[MAX_HOTSPOT_NAME_SIZE];
|
||||||
|
if (r.hotspotId() == 0)
|
||||||
|
strcpy(hotspotName, "");
|
||||||
|
else
|
||||||
|
sl.getString(r.hotspot().nameId, hotspotName, NULL, NULL);
|
||||||
|
|
||||||
|
sl.getString(stringId, buffer, hotspotName, actionName);
|
||||||
|
show(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dialog::showMessage(uint16 messageId, uint16 characterId) {
|
||||||
|
MemoryBlock *data = Resources::getReference().messagesData();
|
||||||
|
uint16 *v = (uint16 *) data->data();
|
||||||
|
uint16 v2, idVal;
|
||||||
|
messageId &= 0x7fff;
|
||||||
|
|
||||||
|
// Skip through header to find table for given character
|
||||||
|
while (READ_LE_UINT16(v) != characterId) v += 2;
|
||||||
|
|
||||||
|
// Scan through secondary list
|
||||||
|
++v;
|
||||||
|
v = (uint16 *) (data->data() + READ_LE_UINT16(v));
|
||||||
|
v2 = 0;
|
||||||
|
while ((idVal = READ_LE_UINT16(v)) != 0xffff) {
|
||||||
|
++v;
|
||||||
|
if (READ_LE_UINT16(v) == messageId) break;
|
||||||
|
++v;
|
||||||
|
}
|
||||||
|
// default response if a specific response not found
|
||||||
|
if (idVal == 0xffff) idVal = 0x8c4;
|
||||||
|
|
||||||
|
if (idVal == 0x76) {
|
||||||
|
/*
|
||||||
|
call sub_154 ; (64E7)
|
||||||
|
mov ax,word ptr ds:[5813h] ; (273F:5813=1BA3h)
|
||||||
|
mov [bx+ANIM_SEGMENT],ax
|
||||||
|
mov ax,word ptr ds:[5817h] ; (273F:5817=0ED8Eh)
|
||||||
|
mov [bx+ANIM_FRAME],ax
|
||||||
|
retn
|
||||||
|
*/
|
||||||
|
} else if (idVal == 0x120) {
|
||||||
|
/*
|
||||||
|
call sub_154 ; (64E7)
|
||||||
|
mov ax,word ptr ds:[5813h] ; (273F:5813=1BA3h)
|
||||||
|
mov [bx+ANIM_SEGMENT],ax
|
||||||
|
mov ax,word ptr ds:[5817h] ; (273F:5817=0ED8Eh)
|
||||||
|
shl ax,1
|
||||||
|
mov [bx+ANIM_FRAME],ax
|
||||||
|
*/
|
||||||
|
} else if (idVal >= 0x8000) {
|
||||||
|
// Handle string display
|
||||||
|
idVal &= 0x7fff;
|
||||||
|
Dialog::show(idVal);
|
||||||
|
|
||||||
|
} else if (idVal != 0) {
|
||||||
|
/* still to be decoded */
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
83
lure/surface.h
Normal file
83
lure/surface.h
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_surface_h__
|
||||||
|
#define __lure_surface_h__
|
||||||
|
|
||||||
|
#include "common/stdafx.h"
|
||||||
|
#include "common/str.h"
|
||||||
|
#include "lure/disk.h"
|
||||||
|
#include "lure/luredefs.h"
|
||||||
|
|
||||||
|
using namespace Common;
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
class Surface {
|
||||||
|
private:
|
||||||
|
MemoryBlock *_data;
|
||||||
|
uint16 _width, _height;
|
||||||
|
public:
|
||||||
|
Surface(MemoryBlock *src, uint16 width, uint16 height);
|
||||||
|
Surface(uint16 width, uint16 height);
|
||||||
|
~Surface();
|
||||||
|
|
||||||
|
static void initialise();
|
||||||
|
static void deinitialise();
|
||||||
|
|
||||||
|
uint16 width() { return _width; }
|
||||||
|
uint16 height() { return _height; }
|
||||||
|
MemoryBlock &data() { return *_data; }
|
||||||
|
|
||||||
|
void loadScreen(uint16 resourceId);
|
||||||
|
void writeChar(uint16 x, uint16 y, uint8 ascii, bool transparent, uint8 colour);
|
||||||
|
void writeString(uint16 x, uint16 y, Common::String line, bool transparent,
|
||||||
|
uint8 colour = DIALOG_TEXT_COLOUR, bool varLength = true);
|
||||||
|
void transparentCopyTo(Surface *dest);
|
||||||
|
void copyTo(Surface *dest);
|
||||||
|
void copyTo(Surface *dest, uint16 x, uint16 y);
|
||||||
|
void copyTo(Surface *dest, const Rect &srcBounds, uint16 destX, uint16 destY,
|
||||||
|
int transparentColour = -1);
|
||||||
|
void copyFrom(MemoryBlock *src) { _data->copyFrom(src); }
|
||||||
|
void copyFrom(MemoryBlock *src, uint32 destOffset);
|
||||||
|
void empty() { _data->empty(); }
|
||||||
|
void fillRect(const Rect &r, uint8 colour);
|
||||||
|
void createDialog(bool blackFlag = false);
|
||||||
|
void copyToScreen(uint16 x, uint16 y);
|
||||||
|
void centerOnScreen();
|
||||||
|
|
||||||
|
static uint16 textWidth(const char *s, int numChars = 0);
|
||||||
|
static Surface *newDialog(uint16 width, uint8 numLines, char **lines, bool varLength = true, uint8 colour = DIALOG_TEXT_COLOUR);
|
||||||
|
static Surface *newDialog(uint16 width, const char *lines, uint8 colour = DIALOG_TEXT_COLOUR);
|
||||||
|
static Surface *getScreen(uint16 resourceId);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Dialog {
|
||||||
|
public:
|
||||||
|
static void show(const char *text);
|
||||||
|
static void show(uint16 stringId);
|
||||||
|
static void showMessage(uint16 messageId, uint16 characterId);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Lure
|
||||||
|
|
||||||
|
#endif
|
41
lure/system.cpp
Normal file
41
lure/system.cpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 "lure/system.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
OSystem *int_system = NULL;
|
||||||
|
|
||||||
|
System::System(OSystem *sys) {
|
||||||
|
int_system = sys;
|
||||||
|
}
|
||||||
|
|
||||||
|
System::~System() {
|
||||||
|
int_system = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSystem &System::getReference() {
|
||||||
|
return *int_system;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Lure
|
40
lure/system.h
Normal file
40
lure/system.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2005-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 __lure_system_h__
|
||||||
|
#define __lure_system_h__
|
||||||
|
|
||||||
|
#include "common/stdafx.h"
|
||||||
|
#include "common/system.h"
|
||||||
|
|
||||||
|
namespace Lure {
|
||||||
|
|
||||||
|
class System {
|
||||||
|
public:
|
||||||
|
System(OSystem *sys);
|
||||||
|
~System();
|
||||||
|
static OSystem &getReference();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namspace Lure
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue