mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-22 20:21:06 +00:00
MADS: Implemented extra message and dirty area classes
This commit is contained in:
parent
3a3a295758
commit
9e356dd945
@ -297,4 +297,8 @@ void Animation::loadInterface(InterfaceSurface &interfaceSurface, MSurface &dept
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::update() {
|
||||
warning("TODO: Animation::update");
|
||||
}
|
||||
|
||||
} // End of namespace MADS
|
||||
|
@ -135,6 +135,11 @@ public:
|
||||
*/
|
||||
void load(MSurface &depthSurface, InterfaceSurface &interfaceSurface, const Common::String &resName,
|
||||
int flags, Common::Array<RGB4> *palAnimData, SceneInfo *sceneInfo);
|
||||
|
||||
/**
|
||||
* Update the animation
|
||||
*/
|
||||
void update();
|
||||
};
|
||||
|
||||
} // End of namespace MADS
|
||||
|
@ -26,6 +26,8 @@
|
||||
namespace MADS {
|
||||
|
||||
Debugger::Debugger(MADSEngine *vm) : GUI::Debugger(), _vm(vm) {
|
||||
_showMousePos = false;
|
||||
|
||||
DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit));
|
||||
}
|
||||
/*
|
||||
@ -46,4 +48,14 @@ static int strToInt(const char *s) {
|
||||
}
|
||||
*/
|
||||
|
||||
bool Debugger::Cmd_Mouse(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
DebugPrintf("Format: mouse [ on | off ]\n");
|
||||
} else {
|
||||
_showMousePos = strcmp(argv[1], "on") == 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace MADS
|
||||
|
@ -33,11 +33,13 @@ class MADSEngine;
|
||||
class Debugger : public GUI::Debugger {
|
||||
private:
|
||||
MADSEngine *_vm;
|
||||
protected:
|
||||
bool Cmd_Mouse(int argc, const char **argv);
|
||||
public:
|
||||
bool _showMousePos;
|
||||
public:
|
||||
Debugger(MADSEngine *vm);
|
||||
virtual ~Debugger() {}
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
} // End of namespace MADS
|
||||
|
@ -93,7 +93,6 @@ void Font::setColors(uint8 v1, uint8 v2, uint8 v3, uint8 v4) {
|
||||
_fontColors[0] = v1;
|
||||
_fontColors[1] = v2;
|
||||
_fontColors[2] = v3;
|
||||
_fontColors[3] = v4;
|
||||
}
|
||||
|
||||
int Font::write(MSurface *surface, const Common::String &msg, const Common::Point &pt, int width, int spaceWidth, uint8 colors[]) {
|
||||
|
@ -278,4 +278,22 @@ void Game::loadResourceSequence(const Common::String prefix, int v) {
|
||||
warning("TODO: loadResourceSequence");
|
||||
}
|
||||
|
||||
Common::String Game::getQuote(int quoteId) {
|
||||
if (_quotes && *_quotes) {
|
||||
// Loop through the list of quotes
|
||||
char *p = (char *)_quotes;
|
||||
while (*p) {
|
||||
// Get a pointer to the quote Id after the string
|
||||
char *idP = p + strlen(p) + 1;
|
||||
if (READ_LE_UINT16(idP) == quoteId)
|
||||
// Found the correct string, so return it
|
||||
return Common::String(p);
|
||||
|
||||
p = idP + 2;
|
||||
}
|
||||
}
|
||||
|
||||
return Common::String();
|
||||
}
|
||||
|
||||
} // End of namespace MADS
|
||||
|
@ -124,6 +124,11 @@ public:
|
||||
* Run the game
|
||||
*/
|
||||
void run();
|
||||
|
||||
/**
|
||||
* Get a quote
|
||||
*/
|
||||
Common::String getQuote(int quoteId);
|
||||
};
|
||||
|
||||
} // End of namespace MADS
|
||||
|
384
engines/mads/messages.cpp
Normal file
384
engines/mads/messages.cpp
Normal file
@ -0,0 +1,384 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "mads/mads.h"
|
||||
#include "mads/font.h"
|
||||
#include "mads/graphics.h"
|
||||
#include "mads/messages.h"
|
||||
#include "mads/scene_data.h"
|
||||
|
||||
namespace MADS {
|
||||
|
||||
KernelMessages::KernelMessages(MADSEngine *vm): _vm(vm) {
|
||||
Scene &scene = _vm->_game->_scene;
|
||||
|
||||
for (int i = 0; i < KERNEL_MESSAGES_SIZE; ++i) {
|
||||
KernelMessage rec;
|
||||
_entries.push_back(rec);
|
||||
}
|
||||
|
||||
scene._textSpacing = -1;
|
||||
_talkFont = _vm->_font->getFont(FONT_CONVERSATION);
|
||||
word_8469E = 0;
|
||||
}
|
||||
|
||||
void KernelMessages::clear() {
|
||||
Scene &scene = _vm->_game->_scene;
|
||||
|
||||
for (uint i = 0; i < _entries.size(); ++i)
|
||||
_entries[i]._flags = 0;
|
||||
|
||||
scene._textSpacing = -1;
|
||||
_talkFont = _vm->_font->getFont(FONT_CONVERSATION);
|
||||
}
|
||||
|
||||
int KernelMessages::add(const Common::Point &pt, uint fontColor, uint8 flags,
|
||||
uint8 abortTimers, uint32 timeout, const Common::String &msg) {
|
||||
Scene &scene = _vm->_game->_scene;
|
||||
|
||||
// Find a free slot
|
||||
uint idx = 0;
|
||||
while ((idx < _entries.size()) && ((_entries[idx]._flags & KMSG_ACTIVE) != 0))
|
||||
++idx;
|
||||
if (idx == _entries.size()) {
|
||||
if (abortTimers == 0)
|
||||
return -1;
|
||||
|
||||
error("KernelMessages overflow");
|
||||
}
|
||||
|
||||
KernelMessage &rec = _entries[idx];
|
||||
rec._msg = msg;
|
||||
rec._flags = flags | KMSG_ACTIVE;
|
||||
rec._color1 = fontColor & 0xff;
|
||||
rec._color2 = fontColor >> 8;
|
||||
rec._position = pt;
|
||||
rec._textDisplayIndex = -1;
|
||||
rec._timeout = timeout;
|
||||
rec._frameTimer = _vm->_game->_currentTimer;
|
||||
rec._abortTimers = abortTimers;
|
||||
rec._abortMode = _vm->_game->_abortTimersMode2;
|
||||
|
||||
rec._actionDetails = scene._action._activeAction;
|
||||
|
||||
if (flags & KMSG_PLAYER_TIMEOUT)
|
||||
rec._frameTimer = _vm->_game->_player._ticksAmount +
|
||||
_vm->_game->_player._priorTimer;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
int KernelMessages::addQuote(int quoteId, int abortTimers, uint32 timeout) {
|
||||
Common::String quoteStr = _vm->_game->getQuote(quoteId);
|
||||
return add(Common::Point(), 0x1110, KMSG_PLAYER_TIMEOUT | KMSG_CENTER_ALIGN, abortTimers, timeout, quoteStr);
|
||||
}
|
||||
|
||||
void KernelMessages::scrollMessage(int msgIndex, int numTicks, bool quoted) {
|
||||
if (msgIndex < 0)
|
||||
return;
|
||||
|
||||
_entries[msgIndex]._flags |= quoted ? (KMSG_SCROLL | KMSG_QUOTED) : KMSG_SCROLL;
|
||||
_entries[msgIndex]._msgOffset = 0;
|
||||
_entries[msgIndex]._numTicks = numTicks;
|
||||
_entries[msgIndex]._frameTimer2 = _vm->_game->_currentTimer;
|
||||
|
||||
Common::String msg = _entries[msgIndex]._msg;
|
||||
_entries[msgIndex]._asciiChar = msg[0];
|
||||
_entries[msgIndex]._asciiChar2 = msg[1];
|
||||
|
||||
if (_entries[msgIndex]._flags & KMSG_PLAYER_TIMEOUT)
|
||||
_entries[msgIndex]._frameTimer2 = _vm->_game->_player._ticksAmount +
|
||||
_vm->_game->_player._priorTimer;
|
||||
|
||||
_entries[msgIndex]._frameTimer = _entries[msgIndex]._frameTimer2;
|
||||
}
|
||||
|
||||
void KernelMessages::setSeqIndex(int msgIndex, int seqIndex) {
|
||||
if (msgIndex >= 0) {
|
||||
_entries[msgIndex]._flags |= KMSG_SEQ_ENTRY;
|
||||
_entries[msgIndex]._sequenceIndex = seqIndex;
|
||||
}
|
||||
}
|
||||
|
||||
void KernelMessages::remove(int msgIndex) {
|
||||
KernelMessage &rec = _entries[msgIndex];
|
||||
Scene &scene = _vm->_game->_scene;
|
||||
|
||||
if (rec._flags & KMSG_ACTIVE) {
|
||||
if (rec._flags & KMSG_SCROLL) {
|
||||
rec._msg.setChar(rec._asciiChar, rec._msgOffset);
|
||||
rec._msg.setChar(rec._asciiChar2, rec._msgOffset + 1);
|
||||
}
|
||||
|
||||
if (rec._textDisplayIndex >= 0)
|
||||
scene._textDisplay.expire(rec._textDisplayIndex);
|
||||
|
||||
rec._flags &= ~KMSG_ACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
void KernelMessages::reset() {
|
||||
for (uint i = 0; i < _entries.size(); ++i)
|
||||
remove(i);
|
||||
|
||||
warning("TODO: KernelMessages::reset - sub_20454");
|
||||
}
|
||||
|
||||
void KernelMessages::update() {
|
||||
uint32 currentTimer = _vm->_game->_currentTimer;
|
||||
|
||||
for (uint i = 0; i < _entries.size(); ++i) {
|
||||
if (((_entries[i]._flags & KMSG_ACTIVE) != 0) &&
|
||||
(currentTimer >= _entries[i]._frameTimer))
|
||||
processText(i);
|
||||
}
|
||||
}
|
||||
|
||||
void KernelMessages::processText(int msgIndex) {
|
||||
Scene &scene = _vm->_game->_scene;
|
||||
KernelMessage &msg = _entries[msgIndex];
|
||||
uint32 currentTimer = _vm->_game->_currentTimer;
|
||||
bool flag = false;
|
||||
|
||||
if ((msg._flags & KMSG_EXPIRE) != 0) {
|
||||
scene._textDisplay.expire(msg._textDisplayIndex);
|
||||
msg._flags &= !KMSG_ACTIVE;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((msg._flags & KMSG_SCROLL) == 0) {
|
||||
msg._timeout -= 3;
|
||||
}
|
||||
|
||||
if (msg._flags & KMSG_SEQ_ENTRY) {
|
||||
SequenceEntry &seqEntry = scene._sequences[msg._sequenceIndex];
|
||||
if (seqEntry._doneFlag || !seqEntry._active)
|
||||
msg._timeout = 0;
|
||||
}
|
||||
|
||||
if ((msg._timeout <= 0) && (_vm->_game->_abortTimers == 0)) {
|
||||
msg._flags |= KMSG_EXPIRE;
|
||||
if (msg._abortTimers != 0) {
|
||||
_vm->_game->_abortTimers = msg._abortTimers;
|
||||
_vm->_game->_abortTimersMode = msg._abortMode;
|
||||
|
||||
if (_vm->_game->_abortTimersMode != ABORTMODE_1) {
|
||||
scene._action._activeAction = msg._actionDetails;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg._frameTimer = currentTimer + 3;
|
||||
int x1 = 0, y1 = 0;
|
||||
|
||||
if (msg._flags & KMSG_SEQ_ENTRY) {
|
||||
SequenceEntry &seqEntry = scene._sequences[msg._sequenceIndex];
|
||||
if (!seqEntry._nonFixed) {
|
||||
SpriteAsset &spriteSet = scene._spriteSlots.getSprite(seqEntry._spritesIndex);
|
||||
MSprite *frame = spriteSet.getFrame(seqEntry._frameIndex - 1);
|
||||
x1 = frame->getBounds().left;
|
||||
y1 = frame->getBounds().top;
|
||||
} else {
|
||||
x1 = seqEntry._msgPos.x;
|
||||
y1 = seqEntry._msgPos.y;
|
||||
}
|
||||
}
|
||||
|
||||
if (msg._flags & KMSG_PLAYER_TIMEOUT) {
|
||||
if (word_8469E != 0) {
|
||||
warning("TODO: KernelMessages::processText");
|
||||
// TODO: Figure out various flags
|
||||
} else {
|
||||
x1 = 160;
|
||||
y1 = 78;
|
||||
}
|
||||
}
|
||||
|
||||
x1 += msg._position.x;
|
||||
y1 += msg._position.y;
|
||||
|
||||
if ((msg._flags & KMSG_SCROLL) && (msg._frameTimer >= currentTimer)) {
|
||||
msg._msg.setChar(msg._asciiChar, msg._msgOffset);
|
||||
|
||||
++msg._msgOffset;
|
||||
msg._msg.setChar(msg._asciiChar2, msg._msgOffset);
|
||||
msg._asciiChar = msg._msg[msg._msgOffset];
|
||||
msg._asciiChar2 = msg._msg[msg._msgOffset + 1];
|
||||
|
||||
if (!msg._asciiChar) {
|
||||
// End of message
|
||||
msg._msg.setChar('\0', msg._msgOffset);
|
||||
msg._flags &= ~KMSG_SCROLL;
|
||||
} else if (msg._flags & KMSG_QUOTED) {
|
||||
msg._msg.setChar('"', msg._msgOffset);
|
||||
msg._msg.setChar('\0', msg._msgOffset + 1);
|
||||
}
|
||||
|
||||
msg._frameTimer = msg._frameTimer2 = currentTimer + msg._numTicks;
|
||||
flag = true;
|
||||
}
|
||||
|
||||
int strWidth = _talkFont->getWidth(msg._msg, scene._textSpacing);
|
||||
|
||||
if (msg._flags & (KMSG_RIGHT_ALIGN | KMSG_CENTER_ALIGN)) {
|
||||
x1 -= (msg._flags & KMSG_CENTER_ALIGN) ? strWidth / 2 : strWidth;
|
||||
}
|
||||
|
||||
// Make sure text appears entirely on-screen
|
||||
int x2 = x1 + strWidth;
|
||||
if (x2 > MADS_SCREEN_WIDTH)
|
||||
x1 -= x2 - MADS_SCREEN_WIDTH;
|
||||
if (x1 > (MADS_SCREEN_WIDTH - 1))
|
||||
x1 = MADS_SCREEN_WIDTH - 1;
|
||||
if (x1 < 0)
|
||||
x1 = 0;
|
||||
|
||||
if (y1 >(MADS_SCENE_HEIGHT - 1))
|
||||
y1 = MADS_SCENE_HEIGHT - 1;
|
||||
if (y1 < 0)
|
||||
y1 = 0;
|
||||
|
||||
if (msg._textDisplayIndex >= 0) {
|
||||
TextDisplay &textEntry = scene._textDisplay[msg._textDisplayIndex];
|
||||
|
||||
if (flag || (textEntry._bounds.left != x1) || (textEntry._bounds.top != y1)) {
|
||||
// Mark the associated text entry as deleted, so it can be re-created
|
||||
scene._textDisplay.expire(msg._textDisplayIndex);
|
||||
msg._textDisplayIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (msg._textDisplayIndex < 0) {
|
||||
// Need to create a new text display entry for this message
|
||||
int idx = scene._textDisplay.add(x1, y1, msg._color1 | (msg._color2 << 8),
|
||||
scene._textSpacing, msg._msg, _talkFont);
|
||||
if (idx >= 0)
|
||||
msg._textDisplayIndex = idx;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
TextDisplay::TextDisplay() {
|
||||
_active = false;
|
||||
_expire = 0;
|
||||
_spacing = 0;
|
||||
_color1 = 0;
|
||||
_color2 = 0;
|
||||
_font = nullptr;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
TextDisplayList::TextDisplayList(MADSEngine *vm) : _vm(vm) {
|
||||
for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i) {
|
||||
TextDisplay rec;
|
||||
rec._active = false;
|
||||
rec._expire = 0;
|
||||
_entries.push_back(rec);
|
||||
}
|
||||
}
|
||||
|
||||
void TextDisplayList::clear() {
|
||||
for (int i = 0; i < TEXT_DISPLAY_SIZE; ++i)
|
||||
_entries[i]._active = false;
|
||||
}
|
||||
|
||||
int TextDisplayList::add(int xp, int yp, uint fontColor, int charSpacing,
|
||||
const Common::String &msg, Font *font) {
|
||||
int usedSlot = -1;
|
||||
|
||||
for (int idx = 0; idx < TEXT_DISPLAY_SIZE; ++idx) {
|
||||
if (!_entries[idx]._active) {
|
||||
usedSlot = idx;
|
||||
|
||||
_entries[idx]._bounds.left = xp;
|
||||
_entries[idx]._bounds.top = yp;
|
||||
_entries[idx]._font = font;
|
||||
_entries[idx]._msg = msg;
|
||||
_entries[idx]._bounds.setWidth(font->getWidth(msg, charSpacing));
|
||||
_entries[idx]._bounds.setHeight(font->getHeight());
|
||||
_entries[idx]._color1 = fontColor & 0xff;
|
||||
_entries[idx]._color2 = fontColor >> 8;
|
||||
_entries[idx]._spacing = charSpacing;
|
||||
_entries[idx]._expire = 1;
|
||||
_entries[idx]._active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return usedSlot;
|
||||
}
|
||||
|
||||
void TextDisplayList::setDirtyAreas() {
|
||||
Scene &scene = _vm->_game->_scene;
|
||||
|
||||
for (uint idx = 0, dirtyIdx = DIRTY_AREAS_TEXT_DISPLAY_IDX; dirtyIdx < DIRTY_AREAS_SIZE; ++idx, ++dirtyIdx) {
|
||||
if ((_entries[idx]._expire >= 0) || !_entries[idx]._active)
|
||||
scene._dirtyAreas[dirtyIdx]._active = false;
|
||||
else {
|
||||
scene._dirtyAreas[dirtyIdx]._textActive = true;
|
||||
scene._dirtyAreas.setTextDisplay(dirtyIdx, _entries[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextDisplayList::setDirtyAreas2() {
|
||||
Scene &scene = _vm->_game->_scene;
|
||||
|
||||
for (uint idx = 0, dirtyIdx = DIRTY_AREAS_TEXT_DISPLAY_IDX; dirtyIdx < DIRTY_AREAS_SIZE; ++idx, ++dirtyIdx) {
|
||||
if (_entries[idx]._active && (_entries[idx]._expire >= 0)) {
|
||||
scene._dirtyAreas.setTextDisplay(dirtyIdx, _entries[idx]);
|
||||
scene._dirtyAreas[dirtyIdx]._textActive = (_entries[idx]._expire <= 0) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextDisplayList::draw(MSurface *view) {
|
||||
error("TODO");
|
||||
/*
|
||||
for (uint idx = 0; idx < _entries.size(); ++idx) {
|
||||
if (_entries[idx]._active && (_entries[idx]._expire >= 0)) {
|
||||
_entries[idx]._font->setColors(_entries[idx]._color1, _entries[idx]._color2, 0);
|
||||
_entries[idx]._font->writeString(view, _entries[idx]._msg,
|
||||
Common::Point(_entries[idx]._bounds.left, _entries[idx]._bounds.top),
|
||||
_entries[idx]._bounds.width(), _entries[idx]._spacing);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void TextDisplayList::cleanUp() {
|
||||
for (uint idx = 0; idx < _entries.size(); ++idx) {
|
||||
if (_entries[idx]._expire < 0) {
|
||||
_entries[idx]._active = false;
|
||||
_entries[idx]._expire = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextDisplayList::expire(int idx) {
|
||||
_entries[idx]._expire = -1;
|
||||
}
|
||||
|
||||
} // End of namespace MADS
|
148
engines/mads/messages.h
Normal file
148
engines/mads/messages.h
Normal file
@ -0,0 +1,148 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MADS_MESSAGES_H
|
||||
#define MADS_MESSAGES_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/array.h"
|
||||
#include "mads/action.h"
|
||||
#include "mads/font.h"
|
||||
#include "mads/msurface.h"
|
||||
|
||||
namespace MADS {
|
||||
|
||||
#define KERNEL_MESSAGES_SIZE 10
|
||||
#define INDEFINITE_TIMEOUT 9999999
|
||||
#define TEXT_DISPLAY_SIZE 40
|
||||
|
||||
enum KernelMessageFlags {
|
||||
KMSG_QUOTED = 1, KMSG_PLAYER_TIMEOUT = 2, KMSG_SEQ_ENTRY = 4, KMSG_SCROLL = 8,
|
||||
KMSG_RIGHT_ALIGN = 0x10, KMSG_CENTER_ALIGN = 0x20, KMSG_EXPIRE = 0x40,
|
||||
KMSG_ACTIVE = 0x80
|
||||
};
|
||||
|
||||
class MADSEngine;
|
||||
|
||||
class KernelMessage {
|
||||
public:
|
||||
uint8 _flags;
|
||||
int _sequenceIndex;
|
||||
char _asciiChar;
|
||||
char _asciiChar2;
|
||||
int _color1;
|
||||
int _color2;
|
||||
Common::Point _position;
|
||||
int _textDisplayIndex;
|
||||
int _msgOffset;
|
||||
int _numTicks;
|
||||
uint32 _frameTimer2;
|
||||
uint32 _frameTimer;
|
||||
uint32 _timeout;
|
||||
int _abortTimers;
|
||||
AbortTimerMode _abortMode;
|
||||
ActionDetails _actionDetails;
|
||||
Common::String _msg;
|
||||
|
||||
KernelMessage();
|
||||
};
|
||||
|
||||
class KernelMessages {
|
||||
private:
|
||||
MADSEngine *_vm;
|
||||
Common::Array<KernelMessage> _entries;
|
||||
Font *_talkFont;
|
||||
public:
|
||||
int word_8469E;
|
||||
public:
|
||||
KernelMessages(MADSEngine *vm);
|
||||
|
||||
void clear();
|
||||
int add(const Common::Point &pt, uint fontColor, uint8 flags, uint8 abortTimers,
|
||||
uint32 timeout, const Common::String &msg);
|
||||
int addQuote(int quoteId, int abortTimers, uint32 timeout);
|
||||
void scrollMessage(int msgIndex, int numTicks, bool quoted);
|
||||
void setSeqIndex(int msgIndex, int seqIndex);
|
||||
void remove(int msgIndex);
|
||||
void reset();
|
||||
void update();
|
||||
void processText(int msgIndex);
|
||||
};
|
||||
|
||||
class TextDisplay {
|
||||
public:
|
||||
bool _active;
|
||||
int _expire;
|
||||
int _spacing;
|
||||
Common::Rect _bounds;
|
||||
uint8 _color1;
|
||||
uint8 _color2;
|
||||
Font *_font;
|
||||
Common::String _msg;
|
||||
|
||||
TextDisplay();
|
||||
};
|
||||
|
||||
#define TEXT_DISPLAY_SIZE 40
|
||||
|
||||
class TextDisplayList {
|
||||
private:
|
||||
MADSEngine *_vm;
|
||||
Common::Array<TextDisplay> _entries;
|
||||
|
||||
/**
|
||||
* Determine dirty areas for active text areas
|
||||
*/
|
||||
void setDirtyAreas2();
|
||||
public:
|
||||
TextDisplayList(MADSEngine *vm);
|
||||
|
||||
/**
|
||||
* Item operator
|
||||
*/
|
||||
TextDisplay &operator[](int idx) {
|
||||
return _entries[idx];
|
||||
}
|
||||
|
||||
/**
|
||||
* Expire a given text display entry
|
||||
*/
|
||||
void expire(int idx);
|
||||
|
||||
int add(int xp, int yp, uint fontColor, int charSpacing, const Common::String &, Font *font);
|
||||
void clear();
|
||||
void draw(MSurface *view);
|
||||
|
||||
/**
|
||||
* Determine dirty areas for active text areas
|
||||
*/
|
||||
void setDirtyAreas();
|
||||
|
||||
/**
|
||||
* Deactivates any text display entries that are finished
|
||||
*/
|
||||
void cleanUp();
|
||||
};
|
||||
|
||||
} // End of namespace MADS
|
||||
|
||||
#endif /* MADS_MESSAGES_H */
|
@ -19,6 +19,7 @@ MODULE_OBJS := \
|
||||
game_data.o \
|
||||
graphics.o \
|
||||
mads.o \
|
||||
messages.o \
|
||||
msprite.o \
|
||||
msurface.o \
|
||||
palette.o \
|
||||
|
@ -29,8 +29,8 @@
|
||||
namespace MADS {
|
||||
|
||||
Scene::Scene(MADSEngine *vm): _vm(vm), _spriteSlots(vm), _action(_vm),
|
||||
_dynamicHotspots(vm), _screenObjects(vm), _interface(vm),
|
||||
_sequences(vm) {
|
||||
_dirtyAreas(_vm), _dynamicHotspots(vm), _interface(vm), _messages(vm),
|
||||
_screenObjects(vm), _sequences(vm), _textDisplay(vm) {
|
||||
_priorSceneId = 0;
|
||||
_nextSceneId = 0;
|
||||
_currentSceneId = 0;
|
||||
@ -45,6 +45,8 @@ Scene::Scene(MADSEngine *vm): _vm(vm), _spriteSlots(vm), _action(_vm),
|
||||
_reloadSceneFlag = false;
|
||||
_destFacing = 0;
|
||||
_freeAnimationFlag = false;
|
||||
_animation = nullptr;
|
||||
_activeAnimation = nullptr;
|
||||
|
||||
_verbList.push_back(VerbInit(VERB_LOOK, 2, 0));
|
||||
_verbList.push_back(VerbInit(VERB_TAKE, 2, 0));
|
||||
@ -356,9 +358,21 @@ void Scene::doFrame() {
|
||||
_vm->_events->setCursor(cursorId);
|
||||
}
|
||||
|
||||
if (!_vm->_game->_abortTimers)
|
||||
if (!_vm->_game->_abortTimers) {
|
||||
// Handle any active sequences
|
||||
_sequences.tick();
|
||||
|
||||
// Handle any active animation
|
||||
if (_activeAnimation)
|
||||
_activeAnimation->update();
|
||||
}
|
||||
|
||||
// If the debugget flag is set, show the mouse position
|
||||
if (_vm->_debugger->_showMousePos) {
|
||||
Common::Point pt = _vm->_events->mousePos();
|
||||
Common::String msg = Common::String::format("(%d,%d)", pt.x, pt.y);
|
||||
_messages.add(Common::Point(5, 5), 0x203, 0, 0, 1, msg);
|
||||
}
|
||||
|
||||
// TODO: Rest of Scene::doFrame
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
#include "mads/assets.h"
|
||||
#include "mads/messages.h"
|
||||
#include "mads/msurface.h"
|
||||
#include "mads/scene_data.h"
|
||||
#include "mads/animation.h"
|
||||
@ -78,7 +79,7 @@ public:
|
||||
int _nextSceneId;
|
||||
int _currentSceneId;
|
||||
Common::Array<VerbInit> _verbList;
|
||||
Common::Array<TextDisplay> _textDisplay;
|
||||
TextDisplayList _textDisplay;
|
||||
SpriteSlots _spriteSlots;
|
||||
SpriteSets _sprites;
|
||||
int _spritesIndex;
|
||||
@ -86,11 +87,12 @@ public:
|
||||
byte *_vocabBuffer;
|
||||
Common::Array<int> _activeVocabs;
|
||||
SequenceList _sequences;
|
||||
Common::Array<KernelMessage> _messages;
|
||||
KernelMessages _messages;
|
||||
Common::String _talkFont;
|
||||
int _textSpacing;
|
||||
Common::Array<Hotspot> _hotspots;
|
||||
ScreenObjects _screenObjects;
|
||||
DirtyAreas _dirtyAreas;
|
||||
int _v1;
|
||||
SceneInfo *_sceneInfo;
|
||||
MSurface _backgroundSurface;
|
||||
@ -104,6 +106,7 @@ public:
|
||||
SceneNodeList _nodes;
|
||||
Common::StringArray _vocabStrings;
|
||||
Animation *_animation;
|
||||
Animation *_activeAnimation;
|
||||
bool _freeAnimationFlag;
|
||||
int _depthStyle;
|
||||
int _bandsRange;
|
||||
@ -118,6 +121,7 @@ public:
|
||||
bool _reloadSceneFlag;
|
||||
Common::Point _destPos;
|
||||
int _destFacing;
|
||||
Common::Point _posAdjust;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -202,11 +202,152 @@ int SpriteSets::add(SpriteAsset *asset, int idx) {
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
TextDisplay::TextDisplay() {
|
||||
_active = false;
|
||||
_spacing = 0;
|
||||
_expire = 0;
|
||||
_col1 = _col2 = 0;
|
||||
void DirtyArea::setArea(int width, int height, int maxWidth, int maxHeight) {
|
||||
if (_bounds.left % 2) {
|
||||
--_bounds.left;
|
||||
++width;
|
||||
}
|
||||
|
||||
if (_bounds.left < 0)
|
||||
_bounds.left = 0;
|
||||
else if (_bounds.left > maxWidth)
|
||||
_bounds.left = maxWidth;
|
||||
int right = _bounds.left + width;
|
||||
if (right < 0)
|
||||
right = 0;
|
||||
if (right > maxWidth)
|
||||
right = maxWidth;
|
||||
|
||||
_bounds.right = right;
|
||||
_bounds2.left = _bounds.width() / 2;
|
||||
_bounds2.right = _bounds.left + (_bounds.width() + 1) / 2 - 1;
|
||||
|
||||
if (_bounds.top < 0)
|
||||
_bounds.top = 0;
|
||||
else if (_bounds.top > maxHeight)
|
||||
_bounds.top = maxHeight;
|
||||
int bottom = _bounds.top + height;
|
||||
if (bottom < 0)
|
||||
bottom = 0;
|
||||
if (bottom > maxHeight)
|
||||
bottom = maxHeight;
|
||||
|
||||
_bounds.bottom = bottom;
|
||||
_bounds2.top = _bounds.height() / 2;
|
||||
_bounds2.bottom = _bounds.top + (_bounds.height() + 1) / 2 - 1;
|
||||
|
||||
_active = true;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
DirtyAreas::DirtyAreas(MADSEngine *vm) : _vm(vm) {
|
||||
for (int i = 0; i < DIRTY_AREAS_SIZE; ++i) {
|
||||
DirtyArea rec;
|
||||
rec._active = false;
|
||||
_entries.push_back(rec);
|
||||
}
|
||||
}
|
||||
|
||||
void DirtyAreas::setSpriteSlot(int dirtyIdx, const SpriteSlot &spriteSlot) {
|
||||
int width, height;
|
||||
DirtyArea &dirtyArea = _entries[dirtyIdx];
|
||||
Scene &scene = _vm->_game->_scene;
|
||||
|
||||
if (spriteSlot._spriteType == ST_FULL_SCREEN_REFRESH) {
|
||||
// Special entry to refresh the entire screen
|
||||
dirtyArea._bounds.left = 0;
|
||||
dirtyArea._bounds.top = 0;
|
||||
width = MADS_SCREEN_WIDTH;
|
||||
height = MADS_SCENE_HEIGHT;
|
||||
} else {
|
||||
// Standard sprite slots
|
||||
dirtyArea._bounds.left = spriteSlot._position.x - scene._posAdjust.x;
|
||||
dirtyArea._bounds.top = spriteSlot._position.y - scene._posAdjust.y;
|
||||
|
||||
SpriteAsset &spriteSet = scene._spriteSlots.getSprite(spriteSlot._spritesIndex);
|
||||
MSprite *frame = spriteSet.getFrame(((spriteSlot._frameNumber & 0x7fff) - 1) & 0x7f);
|
||||
|
||||
if (spriteSlot._scale == -1) {
|
||||
width = frame->getWidth();
|
||||
height = frame->getHeight();
|
||||
} else {
|
||||
width = frame->getWidth() * spriteSlot._scale / 100;
|
||||
height = frame->getHeight() * spriteSlot._scale / 100;
|
||||
|
||||
dirtyArea._bounds.left -= width / 2;
|
||||
dirtyArea._bounds.top += -(height - 1);
|
||||
}
|
||||
}
|
||||
|
||||
dirtyArea.setArea(width, height, MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
|
||||
}
|
||||
|
||||
void DirtyAreas::setTextDisplay(int dirtyIdx, const TextDisplay &textDisplay) {
|
||||
DirtyArea &dirtyArea = _entries[dirtyIdx];
|
||||
dirtyArea._bounds.left = textDisplay._bounds.left;
|
||||
dirtyArea._bounds.top = textDisplay._bounds.top;
|
||||
|
||||
dirtyArea.setArea(textDisplay._bounds.width(), textDisplay._bounds.height(),
|
||||
MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
|
||||
}
|
||||
|
||||
void DirtyAreas::merge(int startIndex, int count) {
|
||||
error("TODO: DirtyAreas::merge");
|
||||
if (startIndex >= count)
|
||||
return;
|
||||
|
||||
for (int outerCtr = startIndex - 1, idx = 0; idx < count; ++outerCtr, ++idx) {
|
||||
if (!_entries[outerCtr]._active)
|
||||
continue;
|
||||
|
||||
for (int innerCtr = outerCtr + 1; innerCtr < count; ++innerCtr) {
|
||||
if (!_entries[innerCtr]._active || !intersects(outerCtr, innerCtr))
|
||||
continue;
|
||||
|
||||
if (_entries[outerCtr]._textActive && _entries[innerCtr]._textActive)
|
||||
mergeAreas(outerCtr, innerCtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if two dirty areas intersect
|
||||
*/
|
||||
bool DirtyAreas::intersects(int idx1, int idx2) {
|
||||
return _entries[idx1]._bounds2.intersects(_entries[idx2]._bounds2);
|
||||
}
|
||||
|
||||
void DirtyAreas::mergeAreas(int idx1, int idx2) {
|
||||
DirtyArea &da1 = _entries[idx1];
|
||||
DirtyArea &da2 = _entries[idx2];
|
||||
|
||||
da1._bounds.extend(da2._bounds);
|
||||
|
||||
da1._bounds2.left = da1._bounds.width() / 2;
|
||||
da1._bounds2.right = da1._bounds.left + (da1._bounds.width() + 1) / 2 - 1;
|
||||
da1._bounds2.top = da1._bounds.height() / 2;
|
||||
da1._bounds2.bottom = da1._bounds.top + (da1._bounds.height() + 1) / 2 - 1;
|
||||
|
||||
da2._active = false;
|
||||
da1._textActive = true;
|
||||
}
|
||||
|
||||
void DirtyAreas::copy(MSurface *dest, MSurface *src, const Common::Point &posAdjust) {
|
||||
for (uint i = 0; i < _entries.size(); ++i) {
|
||||
const Common::Rect &srcBounds = _entries[i]._bounds;
|
||||
|
||||
Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y,
|
||||
srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y);
|
||||
|
||||
if (_entries[i]._active && _entries[i]._bounds.isValidRect())
|
||||
src->copyTo(dest, bounds, Common::Point(_entries[i]._bounds.left, _entries[i]._bounds.top));
|
||||
}
|
||||
}
|
||||
|
||||
void DirtyAreas::clear() {
|
||||
for (uint i = 0; i < _entries.size(); ++i)
|
||||
_entries[i]._active = false;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
@ -315,18 +456,21 @@ void DynamicHotspots::refresh() {
|
||||
|
||||
KernelMessage::KernelMessage() {
|
||||
_flags = 0;
|
||||
_seqInex = 0;
|
||||
_sequenceIndex = 0;
|
||||
_asciiChar = '\0';
|
||||
_asciiChar2 = '\0';
|
||||
_colors = 0;
|
||||
_color1 = 0;
|
||||
_color2 = 0;
|
||||
_msgOffset = 0;
|
||||
_numTicks = 0;
|
||||
_frameTimer2 = 0;
|
||||
_frameTimer = 0;
|
||||
_timeout = 0;
|
||||
_field1C = 0;
|
||||
_abortMode = 0;
|
||||
_nounList[0] = _nounList[1] = _nounList[2] = 0;
|
||||
_abortTimers = 0;
|
||||
_abortMode = ABORTMODE_0;
|
||||
_actionDetails._verbId = 0;
|
||||
_actionDetails._objectNameId = 0;
|
||||
_actionDetails._indirectObjectId = 0;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "mads/assets.h"
|
||||
#include "mads/events.h"
|
||||
#include "mads/game_data.h"
|
||||
#include "mads/messages.h"
|
||||
|
||||
namespace MADS {
|
||||
|
||||
@ -44,6 +45,9 @@ class Scene;
|
||||
#define DEPTH_BANDS_SIZE 15
|
||||
#define MAX_ROUTE_NODES 22
|
||||
|
||||
#define DIRTY_AREAS_SIZE 90
|
||||
#define DIRTY_AREAS_TEXT_DISPLAY_IDX 50
|
||||
|
||||
enum ScrCategory {
|
||||
CAT_NONE = 0, CAT_ACTION = 1, CAT_INV_LIST = 2, CAT_INV_VOCAB = 3,
|
||||
CAT_HOTSPOT = 4, CAT_INV_ANIM = 5, CAT_6 = 6, CAT_INV_SCROLLER = 7,
|
||||
@ -175,20 +179,6 @@ public:
|
||||
int add(SpriteAsset *asset, int idx = 0);
|
||||
};
|
||||
|
||||
class TextDisplay {
|
||||
public:
|
||||
bool _active;
|
||||
int _spacing;
|
||||
Common::Rect _bounds;
|
||||
int _expire;
|
||||
int _col1;
|
||||
int _col2;
|
||||
Common::String _fontName;
|
||||
Common::String _msg;
|
||||
|
||||
TextDisplay();
|
||||
};
|
||||
|
||||
class DynamicHotspot {
|
||||
public:
|
||||
bool _active;
|
||||
@ -226,27 +216,6 @@ public:
|
||||
void refresh();
|
||||
};
|
||||
|
||||
class KernelMessage {
|
||||
public:
|
||||
int _flags;
|
||||
int _seqInex;
|
||||
char _asciiChar;
|
||||
char _asciiChar2;
|
||||
int _colors;
|
||||
Common::Point _posiition;
|
||||
int _msgOffset;
|
||||
int _numTicks;
|
||||
int _frameTimer2;
|
||||
int _frameTimer;
|
||||
int _timeout;
|
||||
int _field1C;
|
||||
int _abortMode;
|
||||
int _nounList[3];
|
||||
Common::String _msg;
|
||||
|
||||
KernelMessage();
|
||||
};
|
||||
|
||||
class Hotspot {
|
||||
public:
|
||||
Common::Rect _bounds;
|
||||
@ -261,6 +230,46 @@ public:
|
||||
Hotspot(Common::SeekableReadStream &f);
|
||||
};
|
||||
|
||||
class DirtyArea {
|
||||
public:
|
||||
Common::Rect _bounds;
|
||||
Common::Rect _bounds2;
|
||||
bool _textActive;
|
||||
bool _active;
|
||||
|
||||
DirtyArea() { _active = false; }
|
||||
void setArea(int width, int height, int maxWidth, int maxHeight);
|
||||
};
|
||||
|
||||
class DirtyAreas {
|
||||
private:
|
||||
MADSEngine *_vm;
|
||||
Common::Array<DirtyArea> _entries;
|
||||
public:
|
||||
DirtyAreas(MADSEngine *vm);
|
||||
|
||||
DirtyArea &operator[](uint idx) {
|
||||
assert(idx < _entries.size());
|
||||
return _entries[idx];
|
||||
}
|
||||
|
||||
void setSpriteSlot(int dirtyIdx, const SpriteSlot &spriteSlot);
|
||||
|
||||
void setTextDisplay(int dirtyIdx, const TextDisplay &textDisplay);
|
||||
|
||||
/**
|
||||
* Merge together any designated dirty areas that overlap
|
||||
* @param startIndex 1-based starting dirty area starting index
|
||||
* @param count Number of entries to process
|
||||
*/
|
||||
void merge(int startIndex, int count);
|
||||
|
||||
bool intersects(int idx1, int idx2);
|
||||
void mergeAreas(int idx1, int idx2);
|
||||
void copy(MSurface *dest, MSurface *src, const Common::Point &posAdjust);
|
||||
void clear();
|
||||
};
|
||||
|
||||
class SceneLogic {
|
||||
protected:
|
||||
Scene *_scene;
|
||||
|
Loading…
x
Reference in New Issue
Block a user