aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine')
-rw-r--r--engines/sci/engine/kernel.cpp2
-rw-r--r--engines/sci/engine/kgraphics.cpp9
-rw-r--r--engines/sci/engine/kgraphics32.cpp123
-rw-r--r--engines/sci/engine/script_patches.cpp33
-rw-r--r--engines/sci/engine/selector.cpp6
-rw-r--r--engines/sci/engine/selector.h4
-rw-r--r--engines/sci/engine/vm_types.cpp24
-rw-r--r--engines/sci/engine/vm_types.h4
-rw-r--r--engines/sci/engine/workarounds.cpp4
9 files changed, 148 insertions, 61 deletions
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index 0df4701334..796dea2382 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -853,7 +853,7 @@ void Kernel::loadKernelNames(GameFeatures *features) {
_kernelNames[0x26] = "Portrait";
else if (g_sci->getPlatform() == Common::kPlatformMacintosh)
_kernelNames[0x84] = "ShowMovie";
- } else if (g_sci->getGameId() == GID_QFG4 && g_sci->isDemo()) {
+ } else if (g_sci->getGameId() == GID_QFG4DEMO) {
_kernelNames[0x7b] = "RemapColors"; // QFG4 Demo has this SCI2 function instead of StrSplit
}
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index c0a3be4c11..93d0d91b65 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -45,6 +45,7 @@
#include "sci/graphics/paint16.h"
#include "sci/graphics/picture.h"
#include "sci/graphics/ports.h"
+#include "sci/graphics/remap.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/text16.h"
#include "sci/graphics/view.h"
@@ -1248,16 +1249,16 @@ reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) {
switch (operation) {
case 0: { // remap by percent
uint16 percent = argv[1].toUint16();
- g_sci->_gfxPalette16->resetRemapping();
- g_sci->_gfxPalette16->setRemappingPercent(254, percent);
+ g_sci->_gfxRemap16->resetRemapping();
+ g_sci->_gfxRemap16->setRemappingPercent(254, percent);
}
break;
case 1: { // remap by range
uint16 from = argv[1].toUint16();
uint16 to = argv[2].toUint16();
uint16 base = argv[3].toUint16();
- g_sci->_gfxPalette16->resetRemapping();
- g_sci->_gfxPalette16->setRemappingRange(254, from, to, base);
+ g_sci->_gfxRemap16->resetRemapping();
+ g_sci->_gfxRemap16->setRemappingRange(254, from, to, base);
}
break;
case 2: // turn remapping off (unused)
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index 0463b125ae..9c5d214488 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -152,12 +152,12 @@ reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) {
// Tests if the coordinate is on the passed object
reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv) {
- uint16 x = argv[0].toUint16();
- uint16 y = argv[1].toUint16();
- reg_t targetObject = argv[2];
- uint16 checkPixels = argv[3].getOffset();
+ int16 x = argv[0].toSint16();
+ int16 y = argv[1].toSint16();
+ reg_t object = argv[2];
+ bool checkPixel = argv[3].toSint16();
- return make_reg(0, g_sci->_gfxFrameout->kernelIsOnMe(x, y, checkPixels, targetObject));
+ return g_sci->_gfxFrameout->kernelIsOnMe(object, Common::Point(x, y), checkPixel);
}
reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) {
@@ -197,16 +197,14 @@ reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) {
if (subop == 0) {
TextAlign alignment = (TextAlign)readSelectorValue(segMan, object, SELECTOR(mode));
- reg_t out;
- return g_sci->_gfxText32->createFontBitmap(width, height, rect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, true, &out);
+ return g_sci->_gfxText32->createFontBitmap(width, height, rect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, true);
} else {
CelInfo32 celInfo;
celInfo.type = kCelTypeView;
celInfo.resourceId = readSelectorValue(segMan, object, SELECTOR(view));
celInfo.loopNo = readSelectorValue(segMan, object, SELECTOR(loop));
celInfo.celNo = readSelectorValue(segMan, object, SELECTOR(cel));
- reg_t out;
- return g_sci->_gfxText32->createFontBitmap(celInfo, rect, text, foreColor, backColor, fontId, skipColor, borderColor, dimmed, &out);
+ return g_sci->_gfxText32->createFontBitmap(celInfo, rect, text, foreColor, backColor, fontId, skipColor, borderColor, dimmed);
}
}
@@ -506,7 +504,6 @@ reg_t kBitmap(EngineState *s, int argc, reg_t *argv) {
}
reg_t kBitmapCreate(EngineState *s, int argc, reg_t *argv) {
- uint32 bitmapHeaderSize = CelObjMem::getBitmapHeaderSize();
int16 width = argv[0].toSint16();
int16 height = argv[1].toSint16();
int16 skipColor = argv[2].toSint16();
@@ -515,11 +512,9 @@ reg_t kBitmapCreate(EngineState *s, int argc, reg_t *argv) {
int16 scaledHeight = argc > 5 ? argv[5].toSint16() : g_sci->_gfxText32->_scaledHeight;
bool useRemap = argc > 6 ? argv[6].toSint16() : false;
- reg_t bitmapMemId = s->_segMan->allocateHunkEntry("Bitmap()", width * height + bitmapHeaderSize);
- byte *bitmap = s->_segMan->getHunkPointer(bitmapMemId);
- memset(bitmap + bitmapHeaderSize, backColor, width * height);
- CelObjMem::buildBitmapHeader(bitmap, width, height, skipColor, 0, 0, scaledWidth, scaledHeight, 0, useRemap);
- return bitmapMemId;
+ BitmapResource bitmap(s->_segMan, width, height, skipColor, 0, 0, scaledWidth, scaledHeight, 0, useRemap);
+ memset(bitmap.getPixels(), backColor, width * height);
+ return bitmap.getObject();
}
reg_t kBitmapDestroy(EngineState *s, int argc, reg_t *argv) {
@@ -579,7 +574,37 @@ reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) {
// called e.g. from TextButton::createBitmap() in Torin's Passage, script 64894
// bitmap, text, textLeft, textTop, textRight, textBottom, foreColor, backColor, skipColor, fontNo, alignment, borderColor, dimmed
- return kStubNull(s, argc + 1, argv - 1);
+ BitmapResource bitmap(argv[0]);
+ Common::String text = s->_segMan->getString(argv[1]);
+ Common::Rect textRect(
+ argv[2].toSint16(),
+ argv[3].toSint16(),
+ argv[4].toSint16() + 1,
+ argv[5].toSint16() + 1
+ );
+ int16 foreColor = argv[6].toSint16();
+ int16 backColor = argv[7].toSint16();
+ int16 skipColor = argv[8].toSint16();
+ GuiResourceId fontId = (GuiResourceId)argv[9].toUint16();
+ TextAlign alignment = (TextAlign)argv[10].toSint16();
+ int16 borderColor = argv[11].toSint16();
+ bool dimmed = argv[12].toUint16();
+
+ // NOTE: Technically the engine checks these things:
+ // textRect.bottom > 0
+ // textRect.right > 0
+ // textRect.left < bitmap.width
+ // textRect.top < bitmap.height
+ // Then clips. But this seems stupid.
+ textRect.clip(Common::Rect(bitmap.getWidth(), bitmap.getHeight()));
+
+ reg_t textBitmapObject = g_sci->_gfxText32->createFontBitmap(textRect.width(), textRect.height(), Common::Rect(textRect.width(), textRect.height()), text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, false);
+ Buffer bitmapBuffer(bitmap.getWidth(), bitmap.getHeight(), bitmap.getPixels());
+ CelObjMem textCel(textBitmapObject);
+ textCel.draw(bitmapBuffer, textRect, Common::Point(textRect.left, textRect.top), false);
+ s->_segMan->freeHunkEntry(textBitmapObject);
+
+ return NULL_REG;
}
reg_t kBitmapDrawColor(EngineState *s, int argc, reg_t *argv) {
@@ -670,14 +695,9 @@ reg_t kBitmapCreateFromUnknown(EngineState *s, int argc, reg_t *argv) {
// but it handles events on its own, using an internal loop, instead of using SCI
// scripts for event management like kEditControl does. Called by script 64914,
// DEdit::hilite().
-reg_t kEditText(EngineState *s, int argc, reg_t *argv) {
- reg_t controlObject = argv[0];
-
- if (!controlObject.isNull()) {
- g_sci->_gfxControls32->kernelTexteditChange(controlObject);
- }
- return s->r_acc;
+reg_t kEditText(EngineState *s, int argc, reg_t *argv) {
+ return g_sci->_gfxControls32->kernelEditText(argv[0]);
}
reg_t kAddLine(EngineState *s, int argc, reg_t *argv) {
@@ -894,6 +914,8 @@ reg_t kPalCycle(EngineState *s, int argc, reg_t *argv) {
}
reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) {
+ // TODO
+#if 0
uint16 operation = argv[0].toUint16();
switch (operation) {
@@ -904,57 +926,57 @@ reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) {
if (g_sci->getGameId() == GID_QFG4 && s->currentRoomNumber() == 140)
return s->r_acc;
- int16 base = (argc >= 2) ? argv[1].toSint16() : 0;
- if (base > 0)
- warning("kRemapColors(0) called with base %d", base);
- g_sci->_gfxPalette32->resetRemapping();
+ int16 color = (argc >= 2) ? argv[1].toSint16() : 0;
+ if (color > 0)
+ warning("kRemapColors(0) called with base %d", color);
+ //g_sci->_gfxPalette32->resetRemapping();
}
break;
case 1: { // remap by range
uint16 color = argv[1].toUint16();
uint16 from = argv[2].toUint16();
uint16 to = argv[3].toUint16();
- uint16 base = argv[4].toUint16();
- uint16 unk5 = (argc >= 6) ? argv[5].toUint16() : 0;
- if (unk5 > 0)
- warning("kRemapColors(1) called with 6 parameters, unknown parameter is %d", unk5);
- g_sci->_gfxPalette32->setRemappingRange(color, from, to, base);
+ uint16 delta = argv[4].toUint16();
+ uint16 depth = (argc >= 6) ? argv[5].toUint16() : 0;
+ if (depth > 0)
+ warning("kRemapColors(1) called with 6 parameters, depth is %d", depth);
+ //g_sci->_gfxPalette32->setRemappingRange(color, from, to, delta);
}
break;
case 2: { // remap by percent
uint16 color = argv[1].toUint16();
uint16 percent = argv[2].toUint16(); // 0 - 100
- if (argc >= 4)
- warning("RemapByPercent called with 4 parameters, unknown parameter is %d", argv[3].toUint16());
- g_sci->_gfxPalette32->setRemappingPercent(color, percent);
+ uint16 depth = (argc >= 4) ? argv[3].toUint16() : 0;
+ if (depth >= 0)
+ warning("RemapByPercent called with 4 parameters, depth is %d", depth);
+ //g_sci->_gfxPalette32->setRemappingPercent(color, percent);
}
break;
case 3: { // remap to gray
// Example call: QFG4 room 490 (Baba Yaga's hut) - params are color 253, 75% and 0.
// In this room, it's used for the cloud before Baba Yaga appears.
- int16 color = argv[1].toSint16();
- int16 percent = argv[2].toSint16(); // 0 - 100
- if (argc >= 4)
- warning("RemapToGray called with 4 parameters, unknown parameter is %d", argv[3].toUint16());
- g_sci->_gfxPalette32->setRemappingPercentGray(color, percent);
+ uint16 color = argv[1].toUint16();
+ uint16 percent = argv[2].toUint16(); // 0 - 100
+ uint16 depth = (argc >= 4) ? argv[3].toUint16() : 0;
+ if (depth >= 0)
+ warning("RemapToGray called with 4 parameters, depth is %d", depth);
+ //g_sci->_gfxPalette32->setRemappingPercentGray(color, percent);
}
break;
case 4: { // remap to percent gray
// Example call: QFG4 rooms 530/535 (swamp) - params are 253, 100%, 200
- int16 color = argv[1].toSint16();
- int16 percent = argv[2].toSint16(); // 0 - 100
- // argv[3] is unknown (a number, e.g. 200) - start color, perhaps?
+ uint16 color = argv[1].toUint16();
+ uint16 percent = argv[2].toUint16(); // 0 - 100
+ uint16 grayPercent = argv[3].toUint16();
+ uint16 depth = (argc >= 5) ? argv[4].toUint16() : 0;
if (argc >= 5)
- warning("RemapToGrayPercent called with 5 parameters, unknown parameter is %d", argv[4].toUint16());
- g_sci->_gfxPalette32->setRemappingPercentGray(color, percent);
+ warning("RemapToGrayPercent called with 5 parameters, depth is %d", depth);
+ //g_sci->_gfxPalette32->setRemappingPercentGray(color, percent);
}
break;
case 5: { // don't map to range
- //int16 mapping = argv[1].toSint16();
- uint16 intensity = argv[2].toUint16();
- // HACK for PQ4
- if (g_sci->getGameId() == GID_PQ4)
- g_sci->_gfxPalette32->kernelSetIntensity(0, 255, intensity, true);
+ //uint16 start = argv[1].toSint16();
+ //uint16 count = argv[2].toUint16();
kStub(s, argc, argv);
}
@@ -962,6 +984,7 @@ reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) {
default:
break;
}
+#endif
return s->r_acc;
}
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index fc0dca5123..8039c5f282 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -813,6 +813,32 @@ static const uint16 kq5PatchWitchCageInit[] = {
PATCH_END
};
+// The multilingual releases of KQ5 hang right at the end during the magic battle with Mordack.
+// It seems additional code was added to wait for signals, but the signals are never set and thus
+// the game hangs. We disable that code, so that the battle works again.
+// This also happened in the original interpreter.
+// We must not change similar code, that happens before.
+
+// Applies to at least: French PC floppy, German PC floppy, Spanish PC floppy
+// Responsible method: stingScript::changeState, dragonScript::changeState, snakeScript::changeState
+static const uint16 kq5SignatureMultilingualEndingGlitch[] = {
+ SIG_MAGICDWORD,
+ 0x89, 0x57, // lsg global[57h]
+ 0x35, 0x00, // ldi 0
+ 0x1a, // eq?
+ 0x18, // not
+ 0x30, SIG_UINT16(0x0011), // bnt [skip signal check]
+ SIG_ADDTOOFFSET(+8), // skip globalSound::prevSignal get code
+ 0x36, // push
+ 0x35, 0x0a, // ldi 0Ah
+ SIG_END
+};
+
+static const uint16 kq5PatchMultilingualEndingGlitch[] = {
+ PATCH_ADDTOOFFSET(+6),
+ 0x32, // change BNT into JMP
+ PATCH_END
+};
// In the final battle, the DOS version uses signals in the music to handle
// timing, while in the Windows version another method is used and the GM
@@ -843,9 +869,10 @@ static const uint16 kq5PatchWinGMSignals[] = {
// script, description, signature patch
static const SciScriptPatcherEntry kq5Signatures[] = {
- { true, 0, "CD: harpy volume change", 1, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume },
- { true, 200, "CD: witch cage init", 1, kq5SignatureWitchCageInit, kq5PatchWitchCageInit },
- { false, 124, "Win: GM Music signal checks", 4, kq5SignatureWinGMSignals, kq5PatchWinGMSignals },
+ { true, 0, "CD: harpy volume change", 1, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume },
+ { true, 200, "CD: witch cage init", 1, kq5SignatureWitchCageInit, kq5PatchWitchCageInit },
+ { true, 124, "Multilingual: Ending glitching out", 3, kq5SignatureMultilingualEndingGlitch, kq5PatchMultilingualEndingGlitch },
+ { false, 124, "Win: GM Music signal checks", 4, kq5SignatureWinGMSignals, kq5PatchWinGMSignals },
SCI_SIGNATUREENTRY_TERMINATOR
};
diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp
index 1393e96880..ac621f58ae 100644
--- a/engines/sci/engine/selector.cpp
+++ b/engines/sci/engine/selector.cpp
@@ -180,6 +180,7 @@ void Kernel::mapSelectors() {
FIND_SELECTOR(back);
FIND_SELECTOR(skip);
FIND_SELECTOR(borderColor);
+ FIND_SELECTOR(width);
FIND_SELECTOR(fixPriority);
FIND_SELECTOR(mirrored);
FIND_SELECTOR(visible);
@@ -192,7 +193,12 @@ void Kernel::mapSelectors() {
FIND_SELECTOR(textLeft);
FIND_SELECTOR(textBottom);
FIND_SELECTOR(textRight);
+ FIND_SELECTOR(title);
+ FIND_SELECTOR(titleFont);
+ FIND_SELECTOR(titleFore);
+ FIND_SELECTOR(titleBack);
FIND_SELECTOR(magnifier);
+ FIND_SELECTOR(frameOut);
FIND_SELECTOR(casts);
#endif
}
diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h
index a8bbbe75e3..f2d06d1cf4 100644
--- a/engines/sci/engine/selector.h
+++ b/engines/sci/engine/selector.h
@@ -147,6 +147,7 @@ struct SelectorCache {
Selector skip;
Selector dimmed;
Selector borderColor;
+ Selector width;
Selector fixPriority;
Selector mirrored;
@@ -155,9 +156,10 @@ struct SelectorCache {
Selector useInsetRect;
Selector inTop, inLeft, inBottom, inRight;
Selector textTop, textLeft, textBottom, textRight;
+ Selector title, titleFont, titleFore, titleBack;
Selector magnifier;
-
+ Selector frameOut;
Selector casts; // needed for sync'ing screen items/planes with scripts, when our save/restore code is patched in (see GfxFrameout::syncWithScripts)
#endif
};
diff --git a/engines/sci/engine/vm_types.cpp b/engines/sci/engine/vm_types.cpp
index 53a5a5c507..d74e2b194c 100644
--- a/engines/sci/engine/vm_types.cpp
+++ b/engines/sci/engine/vm_types.cpp
@@ -230,6 +230,10 @@ int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const {
return toUint16() - right.toUint16();
else
return toSint16() - right.toSint16();
+#ifdef ENABLE_SCI32
+ } else if (getSciVersion() >= SCI_VERSION_2) {
+ return sci32Comparison(right);
+#endif
} else if (pointerComparisonWithInteger(right)) {
return 1;
} else if (right.pointerComparisonWithInteger(*this)) {
@@ -238,6 +242,26 @@ int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const {
return lookForWorkaround(right, "comparison").toSint16();
}
+#ifdef ENABLE_SCI32
+int reg_t::sci32Comparison(const reg_t right) const {
+ // In SCI32, MemIDs are normally indexes into the memory manager's handle
+ // list, but the engine reserves indexes at and above 20000 for objects
+ // that were created inside the engine (as opposed to inside the VM). The
+ // engine compares these as a tiebreaker for graphics objects that are at
+ // the same priority, and it is necessary to at least minimally handle
+ // this situation.
+ // This is obviously a bogus comparision, but then, this entire thing is
+ // bogus. For the moment, it just needs to be deterministic.
+ if (isNumber() && !right.isNumber()) {
+ return 1;
+ } else if (right.isNumber() && !isNumber()) {
+ return -1;
+ }
+
+ return getOffset() - right.getOffset();
+}
+#endif
+
bool reg_t::pointerComparisonWithInteger(const reg_t right) const {
// This function handles the case where a script tries to compare a pointer
// to a number. Normally, we would not want to allow that. However, SCI0 -
diff --git a/engines/sci/engine/vm_types.h b/engines/sci/engine/vm_types.h
index a646478a8e..e60f52e85c 100644
--- a/engines/sci/engine/vm_types.h
+++ b/engines/sci/engine/vm_types.h
@@ -160,6 +160,10 @@ private:
int cmp(const reg_t right, bool treatAsUnsigned) const;
reg_t lookForWorkaround(const reg_t right, const char *operation) const;
bool pointerComparisonWithInteger(const reg_t right) const;
+
+#ifdef ENABLE_SCI32
+ int sci32Comparison(const reg_t right) const;
+#endif
};
static inline reg_t make_reg(SegmentId segment, uint16 offset) {
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 10731e270c..a4e19dc8b9 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -630,7 +630,7 @@ const SciWorkaroundEntry kGraphUpdateBox_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
const SciWorkaroundEntry kIsObject_workarounds[] = {
- { GID_GK1, 50, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // GK1 demo, when asking Grace for messages it gets called with an invalid parameter (type "error") - bug #4950
+ { GID_GK1DEMO, 50, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // GK1 demo, when asking Grace for messages it gets called with an invalid parameter (type "error") - bug #4950
{ GID_ISLANDBRAIN, -1, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // when going to the game options, choosing "Info" and selecting anything from the list, gets called with an invalid parameter (type "error") - bug #4989
{ GID_QFG3, -1, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // when asking for something, gets called with type error parameter
SCI_WORKAROUNDENTRY_TERMINATOR
@@ -670,7 +670,7 @@ const SciWorkaroundEntry kReadNumber_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
const SciWorkaroundEntry kPaletteUnsetFlag_workarounds[] = {
- { GID_QFG4, 100, 100, 0, "doMovie", "changeState", NULL, 0, { WORKAROUND_IGNORE, 0 } }, // after the Sierra logo, no flags are passed, thus the call is meaningless - bug #4947
+ { GID_QFG4DEMO, 100, 100, 0, "doMovie", "changeState", NULL, 0, { WORKAROUND_IGNORE, 0 } }, // after the Sierra logo, no flags are passed, thus the call is meaningless - bug #4947
SCI_WORKAROUNDENTRY_TERMINATOR
};