aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/graphics')
-rw-r--r--engines/sci/graphics/animate.cpp123
-rw-r--r--engines/sci/graphics/animate.h6
-rw-r--r--engines/sci/graphics/compare.cpp26
-rw-r--r--engines/sci/graphics/controls.cpp46
-rw-r--r--engines/sci/graphics/cursor.cpp133
-rw-r--r--engines/sci/graphics/cursor.h23
-rw-r--r--engines/sci/graphics/frameout.cpp131
-rw-r--r--engines/sci/graphics/frameout.h9
-rw-r--r--engines/sci/graphics/menu.cpp2
-rw-r--r--engines/sci/graphics/paint16.cpp8
-rw-r--r--engines/sci/graphics/palette.cpp25
-rw-r--r--engines/sci/graphics/picture.cpp17
-rw-r--r--engines/sci/graphics/portrait.cpp2
-rw-r--r--engines/sci/graphics/ports.cpp29
-rw-r--r--engines/sci/graphics/robot.cpp169
-rw-r--r--engines/sci/graphics/robot.h1
-rw-r--r--engines/sci/graphics/screen.cpp6
-rw-r--r--engines/sci/graphics/text16.cpp79
-rw-r--r--engines/sci/graphics/text16.h10
-rw-r--r--engines/sci/graphics/transitions.cpp144
-rw-r--r--engines/sci/graphics/transitions.h5
-rw-r--r--engines/sci/graphics/view.cpp7
22 files changed, 664 insertions, 337 deletions
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp
index b962e819a6..62c5f9c19e 100644
--- a/engines/sci/graphics/animate.cpp
+++ b/engines/sci/graphics/animate.cpp
@@ -96,7 +96,7 @@ bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) {
invokeSelector(_s, curObject, SELECTOR(doit), argc, argv, 0);
// If a game is being loaded, stop processing
- if (_s->abortScriptProcessing != kAbortNone || g_engine->shouldQuit())
+ if (_s->abortScriptProcessing != kAbortNone)
return true; // Stop processing
// Lookup node again, since the nodetable it was in may have been reallocated.
@@ -141,6 +141,7 @@ void GfxAnimate::makeSortedList(List *list) {
AnimateEntry listEntry;
const reg_t curObject = curNode->value;
listEntry.object = curObject;
+ listEntry.castHandle = NULL_REG;
// Get data from current object
listEntry.givenOrderNo = listNr;
@@ -190,6 +191,34 @@ void GfxAnimate::makeSortedList(List *list) {
Common::sort(_list.begin(), _list.end(), sortHelper);
}
+void GfxAnimate::applyGlobalScaling(AnimateList::iterator entry, GfxView *view) {
+ reg_t curObject = entry->object;
+
+ // Global scaling uses global var 2 and some other stuff to calculate scaleX/scaleY
+ int16 maxScale = readSelectorValue(_s->_segMan, curObject, SELECTOR(maxScale));
+ int16 celHeight = view->getHeight(entry->loopNo, entry->celNo);
+ int16 maxCelHeight = (maxScale * celHeight) >> 7;
+ reg_t globalVar2 = _s->variables[VAR_GLOBAL][2]; // current room object
+ int16 vanishingY = readSelectorValue(_s->_segMan, globalVar2, SELECTOR(vanishingY));
+
+ int16 fixedPortY = _ports->getPort()->rect.bottom - vanishingY;
+ int16 fixedEntryY = entry->y - vanishingY;
+ if (!fixedEntryY)
+ fixedEntryY = 1;
+
+ if ((celHeight == 0) || (fixedPortY == 0))
+ error("global scaling panic");
+
+ entry->scaleY = ( maxCelHeight * fixedEntryY ) / fixedPortY;
+ entry->scaleY = (entry->scaleY * 128) / celHeight;
+
+ entry->scaleX = entry->scaleY;
+
+ // and set objects scale selectors
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(scaleX), entry->scaleX);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(scaleY), entry->scaleY);
+}
+
void GfxAnimate::fill(byte &old_picNotValid, bool maySetNsRect) {
reg_t curObject;
uint16 signal;
@@ -229,44 +258,22 @@ void GfxAnimate::fill(byte &old_picNotValid, bool maySetNsRect) {
it->celNo = viewCelCount - 1;
}
- // Process global scaling, if needed
- if (it->scaleSignal & kScaleSignalDoScaling) {
- if (it->scaleSignal & kScaleSignalGlobalScaling) {
- // Global scaling uses global var 2 and some other stuff to calculate scaleX/scaleY
- int16 maxScale = readSelectorValue(_s->_segMan, curObject, SELECTOR(maxScale));
- int16 celHeight = view->getHeight(it->loopNo, it->celNo);
- int16 maxCelHeight = (maxScale * celHeight) >> 7;
- reg_t globalVar2 = _s->variables[VAR_GLOBAL][2]; // current room object
- int16 vanishingY = readSelectorValue(_s->_segMan, globalVar2, SELECTOR(vanishingY));
-
- int16 fixedPortY = _ports->getPort()->rect.bottom - vanishingY;
- int16 fixedEntryY = it->y - vanishingY;
- if (!fixedEntryY)
- fixedEntryY = 1;
-
- if ((celHeight == 0) || (fixedPortY == 0))
- error("global scaling panic");
-
- it->scaleY = ( maxCelHeight * fixedEntryY ) / fixedPortY;
- it->scaleY = (it->scaleY * 128) / celHeight;
-
- it->scaleX = it->scaleY;
-
- // and set objects scale selectors
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(scaleX), it->scaleX);
- writeSelectorValue(_s->_segMan, curObject, SELECTOR(scaleY), it->scaleY);
- }
- }
-
- //warning("%s view %d, loop %d, cel %d", _s->_segMan->getObjectName(curObject), it->viewId, it->loopNo, it->celNo);
-
if (!view->isScaleable()) {
// Laura Bow 2 (especially floppy) depends on this, some views are not supposed to be scaleable
// this "feature" was removed in later versions of SCI1.1
it->scaleSignal = 0;
it->scaleY = it->scaleX = 128;
+ } else {
+ // Process global scaling, if needed
+ if (it->scaleSignal & kScaleSignalDoScaling) {
+ if (it->scaleSignal & kScaleSignalGlobalScaling) {
+ applyGlobalScaling(it, view);
+ }
+ }
}
+ //warning("%s view %d, loop %d, cel %d, signal %x", _s->_segMan->getObjectName(curObject), it->viewId, it->loopNo, it->celNo, it->signal);
+
bool setNsRect = maySetNsRect;
// Create rect according to coordinates and given cel
@@ -278,6 +285,16 @@ void GfxAnimate::fill(byte &old_picNotValid, bool maySetNsRect) {
} else {
view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect);
}
+
+ // This statement must be here for Hoyle4, otherwise cards are unclickable.
+ // This is probably one of the experimental features that were occasionally
+ // added to SCI interpreters; the corresponding check is absent in many SSCI
+ // versions. m_kiewitz knew about this flag before I (lskovlun) implemented it,
+ // so it is possible that more test cases are known. Also, some presently open
+ // SCI1.1 bugs may be fixed by this and should be re-tested with this patch generalized.
+ if (it->scaleSignal & kScaleSignalDontSetNsrect)
+ setNsRect = false;
+
if (setNsRect) {
writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsLeft), it->celRect.left);
writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsTop), it->celRect.top);
@@ -533,19 +550,6 @@ void GfxAnimate::reAnimate(Common::Rect rect) {
}
}
-void GfxAnimate::preprocessAddToPicList() {
- AnimateList::iterator it;
- const AnimateList::iterator end = _list.end();
-
- for (it = _list.begin(); it != end; ++it) {
- if (it->priority == -1)
- it->priority = _ports->kernelCoordinateToPriority(it->y);
-
- // Do not allow priority to get changed by fill()
- it->signal |= kSignalFixedPriority;
- }
-}
-
void GfxAnimate::addToPicDrawCels() {
reg_t curObject;
GfxView *view = NULL;
@@ -558,8 +562,31 @@ void GfxAnimate::addToPicDrawCels() {
// Get the corresponding view
view = _cache->getView(it->viewId);
+ // kAddToPic does not do loop/cel-number fixups, it also doesn't support global scaling
+
+ if (it->priority == -1)
+ it->priority = _ports->kernelCoordinateToPriority(it->y);
+
+ if (!view->isScaleable()) {
+ // Laura Bow 2 specific - ffs. fill()
+ it->scaleSignal = 0;
+ it->scaleY = it->scaleX = 128;
+ }
+
+ // Create rect according to coordinates and given cel
+ if (it->scaleSignal & kScaleSignalDoScaling) {
+ applyGlobalScaling(it, view);
+ view->getCelScaledRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->scaleX, it->scaleY, it->celRect);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsLeft), it->celRect.left);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsTop), it->celRect.top);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsRight), it->celRect.right);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsBottom), it->celRect.bottom);
+ } else {
+ view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect);
+ }
+
// draw corresponding cel
- _paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
+ _paint16->drawCel(view, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
if ((it->signal & kSignalIgnoreActor) == 0) {
it->celRect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, it->celRect.top, it->celRect.bottom - 1);
_paint16->fillRect(it->celRect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
@@ -677,6 +704,7 @@ void GfxAnimate::kernelAnimate(reg_t listReference, bool cycle, int argc, reg_t
int16 onlyWidth = onlyCast->celRect.width();
if (((onlyWidth == 12) && (onlyHeight == 35)) || // regular benchmark view ("fred", "Speedy", "ego")
((onlyWidth == 29) && (onlyHeight == 45)) || // King's Quest 5 french "fred"
+ ((onlyWidth == 1) && (onlyHeight == 5)) || // Freddy Pharkas "fred"
((onlyWidth == 1) && (onlyHeight == 1))) { // Laura Bow 2 Talkie
// check further that there is only one cel in that view
GfxView *onlyView = _cache->getView(onlyCast->viewId);
@@ -703,7 +731,6 @@ void GfxAnimate::addToPicSetPicNotValid() {
void GfxAnimate::kernelAddToPicList(reg_t listReference, int argc, reg_t *argv) {
List *list;
- byte tempPicNotValid = 0;
_ports->setPort((Port *)_ports->_picWind);
@@ -712,8 +739,6 @@ void GfxAnimate::kernelAddToPicList(reg_t listReference, int argc, reg_t *argv)
error("kAddToPic called with non-list as parameter");
makeSortedList(list);
- preprocessAddToPicList();
- fill(tempPicNotValid, getSciVersion() >= SCI_VERSION_1_1 ? true : false);
addToPicDrawCels();
addToPicSetPicNotValid();
diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h
index f25e54915e..23e7a624d8 100644
--- a/engines/sci/graphics/animate.h
+++ b/engines/sci/graphics/animate.h
@@ -53,7 +53,8 @@ enum ViewSignals {
enum ViewScaleSignals {
kScaleSignalDoScaling = 0x0001, // enables scaling when drawing that cel (involves scaleX and scaleY)
kScaleSignalGlobalScaling = 0x0002, // means that global scaling shall get applied on that cel (sets scaleX/scaleY)
- kScaleSignalUnknown2 = 0x0004 // really unknown
+ kScaleSignalDontSetNsrect = 0x0004 // do not set nsRect inside kAnimate(); for a test case see bug #3038424
+
};
struct AnimateEntry {
@@ -83,6 +84,7 @@ class GfxPaint16;
class GfxScreen;
class GfxPalette;
class GfxTransitions;
+class GfxView;
/**
* Animate class, kAnimate and relevant functions for SCI16 (SCI0-SCI1.1) games
*/
@@ -94,13 +96,13 @@ public:
void disposeLastCast();
bool invoke(List *list, int argc, reg_t *argv);
void makeSortedList(List *list);
+ void applyGlobalScaling(AnimateList::iterator entry, GfxView *view);
void fill(byte &oldPicNotValid, bool maySetNsRect);
void update();
void drawCels();
void updateScreen(byte oldPicNotValid);
void restoreAndDelete(int argc, reg_t *argv);
void reAnimate(Common::Rect rect);
- void preprocessAddToPicList();
void addToPicDrawCels();
void addToPicDrawView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 leftPos, int16 topPos, int16 priority, int16 control);
diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp
index 1c961b2ad6..6a99d2384e 100644
--- a/engines/sci/graphics/compare.cpp
+++ b/engines/sci/graphics/compare.cpp
@@ -185,9 +185,9 @@ reg_t GfxCompare::kernelCanBeHere(reg_t curObject, reg_t listReference) {
checkRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight));
checkRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom));
- if (!checkRect.isValidRect()) { // can occur in Iceman - HACK? TODO: is this really occuring in sierra sci? check this
+ if (!checkRect.isValidRect()) { // can occur in Iceman and Mother Goose - HACK? TODO: is this really occuring in sierra sci? check this
warning("kCan(t)BeHere - invalid rect %d, %d -> %d, %d", checkRect.left, checkRect.top, checkRect.right, checkRect.bottom);
- return NULL_REG;
+ return NULL_REG; // this means "can be here"
}
adjustedRect = _coordAdjuster->onControl(checkRect);
@@ -237,20 +237,24 @@ void GfxCompare::kernelBaseSetter(reg_t object) {
Common::Rect celRect;
GfxView *tmpView = _cache->getView(viewId);
- if (tmpView->isSci2Hires())
- _screen->adjustToUpscaledCoordinates(y, x);
+ if (!tmpView->isScaleable())
+ scaleSignal = 0;
if (scaleSignal & kScaleSignalDoScaling) {
- int16 scaleX = readSelectorValue(_segMan, object, SELECTOR(scaleX));
- int16 scaleY = readSelectorValue(_segMan, object, SELECTOR(scaleY));
- tmpView->getCelScaledRect(loopNo, celNo, x, y, z, scaleX, scaleY, celRect);
+ celRect.left = readSelectorValue(_segMan, object, SELECTOR(nsLeft));
+ celRect.right = readSelectorValue(_segMan, object, SELECTOR(nsRight));
+ celRect.top = readSelectorValue(_segMan, object, SELECTOR(nsTop));
+ celRect.bottom = readSelectorValue(_segMan, object, SELECTOR(nsBottom));
} else {
+ if (tmpView->isSci2Hires())
+ _screen->adjustToUpscaledCoordinates(y, x);
+
tmpView->getCelRect(loopNo, celNo, x, y, z, celRect);
- }
- if (tmpView->isSci2Hires()) {
- _screen->adjustBackUpscaledCoordinates(celRect.top, celRect.left);
- _screen->adjustBackUpscaledCoordinates(celRect.bottom, celRect.right);
+ if (tmpView->isSci2Hires()) {
+ _screen->adjustBackUpscaledCoordinates(celRect.top, celRect.left);
+ _screen->adjustBackUpscaledCoordinates(celRect.bottom, celRect.right);
+ }
}
celRect.bottom = y + 1;
diff --git a/engines/sci/graphics/controls.cpp b/engines/sci/graphics/controls.cpp
index 5891413be8..66376a793c 100644
--- a/engines/sci/graphics/controls.cpp
+++ b/engines/sci/graphics/controls.cpp
@@ -150,7 +150,7 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
uint16 maxChars = readSelectorValue(_segMan, controlObject, SELECTOR(max));
reg_t textReference = readSelector(_segMan, controlObject, SELECTOR(text));
Common::String text;
- uint16 textSize, eventType, eventKey = 0;
+ uint16 textSize, eventType, eventKey = 0, modifiers = 0;
bool textChanged = false;
bool textAddChar = false;
Common::Rect rect;
@@ -159,6 +159,8 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
error("kEditControl called on object that doesnt have a text reference");
text = _segMan->getString(textReference);
+ uint16 oldCursorPos = cursorPos;
+
if (!eventObject.isNull()) {
textSize = text.size();
eventType = readSelectorValue(_segMan, eventObject, SELECTOR(type));
@@ -169,6 +171,7 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
break;
case SCI_EVENT_KEYBOARD:
eventKey = readSelectorValue(_segMan, eventObject, SELECTOR(message));
+ modifiers = readSelectorValue(_segMan, eventObject, SELECTOR(modifiers));
switch (eventKey) {
case SCI_KEY_BACKSPACE:
if (cursorPos > 0) {
@@ -177,8 +180,10 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
}
break;
case SCI_KEY_DELETE:
- text.deleteChar(cursorPos);
- textChanged = true;
+ if (cursorPos < textSize) {
+ text.deleteChar(cursorPos);
+ textChanged = true;
+ }
break;
case SCI_KEY_HOME: // HOME
cursorPos = 0; textChanged = true;
@@ -196,8 +201,20 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
cursorPos++; textChanged = true;
}
break;
+ case 3: // returned in SCI1 late and newer when Control - C is pressed
+ if (modifiers & SCI_KEYMOD_CTRL) {
+ // Control-C erases the whole line
+ cursorPos = 0; text.clear();
+ textChanged = true;
+ }
+ break;
default:
- if (eventKey > 31 && eventKey < 256 && textSize < maxChars) {
+ if ((modifiers & SCI_KEYMOD_CTRL) && eventKey == 99) {
+ // Control-C in earlier SCI games (SCI0 - SCI1 middle)
+ // Control-C erases the whole line
+ cursorPos = 0; text.clear();
+ textChanged = true;
+ } else if (eventKey > 31 && eventKey < 256 && textSize < maxChars) {
// insert pressed character
textAddChar = true;
textChanged = true;
@@ -208,6 +225,11 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
}
}
+ if (g_sci->getVocabulary() && !textChanged && oldCursorPos != cursorPos) {
+ assert(!textAddChar);
+ textChanged = g_sci->getVocabulary()->checkAltInput(text, cursorPos);
+ }
+
if (textChanged) {
GuiResourceId oldFontId = _text16->GetFontId();
GuiResourceId fontId = readSelectorValue(_segMan, controlObject, SELECTOR(font));
@@ -215,18 +237,28 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
readSelectorValue(_segMan, controlObject, SELECTOR(nsRight)), readSelectorValue(_segMan, controlObject, SELECTOR(nsBottom)));
_text16->SetFont(fontId);
if (textAddChar) {
- // We check, if we are really able to add the new char
- uint16 textWidth = 0;
+
const char *textPtr = text.c_str();
+
+ // We check if we are really able to add the new char
+ uint16 textWidth = 0;
while (*textPtr)
- textWidth += _text16->_font->getCharWidth(*textPtr++);
+ textWidth += _text16->_font->getCharWidth((byte)*textPtr++);
textWidth += _text16->_font->getCharWidth(eventKey);
+
+ // Does it fit?
if (textWidth >= rect.width()) {
_text16->SetFont(oldFontId);
return;
}
+
text.insertChar(eventKey, cursorPos++);
+
+ // Note: the following checkAltInput call might make the text
+ // too wide to fit, but SSCI fails to check that too.
}
+ if (g_sci->getVocabulary())
+ g_sci->getVocabulary()->checkAltInput(text, cursorPos);
texteditCursorErase();
_paint16->eraseRect(rect);
_text16->Box(text.c_str(), 0, rect, SCI_TEXT16_ALIGNMENT_LEFT, -1);
diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp
index a906899113..7a37d7e865 100644
--- a/engines/sci/graphics/cursor.cpp
+++ b/engines/sci/graphics/cursor.cpp
@@ -49,10 +49,21 @@ GfxCursor::GfxCursor(ResourceManager *resMan, GfxPalette *palette, GfxScreen *sc
// center mouse cursor
setPosition(Common::Point(_screen->getWidth() / 2, _screen->getHeight() / 2));
_moveZoneActive = false;
+
+ _zoomZoneActive = false;
+ _zoomZone = Common::Rect();
+ _zoomCursorView = 0;
+ _zoomCursorLoop = 0;
+ _zoomCursorCel = 0;
+ _zoomPicView = 0;
+ _zoomColor = 0;
+ _zoomMultiplier = 0;
+ _cursorSurface = 0;
}
GfxCursor::~GfxCursor() {
purgeCache();
+ kernelClearZoomZone();
}
void GfxCursor::init(GfxCoordAdjuster *coordAdjuster, EventManager *event) {
@@ -266,6 +277,16 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu
kernelShow();
}
+// this list contains all mandatory set cursor changes, that need special handling
+// ffs. GfxCursor::setPosition (below)
+// Game, newPosition, validRect
+static const SciCursorSetPositionWorkarounds setPositionWorkarounds[] = {
+ { GID_ISLANDBRAIN, 84, 109, 46, 76, 174, 243 }, // island of dr. brain / game menu
+ { GID_LSL5, 23, 171, 0, 0, 26, 320 }, // larry 5 / skip forward helper
+ { GID_QFG1VGA, 64, 174, 40, 37, 74, 284 }, // Quest For Glory 1 VGA / run/walk/sleep sub-menu
+ { (SciGameId)0, -1, -1, -1, -1, -1, -1 }
+};
+
void GfxCursor::setPosition(Common::Point pos) {
// Don't set position, when cursor is not visible.
// This fixes eco quest 1 (floppy) right at the start, which is setting
@@ -282,6 +303,31 @@ void GfxCursor::setPosition(Common::Point pos) {
_screen->adjustToUpscaledCoordinates(pos.y, pos.x);
g_system->warpMouse(pos.x, pos.y);
}
+
+ // Some games display a new menu, set mouse position somewhere within and
+ // expect it to be in there. This is fine for a real mouse, but on wii using
+ // wii-mote or touch interfaces this won't work. In fact on those platforms
+ // the menus will close immediately because of that behaviour.
+ // We identify those cases and set a reaction-rect. If the mouse it outside
+ // of that rect, we won't report the position back to the scripts.
+ // As soon as the mouse was inside once, we will revert to normal behaviour
+ // Currently this code is enabled for all platforms, especially because we can't
+ // differentiate between e.g. Windows used via mouse and Windows used via touchscreen
+ // The workaround won't hurt real-mouse platforms
+ const SciGameId gameId = g_sci->getGameId();
+ const SciCursorSetPositionWorkarounds *workaround;
+ workaround = setPositionWorkarounds;
+ while (workaround->newPositionX != -1) {
+ if (workaround->gameId == gameId
+ && ((workaround->newPositionX == pos.x) && (workaround->newPositionY == pos.y))) {
+ EngineState *s = g_sci->getEngineState();
+ s->_cursorWorkaroundActive = true;
+ s->_cursorWorkaroundPoint = pos;
+ s->_cursorWorkaroundRect = Common::Rect(workaround->rectLeft, workaround->rectTop, workaround->rectRight, workaround->rectBottom);
+ return;
+ }
+ workaround++;
+ }
}
Common::Point GfxCursor::getPosition() {
@@ -294,9 +340,10 @@ Common::Point GfxCursor::getPosition() {
}
void GfxCursor::refreshPosition() {
+ Common::Point mousePoint = getPosition();
+
if (_moveZoneActive) {
bool clipped = false;
- Common::Point mousePoint = getPosition();
if (mousePoint.x < _moveZone.left) {
mousePoint.x = _moveZone.left;
@@ -318,6 +365,52 @@ void GfxCursor::refreshPosition() {
if (clipped)
setPosition(mousePoint);
}
+
+ if (_zoomZoneActive) {
+ // Cursor
+ const CelInfo *cursorCelInfo = _zoomCursorView->getCelInfo(_zoomCursorLoop, _zoomCursorCel);
+ const byte *cursorBitmap = _zoomCursorView->getBitmap(_zoomCursorLoop, _zoomCursorCel);
+ // Pic
+ const CelInfo *picCelInfo = _zoomPicView->getCelInfo(0, 0);
+ const byte *rawPicBitmap = _zoomPicView->getBitmap(0, 0);
+
+ // Compute hotspot of cursor
+ Common::Point cursorHotspot = Common::Point((cursorCelInfo->width >> 1) - cursorCelInfo->displaceX, cursorCelInfo->height - cursorCelInfo->displaceY - 1);
+
+ int16 targetX = ((mousePoint.x - _moveZone.left) * _zoomMultiplier);
+ int16 targetY = ((mousePoint.y - _moveZone.top) * _zoomMultiplier);
+ if (targetX < 0)
+ targetX = 0;
+ if (targetY < 0)
+ targetY = 0;
+
+ targetX -= cursorHotspot.x;
+ targetY -= cursorHotspot.y;
+
+ // Sierra SCI actually drew only within zoom area, thus removing the need to fill any other pixels with upmost/left
+ // color of the picture cel. This also made the cursor not appear on top of everything. They actually drew the
+ // cursor manually within kAnimate processing and used a hidden cursor for moving.
+ // TODO: we should also do this
+
+ // Replace the special magnifier color with the associated magnified pixels
+ for (int x = 0; x < cursorCelInfo->width; x++) {
+ for (int y = 0; y < cursorCelInfo->height; y++) {
+ int curPos = cursorCelInfo->width * y + x;
+ if (cursorBitmap[curPos] == _zoomColor) {
+ int16 rawY = targetY + y;
+ int16 rawX = targetX + x;
+ if ((rawY >= 0) && (rawY < picCelInfo->height) && (rawX >= 0) && (rawX < picCelInfo->width)) {
+ int rawPos = picCelInfo->width * rawY + rawX;
+ _cursorSurface[curPos] = rawPicBitmap[rawPos];
+ } else {
+ _cursorSurface[curPos] = rawPicBitmap[0]; // use left and upmost pixel color
+ }
+ }
+ }
+ }
+
+ CursorMan.replaceCursor((const byte *)_cursorSurface, cursorCelInfo->width, cursorCelInfo->height, cursorHotspot.x, cursorHotspot.y, cursorCelInfo->clearKey);
+ }
}
void GfxCursor::kernelResetMoveZone() {
@@ -329,6 +422,44 @@ void GfxCursor::kernelSetMoveZone(Common::Rect zone) {
_moveZoneActive = true;
}
+void GfxCursor::kernelClearZoomZone() {
+ kernelResetMoveZone();
+ _zoomZone = Common::Rect();
+ _zoomColor = 0;
+ _zoomMultiplier = 0;
+ _zoomZoneActive = false;
+ delete _zoomCursorView;
+ _zoomCursorView = 0;
+ delete _zoomPicView;
+ _zoomPicView = 0;
+ delete[] _cursorSurface;
+ _cursorSurface = 0;
+}
+
+void GfxCursor::kernelSetZoomZone(byte multiplier, Common::Rect zone, GuiResourceId viewNum, int loopNum, int celNum, GuiResourceId picNum, byte zoomColor) {
+ kernelClearZoomZone();
+
+ _zoomMultiplier = multiplier;
+
+ if (_zoomMultiplier != 1 && _zoomMultiplier != 2 && _zoomMultiplier != 4)
+ error("Unexpected zoom multiplier (expected 1, 2 or 4)");
+
+ _zoomCursorView = new GfxView(_resMan, _screen, _palette, viewNum);
+ _zoomCursorLoop = (byte)loopNum;
+ _zoomCursorCel = (byte)celNum;
+ _zoomPicView = new GfxView(_resMan, _screen, _palette, picNum);
+ const CelInfo *cursorCelInfo = _zoomCursorView->getCelInfo(_zoomCursorLoop, _zoomCursorCel);
+ const byte *cursorBitmap = _zoomCursorView->getBitmap(_zoomCursorLoop, _zoomCursorCel);
+ _cursorSurface = new byte[cursorCelInfo->width * cursorCelInfo->height];
+ memcpy(_cursorSurface, cursorBitmap, cursorCelInfo->width * cursorCelInfo->height);
+
+ _zoomZone = zone;
+ kernelSetMoveZone(_zoomZone);
+
+ _zoomColor = zoomColor;
+ _zoomZoneActive = true;
+}
+
void GfxCursor::kernelSetPos(Common::Point pos) {
_coordAdjuster->setCursorPos(pos);
kernelMoveCursor(pos);
diff --git a/engines/sci/graphics/cursor.h b/engines/sci/graphics/cursor.h
index 787841f5be..ae3b51e26a 100644
--- a/engines/sci/graphics/cursor.h
+++ b/engines/sci/graphics/cursor.h
@@ -40,6 +40,16 @@ class GfxPalette;
typedef Common::HashMap<int, GfxView *> CursorCache;
+struct SciCursorSetPositionWorkarounds {
+ SciGameId gameId;
+ int16 newPositionY;
+ int16 newPositionX;
+ int16 rectTop;
+ int16 rectLeft;
+ int16 rectBottom;
+ int16 rectRight;
+};
+
class GfxCursor {
public:
GfxCursor(ResourceManager *resMan, GfxPalette *palette, GfxScreen *screen);
@@ -69,6 +79,9 @@ public:
*/
void kernelSetMoveZone(Common::Rect zone);
+ void kernelClearZoomZone();
+ void kernelSetZoomZone(byte multiplier, Common::Rect zone, GuiResourceId viewNum, int loopNum, int celNum, GuiResourceId picNum, byte zoomColor);
+
void kernelSetPos(Common::Point pos);
void kernelMoveCursor(Common::Point pos);
@@ -86,6 +99,16 @@ private:
bool _moveZoneActive;
Common::Rect _moveZone; // Rectangle in which the pointer can move
+ bool _zoomZoneActive;
+ Common::Rect _zoomZone;
+ GfxView *_zoomCursorView;
+ byte _zoomCursorLoop;
+ byte _zoomCursorCel;
+ GfxView *_zoomPicView;
+ byte _zoomColor;
+ byte _zoomMultiplier;
+ byte *_cursorSurface;
+
CursorCache _cachedCursors;
bool _isVisible;
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index a433b26ef2..fc374ea143 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -70,6 +70,7 @@ void GfxFrameout::kernelAddPlane(reg_t object) {
newPlane.pictureId = 0xFFFF;
newPlane.priority = readSelectorValue(_segMan, object, SELECTOR(priority));
newPlane.lastPriority = 0xFFFF; // hidden
+ newPlane.planeOffsetX = 0;
_planes.push_back(newPlane);
kernelUpdatePlane(object);
@@ -91,6 +92,43 @@ void GfxFrameout::kernelUpdatePlane(reg_t object) {
addPlanePicture(object, it->pictureId, 0);
}
}
+ it->planeRect.top = readSelectorValue(_segMan, object, SELECTOR(top));
+ it->planeRect.left = readSelectorValue(_segMan, object, SELECTOR(left));
+ it->planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)) + 1;
+ it->planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)) + 1;
+
+ Common::Rect screenRect(_screen->getWidth(), _screen->getHeight());
+ it->planeRect.top = (it->planeRect.top * screenRect.height()) / scriptsRunningHeight;
+ it->planeRect.left = (it->planeRect.left * screenRect.width()) / scriptsRunningWidth;
+ it->planeRect.bottom = (it->planeRect.bottom * screenRect.height()) / scriptsRunningHeight;
+ it->planeRect.right = (it->planeRect.right * screenRect.width()) / scriptsRunningWidth;
+
+ // We get negative left in kq7 in scrolling rooms
+ if (it->planeRect.left < 0) {
+ it->planeOffsetX = -it->planeRect.left;
+ it->planeRect.left = 0;
+ }
+ if (it->planeRect.top < 0)
+ it->planeRect.top = 0;
+ // We get bad plane-bottom in sq6
+ if (it->planeRect.right > _screen->getWidth())
+ it->planeRect.right = _screen->getWidth();
+ if (it->planeRect.bottom > _screen->getHeight())
+ it->planeRect.bottom = _screen->getHeight();
+
+ it->planeClipRect = Common::Rect(it->planeRect.width(), it->planeRect.height());
+ it->upscaledPlaneRect = it->planeRect;
+ it->upscaledPlaneClipRect = it->planeClipRect;
+ if (_screen->getUpscaledHires()) {
+ _screen->adjustToUpscaledCoordinates(it->upscaledPlaneRect.top, it->upscaledPlaneRect.left);
+ _screen->adjustToUpscaledCoordinates(it->upscaledPlaneRect.bottom, it->upscaledPlaneRect.right);
+ _screen->adjustToUpscaledCoordinates(it->upscaledPlaneClipRect.top, it->upscaledPlaneClipRect.left);
+ _screen->adjustToUpscaledCoordinates(it->upscaledPlaneClipRect.bottom, it->upscaledPlaneClipRect.right);
+ }
+
+ it->planePictureMirrored = readSelectorValue(_segMan, object, SELECTOR(mirrored));
+ it->planeBack = readSelectorValue(_segMan, object, SELECTOR(back));
+
sortPlanes();
return;
}
@@ -98,6 +136,10 @@ void GfxFrameout::kernelUpdatePlane(reg_t object) {
error("kUpdatePlane called on plane that wasn't added before");
}
+void GfxFrameout::kernelRepaintPlane(reg_t object) {
+ // TODO
+}
+
void GfxFrameout::kernelDeletePlane(reg_t object) {
deletePlanePictures(object);
for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) {
@@ -147,6 +189,10 @@ void GfxFrameout::kernelAddScreenItem(reg_t object) {
_screenItems.push_back(object);
}
+void GfxFrameout::kernelUpdateScreenItem(reg_t object) {
+ // TODO
+}
+
void GfxFrameout::kernelDeleteScreenItem(reg_t object) {
for (uint32 itemNr = 0; itemNr < _screenItems.size(); itemNr++) {
if (_screenItems[itemNr] == object) {
@@ -207,72 +253,31 @@ void GfxFrameout::kernelFrameout() {
_palette->palVaryUpdate();
// Allocate enough space for all screen items
+ // TODO: Modify _screenItems to hold FrameoutEntry entries instead.
+ // Creating and destroying this in kernelFrameout() is overkill!
FrameoutEntry *itemData = new FrameoutEntry[_screenItems.size()];
for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) {
reg_t planeObject = it->object;
uint16 planeLastPriority = it->lastPriority;
- Common::Rect planeRect;
- planeRect.top = readSelectorValue(_segMan, planeObject, SELECTOR(top));
- planeRect.left = readSelectorValue(_segMan, planeObject, SELECTOR(left));
- planeRect.bottom = readSelectorValue(_segMan, planeObject, SELECTOR(bottom)) + 1;
- planeRect.right = readSelectorValue(_segMan, planeObject, SELECTOR(right)) + 1;
-
// Update priority here, sq6 sets it w/o UpdatePlane
uint16 planePriority = it->priority = readSelectorValue(_segMan, planeObject, SELECTOR(priority));
- Common::Rect screenRect(_screen->getWidth(), _screen->getHeight());
- planeRect.top = (planeRect.top * screenRect.height()) / scriptsRunningHeight;
- planeRect.left = (planeRect.left * screenRect.width()) / scriptsRunningWidth;
- planeRect.bottom = (planeRect.bottom * screenRect.height()) / scriptsRunningHeight;
- planeRect.right = (planeRect.right * screenRect.width()) / scriptsRunningWidth;
-
- int16 planeOffsetX = 0;
-
- // We get negative left in kq7 in scrolling rooms
- if (planeRect.left < 0) {
- planeOffsetX = -planeRect.left;
- planeRect.left = 0;
- }
- if (planeRect.top < 0)
- planeRect.top = 0;
- // We get bad plane-bottom in sq6
- if (planeRect.right > _screen->getWidth())
- planeRect.right = _screen->getWidth();
- if (planeRect.bottom > _screen->getHeight())
- planeRect.bottom = _screen->getHeight();
-
it->lastPriority = planePriority;
if (planePriority == 0xffff) { // Plane currently not meant to be shown
// If plane was shown before, delete plane rect
if (planePriority != planeLastPriority)
- _paint32->fillRect(planeRect, 0);
+ _paint32->fillRect(it->planeRect, 0);
continue;
}
- Common::Rect planeClipRect(planeRect.width(), planeRect.height());
-
- Common::Rect upscaledPlaneRect = planeRect;
- Common::Rect upscaledPlaneClipRect = planeClipRect;
- if (_screen->getUpscaledHires()) {
- _screen->adjustToUpscaledCoordinates(upscaledPlaneRect.top, upscaledPlaneRect.left);
- _screen->adjustToUpscaledCoordinates(upscaledPlaneRect.bottom, upscaledPlaneRect.right);
- _screen->adjustToUpscaledCoordinates(upscaledPlaneClipRect.top, upscaledPlaneClipRect.left);
- _screen->adjustToUpscaledCoordinates(upscaledPlaneClipRect.bottom, upscaledPlaneClipRect.right);
- }
-
- byte planeBack = readSelectorValue(_segMan, planeObject, SELECTOR(back));
- if (planeBack)
- _paint32->fillRect(planeRect, planeBack);
+ if (it->planeBack)
+ _paint32->fillRect(it->planeRect, it->planeBack);
GuiResourceId planeMainPictureId = it->pictureId;
- bool planePictureMirrored = false;
- if (readSelectorValue(_segMan, planeObject, SELECTOR(mirrored)))
- planePictureMirrored = true;
-
- _coordAdjuster->pictureSetDisplayArea(planeRect);
+ _coordAdjuster->pictureSetDisplayArea(it->planeRect);
_palette->drewPicture(planeMainPictureId);
// Fill our itemlist for this plane
@@ -360,25 +365,25 @@ void GfxFrameout::kernelFrameout() {
// Out of view
int16 pictureCelStartX = itemEntry->picStartX + itemEntry->x;
int16 pictureCelEndX = pictureCelStartX + itemEntry->picture->getSci32celWidth(itemEntry->celNo);
- int16 planeStartX = planeOffsetX;
- int16 planeEndX = planeStartX + planeRect.width();
+ int16 planeStartX = it->planeOffsetX;
+ int16 planeEndX = planeStartX + it->planeRect.width();
if (pictureCelEndX < planeStartX)
continue;
if (pictureCelStartX > planeEndX)
continue;
- int16 pictureOffsetX = planeOffsetX;
+ int16 pictureOffsetX = it->planeOffsetX;
int16 pictureX = itemEntry->x;
- if ((planeOffsetX) || (itemEntry->picStartX)) {
- if (planeOffsetX <= itemEntry->picStartX) {
- pictureX += itemEntry->picStartX - planeOffsetX;
+ if ((it->planeOffsetX) || (itemEntry->picStartX)) {
+ if (it->planeOffsetX <= itemEntry->picStartX) {
+ pictureX += itemEntry->picStartX - it->planeOffsetX;
pictureOffsetX = 0;
} else {
- pictureOffsetX = planeOffsetX - itemEntry->picStartX;
+ pictureOffsetX = it->planeOffsetX - itemEntry->picStartX;
}
}
- itemEntry->picture->drawSci32Vga(itemEntry->celNo, pictureX, itemEntry->y, pictureOffsetX, planePictureMirrored);
+ itemEntry->picture->drawSci32Vga(itemEntry->celNo, pictureX, itemEntry->y, pictureOffsetX, it->planePictureMirrored);
// warning("picture cel %d %d", itemEntry->celNo, itemEntry->priority);
} else if (itemEntry->viewId != 0xFFFF) {
@@ -403,7 +408,7 @@ void GfxFrameout::kernelFrameout() {
break;
}
// Adjust according to current scroll position
- itemEntry->x -= planeOffsetX;
+ itemEntry->x -= it->planeOffsetX;
uint16 useInsetRect = readSelectorValue(_segMan, itemEntry->object, SELECTOR(useInsetRect));
if (useInsetRect) {
@@ -426,7 +431,7 @@ void GfxFrameout::kernelFrameout() {
Common::Rect nsRect = itemEntry->celRect;
// Translate back to actual coordinate within scrollable plane
- nsRect.translate(planeOffsetX, 0);
+ nsRect.translate(it->planeOffsetX, 0);
switch (getSciVersion()) {
case SCI_VERSION_2:
if (view->isSci2Hires()) {
@@ -465,13 +470,13 @@ void GfxFrameout::kernelFrameout() {
Common::Rect clipRect, translatedClipRect;
clipRect = itemEntry->celRect;
if (view->isSci2Hires()) {
- clipRect.clip(upscaledPlaneClipRect);
+ clipRect.clip(it->upscaledPlaneClipRect);
translatedClipRect = clipRect;
- translatedClipRect.translate(upscaledPlaneRect.left, upscaledPlaneRect.top);
+ translatedClipRect.translate(it->upscaledPlaneRect.left, it->upscaledPlaneRect.top);
} else {
- clipRect.clip(planeClipRect);
+ clipRect.clip(it->planeClipRect);
translatedClipRect = clipRect;
- translatedClipRect.translate(planeRect.left, planeRect.top);
+ translatedClipRect.translate(it->planeRect.left, it->planeRect.top);
}
if (!clipRect.isEmpty()) {
@@ -501,8 +506,8 @@ void GfxFrameout::kernelFrameout() {
itemEntry->y = ((itemEntry->y * _screen->getHeight()) / scriptsRunningHeight);
itemEntry->x = ((itemEntry->x * _screen->getWidth()) / scriptsRunningWidth);
- uint16 curX = itemEntry->x + planeRect.left;
- uint16 curY = itemEntry->y + planeRect.top;
+ uint16 curX = itemEntry->x + it->planeRect.left;
+ uint16 curY = itemEntry->y + it->planeRect.top;
for (uint32 i = 0; i < text.size(); i++) {
unsigned char curChar = text[i];
// TODO: proper text splitting... this is a hack
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index f8f7e54a27..07297a91af 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -32,7 +32,14 @@ struct PlaneEntry {
reg_t object;
uint16 priority;
uint16 lastPriority;
+ int16 planeOffsetX;
GuiResourceId pictureId;
+ Common::Rect planeRect;
+ Common::Rect planeClipRect;
+ Common::Rect upscaledPlaneRect;
+ Common::Rect upscaledPlaneClipRect;
+ bool planePictureMirrored;
+ byte planeBack;
};
typedef Common::List<PlaneEntry> PlaneList;
@@ -81,8 +88,10 @@ public:
void kernelAddPlane(reg_t object);
void kernelUpdatePlane(reg_t object);
+ void kernelRepaintPlane(reg_t object);
void kernelDeletePlane(reg_t object);
void kernelAddScreenItem(reg_t object);
+ void kernelUpdateScreenItem(reg_t object);
void kernelDeleteScreenItem(reg_t object);
int16 kernelGetHighPlanePri();
void kernelAddPicAt(reg_t planeObj, int16 forWidth, GuiResourceId pictureId);
diff --git a/engines/sci/graphics/menu.cpp b/engines/sci/graphics/menu.cpp
index 630626c128..06470bc560 100644
--- a/engines/sci/graphics/menu.cpp
+++ b/engines/sci/graphics/menu.cpp
@@ -905,7 +905,7 @@ void GfxMenu::kernelDrawStatus(const char *text, int16 colorPen, int16 colorBack
_paint16->fillRect(_ports->_menuBarRect, 1, colorBack);
_ports->penColor(colorPen);
_ports->moveTo(0, 1);
- _text16->Draw_String(text);
+ _text16->Draw_Status(text);
_paint16->bitsShow(_ports->_menuBarRect);
_ports->setPort(oldPort);
}
diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp
index dbc738e2f7..3c115f0c8e 100644
--- a/engines/sci/graphics/paint16.cpp
+++ b/engines/sci/graphics/paint16.cpp
@@ -380,6 +380,14 @@ void GfxPaint16::kernelDrawPicture(GuiResourceId pictureId, int16 animationNr, b
drawPicture(pictureId, animationNr, mirroredFlag, addToFlag, EGApaletteNo);
_transitions->setup(animationNr, animationBlackoutFlag);
} else {
+ // We need to set it for SCI1EARLY+ (sierra sci also did so), otherwise we get at least the following issues:
+ // LSL5 (english) - last wakeup (taj mahal flute dream)
+ // SQ5 (english v1.03) - during the scene following the scrubbing
+ // in both situations a window is shown when kDrawPic is called, which would result otherwise in
+ // no showpic getting called from kAnimate and we would get graphic corruption
+ // XMAS1990 EGA did not set it in this case, VGA did
+ if (getSciVersion() >= SCI_VERSION_1_EARLY)
+ _screen->_picNotValid = 1;
_ports->beginUpdate(_ports->_picWind);
drawPicture(pictureId, animationNr, mirroredFlag, addToFlag, EGApaletteNo);
_ports->endUpdate(_ports->_picWind);
diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index 5c17f76558..76b2ed53fc 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -340,7 +340,8 @@ void GfxPalette::drewPicture(GuiResourceId pictureId) {
_sysPalette.timestamp++;
if (_palVaryResourceId != -1) {
- palVaryLoadTargetPalette(pictureId);
+ if (g_sci->getEngineState()->gameIsRestarting == 0) // only if not restored nor restarted
+ palVaryLoadTargetPalette(pictureId);
}
}
@@ -613,9 +614,18 @@ bool GfxPalette::kernelPalVaryInit(GuiResourceId resourceId, uint16 ticks, uint1
_palVaryStepStop = stepStop;
_palVaryDirection = direction;
// if no ticks are given, jump directly to destination
- if (!_palVaryTicks)
+ if (!_palVaryTicks) {
_palVaryDirection = stepStop;
- palVaryInstallTimer();
+ // sierra sci set the timer to 1 tick instead of calling it directly
+ // we have to change this to prevent a race condition to happen in
+ // at least freddy pharkas during nighttime. In that case kPalVary is
+ // called right before a transition and because we load pictures much
+ // faster, the 1 tick won't pass sometimes resulting in the palette
+ // being daytime instead of nighttime during the transition.
+ palVaryProcess(1, true);
+ } else {
+ palVaryInstallTimer();
+ }
return true;
}
return false;
@@ -632,9 +642,14 @@ int16 GfxPalette::kernelPalVaryReverse(int16 ticks, uint16 stepStop, int16 direc
_palVaryStepStop = stepStop;
_palVaryDirection = direction != -1 ? -direction : -_palVaryDirection;
- if (!_palVaryTicks)
+ if (!_palVaryTicks) {
_palVaryDirection = _palVaryStepStop - _palVaryStep;
- palVaryInstallTimer();
+ // ffs. see palVaryInit right above, we fix the code here as well
+ // just in case
+ palVaryProcess(1, true);
+ } else {
+ palVaryInstallTimer();
+ }
return kernelPalVaryGetCurrentStep();
}
diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp
index e568316919..39666b82cb 100644
--- a/engines/sci/graphics/picture.cpp
+++ b/engines/sci/graphics/picture.cpp
@@ -120,10 +120,6 @@ void GfxPicture::drawSci11Vga() {
// [priorityBandData:WORD] * priorityBandCount
// [priority:BYTE] [unknown:BYTE]
- // Create palette and set it
- _palette->createFromData(inbuffer + palette_data_ptr, size - palette_data_ptr, &palette);
- _palette->set(&palette, true);
-
// priority bands are supposed to be 14 for sci1.1 pictures
assert(priorityBandsCount == 14);
@@ -132,8 +128,13 @@ void GfxPicture::drawSci11Vga() {
}
// display Cel-data
- if (has_cel)
+ if (has_cel) {
+ // Create palette and set it
+ _palette->createFromData(inbuffer + palette_data_ptr, size - palette_data_ptr, &palette);
+ _palette->set(&palette, true);
+
drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, 0);
+ }
// process vector data
drawVectorData(inbuffer + vector_dataPos, vector_size);
@@ -852,11 +853,11 @@ void GfxPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, by
// Now remove screens, that already got the right color/priority/control
if ((screenMask & GFX_SCREEN_MASK_VISUAL) && (searchColor == color))
- screenMask ^= GFX_SCREEN_MASK_VISUAL;
+ screenMask &= ~GFX_SCREEN_MASK_VISUAL;
if ((screenMask & GFX_SCREEN_MASK_PRIORITY) && (searchPriority == priority))
- screenMask ^= GFX_SCREEN_MASK_PRIORITY;
+ screenMask &= ~GFX_SCREEN_MASK_PRIORITY;
if ((screenMask & GFX_SCREEN_MASK_CONTROL) && (searchControl == control))
- screenMask ^= GFX_SCREEN_MASK_CONTROL;
+ screenMask &= ~GFX_SCREEN_MASK_CONTROL;
// Exit, if no screens left
if (!screenMask)
diff --git a/engines/sci/graphics/portrait.cpp b/engines/sci/graphics/portrait.cpp
index 8f4fe094a8..f21fa39476 100644
--- a/engines/sci/graphics/portrait.cpp
+++ b/engines/sci/graphics/portrait.cpp
@@ -185,7 +185,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint
curEvent = _event->getSciEvent(SCI_EVENT_ANY);
if (curEvent.type == SCI_EVENT_MOUSE_PRESS ||
(curEvent.type == SCI_EVENT_KEYBOARD && curEvent.data == SCI_KEY_ESC) ||
- g_engine->shouldQuit())
+ g_sci->getEngineState()->abortScriptProcessing == kAbortQuitGame)
userAbort = true;
curPosition = _audio->getAudioPosition();
} while ((curPosition != -1) && (curPosition < timerPosition) && (!userAbort));
diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp
index dddd9b1c86..e7f319a25c 100644
--- a/engines/sci/graphics/ports.cpp
+++ b/engines/sci/graphics/ports.cpp
@@ -105,16 +105,9 @@ void GfxPorts::init(bool usesOldGfxFunctions, GfxPaint16 *paint16, GfxText16 *te
case GID_CNICK_KQ:
offTop = 0;
break;
- case GID_MOTHERGOOSE:
- // TODO: if mother goose EGA also uses offTop we can simply remove this check altogether
- switch (getSciVersion()) {
- case SCI_VERSION_1_EARLY:
- case SCI_VERSION_1_1:
- offTop = 0;
- break;
- default:
- break;
- }
+ case GID_MOTHERGOOSE256:
+ // only the SCI1 and SCI1.1 (VGA) versions need this
+ offTop = 0;
break;
case GID_FAIRYTALES:
// Mixed-Up Fairy Tales (& its demo) uses -w 26 0 200 320. If we don't
@@ -308,7 +301,7 @@ Window *GfxPorts::addWindow(const Common::Rect &dims, const Common::Rect *restor
Common::Rect r;
if (!pwnd) {
- error("Can't open window!");
+ error("Can't open window");
return 0;
}
@@ -376,6 +369,20 @@ Window *GfxPorts::addWindow(const Common::Rect &dims, const Common::Rect *restor
if (draw)
drawWindow(pwnd);
setPort((Port *)pwnd);
+
+ // FIXME: changing setOrigin to not clear the rightmost bit fixes the display of windows
+ // in some fanmade games (e.g. New Year's Mystery (Updated)). Since the fanmade games
+ // use an unmodified SCI interpreter, this leads me to believe that there either is some
+ // off-by-one error in the window drawing code, or there is another place where the
+ // rightmost bit should be cleeared. New Year's Mystery is a good test case for this, as
+ // it draws dialogs and then draws cels on top of them, for fancier dialog corners (like,
+ // for example, KQ5). KQ5 has a custom window style, however, whereas New Year's mystery
+ // has a "classic" style with only SCI_WINDOWMGR_STYLE_NOFRAME set. If
+ // SCI_WINDOWMGR_STYLE_NOFRAME is removed, the window is cleared correctly, because it
+ // grows slightly, covering the view pixels on the left. In any case, the views and the
+ // window have a difference of one pixel when they're drawn via kNewWindow and kDrawCel,
+ // which causes the glitch to appear when the window is closed.
+
// All SCI0 games till kq4 .502 (not including) did not adjust against _wmgrPort, we set _wmgrPort->top to 0 in that case
setOrigin(pwnd->rect.left, pwnd->rect.top + _wmgrPort->top);
pwnd->rect.moveTo(0, 0);
diff --git a/engines/sci/graphics/robot.cpp b/engines/sci/graphics/robot.cpp
index 1572a0a9ec..0792c6596e 100644
--- a/engines/sci/graphics/robot.cpp
+++ b/engines/sci/graphics/robot.cpp
@@ -37,7 +37,6 @@ GfxRobot::GfxRobot(ResourceManager *resMan, GfxScreen *screen, GuiResourceId res
: _resMan(resMan), _screen(screen), _resourceId(resourceId) {
assert(resourceId != -1);
initData(resourceId);
- _resourceData = 0;
}
GfxRobot::~GfxRobot() {
@@ -57,119 +56,13 @@ void GfxRobot::initData(GuiResourceId resourceId) {
warning("Unable to open robot file %s", fileName);
return;
}
-
- byte version = _resourceData[6];
- if (version != 4 && version != 5) {
- warning("Robot version %d isn't supported yet", version);
- return;
- }
-
-// sample data:
-// Header - 14 bytes
-// DWORD:Sample Size - 2 needs to be subtracted (??!!)
-// ???
-// Actual samples following
-
-// version may be 3, 4 and 5
-// version 3 has a different header (unknown to this point)
-//
-// main header (56 bytes + 2 bytes resource id)
-// followed by sample data if hasSound == 1
-//
-
-// 90.rbt (640x390, 22050, 1 16, ADPCM) 67 frames
-// 00000000: 16 00 53 4f 4c 00 05 00-ad 08 00 00 f0 00 43 00 ..SOL.........C.
-// ^ signature ^ version ^ ^ ^ frames
-// ^ 2221
-// 00000010: b0 04 00 a0 00 00 00 00-01 01 00 00 0a 00 01 00
-// ^ ^ ^ ^ ^ ^ ^ ^ ^
-// hasSound
-// 00000020: 03 00 01 00 00 cf 03 00-00 00 00 00 00 00 00 00
-// ^ ^ ^ pixel count ^
-// ^
-// 00000030: 00 00 00 00 00 00 00 00-00 00 00 00
-// ^ ^
-// Sample-Data (Header):
-// compression must be 0 for now
-// 0000003c: f2 9f 00 00 00 00 d2 4d 00 00 20 52-00 00
-// ^ ^ ^
-// byte count compression
-// 40946
-// Actual Samples following
-// a5 11 04 02 85 90 ...M.. R........
-//
-// Offset 41020
-// Palette
-
-// 91.rbt (320x240, 22050, 1 16, ADPCM) 90 frames
-// 00000000: 16 00 53 4f 4c 00 05 00-ad 08 00 00 f0 00 5a 00 ..SOL.........Z.
-// ^ frames
-// 00000010: b0 04 00 a0 00 00 00 00-01 01 00 00 0a 00 01 00 ................
-// 00000020: 03 00 01 00 00 2c 01 00-00 00 00 00 00 00 00 00 .....,..........
-// ^ pixel count
-// 00000030: 00 00 00 00 00 00 00 00-00 00 00 00 f2 9f 00 00 ................ offset 60
-// ^ data begin (sample)
-// 00000040: 00 00 d2 4d 00 00 20 52-00 00 82 01 00 01 00 01 ...M.. R........
-// ...
-// 0000a030: 8d 8d 8f 8e 8f 90 90 91-92 92 92 94 0e 00 00 00 ................ offset 41004
-// ^ palette start
-// 0000a040: 00 00 00 00 00 00 01 00-00 09 01 00 00 00 00 00 ................
-// 0000a050: 00 00 00 00 00 37 00 00-00 51 00 01 01 00 00 00 .....7...Q......
-// ^ color start^ color count
-// 0000a060: 00 58 6b 2b 4b 69 28 50-5b 24 68 50 20 5b 53 21 .Xk+Ki(P[$hP [S!
-// ^ start pal data
-// [...]
-// 0000a110: 24 05 41 14 04 18 25 10-64 00 00 2d 18 05 58 00 $.A...%.d..-..X.
-// 0000a120: 00 16 20 07 50 00 00 20-19 01 2d 0e 00 48 00 00 .. .P.. ..-..H..
-// 0000a130: 40 00 00 10 18 05 38 00-00 30 00 00 28 00 00 0b @.....8..0..(...
-// 0000a140: 0e 00 20 00 00 18 00 00-00 08 00 10 00 00 08 00 .. .............
-// 0000a150: 00 00 00 00 70 70 70 70-70 70 70 70 70 70 70 70 ....pppppppppppp
-// [...]
-// 0000a4e0: 70 70 70 70 70 70 70 70-70 70 70 70 34 0a 75 0a pppppppppppp4.u.
-// 0000a4f0: 4a 0b c5 0b f4 0b 54 0c-bd 0c 7a 0d 91 0e 1f 10 J.....T...z.....
-// 0000a500: 16 12 72 14 19 17 ef 19-9a 1c b3 1e 79 20 c1 22 ..r.........y ."
-// 0000a510: 33 22 33 23 e0 25 84 26-eb 26 1a 2d 43 2d af 2d 3"3#.%.&.&.-C-.-
-// [...]
-// 0000aff0: 20 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20
-// 0000b000: 01 00 7f 64 40 01 f0 00-00 00 00 00 00 00 00 00 ...d@...........
-// ^width^height
-// 0000b010: 1c 0a 02 00 7f 7f 7f 7f-04 08 00 00 00 f0 00 00 ................
-// 0000b020: 00 00 43 e0 7f ff ff ff-ff ff ff ff ff ff ff ff ..C.............
-// 0000b030: ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................
-
-// 161.rbt (112x155, 22050, 1 16, ADPCM) 29 frames
-// 00000000: 16 00 53 4f 4c 00 05 00-ad 08 00 00 96 00 1d 00 ..SOL...........
-// ^ frames
-// 00000010: b0 04 00 a0 00 00 00 00-01 01 00 00 0a 00 01 00 ................
-// 00000020: 03 00 01 00 47 3e 00 00-00 00 00 00 00 00 00 00 ....G>..........
-// ^ pixel count
-// 00000030: 00 00 00 00 00 00 00 00-00 00 00 00 f2 9f 00 00 ................
-// ^ data begin (sample)
-// 00000040: 00 00 d2 4d 00 00 20 52-00 00 00 00 00 00 00 00 ...M.. R........
-// 00000050: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
-
-// 213.rbt (125x248, nosound) 30 frames
-// 00000000: 16 00 53 4f 4c 00 05 00-ad 08 00 00 96 00 1e 00 ..SOL...........
-// ^ frames
-// 00000010: b0 04 00 00 00 00 00 00-01 00 00 00 0a 00 01 00 ................
-// ^ ?! ^ no sound?!
-// 00000020: 03 00 01 00 82 6e 00 00-00 00 00 00 00 00 00 00 .....n..........
-// ^ pixel count
-// 00000030: 00 00 00 00 00 00 00 00-00 00 00 00 0e 00 00 00 ................
-// ^ data begin (palette)
-// 00000040: 00 00 00 00 00 00 01 00-00 ca 00 00 00 00 00 00 ................
-// 00000050: 00 00 00 00 00 37 00 00-00 3c 00 01 01 00 00 00 .....7...<......
-// 00000060: 00 d0 d0 c0 d0 c0 a8 c8-b8 c0 d0 b0 a0 c0 a8 88
-// ^ palette data start
-// 00000070: c0 a0 a0 c8 98 90 d0 88-60 b0 90 80 b8 88 80 a0 ........`.......
-// 00000080: 90 98 b0 88 90 c0 78 60-a0 80 80 a0 80 70 c8 70 ......x`.....p.p
-// [...]
-// 00000110: 00 00 00 00 08 70 70 70-70 70 70 70 70 70 70 70 .....ppppppppppp
-// ^ ??
-// 00000120: 70 70 70 70 70 70 70 70-70 70 70 70 70 70 70 70 pppppppppppppppp
+ // The RBT video starts with a SOL audio file, followed by
+ // video data which is appended after it
_frameCount = READ_LE_UINT16(_resourceData + 14);
+ _audioSize = READ_LE_UINT16(_resourceData + 15);
+
//_frameSize = READ_LE_UINT32(_resourceData + 34);
byte hasSound = _resourceData[25];
@@ -179,21 +72,57 @@ void GfxRobot::initData(GuiResourceId resourceId) {
// TODO: just trying around in here...
void GfxRobot::draw() {
- byte *bitmapData = _resourceData + ROBOT_FILE_STARTOFDATA;
+ byte *bitmapData = _resourceData + _audioSize;
int x, y;
- //int frame;
+ int frame;
return;
- //for (frame = 0; frame < 30; frame++) {
- for (y = 0; y < _height; y++) {
- for (x = 0; x < _width; x++) {
- _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, *bitmapData, 0, 0);
- bitmapData++;
+ // Each frame contains these bytes:
+ // 01 00 7f 64 - always the same, perhaps resource type + extra
+ // 40 01 - total frame width (320 in this case)
+ // f0 00 - total frame height (240 in this case)
+ // The total video size is calculated from the maximum width, height
+ // of all the frames in the robot file
+ // 4 zeroes
+ // 4 bytes, perhaps frame x, y on screen?
+ // 2 bytes, unknown
+ // 2 bytes, a small number (e.g. 01 00 or 02 00)
+ // 7f 7f - 127x127
+ // 7f 7f - 127x127
+ // 2 bytes, related to frame size?
+ // 00 00
+ // 00 f0
+ // 4 zeroes
+ // 43 e0
+ // 7f ff
+
+ // The frames themselves seem to contain a size of the actual drawn data
+ // on screen. The frame data seems to be uncompressed, placed on screen
+ // at appropriate x,y coordinates, and each frame can have a different size.
+ // This is apparent from the fact that a 320x240 frame (e.g. in Phantasmagoria
+ // demo, 91.rbt) has 4833, 4898, 5111, etc bytes, whereas a full frame would
+ // be 320x240 = 76800 bytes. Thus, each frame is either somehow compressed
+ // (but the data seems uncompressed?), or only the part that changes is drawn
+ // on screen, something like the MPEG I-frames
+
+ for (frame = 0; frame < _frameCount; frame++) {
+ bitmapData += 4; // skip header bytes
+ _width = READ_LE_UINT16(bitmapData + 4); bitmapData += 2;
+ _height = READ_LE_UINT16(bitmapData + 6); bitmapData += 2;
+
+ for (y = 0; y < _width; y++) {
+ for (x = 0; x < _height; x++) {
+ _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, *bitmapData, 0, 0);
+ bitmapData++;
+ }
}
+
+ _screen->copyToScreen();
+ // Sleep for a second
+ g_sci->sleep(1000);
}
- //}
- _screen->copyToScreen();
+
}
#endif
diff --git a/engines/sci/graphics/robot.h b/engines/sci/graphics/robot.h
index 3ea9a7f735..76dca35a82 100644
--- a/engines/sci/graphics/robot.h
+++ b/engines/sci/graphics/robot.h
@@ -51,6 +51,7 @@ private:
uint16 _height;
uint16 _frameCount;
uint32 _frameSize; // is width * height (pixelCount)
+ uint16 _audioSize;
};
#endif
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 839b9975c5..6eabc7c9f0 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -345,11 +345,11 @@ byte GfxScreen::isFillMatch(int16 x, int16 y, byte screenMask, byte t_color, byt
int offset = y * _width + x;
byte match = 0;
- if (screenMask & GFX_SCREEN_MASK_VISUAL && *(_visualScreen + offset) == t_color)
+ if ((screenMask & GFX_SCREEN_MASK_VISUAL) && *(_visualScreen + offset) == t_color)
match |= GFX_SCREEN_MASK_VISUAL;
- if (screenMask & GFX_SCREEN_MASK_PRIORITY && *(_priorityScreen + offset) == t_pri)
+ if ((screenMask & GFX_SCREEN_MASK_PRIORITY) && *(_priorityScreen + offset) == t_pri)
match |= GFX_SCREEN_MASK_PRIORITY;
- if (screenMask & GFX_SCREEN_MASK_CONTROL && *(_controlScreen + offset) == t_con)
+ if ((screenMask & GFX_SCREEN_MASK_CONTROL) && *(_controlScreen + offset) == t_con)
match |= GFX_SCREEN_MASK_CONTROL;
return match;
}
diff --git a/engines/sci/graphics/text16.cpp b/engines/sci/graphics/text16.cpp
index f5eb268863..3fba3006c7 100644
--- a/engines/sci/graphics/text16.cpp
+++ b/engines/sci/graphics/text16.cpp
@@ -30,6 +30,7 @@
#include "sci/sci.h"
#include "sci/engine/state.h"
#include "sci/graphics/cache.h"
+#include "sci/graphics/coordadjuster.h"
#include "sci/graphics/ports.h"
#include "sci/graphics/paint16.h"
#include "sci/graphics/font.h"
@@ -88,7 +89,7 @@ void GfxText16::ClearChar(int16 chr) {
// will process the encountered code and set new font/set color. We only support
// one-digit codes currently, don't know if multi-digit codes are possible.
// Returns textcode character count.
-int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int16 orgPenColor) {
+int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int16 orgPenColor, bool doingDrawing) {
const char *textCode = text;
int16 textCodeSize = 0;
char curCode;
@@ -126,8 +127,20 @@ int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int1
}
}
break;
- case 'r': // reference?!
- // Used in Pepper, no idea how this works out
+ case 'r': // reference (used in pepper)
+ if (doingDrawing) {
+ if (_codeRefTempRect.top == -1) {
+ // Starting point
+ _codeRefTempRect.top = _ports->_curPort->curTop;
+ _codeRefTempRect.left = _ports->_curPort->curLeft;
+ } else {
+ // End point reached
+ _codeRefTempRect.bottom = _ports->_curPort->curTop + _ports->_curPort->fontHeight;
+ _codeRefTempRect.right = _ports->_curPort->curLeft;
+ _codeRefRects.push_back(_codeRefTempRect);
+ _codeRefTempRect.left = _codeRefTempRect.top = -1;
+ }
+ }
break;
}
return textCodeSize;
@@ -162,7 +175,7 @@ int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgF
case 0x7C:
if (getSciVersion() >= SCI_VERSION_1_1) {
curCharCount++;
- curCharCount += CodeProcessing(text, orgFontId, previousPenColor);
+ curCharCount += CodeProcessing(text, orgFontId, previousPenColor, false);
continue;
}
break;
@@ -258,7 +271,7 @@ void GfxText16::Width(const char *text, int16 from, int16 len, GuiResourceId org
break;
case 0x7C:
if (getSciVersion() >= SCI_VERSION_1_1) {
- len -= CodeProcessing(text, orgFontId, 0);
+ len -= CodeProcessing(text, orgFontId, 0, false);
break;
}
default:
@@ -359,7 +372,7 @@ void GfxText16::Draw(const char *text, int16 from, int16 len, GuiResourceId orgF
break;
case 0x7C:
if (getSciVersion() >= SCI_VERSION_1_1) {
- len -= CodeProcessing(text, orgFontId, orgPenColor);
+ len -= CodeProcessing(text, orgFontId, orgPenColor, true);
break;
}
default:
@@ -408,6 +421,10 @@ void GfxText16::Box(const char *text, int16 bshow, const Common::Rect &rect, Tex
doubleByteMode = true;
}
+ // Reset reference code rects
+ _codeRefRects.clear();
+ _codeRefTempRect.left = _codeRefTempRect.top = -1;
+
maxTextWidth = 0;
while (*text) {
charCount = GetLongest(text, rect.width(), fontId);
@@ -474,6 +491,32 @@ void GfxText16::Draw_String(const char *text) {
_ports->penColor(previousPenColor);
}
+// we need to have a separate status drawing code
+// In KQ4 the IV char is actually 0xA, which would otherwise get considered as linebreak and not printed
+void GfxText16::Draw_Status(const char *text) {
+ uint16 curChar, charWidth;
+ uint16 textLen = strlen(text);
+ Common::Rect rect;
+
+ GetFont();
+ if (!_font)
+ return;
+
+ rect.top = _ports->_curPort->curTop;
+ rect.bottom = rect.top + _ports->_curPort->fontHeight;
+ while (textLen--) {
+ curChar = (*(const byte *)text++);
+ switch (curChar) {
+ case 0:
+ break;
+ default:
+ charWidth = _font->getCharWidth(curChar);
+ _font->draw(curChar, _ports->_curPort->top + _ports->_curPort->curTop, _ports->_curPort->left + _ports->_curPort->curLeft, _ports->_curPort->penClr, _ports->_curPort->greyedOutput);
+ _ports->_curPort->curLeft += charWidth;
+ }
+ }
+}
+
// Sierra did this in their PC98 interpreter only, they identify a text as being
// sjis and then switch to font 900
bool GfxText16::SwitchToFont900OnSjis(const char *text) {
@@ -485,6 +528,30 @@ bool GfxText16::SwitchToFont900OnSjis(const char *text) {
return false;
}
+reg_t GfxText16::allocAndFillReferenceRectArray() {
+ uint rectCount = _codeRefRects.size();
+ if (rectCount) {
+ reg_t rectArray;
+ byte *rectArrayPtr = g_sci->getEngineState()->_segMan->allocDynmem(4 * 2 * (rectCount + 1), "text code reference rects", &rectArray);
+ GfxCoordAdjuster *coordAdjuster = g_sci->_gfxCoordAdjuster;
+ for (uint curRect = 0; curRect < rectCount; curRect++) {
+ coordAdjuster->kernelLocalToGlobal(_codeRefRects[curRect].left, _codeRefRects[curRect].top);
+ coordAdjuster->kernelLocalToGlobal(_codeRefRects[curRect].right, _codeRefRects[curRect].bottom);
+ WRITE_LE_UINT16(rectArrayPtr + 0, _codeRefRects[curRect].left);
+ WRITE_LE_UINT16(rectArrayPtr + 2, _codeRefRects[curRect].top);
+ WRITE_LE_UINT16(rectArrayPtr + 4, _codeRefRects[curRect].right);
+ WRITE_LE_UINT16(rectArrayPtr + 6, _codeRefRects[curRect].bottom);
+ rectArrayPtr += 8;
+ }
+ WRITE_LE_UINT16(rectArrayPtr + 0, 0x7777);
+ WRITE_LE_UINT16(rectArrayPtr + 2, 0x7777);
+ WRITE_LE_UINT16(rectArrayPtr + 4, 0x7777);
+ WRITE_LE_UINT16(rectArrayPtr + 6, 0x7777);
+ return rectArray;
+ }
+ return NULL_REG;
+}
+
void GfxText16::kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight) {
Common::Rect rect(0, 0, 0, 0);
Size(rect, text, font, maxWidth);
diff --git a/engines/sci/graphics/text16.h b/engines/sci/graphics/text16.h
index 9b8b6d9f19..dc3ed2f62b 100644
--- a/engines/sci/graphics/text16.h
+++ b/engines/sci/graphics/text16.h
@@ -32,6 +32,8 @@ namespace Sci {
#define SCI_TEXT16_ALIGNMENT_CENTER 1
#define SCI_TEXT16_ALIGNMENT_LEFT 0
+typedef Common::Array<Common::Rect> CodeRefRectArray;
+
class GfxPorts;
class GfxPaint16;
class GfxScreen;
@@ -48,7 +50,7 @@ public:
GfxFont *GetFont();
void SetFont(GuiResourceId fontId);
- int16 CodeProcessing(const char *&text, GuiResourceId orgFontId, int16 orgPenColor);
+ int16 CodeProcessing(const char *&text, GuiResourceId orgFontId, int16 orgPenColor, bool doingDrawing);
void ClearChar(int16 chr);
@@ -62,9 +64,12 @@ public:
void Show(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 orgPenColor);
void Box(const char *text, int16 bshow, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId);
void Draw_String(const char *text);
+ void Draw_Status(const char *text);
GfxFont *_font;
+ reg_t allocAndFillReferenceRectArray();
+
void kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight);
void kernelTextFonts(int argc, reg_t *argv);
void kernelTextColors(int argc, reg_t *argv);
@@ -83,6 +88,9 @@ private:
GuiResourceId *_codeFonts;
int _codeColorsCount;
uint16 *_codeColors;
+
+ Common::Rect _codeRefTempRect;
+ CodeRefRectArray _codeRefRects;
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/transitions.cpp b/engines/sci/graphics/transitions.cpp
index abb5e74cbd..3f4ce7bbc8 100644
--- a/engines/sci/graphics/transitions.cpp
+++ b/engines/sci/graphics/transitions.cpp
@@ -37,6 +37,8 @@
namespace Sci {
+//#define DISABLE_TRANSITIONS // uncomment to disable room transitions (for development only! helps in testing games quickly)
+
GfxTransitions::GfxTransitions(GfxScreen *screen, GfxPalette *palette, bool isVGA)
: _screen(screen), _palette(palette), _isVGA(isVGA) {
init();
@@ -116,16 +118,33 @@ void GfxTransitions::init() {
void GfxTransitions::setup(int16 number, bool blackoutFlag) {
if (number != -1) {
+#ifndef DISABLE_TRANSITIONS
_number = number;
+#else
+ _number = SCI_TRANSITIONS_NONE;
+#endif
_blackoutFlag = blackoutFlag;
}
}
-void GfxTransitions::updateScreenAndWait(int msec) {
+bool GfxTransitions::doCreateFrame(uint32 shouldBeAtMsec) {
+ uint32 msecPos = g_system->getMillis() - _transitionStartTime;
+
+ if (shouldBeAtMsec > msecPos)
+ return true;
+ return false;
+}
+
+void GfxTransitions::updateScreenAndWait(uint32 shouldBeAtMsec) {
Common::Event ev;
- g_system->updateScreen();
- g_system->delayMillis(msec);
+
while (g_system->getEventManager()->pollEvent(ev)) {} // discard all events
+
+ g_system->updateScreen();
+ // if we have still some time left, delay accordingly
+ uint32 msecPos = g_system->getMillis() - _transitionStartTime;
+ if (shouldBeAtMsec > msecPos)
+ g_system->delayMillis(shouldBeAtMsec - msecPos);
}
// will translate a number and return corresponding translationEntry
@@ -191,6 +210,7 @@ void GfxTransitions::doTransition(int16 number, bool blackoutFlag) {
setNewPalette(blackoutFlag);
}
+ _transitionStartTime = g_system->getMillis();
switch (number) {
case SCI_TRANSITIONS_VERTICALROLL_FROMCENTER:
verticalRollFromCenter(blackoutFlag);
@@ -285,11 +305,14 @@ void GfxTransitions::copyRectToScreen(const Common::Rect rect, bool blackoutFlag
void GfxTransitions::fadeOut() {
byte oldPalette[4 * 256], workPalette[4 * 256];
int16 stepNr, colorNr;
+ // Sierra did not fade in/out color 255 for sci1.1, but they used it in
+ // several pictures (e.g. qfg3 demo/intro), so the fading looked weird
+ int16 tillColorNr = getSciVersion() >= SCI_VERSION_1_1 ? 256 : 255;
g_system->grabPalette(oldPalette, 0, 256);
for (stepNr = 100; stepNr >= 0; stepNr -= 10) {
- for (colorNr = 1; colorNr < 255; colorNr++){
+ for (colorNr = 1; colorNr < tillColorNr; colorNr++){
workPalette[colorNr * 4 + 0] = oldPalette[colorNr * 4] * stepNr / 100;
workPalette[colorNr * 4 + 1] = oldPalette[colorNr * 4 + 1] * stepNr / 100;
workPalette[colorNr * 4 + 2] = oldPalette[colorNr * 4 + 2] * stepNr / 100;
@@ -303,9 +326,12 @@ void GfxTransitions::fadeOut() {
// the load
void GfxTransitions::fadeIn() {
int16 stepNr;
+ // Sierra did not fade in/out color 255 for sci1.1, but they used it in
+ // several pictures (e.g. qfg3 demo/intro), so the fading looked weird
+ int16 tillColorNr = getSciVersion() >= SCI_VERSION_1_1 ? 256 : 255;
for (stepNr = 0; stepNr <= 100; stepNr += 10) {
- _palette->kernelSetIntensity(1, 255, stepNr, true);
+ _palette->kernelSetIntensity(1, tillColorNr, stepNr, true);
g_sci->getEngineState()->wait(2);
}
}
@@ -315,6 +341,7 @@ void GfxTransitions::fadeIn() {
void GfxTransitions::pixelation(bool blackoutFlag) {
uint16 mask = 0x40, stepNr = 0;
Common::Rect pixelRect;
+ uint32 msecCount = 0;
do {
mask = (mask & 1) ? (mask >> 1) ^ 0xB400 : mask >> 1;
@@ -326,7 +353,8 @@ void GfxTransitions::pixelation(bool blackoutFlag) {
if (!pixelRect.isEmpty())
copyRectToScreen(pixelRect, blackoutFlag);
if ((stepNr & 0x3FF) == 0) {
- updateScreenAndWait(5);
+ msecCount += 9;
+ updateScreenAndWait(msecCount);
}
stepNr++;
} while (mask != 0x40);
@@ -337,6 +365,7 @@ void GfxTransitions::pixelation(bool blackoutFlag) {
void GfxTransitions::blocks(bool blackoutFlag) {
uint16 mask = 0x40, stepNr = 0;
Common::Rect blockRect;
+ uint32 msecCount = 0;
do {
mask = (mask & 1) ? (mask >> 1) ^ 0x240 : mask >> 1;
@@ -348,7 +377,8 @@ void GfxTransitions::blocks(bool blackoutFlag) {
if (!blockRect.isEmpty())
copyRectToScreen(blockRect, blackoutFlag);
if ((stepNr & 7) == 0) {
- updateScreenAndWait(4);
+ msecCount += 5;
+ updateScreenAndWait(msecCount);
}
stepNr++;
} while (mask != 0x40);
@@ -359,6 +389,7 @@ void GfxTransitions::blocks(bool blackoutFlag) {
void GfxTransitions::straight(int16 number, bool blackoutFlag) {
int16 stepNr = 0;
Common::Rect newScreenRect = _picRect;
+ uint32 msecCount = 0;
switch (number) {
case SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT:
@@ -366,7 +397,8 @@ void GfxTransitions::straight(int16 number, bool blackoutFlag) {
while (newScreenRect.left >= _picRect.left) {
copyRectToScreen(newScreenRect, blackoutFlag);
if ((stepNr & 1) == 0) {
- updateScreenAndWait(1);
+ msecCount += 2;
+ updateScreenAndWait(msecCount);
}
stepNr++;
newScreenRect.translate(-1, 0);
@@ -378,7 +410,8 @@ void GfxTransitions::straight(int16 number, bool blackoutFlag) {
while (newScreenRect.right <= _picRect.right) {
copyRectToScreen(newScreenRect, blackoutFlag);
if ((stepNr & 1) == 0) {
- updateScreenAndWait(1);
+ msecCount += 2;
+ updateScreenAndWait(msecCount);
}
stepNr++;
newScreenRect.translate(1, 0);
@@ -389,7 +422,8 @@ void GfxTransitions::straight(int16 number, bool blackoutFlag) {
newScreenRect.top = newScreenRect.bottom - 1;
while (newScreenRect.top >= _picRect.top) {
copyRectToScreen(newScreenRect, blackoutFlag);
- updateScreenAndWait(3);
+ msecCount += 4;
+ updateScreenAndWait(msecCount);
stepNr++;
newScreenRect.translate(0, -1);
}
@@ -399,7 +433,8 @@ void GfxTransitions::straight(int16 number, bool blackoutFlag) {
newScreenRect.bottom = newScreenRect.top + 1;
while (newScreenRect.bottom <= _picRect.bottom) {
copyRectToScreen(newScreenRect, blackoutFlag);
- updateScreenAndWait(3);
+ msecCount += 4;
+ updateScreenAndWait(msecCount);
stepNr++;
newScreenRect.translate(0, 1);
}
@@ -428,6 +463,7 @@ void GfxTransitions::scroll(int16 number) {
Common::Rect oldScreenRect = _picRect;
Common::Rect newMoveRect = _picRect;
Common::Rect newScreenRect = _picRect;
+ uint32 msecCount = 0;
_screen->copyFromScreen(_oldScreen);
screenWidth = _screen->getDisplayWidth(); screenHeight = _screen->getDisplayHeight();
@@ -438,42 +474,36 @@ void GfxTransitions::scroll(int16 number) {
newMoveRect.left = newMoveRect.right;
while (oldMoveRect.left < oldMoveRect.right) {
oldMoveRect.right--; oldScreenRect.left++;
- if (oldMoveRect.right > oldMoveRect.left)
- scrollCopyOldToScreen(oldScreenRect, oldMoveRect.left, oldMoveRect.top);
newScreenRect.right++; newMoveRect.left--;
- _screen->copyRectToScreen(newScreenRect, newMoveRect.left, newMoveRect.top);
if ((stepNr & 1) == 0) {
- updateScreenAndWait(1);
+ msecCount += 5;
+ if (doCreateFrame(msecCount)) {
+ if (oldMoveRect.right > oldMoveRect.left)
+ scrollCopyOldToScreen(oldScreenRect, oldMoveRect.left, oldMoveRect.top);
+ _screen->copyRectToScreen(newScreenRect, newMoveRect.left, newMoveRect.top);
+ updateScreenAndWait(msecCount);
+ }
}
stepNr++;
}
- if ((stepNr & 1) == 0) {
- if (g_system->getMillis() - g_sci->getEngineState()->_screenUpdateTime >= 1000 / 60) {
- g_system->updateScreen();
- g_sci->getEngineState()->_screenUpdateTime = g_system->getMillis();
- }
- }
break;
case SCI_TRANSITIONS_SCROLL_RIGHT:
newScreenRect.left = newScreenRect.right;
while (oldMoveRect.left < oldMoveRect.right) {
oldMoveRect.left++; oldScreenRect.right--;
- if (oldMoveRect.right > oldMoveRect.left)
- scrollCopyOldToScreen(oldScreenRect, oldMoveRect.left, oldMoveRect.top);
newScreenRect.left--;
- _screen->copyRectToScreen(newScreenRect, newMoveRect.left, newMoveRect.top);
if ((stepNr & 1) == 0) {
- updateScreenAndWait(1);
+ msecCount += 5;
+ if (doCreateFrame(msecCount)) {
+ if (oldMoveRect.right > oldMoveRect.left)
+ scrollCopyOldToScreen(oldScreenRect, oldMoveRect.left, oldMoveRect.top);
+ _screen->copyRectToScreen(newScreenRect, newMoveRect.left, newMoveRect.top);
+ updateScreenAndWait(msecCount);
+ }
}
stepNr++;
}
- if ((stepNr & 1) == 0) {
- if (g_system->getMillis() - g_sci->getEngineState()->_screenUpdateTime >= 1000 / 60) {
- g_system->updateScreen();
- g_sci->getEngineState()->_screenUpdateTime = g_system->getMillis();
- }
- }
break;
case SCI_TRANSITIONS_SCROLL_UP:
@@ -481,11 +511,15 @@ void GfxTransitions::scroll(int16 number) {
newMoveRect.top = newMoveRect.bottom;
while (oldMoveRect.top < oldMoveRect.bottom) {
oldMoveRect.top++; oldScreenRect.top++;
- if (oldMoveRect.top < oldMoveRect.bottom)
- scrollCopyOldToScreen(oldScreenRect, _picRect.left, _picRect.top);
newScreenRect.bottom++; newMoveRect.top--;
- _screen->copyRectToScreen(newScreenRect, newMoveRect.left, newMoveRect.top);
- updateScreenAndWait(3);
+
+ msecCount += 5;
+ if (doCreateFrame(msecCount)) {
+ if (oldMoveRect.top < oldMoveRect.bottom)
+ scrollCopyOldToScreen(oldScreenRect, _picRect.left, _picRect.top);
+ _screen->copyRectToScreen(newScreenRect, newMoveRect.left, newMoveRect.top);
+ updateScreenAndWait(msecCount);
+ }
}
break;
@@ -493,14 +527,22 @@ void GfxTransitions::scroll(int16 number) {
newScreenRect.top = newScreenRect.bottom;
while (oldMoveRect.top < oldMoveRect.bottom) {
oldMoveRect.top++; oldScreenRect.bottom--;
- if (oldMoveRect.top < oldMoveRect.bottom)
- scrollCopyOldToScreen(oldScreenRect, oldMoveRect.left, oldMoveRect.top);
newScreenRect.top--;
- _screen->copyRectToScreen(newScreenRect, _picRect.left, _picRect.top);
- updateScreenAndWait(3);
+
+ msecCount += 5;
+ if (doCreateFrame(msecCount)) {
+ if (oldMoveRect.top < oldMoveRect.bottom)
+ scrollCopyOldToScreen(oldScreenRect, oldMoveRect.left, oldMoveRect.top);
+ _screen->copyRectToScreen(newScreenRect, _picRect.left, _picRect.top);
+ updateScreenAndWait(msecCount);
+ }
}
break;
}
+
+ // Copy over final position just in case
+ _screen->copyRectToScreen(newScreenRect);
+ g_system->updateScreen();
}
// Vertically displays new screen starting from center - works on _picRect area
@@ -508,6 +550,7 @@ void GfxTransitions::scroll(int16 number) {
void GfxTransitions::verticalRollFromCenter(bool blackoutFlag) {
Common::Rect leftRect = Common::Rect(_picRect.left + (_picRect.width() / 2) -1, _picRect.top, _picRect.left + (_picRect.width() / 2), _picRect.bottom);
Common::Rect rightRect = Common::Rect(leftRect.right, _picRect.top, leftRect.right + 1, _picRect.bottom);
+ uint32 msecCount = 0;
while ((leftRect.left >= _picRect.left) || (rightRect.right <= _picRect.right)) {
if (leftRect.left < _picRect.left)
@@ -516,7 +559,8 @@ void GfxTransitions::verticalRollFromCenter(bool blackoutFlag) {
rightRect.translate(-1, 0);
copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(-1, 0);
copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(1, 0);
- updateScreenAndWait(2);
+ msecCount += 3;
+ updateScreenAndWait(msecCount);
}
}
@@ -525,11 +569,13 @@ void GfxTransitions::verticalRollFromCenter(bool blackoutFlag) {
void GfxTransitions::verticalRollToCenter(bool blackoutFlag) {
Common::Rect leftRect = Common::Rect(_picRect.left, _picRect.top, _picRect.left + 1, _picRect.bottom);
Common::Rect rightRect = Common::Rect(_picRect.right - 1, _picRect.top, _picRect.right, _picRect.bottom);
+ uint32 msecCount = 0;
while (leftRect.left < rightRect.right) {
copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(1, 0);
copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(-1, 0);
- updateScreenAndWait(2);
+ msecCount += 3;
+ updateScreenAndWait(msecCount);
}
}
@@ -538,6 +584,7 @@ void GfxTransitions::verticalRollToCenter(bool blackoutFlag) {
void GfxTransitions::horizontalRollFromCenter(bool blackoutFlag) {
Common::Rect upperRect = Common::Rect(_picRect.left, _picRect.top + (_picRect.height() / 2) - 1, _picRect.right, _picRect.top + (_picRect.height() / 2));
Common::Rect lowerRect = Common::Rect(upperRect.left, upperRect.bottom, upperRect.right, upperRect.bottom + 1);
+ uint32 msecCount = 0;
while ((upperRect.top >= _picRect.top) || (lowerRect.bottom <= _picRect.bottom)) {
if (upperRect.top < _picRect.top)
@@ -546,7 +593,8 @@ void GfxTransitions::horizontalRollFromCenter(bool blackoutFlag) {
lowerRect.translate(0, -1);
copyRectToScreen(upperRect, blackoutFlag); upperRect.translate(0, -1);
copyRectToScreen(lowerRect, blackoutFlag); lowerRect.translate(0, 1);
- updateScreenAndWait(3);
+ msecCount += 4;
+ updateScreenAndWait(msecCount);
}
}
@@ -555,11 +603,13 @@ void GfxTransitions::horizontalRollFromCenter(bool blackoutFlag) {
void GfxTransitions::horizontalRollToCenter(bool blackoutFlag) {
Common::Rect upperRect = Common::Rect(_picRect.left, _picRect.top, _picRect.right, _picRect.top + 1);
Common::Rect lowerRect = Common::Rect(upperRect.left, _picRect.bottom - 1, upperRect.right, _picRect.bottom);
+ uint32 msecCount = 0;
while (upperRect.top < lowerRect.bottom) {
copyRectToScreen(upperRect, blackoutFlag); upperRect.translate(0, 1);
copyRectToScreen(lowerRect, blackoutFlag); lowerRect.translate(0, -1);
- updateScreenAndWait(3);
+ msecCount += 4;
+ updateScreenAndWait(msecCount);
}
}
@@ -571,6 +621,7 @@ void GfxTransitions::diagonalRollFromCenter(bool blackoutFlag) {
Common::Rect lowerRect(upperRect.left, upperRect.top, upperRect.right, upperRect.bottom);
Common::Rect leftRect(upperRect.left, upperRect.top, upperRect.left + 1, lowerRect.bottom);
Common::Rect rightRect(upperRect.right, upperRect.top, upperRect.right + 1, lowerRect.bottom);
+ uint32 msecCount = 0;
while ((upperRect.top >= _picRect.top) || (lowerRect.bottom <= _picRect.bottom)) {
if (upperRect.top < _picRect.top) {
@@ -589,7 +640,8 @@ void GfxTransitions::diagonalRollFromCenter(bool blackoutFlag) {
copyRectToScreen(lowerRect, blackoutFlag); lowerRect.translate(0, 1); lowerRect.left--; lowerRect.right++;
copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(-1, 0); leftRect.top--; leftRect.bottom++;
copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(1, 0); rightRect.top--; rightRect.bottom++;
- updateScreenAndWait(3);
+ msecCount += 4;
+ updateScreenAndWait(msecCount);
}
}
@@ -600,13 +652,15 @@ void GfxTransitions::diagonalRollToCenter(bool blackoutFlag) {
Common::Rect lowerRect(_picRect.left, _picRect.bottom - 1, _picRect.right, _picRect.bottom);
Common::Rect leftRect(_picRect.left, _picRect.top, _picRect.left + 1, _picRect.bottom);
Common::Rect rightRect(_picRect.right - 1, _picRect.top, _picRect.right, _picRect.bottom);
+ uint32 msecCount = 0;
while (upperRect.top < lowerRect.bottom) {
copyRectToScreen(upperRect, blackoutFlag); upperRect.translate(0, 1); upperRect.left++; upperRect.right--;
copyRectToScreen(lowerRect, blackoutFlag); lowerRect.translate(0, -1); lowerRect.left++; lowerRect.right--;
copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(1, 0);
copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(-1, 0);
- updateScreenAndWait(3);
+ msecCount += 4;
+ updateScreenAndWait(msecCount);
}
}
diff --git a/engines/sci/graphics/transitions.h b/engines/sci/graphics/transitions.h
index 233638ffda..674b7a8173 100644
--- a/engines/sci/graphics/transitions.h
+++ b/engines/sci/graphics/transitions.h
@@ -91,7 +91,8 @@ private:
void horizontalRollToCenter(bool blackoutFlag);
void diagonalRollFromCenter(bool blackoutFlag);
void diagonalRollToCenter(bool blackoutFlag);
- void updateScreenAndWait(int msec);
+ bool doCreateFrame(uint32 shouldBeAtMsec);
+ void updateScreenAndWait(uint32 shouldBeAtMsec);
GfxScreen *_screen;
GfxPalette *_palette;
@@ -102,6 +103,8 @@ private:
bool _blackoutFlag;
Common::Rect _picRect;
byte *_oldScreen; // buffer for saving current active screen data to, has dimenions of _screen->_displayScreen
+
+ uint32 _transitionStartTime; // when the current transition started in milliseconds
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp
index 5f48574dcb..6b22ed397e 100644
--- a/engines/sci/graphics/view.cpp
+++ b/engines/sci/graphics/view.cpp
@@ -128,8 +128,11 @@ void GfxView::initData(GuiResourceId resourceId) {
_palette->createFromData(&_resourceData[palOffset], _resourceSize - palOffset, &_viewPalette);
_embeddedPal = true;
} else {
- // Only use the EGA-mapping, when being SCI1
- if (getSciVersion() >= SCI_VERSION_1_EGA) {
+ // Only use the EGA-mapping, when being SCI1 EGA
+ // SCI1 VGA conversion games (which will get detected as SCI1EARLY/MIDDLE/LATE) have some views
+ // with broken mapping tables. I guess those games won't use the mapping, so I rather disable it
+ // for them
+ if (getSciVersion() == SCI_VERSION_1_EGA) {
_EGAmapping = &_resourceData[palOffset];
for (EGAmapNr = 0; EGAmapNr < SCI_VIEW_EGAMAPPING_COUNT; EGAmapNr++) {
if (memcmp(_EGAmapping, EGAmappingStraight, SCI_VIEW_EGAMAPPING_SIZE) != 0)