Add patch #1374870 - New Lure of the Temptress module

svn-id: r20536
This commit is contained in:
Travis Howell 2006-02-11 12:54:56 +00:00
parent cbb2ca005c
commit 6703dc7fa1
47 changed files with 8270 additions and 0 deletions

View file

@ -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 \

View file

@ -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
View file

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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