From 10c7835cfcdd8f0eb1eadf52ac9cfd39d2d6be61 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Wed, 15 Feb 2006 00:57:50 +0000 Subject: Moved all he-specific source files to engines/scumm/he/ subdirectory svn-id: r20696 --- engines/scumm/actor.cpp | 4 +- engines/scumm/akos.cpp | 4 +- engines/scumm/charset.cpp | 2 +- engines/scumm/cursor.cpp | 4 +- engines/scumm/floodfill_he.cpp | 293 ---- engines/scumm/floodfill_he.h | 67 - engines/scumm/gfx.cpp | 4 +- engines/scumm/he/floodfill_he.cpp | 293 ++++ engines/scumm/he/floodfill_he.h | 67 + engines/scumm/he/intern_he.h | 606 ++++++++ engines/scumm/he/logic_he.cpp | 836 ++++++++++ engines/scumm/he/logic_he.h | 124 ++ engines/scumm/he/palette_he.cpp | 317 ++++ engines/scumm/he/resource_v7he.cpp | 1912 +++++++++++++++++++++++ engines/scumm/he/resource_v7he.h | 556 +++++++ engines/scumm/he/script_v100he.cpp | 2978 ++++++++++++++++++++++++++++++++++++ engines/scumm/he/script_v6he.cpp | 1276 +++++++++++++++ engines/scumm/he/script_v72he.cpp | 2368 ++++++++++++++++++++++++++++ engines/scumm/he/script_v7he.cpp | 1153 ++++++++++++++ engines/scumm/he/script_v80he.cpp | 811 ++++++++++ engines/scumm/he/script_v90he.cpp | 2636 +++++++++++++++++++++++++++++++ engines/scumm/he/sound_he.cpp | 516 +++++++ engines/scumm/he/sprite_he.cpp | 1440 +++++++++++++++++ engines/scumm/he/sprite_he.h | 222 +++ engines/scumm/he/wiz_he.cpp | 2088 +++++++++++++++++++++++++ engines/scumm/he/wiz_he.h | 211 +++ engines/scumm/input.cpp | 4 +- engines/scumm/intern_he.h | 606 -------- engines/scumm/logic_he.cpp | 836 ---------- engines/scumm/logic_he.h | 124 -- engines/scumm/module.mk | 26 +- engines/scumm/object.cpp | 2 +- engines/scumm/palette_he.cpp | 317 ---- engines/scumm/resource.cpp | 2 +- engines/scumm/resource_v7he.cpp | 1912 ----------------------- engines/scumm/resource_v7he.h | 556 ------- engines/scumm/room.cpp | 2 +- engines/scumm/saveload.cpp | 4 +- engines/scumm/script_v100he.cpp | 2978 ------------------------------------ engines/scumm/script_v6he.cpp | 1276 --------------- engines/scumm/script_v72he.cpp | 2368 ---------------------------- engines/scumm/script_v7he.cpp | 1153 -------------- engines/scumm/script_v80he.cpp | 811 ---------- engines/scumm/script_v90he.cpp | 2636 ------------------------------- engines/scumm/scumm.cpp | 8 +- engines/scumm/sound_he.cpp | 516 ------- engines/scumm/sprite_he.cpp | 1440 ----------------- engines/scumm/sprite_he.h | 222 --- engines/scumm/string.cpp | 2 +- engines/scumm/vars.cpp | 4 +- engines/scumm/wiz_he.cpp | 2088 ------------------------- engines/scumm/wiz_he.h | 211 --- 52 files changed, 20446 insertions(+), 20446 deletions(-) delete mode 100644 engines/scumm/floodfill_he.cpp delete mode 100644 engines/scumm/floodfill_he.h create mode 100644 engines/scumm/he/floodfill_he.cpp create mode 100644 engines/scumm/he/floodfill_he.h create mode 100644 engines/scumm/he/intern_he.h create mode 100644 engines/scumm/he/logic_he.cpp create mode 100644 engines/scumm/he/logic_he.h create mode 100644 engines/scumm/he/palette_he.cpp create mode 100644 engines/scumm/he/resource_v7he.cpp create mode 100644 engines/scumm/he/resource_v7he.h create mode 100644 engines/scumm/he/script_v100he.cpp create mode 100644 engines/scumm/he/script_v6he.cpp create mode 100644 engines/scumm/he/script_v72he.cpp create mode 100644 engines/scumm/he/script_v7he.cpp create mode 100644 engines/scumm/he/script_v80he.cpp create mode 100644 engines/scumm/he/script_v90he.cpp create mode 100644 engines/scumm/he/sound_he.cpp create mode 100644 engines/scumm/he/sprite_he.cpp create mode 100644 engines/scumm/he/sprite_he.h create mode 100644 engines/scumm/he/wiz_he.cpp create mode 100644 engines/scumm/he/wiz_he.h delete mode 100644 engines/scumm/intern_he.h delete mode 100644 engines/scumm/logic_he.cpp delete mode 100644 engines/scumm/logic_he.h delete mode 100644 engines/scumm/palette_he.cpp delete mode 100644 engines/scumm/resource_v7he.cpp delete mode 100644 engines/scumm/resource_v7he.h delete mode 100644 engines/scumm/script_v100he.cpp delete mode 100644 engines/scumm/script_v6he.cpp delete mode 100644 engines/scumm/script_v72he.cpp delete mode 100644 engines/scumm/script_v7he.cpp delete mode 100644 engines/scumm/script_v80he.cpp delete mode 100644 engines/scumm/script_v90he.cpp delete mode 100644 engines/scumm/sound_he.cpp delete mode 100644 engines/scumm/sprite_he.cpp delete mode 100644 engines/scumm/sprite_he.h delete mode 100644 engines/scumm/wiz_he.cpp delete mode 100644 engines/scumm/wiz_he.h (limited to 'engines/scumm') diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index 686df5e42e..5bfd1d82e2 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -29,12 +29,12 @@ #include "scumm/charset.h" #include "scumm/costume.h" #include "scumm/intern.h" -#include "scumm/intern_he.h" +#include "scumm/he/intern_he.h" #include "scumm/object.h" #include "scumm/resource.h" #include "scumm/saveload.h" #include "scumm/sound.h" -#include "scumm/sprite_he.h" +#include "scumm/he/sprite_he.h" #include "scumm/usage_bits.h" #include "scumm/util.h" diff --git a/engines/scumm/akos.cpp b/engines/scumm/akos.cpp index d8f484f1d3..858e722579 100644 --- a/engines/scumm/akos.cpp +++ b/engines/scumm/akos.cpp @@ -29,10 +29,10 @@ #include "scumm/imuse.h" #include "scumm/imuse_digi/dimuse.h" #include "scumm/intern.h" -#include "scumm/intern_he.h" +#include "scumm/he/intern_he.h" #include "scumm/sound.h" #include "scumm/util.h" -#include "scumm/wiz_he.h" +#include "scumm/he/wiz_he.h" namespace Scumm { diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp index e8086ed30a..3eca87d110 100644 --- a/engines/scumm/charset.cpp +++ b/engines/scumm/charset.cpp @@ -24,7 +24,7 @@ #include "scumm/scumm.h" #include "scumm/nut_renderer.h" #include "scumm/util.h" -#include "scumm/wiz_he.h" +#include "scumm/he/wiz_he.h" namespace Scumm { diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp index 6fee33e79b..0be6a48c53 100644 --- a/engines/scumm/cursor.cpp +++ b/engines/scumm/cursor.cpp @@ -26,9 +26,9 @@ #include "scumm/bomp.h" #include "scumm/charset.h" #include "scumm/intern.h" -#include "scumm/intern_he.h" +#include "scumm/he/intern_he.h" #include "scumm/object.h" -#include "scumm/resource_v7he.h" +#include "scumm/he/resource_v7he.h" #include "scumm/saveload.h" #include "scumm/scumm.h" diff --git a/engines/scumm/floodfill_he.cpp b/engines/scumm/floodfill_he.cpp deleted file mode 100644 index c7df765606..0000000000 --- a/engines/scumm/floodfill_he.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" - -#include "scumm/floodfill_he.h" -#include "scumm/intern_he.h" -#include "scumm/resource.h" -#include "scumm/scumm.h" - -namespace Scumm { - -static bool floodFillPixelCheck(int x, int y, const FloodFillState *ffs) { - int diffColor = ffs->color1 - ffs->color2; - if (x >= 0 && x < ffs->dst_w && y >= 0 && y < ffs->dst_h) { - uint8 color = *(ffs->dst + y * ffs->dst_w + x); - diffColor = color - ffs->color1; - } - return diffColor == 0; -} - -static void floodFillProcessRect(FloodFillState *ffs, const Common::Rect *r) { - Common::Rect *dr = &ffs->dstBox; - if (dr->right >= dr->left && dr->top <= dr->bottom) { - int rw = r->right - r->left + 1; - int rh = r->bottom - r->top + 1; - assert(r->top + rh <= ffs->dst_h); - assert(r->left + rw <= ffs->dst_w); - uint8 *dst = ffs->dst + r->top * ffs->dst_w + r->left; - if (rw <= 1) { - --rh; - while (rh >= 0) { - *dst = ffs->color2; - dst += ffs->dst_w; - --rh; - } - } else { - --rh; - while (rh >= 0) { - memset(dst, ffs->color2, rw); - dst += ffs->dst_w; - --rh; - } - } - dr->extend(*r); - } else { - *dr = *r; - } -} - -static void floodFillAddLine(FloodFillLine **ffl, int y, int x1, int x2, int dy) { - (*ffl)->y = y; - (*ffl)->x1 = x1; - (*ffl)->x2 = x2; - (*ffl)->inc = dy; - (*ffl)++; -} - -static void floodFillProcess(int x, int y, FloodFillState *ffs, FloodFillPixelCheckCallback pixelCheckCallback) { - ffs->dstBox.left = ffs->dstBox.top = 12345; - ffs->dstBox.right = ffs->dstBox.bottom = -12345; - - FloodFillLine **fillLineCur = &ffs->fillLineTableCur; - FloodFillLine **fillLineEnd = &ffs->fillLineTableEnd; - - assert(*fillLineCur < *fillLineEnd); - if (ffs->srcBox.top <= y + 1 && ffs->srcBox.bottom >= y + 1) { - (*fillLineCur)->y = y; - (*fillLineCur)->x1 = x; - (*fillLineCur)->x2 = x; - (*fillLineCur)->inc = 1; - (*fillLineCur)++; - } - - assert(*fillLineCur < *fillLineEnd); - if (ffs->srcBox.top <= y && ffs->srcBox.bottom >= y) { - (*fillLineCur)->y = y + 1; - (*fillLineCur)->x1 = x; - (*fillLineCur)->x2 = x; - (*fillLineCur)->inc = -1; - (*fillLineCur)++; - } - - assert(ffs->fillLineTable <= *fillLineCur); - FloodFillLine **fillLineStart = fillLineCur; - - while (ffs->fillLineTable < *fillLineStart) { - Common::Rect r; - int x_start; - FloodFillLine *fflCur = --(*fillLineCur); - int dy = fflCur->inc; - int x_end = fflCur->x2; - int x1 = fflCur->x1; - int x2 = fflCur->x1 + 1; - r.bottom = r.top = y = fflCur->y + fflCur->inc; - r.left = x2; - r.right = x1; - x = x1; - while (ffs->srcBox.left <= x) { - if (!(*pixelCheckCallback)(x, y, ffs)) { - break; - } - r.left = x; - --x; - } - if (r.right >= r.left && r.top <= r.bottom) { - floodFillProcessRect(ffs, &r); - } - if (x >= x1) goto skip; - x_start = x + 1; - if (x1 > x_start) { - assert(*fillLineEnd > *fillLineCur); - if (ffs->srcBox.top <= y - dy && ffs->srcBox.bottom >= y - dy) { - --x1; - floodFillAddLine(fillLineCur, y, x_start, x1, -dy); - } - } - x = x2; - while (x_start <= x_end) { - r.left = x; - r.top = y; - r.right = x - 1; - r.bottom = y; - while (ffs->srcBox.right >= x) { - if (!(*pixelCheckCallback)(x, y, ffs)) { - break; - } - r.right = x; - ++x; - } - if (r.right >= r.left && r.top <= r.bottom) { - floodFillProcessRect(ffs, &r); - } - assert(ffs->fillLineTableCur < ffs->fillLineTableEnd); - if (ffs->srcBox.top <= y + dy && ffs->srcBox.bottom >= y + dy) { - floodFillAddLine(&ffs->fillLineTableCur, y, x_start, x - 1, dy); - } - x_start = x_end + 1; - if (x > x_start) { - assert(ffs->fillLineTableCur < ffs->fillLineTableEnd); - if (ffs->srcBox.top <= y - dy && ffs->srcBox.bottom >= y - dy) { - floodFillAddLine(&ffs->fillLineTableCur, y, x_start, x - 1, -dy); - } - } -skip: - ++x; - while (x <= x_end) { - if ((*pixelCheckCallback)(x, y, ffs)) { - break; - } - ++x; - } - x_start = x; - } - } -} - -void floodFill(FloodFillParameters *ffp, ScummEngine_v90he *vm) { - uint8 *dst; - VirtScreen *vs = &vm->virtscr[kMainVirtScreen]; - if (ffp->flags & 0x8000) { - dst = vs->getBackPixels(0, vs->topline); - } else { - dst = vs->getPixels(0, vs->topline); - } - uint8 color = ffp->flags & 0xFF; - - Common::Rect r; - r.left = r.top = 12345; - r.right = r.bottom = -12345; - - FloodFillState *ffs = new FloodFillState; - ffs->fillLineTableCount = vs->h * 2; - ffs->fillLineTable = new FloodFillLine[ffs->fillLineTableCount]; - ffs->color2 = color; - ffs->dst = dst; - ffs->dst_w = vs->w; - ffs->dst_h = vs->h; - ffs->srcBox = ffp->box; - ffs->fillLineTableCur = &ffs->fillLineTable[0]; - ffs->fillLineTableEnd = &ffs->fillLineTable[ffs->fillLineTableCount]; - - if (ffp->x < 0 || ffp->y < 0 || ffp->x >= vs->w || ffp->y >= vs->h) { - ffs->color1 = color; - } else { - ffs->color1 = *(dst + ffp->y * vs->w + ffp->x); - } - - debug(5, "floodFill() x=%d y=%d color1=%d ffp->flags=0x%X", ffp->x, ffp->y, ffs->color1, ffp->flags); - if (ffs->color1 != color) { - floodFillProcess(ffp->x, ffp->y, ffs, floodFillPixelCheck); - r = ffs->dstBox; - } - r.debugPrint(5, "floodFill() dirty_rect"); - - delete[] ffs->fillLineTable; - delete ffs; - - vm->VAR(119) = 1; - - if (r.left <= r.right && r.top <= r.bottom) { - if (ffp->flags & 0x8000) { - vm->gdi.copyVirtScreenBuffers(r); - } else { - ++r.bottom; - vm->markRectAsDirty(kMainVirtScreen, r); - } - } -} - -void Wiz::fillWizFlood(const WizParameters *params) { - if (params->processFlags & kWPFClipBox2) { - int px = params->box2.left; - int py = params->box2.top; - uint8 *dataPtr = _vm->getResourceAddress(rtImage, params->img.resNum); - if (dataPtr) { - int state = 0; - if (params->processFlags & kWPFNewState) { - state = params->img.state; - } - uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); - assert(wizh); - int c = READ_LE_UINT32(wizh + 0x0); - int w = READ_LE_UINT32(wizh + 0x4); - int h = READ_LE_UINT32(wizh + 0x8); - assert(c == 0); - Common::Rect imageRect(w, h); - if (params->processFlags & kWPFClipBox) { - if (!imageRect.intersects(params->box)) { - return; - } - imageRect.clip(params->box); - } - uint8 color = _vm->VAR(93); - if (params->processFlags & kWPFFillColor) { - color = params->fillColor; - } - if (imageRect.contains(px, py)) { - uint8 *wizd = _vm->findWrappedBlock(MKID('WIZD'), dataPtr, state, 0); - assert(wizd); - - FloodFillState *ffs = new FloodFillState; - ffs->fillLineTableCount = h * 2; - ffs->fillLineTable = new FloodFillLine[ffs->fillLineTableCount]; - ffs->color2 = color; - ffs->dst = wizd; - ffs->dst_w = w; - ffs->dst_h = h; - ffs->srcBox = imageRect; - ffs->fillLineTableCur = &ffs->fillLineTable[0]; - ffs->fillLineTableEnd = &ffs->fillLineTable[ffs->fillLineTableCount]; - - if (px < 0 || py < 0 || px >= w || py >= h) { - ffs->color1 = color; - } else { - ffs->color1 = *(wizd + py * w + px); - } - - debug(0, "floodFill() x=%d y=%d color1=%d", px, py, ffs->color1); - - if (ffs->color1 != color) { - floodFillProcess(px, py, ffs, floodFillPixelCheck); - } - - delete[] ffs->fillLineTable; - delete ffs; - } - } - } - _vm->res.setModified(rtImage, params->img.resNum); -} - -} // End of namespace Scumm diff --git a/engines/scumm/floodfill_he.h b/engines/scumm/floodfill_he.h deleted file mode 100644 index 7d0fa7073f..0000000000 --- a/engines/scumm/floodfill_he.h +++ /dev/null @@ -1,67 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#if !defined(FLOODFILL_HE_H) && !defined(DISABLE_HE) -#define FLOODFILL_HE_H - -#include "common/rect.h" - -namespace Scumm { - -struct FloodFillParameters { - Common::Rect box; - int32 x; - int32 y; - int32 flags; -}; - -struct FloodFillLine { - int y; - int x1; - int x2; - int inc; -}; - -struct FloodFillState { - FloodFillLine *fillLineTable; - FloodFillLine *fillLineTableEnd; - FloodFillLine *fillLineTableCur; - Common::Rect dstBox; - Common::Rect srcBox; - uint8 *dst; - int dst_w; - int dst_h; - int color1; - int color2; - int fillLineTableCount; -}; - -class ScummEngine_v90he; - -typedef bool (*FloodFillPixelCheckCallback)(int x, int y, const FloodFillState *ffs); - -void floodFill(FloodFillParameters *ffp, ScummEngine_v90he *vm); - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index 6746c7088e..8831491c14 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -27,11 +27,11 @@ #include "scumm/charset.h" #include "scumm/intern.h" #ifndef DISABLE_HE -#include "scumm/intern_he.h" +#include "scumm/he/intern_he.h" #endif #include "scumm/resource.h" #include "scumm/usage_bits.h" -#include "scumm/wiz_he.h" +#include "scumm/he/wiz_he.h" namespace Scumm { diff --git a/engines/scumm/he/floodfill_he.cpp b/engines/scumm/he/floodfill_he.cpp new file mode 100644 index 0000000000..3736cb4d36 --- /dev/null +++ b/engines/scumm/he/floodfill_he.cpp @@ -0,0 +1,293 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" + +#include "scumm/he/floodfill_he.h" +#include "scumm/he/intern_he.h" +#include "scumm/resource.h" +#include "scumm/scumm.h" + +namespace Scumm { + +static bool floodFillPixelCheck(int x, int y, const FloodFillState *ffs) { + int diffColor = ffs->color1 - ffs->color2; + if (x >= 0 && x < ffs->dst_w && y >= 0 && y < ffs->dst_h) { + uint8 color = *(ffs->dst + y * ffs->dst_w + x); + diffColor = color - ffs->color1; + } + return diffColor == 0; +} + +static void floodFillProcessRect(FloodFillState *ffs, const Common::Rect *r) { + Common::Rect *dr = &ffs->dstBox; + if (dr->right >= dr->left && dr->top <= dr->bottom) { + int rw = r->right - r->left + 1; + int rh = r->bottom - r->top + 1; + assert(r->top + rh <= ffs->dst_h); + assert(r->left + rw <= ffs->dst_w); + uint8 *dst = ffs->dst + r->top * ffs->dst_w + r->left; + if (rw <= 1) { + --rh; + while (rh >= 0) { + *dst = ffs->color2; + dst += ffs->dst_w; + --rh; + } + } else { + --rh; + while (rh >= 0) { + memset(dst, ffs->color2, rw); + dst += ffs->dst_w; + --rh; + } + } + dr->extend(*r); + } else { + *dr = *r; + } +} + +static void floodFillAddLine(FloodFillLine **ffl, int y, int x1, int x2, int dy) { + (*ffl)->y = y; + (*ffl)->x1 = x1; + (*ffl)->x2 = x2; + (*ffl)->inc = dy; + (*ffl)++; +} + +static void floodFillProcess(int x, int y, FloodFillState *ffs, FloodFillPixelCheckCallback pixelCheckCallback) { + ffs->dstBox.left = ffs->dstBox.top = 12345; + ffs->dstBox.right = ffs->dstBox.bottom = -12345; + + FloodFillLine **fillLineCur = &ffs->fillLineTableCur; + FloodFillLine **fillLineEnd = &ffs->fillLineTableEnd; + + assert(*fillLineCur < *fillLineEnd); + if (ffs->srcBox.top <= y + 1 && ffs->srcBox.bottom >= y + 1) { + (*fillLineCur)->y = y; + (*fillLineCur)->x1 = x; + (*fillLineCur)->x2 = x; + (*fillLineCur)->inc = 1; + (*fillLineCur)++; + } + + assert(*fillLineCur < *fillLineEnd); + if (ffs->srcBox.top <= y && ffs->srcBox.bottom >= y) { + (*fillLineCur)->y = y + 1; + (*fillLineCur)->x1 = x; + (*fillLineCur)->x2 = x; + (*fillLineCur)->inc = -1; + (*fillLineCur)++; + } + + assert(ffs->fillLineTable <= *fillLineCur); + FloodFillLine **fillLineStart = fillLineCur; + + while (ffs->fillLineTable < *fillLineStart) { + Common::Rect r; + int x_start; + FloodFillLine *fflCur = --(*fillLineCur); + int dy = fflCur->inc; + int x_end = fflCur->x2; + int x1 = fflCur->x1; + int x2 = fflCur->x1 + 1; + r.bottom = r.top = y = fflCur->y + fflCur->inc; + r.left = x2; + r.right = x1; + x = x1; + while (ffs->srcBox.left <= x) { + if (!(*pixelCheckCallback)(x, y, ffs)) { + break; + } + r.left = x; + --x; + } + if (r.right >= r.left && r.top <= r.bottom) { + floodFillProcessRect(ffs, &r); + } + if (x >= x1) goto skip; + x_start = x + 1; + if (x1 > x_start) { + assert(*fillLineEnd > *fillLineCur); + if (ffs->srcBox.top <= y - dy && ffs->srcBox.bottom >= y - dy) { + --x1; + floodFillAddLine(fillLineCur, y, x_start, x1, -dy); + } + } + x = x2; + while (x_start <= x_end) { + r.left = x; + r.top = y; + r.right = x - 1; + r.bottom = y; + while (ffs->srcBox.right >= x) { + if (!(*pixelCheckCallback)(x, y, ffs)) { + break; + } + r.right = x; + ++x; + } + if (r.right >= r.left && r.top <= r.bottom) { + floodFillProcessRect(ffs, &r); + } + assert(ffs->fillLineTableCur < ffs->fillLineTableEnd); + if (ffs->srcBox.top <= y + dy && ffs->srcBox.bottom >= y + dy) { + floodFillAddLine(&ffs->fillLineTableCur, y, x_start, x - 1, dy); + } + x_start = x_end + 1; + if (x > x_start) { + assert(ffs->fillLineTableCur < ffs->fillLineTableEnd); + if (ffs->srcBox.top <= y - dy && ffs->srcBox.bottom >= y - dy) { + floodFillAddLine(&ffs->fillLineTableCur, y, x_start, x - 1, -dy); + } + } +skip: + ++x; + while (x <= x_end) { + if ((*pixelCheckCallback)(x, y, ffs)) { + break; + } + ++x; + } + x_start = x; + } + } +} + +void floodFill(FloodFillParameters *ffp, ScummEngine_v90he *vm) { + uint8 *dst; + VirtScreen *vs = &vm->virtscr[kMainVirtScreen]; + if (ffp->flags & 0x8000) { + dst = vs->getBackPixels(0, vs->topline); + } else { + dst = vs->getPixels(0, vs->topline); + } + uint8 color = ffp->flags & 0xFF; + + Common::Rect r; + r.left = r.top = 12345; + r.right = r.bottom = -12345; + + FloodFillState *ffs = new FloodFillState; + ffs->fillLineTableCount = vs->h * 2; + ffs->fillLineTable = new FloodFillLine[ffs->fillLineTableCount]; + ffs->color2 = color; + ffs->dst = dst; + ffs->dst_w = vs->w; + ffs->dst_h = vs->h; + ffs->srcBox = ffp->box; + ffs->fillLineTableCur = &ffs->fillLineTable[0]; + ffs->fillLineTableEnd = &ffs->fillLineTable[ffs->fillLineTableCount]; + + if (ffp->x < 0 || ffp->y < 0 || ffp->x >= vs->w || ffp->y >= vs->h) { + ffs->color1 = color; + } else { + ffs->color1 = *(dst + ffp->y * vs->w + ffp->x); + } + + debug(5, "floodFill() x=%d y=%d color1=%d ffp->flags=0x%X", ffp->x, ffp->y, ffs->color1, ffp->flags); + if (ffs->color1 != color) { + floodFillProcess(ffp->x, ffp->y, ffs, floodFillPixelCheck); + r = ffs->dstBox; + } + r.debugPrint(5, "floodFill() dirty_rect"); + + delete[] ffs->fillLineTable; + delete ffs; + + vm->VAR(119) = 1; + + if (r.left <= r.right && r.top <= r.bottom) { + if (ffp->flags & 0x8000) { + vm->gdi.copyVirtScreenBuffers(r); + } else { + ++r.bottom; + vm->markRectAsDirty(kMainVirtScreen, r); + } + } +} + +void Wiz::fillWizFlood(const WizParameters *params) { + if (params->processFlags & kWPFClipBox2) { + int px = params->box2.left; + int py = params->box2.top; + uint8 *dataPtr = _vm->getResourceAddress(rtImage, params->img.resNum); + if (dataPtr) { + int state = 0; + if (params->processFlags & kWPFNewState) { + state = params->img.state; + } + uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); + assert(wizh); + int c = READ_LE_UINT32(wizh + 0x0); + int w = READ_LE_UINT32(wizh + 0x4); + int h = READ_LE_UINT32(wizh + 0x8); + assert(c == 0); + Common::Rect imageRect(w, h); + if (params->processFlags & kWPFClipBox) { + if (!imageRect.intersects(params->box)) { + return; + } + imageRect.clip(params->box); + } + uint8 color = _vm->VAR(93); + if (params->processFlags & kWPFFillColor) { + color = params->fillColor; + } + if (imageRect.contains(px, py)) { + uint8 *wizd = _vm->findWrappedBlock(MKID('WIZD'), dataPtr, state, 0); + assert(wizd); + + FloodFillState *ffs = new FloodFillState; + ffs->fillLineTableCount = h * 2; + ffs->fillLineTable = new FloodFillLine[ffs->fillLineTableCount]; + ffs->color2 = color; + ffs->dst = wizd; + ffs->dst_w = w; + ffs->dst_h = h; + ffs->srcBox = imageRect; + ffs->fillLineTableCur = &ffs->fillLineTable[0]; + ffs->fillLineTableEnd = &ffs->fillLineTable[ffs->fillLineTableCount]; + + if (px < 0 || py < 0 || px >= w || py >= h) { + ffs->color1 = color; + } else { + ffs->color1 = *(wizd + py * w + px); + } + + debug(0, "floodFill() x=%d y=%d color1=%d", px, py, ffs->color1); + + if (ffs->color1 != color) { + floodFillProcess(px, py, ffs, floodFillPixelCheck); + } + + delete[] ffs->fillLineTable; + delete ffs; + } + } + } + _vm->res.setModified(rtImage, params->img.resNum); +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/floodfill_he.h b/engines/scumm/he/floodfill_he.h new file mode 100644 index 0000000000..7d0fa7073f --- /dev/null +++ b/engines/scumm/he/floodfill_he.h @@ -0,0 +1,67 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#if !defined(FLOODFILL_HE_H) && !defined(DISABLE_HE) +#define FLOODFILL_HE_H + +#include "common/rect.h" + +namespace Scumm { + +struct FloodFillParameters { + Common::Rect box; + int32 x; + int32 y; + int32 flags; +}; + +struct FloodFillLine { + int y; + int x1; + int x2; + int inc; +}; + +struct FloodFillState { + FloodFillLine *fillLineTable; + FloodFillLine *fillLineTableEnd; + FloodFillLine *fillLineTableCur; + Common::Rect dstBox; + Common::Rect srcBox; + uint8 *dst; + int dst_w; + int dst_h; + int color1; + int color2; + int fillLineTableCount; +}; + +class ScummEngine_v90he; + +typedef bool (*FloodFillPixelCheckCallback)(int x, int y, const FloodFillState *ffs); + +void floodFill(FloodFillParameters *ffp, ScummEngine_v90he *vm); + +} // End of namespace Scumm + +#endif diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h new file mode 100644 index 0000000000..da14983e21 --- /dev/null +++ b/engines/scumm/he/intern_he.h @@ -0,0 +1,606 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef SCUMM_INTERN_HE_H +#define SCUMM_INTERN_HE_H + +#include "scumm/intern.h" +#ifndef DISABLE_HE +#include "scumm/he/floodfill_he.h" +#include "scumm/he/wiz_he.h" +#endif + +namespace Scumm { + +#ifndef DISABLE_HE +class ResExtractor; +class LogicHE; +class Sprite; +#endif + +class ScummEngine_v60he : public ScummEngine_v6 { +protected: + typedef void (ScummEngine_v60he::*OpcodeProcv60he)(); + struct OpcodeEntryv60he { + OpcodeProcv60he proc; + const char *desc; + }; + + const OpcodeEntryv60he *_opcodesv60he; + + Common::File _hFileTable[17]; + +public: + ScummEngine_v60he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex) : ScummEngine_v6(detector, syst, gs, md5sum, substResFileNameIndex) {} + + virtual void scummInit(); + +protected: + virtual void setupOpcodes(); + virtual void executeOpcode(byte i); + virtual const char *getOpcodeDesc(byte i); + + virtual void saveOrLoad(Serializer *s); + + void localizeArray(int slot, byte scriptSlot); + void redimArray(int arrayId, int newX, int newY, int d); + int readFileToArray(int slot, int32 size); + void writeFileFromArray(int slot, int resID); + int virtScreenSave(byte *dst, int x1, int y1, int x2, int y2); + void virtScreenLoad(int resIdx, int x1, int y1, int x2, int y2); + virtual void decodeParseString(int a, int b); + void swapObjects(int object1, int object2); + + /* HE version 60 script opcodes */ + void o60_setState(); + void o60_roomOps(); + void o60_actorOps(); + void o60_kernelSetFunctions(); + void o60_kernelGetFunctions(); + void o60_openFile(); + void o60_closeFile(); + void o60_deleteFile(); + void o60_readFile(); + void o60_rename(); + void o60_writeFile(); + void o60_soundOps(); + void o60_seekFilePos(); + void o60_localizeArrayToScript(); + void o60_redimArray(); + void o60_readFilePos(); +}; + +#ifndef DISABLE_HE +class ScummEngine_v70he : public ScummEngine_v60he { + friend class ResExtractor; + friend class Wiz; + +protected: + typedef void (ScummEngine_v70he::*OpcodeProcv70he)(); + struct OpcodeEntryv70he { + OpcodeProcv70he proc; + const char *desc; + }; + + const OpcodeEntryv70he *_opcodesv70he; + + ResExtractor *_resExtractor; + + byte *_heV7RoomOffsets; + + int32 _heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags, _heSndSoundFreq; + + bool _skipProcessActors; + +public: + ScummEngine_v70he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex); + ~ScummEngine_v70he(); + + Wiz *_wiz; + + byte *heFindResourceData(uint32 tag, byte *ptr); + byte *heFindResource(uint32 tag, byte *ptr); + byte *findWrappedBlock(uint32 tag, byte *ptr, int state, bool flagError); + +protected: + virtual void setupOpcodes(); + virtual void executeOpcode(byte i); + virtual const char *getOpcodeDesc(byte i); + + virtual void setupScummVars(); + virtual void initScummVars(); + + virtual void saveOrLoad(Serializer *s); + + virtual void readRoomsOffsets(); + virtual void readGlobalObjects(); + virtual void readIndexBlock(uint32 blocktype, uint32 itemsize); + + virtual int getActorFromPos(int x, int y); + + int getStringCharWidth(byte chr); + virtual int setupStringArray(int size); + void appendSubstring(int dst, int src, int len2, int len); + + virtual void setCursorFromImg(uint img, uint room, uint imgindex); + + virtual void clearDrawQueues(); + + void remapHEPalette(const uint8 *src, uint8 *dst); + + /* HE version 70 script opcodes */ + void o70_startSound(); + void o70_pickupObject(); + void o70_getActorRoom(); + void o70_resourceRoutines(); + void o70_systemOps(); + void o70_kernelSetFunctions(); + void o70_seekFilePos(); + void o70_copyString(); + void o70_getStringWidth(); + void o70_getStringLen(); + void o70_appendString(); + void o70_concatString(); + void o70_compareString(); + void o70_isResourceLoaded(); + void o70_readINI(); + void o70_writeINI(); + void o70_getStringLenForWidth(); + void o70_getCharIndexInString(); + void o70_setFilePath(); + void o70_setSystemMessage(); + void o70_polygonOps(); + void o70_polygonHit(); + + byte VAR_NUM_SOUND_CHANNELS; + byte VAR_WIZ_TCOLOR; +}; + +class ScummEngine_v71he : public ScummEngine_v70he { +public: + ScummEngine_v71he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex); + +protected: + virtual void saveOrLoad(Serializer *s); + + virtual void redrawBGAreas(); + + virtual void processActors(); + void preProcessAuxQueue(); + void postProcessAuxQueue(); + +public: + /* Actor AuxQueue stuff (HE) */ + AuxBlock _auxBlocks[16]; + uint16 _auxBlocksNum; + AuxEntry _auxEntries[16]; + uint16 _auxEntriesNum; + + void queueAuxBlock(Actor *a); + void queueAuxEntry(int actorNum, int subIndex); +}; + +class ScummEngine_v72he : public ScummEngine_v71he { +protected: + typedef void (ScummEngine_v72he::*OpcodeProcV72he)(); + struct OpcodeEntryV72he { + OpcodeProcV72he proc; + const char *desc; + }; + +#if !defined(__GNUC__) + #pragma START_PACK_STRUCTS +#endif + + struct ArrayHeader { + int32 type; //0 + int32 dim1start; //4 + int32 dim1end; //8 + int32 dim2start; //0C + int32 dim2end; //10 + byte data[1]; //14 + } GCC_PACK; + +#if !defined(__GNUC__) + #pragma END_PACK_STRUCTS +#endif + + const OpcodeEntryV72he *_opcodesV72he; + + int _stringLength; + byte _stringBuffer[4096]; + + WizParameters _wizParams; + +public: + ScummEngine_v72he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex); + + virtual void scummInit(); + +protected: + virtual void setupOpcodes(); + virtual void executeOpcode(byte i); + virtual const char *getOpcodeDesc(byte i); + + virtual void setupScummVars(); + virtual void initScummVars(); + virtual void readArrayFromIndexFile(); + + virtual byte *getStringAddress(int i); + virtual void readMAXS(int blockSize); + + virtual void redrawBGAreas(); + + ArrayHeader *defineArray(int array, int type, int dim2start, int dim2end, int dim1start, int dim1end); + virtual int readArray(int array, int idx2, int idx1); + virtual void writeArray(int array, int idx2, int idx1, int value); + void redimArray(int arrayId, int newDim2start, int newDim2end, + int newDim1start, int newDim1end, int type); + void checkArrayLimits(int array, int dim2start, int dim2end, int dim1start, int dim1end); + void copyArray(int array1, int a1_dim2start, int a1_dim2end, int a1_dim1start, int a1_dim1end, + int array2, int a2_dim2start, int a2_dim2end, int a2_dim1start, int a2_dim1end); + void copyArrayHelper(ArrayHeader *ah, int idx2, int idx1, int len1, byte **data, int *size, int *num); + virtual int setupStringArray(int size); + int readFileToArray(int slot, int32 size); + void writeFileFromArray(int slot, int32 resID); + + virtual void decodeParseString(int a, int b); + void decodeScriptString(byte *dst, bool scriptString = false); + void copyScriptString(byte *dst, int dstSize); + int convertFilePath(byte *dst, bool setFilePath = false); + + int findObject(int x, int y, int num, int *args); + int getSoundResourceSize(int id); + + virtual bool handleNextCharsetCode(Actor *a, int *c); + + /* HE version 72 script opcodes */ + void o72_pushDWord(); + void o72_getScriptString(); + void o72_isAnyOf(); + void o72_resetCutscene(); + void o72_findObjectWithClassOf(); + void o72_getObjectImageX(); + void o72_getObjectImageY(); + void o72_captureWizImage(); + void o72_getTimer(); + void o72_setTimer(); + void o72_getSoundPosition(); + void o72_startScript(); + void o72_startObject(); + void o72_drawObject(); + void o72_printWizImage(); + void o72_getArrayDimSize(); + void o72_getNumFreeArrays(); + void o72_roomOps(); + void o72_actorOps(); + void o72_verbOps(); + void o72_findObject(); + void o72_arrayOps(); + void o72_systemOps(); + void o72_talkActor(); + void o72_talkEgo(); + void o72_dimArray(); + void o72_dim2dimArray(); + void o72_traceStatus(); + void o72_debugInput(); + void o72_drawWizImage(); + void o72_kernelGetFunctions(); + void o72_jumpToScript(); + void o72_openFile(); + void o72_readFile(); + void o72_writeFile(); + void o72_findAllObjects(); + void o72_deleteFile(); + void o72_rename(); + void o72_getPixel(); + void o72_pickVarRandom(); + void o72_redimArray(); + void o72_readINI(); + void o72_writeINI(); + void o72_getResourceSize(); + void o72_setFilePath(); + void o72_setSystemMessage(); + + byte VAR_NUM_ROOMS; + byte VAR_NUM_SCRIPTS; + byte VAR_NUM_SOUNDS; + byte VAR_NUM_COSTUMES; + byte VAR_NUM_IMAGES; + byte VAR_NUM_CHARSETS; + + byte VAR_POLYGONS_ONLY; +}; + +class ScummEngine_v80he : public ScummEngine_v72he { +protected: + typedef void (ScummEngine_v80he::*OpcodeProcV80he)(); + struct OpcodeEntryV80he { + OpcodeProcV80he proc; + const char *desc; + }; + + const OpcodeEntryV80he *_opcodesV80he; + + int32 _heSndResId, _curSndId, _sndPtrOffs, _sndTmrOffs; + +public: + ScummEngine_v80he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex); + +protected: + virtual void setupOpcodes(); + virtual void executeOpcode(byte i); + virtual const char *getOpcodeDesc(byte i); + + virtual void setupScummVars(); + virtual void initScummVars(); + + virtual void initCharset(int charset); + + virtual void clearDrawQueues(); + + void createSound(int snd1id, int snd2id); + + void drawLine(int x1, int y1, int x, int unk1, int unk2, int type, int id); + void drawPixel(int x, int y, int flags); + + /* HE version 80 script opcodes */ + void o80_createSound(); + void o80_getFileSize(); + void o80_stringToInt(); + void o80_getSoundVar(); + void o80_localizeArrayToRoom(); + void o80_sourceDebug(); + void o80_readConfigFile(); + void o80_writeConfigFile(); + void o80_cursorCommand(); + void o80_setState(); + void o80_drawWizPolygon(); + void o80_drawLine(); + void o80_pickVarRandom(); + + byte VAR_PLATFORM; + byte VAR_WINDOWS_VERSION; + byte VAR_CURRENT_CHARSET; + byte VAR_COLOR_DEPTH; +}; + +class ScummEngine_v90he : public ScummEngine_v80he { + friend class LogicHE; + friend class Sprite; + +protected: + typedef void (ScummEngine_v90he::*OpcodeProcV90he)(); + struct OpcodeEntryV90he { + OpcodeProcV90he proc; + const char *desc; + }; + + const OpcodeEntryV90he *_opcodesV90he; + + FloodFillParameters _floodFillParams; + + struct VideoParameters { + byte filename[260]; + int32 status; + int32 flags; + int32 unk2; + int32 wizResNum; + }; + + VideoParameters _videoParams; + + int32 _heObject, _heObjectNum; + int32 _hePaletteNum; + + int32 _curMaxSpriteId; + int32 _curSpriteId; + int32 _curSpriteGroupId; + +public: + ScummEngine_v90he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex); + ~ScummEngine_v90he(); + + virtual void scummInit(); + + LogicHE *_logicHE; + Sprite *_sprite; + +protected: + virtual void allocateArrays(); + virtual void setupOpcodes(); + virtual void executeOpcode(byte i); + virtual const char *getOpcodeDesc(byte i); + + virtual void setupScummVars(); + virtual void initScummVars(); + + virtual void saveOrLoad(Serializer *s); + + virtual void readMAXS(int blockSize); + + virtual void processActors(); + + int computeWizHistogram(int resnum, int state, int x, int y, int w, int h); + void getArrayDim(int array, int *dim2start, int *dim2end, int *dim1start, int *dim1end); + void sortArray(int array, int dim2start, int dim2end, int dim1start, int dim1end, int sortOrder); + +public: + int getGroupSpriteArray(int spriteGroupId); + +protected: + uint8 *getHEPaletteIndex(int palSlot); + int getHEPaletteColor(int palSlot, int color); + int getHEPaletteSimilarColor(int palSlot, int red, int green, int start, int end); + int getHEPaletteColorComponent(int palSlot, int color, int component); + void setHEPaletteColor(int palSlot, uint8 color, uint8 r, uint8 g, uint8 b); + void setHEPaletteFromPtr(int palSlot, const uint8 *palData); + void setHEPaletteFromCostume(int palSlot, int resId); + void setHEPaletteFromImage(int palSlot, int resId, int state); + void setHEPaletteFromRoom(int palSlot, int resId, int state); + void restoreHEPalette(int palSlot); + void copyHEPalette(int dstPalSlot, int srcPalSlot); + void copyHEPaletteColor(int palSlot, uint8 dstColor, uint8 srcColor); + + + void setDefaultCursor(); + +protected: + /* HE version 90 script opcodes */ + void o90_dup_n(); + void o90_min(); + void o90_max(); + void o90_sin(); + void o90_cos(); + void o90_sqrt(); + void o90_atan2(); + void o90_getSegmentAngle(); + void o90_getActorData(); + void o90_startScriptUnk(); + void o90_jumpToScriptUnk(); + void o90_videoOps(); + void o90_getVideoData(); + void o90_wizImageOps(); + void o90_getDistanceBetweenPoints(); + void o90_getSpriteInfo(); + void o90_setSpriteInfo(); + void o90_getSpriteGroupInfo(); + void o90_setSpriteGroupInfo(); + void o90_getWizData(); + void o90_floodFill(); + void o90_mod(); + void o90_shl(); + void o90_shr(); + void o90_xor(); + void o90_findAllObjectsWithClassOf(); + void o90_getPolygonOverlap(); + void o90_cond(); + void o90_dim2dim2Array(); + void o90_redim2dimArray(); + void o90_getLinesIntersectionPoint(); + void o90_sortArray(); + void o90_getObjectData(); + void o90_getPaletteData(); + void o90_paletteOps(); + void o90_fontUnk(); + void o90_getActorAnimProgress(); + void o90_kernelGetFunctions(); + void o90_kernelSetFunctions(); + + byte VAR_NUM_SPRITE_GROUPS; + byte VAR_NUM_SPRITES; + byte VAR_NUM_PALETTES; + byte VAR_NUM_UNK; + + byte VAR_U32_VERSION; + byte VAR_U32_ARRAY_UNK; +}; + +class ScummEngine_v99he : public ScummEngine_v90he { +public: + ScummEngine_v99he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex) : ScummEngine_v90he(detector, syst, gs, md5sum, substResFileNameIndex) {} + + virtual void scummInit(); + +protected: + virtual void initScummVars(); + + virtual void readMAXS(int blockSize); + + virtual void saveOrLoad(Serializer *s); + + virtual void copyPalColor(int dst, int src); + virtual void darkenPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor); + virtual void setPaletteFromPtr(const byte *ptr, int numcolor = -1); + virtual void setPalColor(int index, int r, int g, int b); + virtual void updatePalette(); +}; + +class ScummEngine_v100he : public ScummEngine_v99he { +protected: + typedef void (ScummEngine_v100he::*OpcodeProcV100he)(); + struct OpcodeEntryV100he { + OpcodeProcV100he proc; + const char *desc; + }; + + int32 _heResId, _heResType; + + const OpcodeEntryV100he *_opcodesV100he; + +public: + ScummEngine_v100he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex) : ScummEngine_v99he(detector, syst, gs, md5sum, substResFileNameIndex) {} + +protected: + virtual void setupOpcodes(); + virtual void executeOpcode(byte i); + virtual const char *getOpcodeDesc(byte i); + + virtual void saveOrLoad(Serializer *s); + + virtual void decodeParseString(int a, int b); + + /* HE version 100 script opcodes */ + void o100_actorOps(); + void o100_arrayOps(); + void o100_dim2dimArray(); + void o100_redim2dimArray(); + void o100_dimArray(); + void o100_drawLine(); + void o100_drawObject(); + void o100_floodFill(); + void o100_setSpriteGroupInfo(); + void o100_resourceRoutines(); + void o100_wizImageOps(); + void o100_jumpToScript(); + void o100_createSound(); + void o100_dim2dim2Array(); + void o100_paletteOps(); + void o100_jumpToScriptUnk(); + void o100_startScriptUnk(); + void o100_redimArray(); + void o100_roomOps(); + void o100_setSystemMessage(); + void o100_startSound(); + void o100_setSpriteInfo(); + void o100_startScript(); + void o100_systemOps(); + void o100_cursorCommand(); + void o100_videoOps(); + void o100_wait(); + void o100_writeFile(); + void o100_isResourceLoaded(); + void o100_getResourceSize(); + void o100_getSpriteGroupInfo(); + void o100_getPaletteData(); + void o100_readFile(); + void o100_getSpriteInfo(); + void o100_getWizData(); + void o100_getVideoData(); +}; +#endif + + +} // End of namespace Scumm + +#endif diff --git a/engines/scumm/he/logic_he.cpp b/engines/scumm/he/logic_he.cpp new file mode 100644 index 0000000000..eb9e4edf07 --- /dev/null +++ b/engines/scumm/he/logic_he.cpp @@ -0,0 +1,836 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" + +#include "scumm/he/intern_he.h" +#include "scumm/he/logic_he.h" + +namespace Scumm { + +LogicHE::LogicHE(ScummEngine_v90he *vm) : _vm(vm) { + // Originally it used 0x930 and stored both floats and doubles inside + _userData = (float *)calloc(550, sizeof(float)); + _userDataD = (double *)calloc(30, sizeof(double)); +} + +LogicHE::~LogicHE() { + free(_userData); + free(_userDataD); +} + +void LogicHE::writeScummVar(int var, int32 value) { + _vm->writeVar(var, value); +} + +static int32 scumm_round(double arg) { + return (int32)(arg + 0.5); +} + +int LogicHE::versionID() { + return 1; +} + +int LogicHE::getFromArray(int arg0, int idx2, int idx1) { + _vm->VAR(_vm->VAR_U32_ARRAY_UNK) = arg0; + return _vm->readArray(116, idx2, idx1); +} + +void LogicHE::putInArray(int arg0, int idx2, int idx1, int val) { + _vm->VAR(_vm->VAR_U32_ARRAY_UNK) = arg0; + _vm->writeArray(116, idx2, idx1, val); +} + +int32 LogicHE::dispatch(int op, int numArgs, int32 *args) { +#if 1 + char tmp[32], str[256]; + + if (numArgs > 0) + snprintf(tmp, 32, "%d", args[0]); + else + *tmp = 0; + + snprintf(str, 256, "LogicHE::dispatch(%d, %d, [%s", op, numArgs, tmp); + + for (int i = 1; i < numArgs; i++) { + snprintf(tmp, 32, ", %d", args[i]); + strncat(str, tmp, 256); + } + strncat(str, "])", 256); + + debug(0, str); +#else + // Used for parallel trace utility + for (int i = 0; i < numArgs; i++) + debug(0, "args[%d] = %d;", i, args[i]); + + debug(0, "dispatch(%d, %d, args);", op, numArgs); + +#endif + + return 1; +} + +/*********************** + * Putt-Putt Joins the Race + * + */ + +int LogicHErace::versionID() { + return 1; +} + +int32 LogicHErace::dispatch(int op, int numArgs, int32 *args) { + int32 res; + + switch (op) { + case 1003: + res = op_1003(args); + break; + + case 1004: + res = op_1004(args); + break; + + case 1100: + res = op_1100(args); + break; + + case 1101: + res = op_1101(args); + break; + + case 1102: + res = op_1102(args); + break; + + case 1103: + res = op_1103(args); + break; + + case 1110: + res = op_1110(); + break; + + case 1120: + res = op_1120(args); + break; + + case 1130: + res = op_1130(args); + break; + + case 1140: + res = op_1140(args); + break; + + default: + res = 0; + break; + + } + + return res; +} + +#define RAD2DEG (180 / PI) +#define DEG2RAD (PI / 180) + +int32 LogicHErace::op_1003(int32 *args) { + int value = args[2] ? args[2] : 1; + + writeScummVar(108, (int32)(atan2((double)args[0], (double)args[1]) * RAD2DEG * value)); + + return 1; +} + +int32 LogicHErace::op_1004(int32 *args) { + int value = args[1] ? args[1] : 1; + + writeScummVar(108, (int32)(sqrt((float)args[0]) * value)); + + return 1; +} + +int32 LogicHErace::op_1100(int32 *args) { + _userData[516] = (float)args[0] / args[10]; + _userData[517] = (float)args[1] / args[10]; + _userData[518] = (float)args[2] / args[10]; + _userData[519] = (float)args[3] / args[10]; + _userData[520] = (float)args[4] / args[10]; + + op_sub1(_userData[520]); + + _userData[521] = (float)args[5] / args[10]; + + op_sub2(_userData[521]); + + _userData[532] = (float)args[10]; + + _userData[524] = (float)args[8]; + _userData[525] = (float)args[9]; + _userData[522] = (float)args[6] / args[10]; + _userData[523] = (float)args[7] / args[10]; + _userData[526] = (float)args[6] / args[8] / args[10]; + _userData[527] = (float)args[7] / args[9] / args[10]; + + writeScummVar(108, (int32)((float)args[6] / args[8] * args[10])); + + writeScummVar(109, (int32)((float)args[7] / args[9] * args[10])); + + _userData[528] = (float)(_userData[519] - _userData[523] * 0.5); + _userData[529] = (float)(_userData[519] + _userData[523] * 0.5); + + writeScummVar(110, (int32)(_userData[528] * args[10])); + writeScummVar(111, (int32)(_userData[529] * args[10])); + + _userData[530] = (float)(_userData[517] / tan(_userData[529] * DEG2RAD)); + _userData[531] = (float)(_userData[517] / tan(_userData[528] * DEG2RAD)); + + writeScummVar(112, (int32)(_userData[530] * args[10])); + writeScummVar(113, (int32)(_userData[531] * args[10])); + + return 1; +} + +int32 LogicHErace::op_1101(int32 *args) { + int32 retval; + float temp; + + temp = args[0] / _userData[532]; + + if (_userData[519] == temp) { + retval = (int32)temp; + } else { + _userData[519] = temp; + op_sub3(temp); + retval = 1; + } + + temp = args[1] / _userData[532]; + + if (_userData[520] != temp) { + _userData[520] = temp; + op_sub1(temp); + retval = 1; + } + + temp = args[2] / _userData[532]; + + if (_userData[521] != temp) { + _userData[521] = temp; + op_sub2(temp); + retval = 1; + } + + return retval; +} + +int32 LogicHErace::op_1102(int32 *args) { + int32 retval; + float temp; + + temp = args[0] / _userData[532]; + if (_userData[516] != temp) { + _userData[516] = temp; + retval = 1; + } else { + retval = (int32)_userData[532]; + } + + temp = args[1] / _userData[532]; + if (_userData[517] != temp) { + _userData[517] = temp; + retval = 1; + } + + temp = args[2] / _userData[532]; + if (_userData[518] != temp) { + _userData[518] = temp; + retval = 1; + } + + return retval; +} + +int32 LogicHErace::op_1103(int32 *args) { + double angle = args[0] / args[1] * DEG2RAD; + + writeScummVar(108, (int32)(sin(angle) * args[2])); + writeScummVar(109, (int32)(cos(angle) * args[2])); + + return 1; +} + +int32 LogicHErace::op_1110() { + writeScummVar(108, (int32)(_userData[526] * _userData[532] * _userData[532])); + writeScummVar(109, (int32)(_userData[527] * _userData[532] * _userData[532])); + writeScummVar(110, (int32)(_userData[532])); + + return 1; +} + +int32 LogicHErace::op_1120(int32 *args) { + double a0, a1, a2, expr; + double res1, res2; + + a0 = args[0] / _userData[532] - _userData[516]; + a1 = args[1] / _userData[532] - _userData[517]; + a2 = args[2] / _userData[532] - _userData[518]; + + expr = a2 * _userDataD[17] + a1 * _userDataD[14] + a0 * _userDataD[11]; + + res1 = (atan2(a2 * _userDataD[15] + a1 * _userDataD[12] + a0 * _userDataD[9], expr) * RAD2DEG) + / _userData[526]; + res2 = (atan2(a2 * _userDataD[16] + a1 * _userDataD[13] + a0 * _userDataD[10], expr) * RAD2DEG + - _userData[528]) / _userData[527]; + + writeScummVar(108, (int32)res1); + writeScummVar(109, (int32)res2); + + return 1; +} + +int32 LogicHErace::op_1130(int32 *args) { + double cs = cos(args[0] / _userData[532] * DEG2RAD); + double sn = sin(args[0] / _userData[532] * DEG2RAD); + + writeScummVar(108, (int32)(cs * args[1] + sn * args[2])); + + writeScummVar(109, (int32)(cs * args[2] - sn * args[1])); + + return 1; +} + +int32 LogicHErace::op_1140(int32 *args) { + double arg2 = -args[2] * args[2]; + double arg3 = -args[3] * args[3]; + double sq = sqrt(arg2 + arg3); + double res; + + arg2 = arg2 / sq; + arg3 = arg3 / sq; + + res = (args[0] - 2 * (arg2 * args[0] + arg3 * args[1]) * arg2) * 0.86956525; + + writeScummVar(108, (int32)res); + + res = args[1] - 2 * (arg2 * args[0] + arg3 * args[1]) * arg3; + + if (-args[3] * args[3] >= 0) + res *= 0.83333331f; + + writeScummVar(109, (int32)res); + + return 1; +} + +void LogicHErace::op_sub1(float arg) { + _userDataD[10] = _userDataD[12] = _userDataD[14] = _userDataD[16] = 0; + _userDataD[13] = 1; + + _userDataD[9] = cos(arg * DEG2RAD); + _userDataD[15] = sin(arg * DEG2RAD); + _userDataD[11] = -_userDataD[15]; + _userDataD[17] = _userDataD[9]; +} + +void LogicHErace::op_sub2(float arg) { + _userDataD[20] = _userDataD[21] = _userDataD[24] = _userDataD[25] = 0; + _userDataD[26] = 1; + + _userDataD[19] = sin(arg * DEG2RAD); + _userDataD[18] = cos(arg * DEG2RAD); + _userDataD[21] = -_userDataD[19]; + _userDataD[22] = _userDataD[18]; +} + +void LogicHErace::op_sub3(float arg) { + _userDataD[1] = _userDataD[2] = _userDataD[3] = _userDataD[6] = 0; + _userDataD[0] = 1; + + _userDataD[4] = cos(arg * DEG2RAD); + _userDataD[5] = sin(arg * DEG2RAD); + _userDataD[7] = -_userDataD[5]; + _userDataD[8] = _userDataD[4]; +} + +/*********************** + * Freddi Fish's One-Stop Fun Shop + * Pajama Sam's One-Stop Fun Shop + * Putt-Putt's One-Stop Fun Shop + * + */ + +int LogicHEfunshop::versionID() { + return 1; +} + +int32 LogicHEfunshop::dispatch(int op, int numArgs, int32 *args) { + switch (op) { + case 1004: + op_1004(args); + break; + + case 1005: + op_1005(args); + break; + + default: + break; + + } + + return 0; +} + +void LogicHEfunshop::op_1004(int32 *args) { + double data[8], at, sq; + int32 x, y; + int i=0; + + for (i = 0; i <= 6; i += 2) { + data[i] = getFromArray(args[0], 0, 519 + i); + data[i + 1] = getFromArray(args[0], 0, 519 + i + 1); + } + int s = checkShape((int32)data[0], (int32)data[1], (int32)data[4], (int32)data[5], + (int32)data[2], (int32)data[3], (int32)data[6], (int32)data[7], &x, &y); + + if (s != 1) { + error("LogicHEfunshop::op_1004: Your shape has defied the laws of physics\n"); + return; + } + + for (i = 0; i <= 6; i += 2) { + data[i] -= (double)x; + data[i + 1] -= (double)y; + } + + double a1 = (double)args[1] * DEG2RAD; + + for (i = 0; i <= 6; i += 2) { + at = atan2(data[i + 1], data[i]); + sq = sqrt(data[i + 1] * data[i + 1] + data[i] * data[i]); + + if (at <= 0) + at += 2 * PI; + + data[i] = cos(at + a1) * sq; + data[i + 1] = sin(at + a1) * sq; + } + + int minx = 2; + int miny = 3; + + for (i = 0; i <= 6; i += 2) { + if (data[i] < data[minx]) + minx = i; + if (data[i + 1] < data[miny]) + miny = i + 1; + } + + for (i = 0; i <= 6; i += 2) { + data[i] -= data[minx]; + data[i + 1] -= data[miny]; + + putInArray(args[0], 0, 519 + i, scumm_round(data[i])); + putInArray(args[0], 0, 519 + i + 1, scumm_round(data[i + 1])); + } +} + +void LogicHEfunshop::op_1005(int32 *args) { + double data[8]; + double args1, args2; + int i=0; + for (i = 520; i <= 526; i += 2) { + data[i - 520] = getFromArray(args[0], 0, i - 1); + data[i - 520 + 1] = getFromArray(args[0], 0, i); + } + + args1 = args[1] * 0.01 + 1; + args2 = args[2] * 0.01 + 1; + + for (i = 0; i < 4; i++) { + data[2 * i] *= args1; + data[2 * i + 1] *= args2; + } + + for (i = 520; i <= 526; i += 2) { + putInArray(args[0], 0, i - 1, scumm_round(data[i - 520])); + putInArray(args[0], 0, i, scumm_round(data[i - 520 + 1])); + } +} + +int LogicHEfunshop::checkShape(int32 data0, int32 data1, int32 data4, int32 data5, int32 data2, int32 data3, int32 data6, int32 data7, int32 *x, int32 *y) { + int32 diff5_1, diff0_4, diff7_3, diff2_6; + int32 diff1, diff2; + int32 delta, delta2; + int32 sum1, sum2; + + diff0_4 = data0 - data4; + diff5_1 = data5 - data1; + diff1 = data1 * data4 - data0 * data5; + sum1 = diff0_4 * data3 + diff1 + diff5_1 * data2; + sum2 = diff0_4 * data7 + diff1 + diff5_1 * data6; + + if (sum1 != 0 && sum2 != 0) { + sum2 ^= sum1; + + if (sum2 >= 0) + return 0; + } + + diff2_6 = data2 - data6; + diff7_3 = data7 - data3; + diff2 = data3 * data6 - data2 * data7; + sum1 = diff2_6 * data1 + diff2 + diff7_3 * data0; + sum2 = diff2_6 * data5 + diff2 + diff7_3 * data4;; + + if (sum1 != 0 && sum2 != 0) { + sum2 ^= sum1; + + if (sum2 >= 0) + return 0; + } + + delta = diff2_6 * diff5_1 - diff0_4 * diff7_3; + + if (delta == 0) { + return 2; + } + + if (delta < 0) { + data7 = -((delta + 1) >> 1); + } else { + data7 = delta >> 1; + } + + delta2 = diff2 * diff0_4 - diff1 * diff2_6; + + if (delta2 < 0) { + delta2 -= data7; + } else { + delta2 += data7; + } + + *x = delta2 / delta; + + delta2 = diff1 * diff7_3 - diff2 * diff5_1; + + if (delta2 < 0) { + delta2 -= data7; + } else { + delta2 += data7; + } + + *y = delta2 / delta; + + return 1; +} + +/*********************** + * Backyard Football + * Backyard Football Demo + * + */ + +int LogicHEfootball::versionID() { + return 1; +} + +int32 LogicHEfootball::dispatch(int op, int numArgs, int32 *args) { + int res = 0; + + switch (op) { + case 1004: + res = op_1004(args); + break; + + case 1006: + res = op_1006(args); + break; + + case 1007: + res = op_1007(args); + break; + + case 1010: + res = op_1010(args); + break; + + case 1022: + res = op_1022(args); + break; + + case 1023: + res = op_1023(args); + break; + + case 1024: + res = op_1024(args); + break; + + case 8221968: + // Someone had a fun and used his birthday as opcode number + res = getFromArray(args[0], args[1], args[2]); + break; + + case 1492: case 1493: case 1494: case 1495: case 1496: + case 1497: case 1498: case 1499: case 1500: case 1501: + case 1502: case 1503: case 1504: case 1505: case 1506: + case 1507: case 1508: case 1509: case 1510: case 1511: + case 1512: case 1513: case 1514: case 1555: + // DirectPlay-related + // 1513: initialize + // 1555: set fake lag + break; + + case 2200: case 2201: case 2202: case 2203: case 2204: + case 2205: case 2206: case 2207: case 2208: case 2209: + case 2210: case 2211: case 2212: case 2213: case 2214: + case 2215: case 2216: case 2217: case 2218: case 2219: + case 2220: case 2221: case 2222: case 2223: case 2224: + case 2225: case 2226: case 2227: case 2228: + // Boneyards-related + break; + + case 3000: case 3001: case 3002: case 3003: case 3004: + // Internet-related + // 3000: check for updates + // 3001: check network status + // 3002: autoupdate + // 3003: close connection + break; + + default: + LogicHE::dispatch(op, numArgs, args); + error("Tell sev how to reproduce it"); + } + + return res; +} + +int LogicHEfootball::op_1004(int32 *args) { + double res, a2, a4, a5; + + a5 = ((double)args[4] - (double)args[1]) / ((double)args[5] - (double)args[2]); + a4 = ((double)args[3] - (double)args[0]) / ((double)args[5] - (double)args[2]); + a2 = (double)args[2] - (double)args[0] * a4 - args[1] * a5; + + res = (double)args[6] * a4 + (double)args[7] * a5 + a2; + writeScummVar(108, (int32)res); + + writeScummVar(109, (int32)a2); + writeScummVar(110, (int32)a5); + writeScummVar(111, (int32)a4); + + return 1; +} + +int LogicHEfootball::op_1006(int32 *args) { + double res; + + res = (1.0 - args[1] * 2.9411764e-4 * 5.3050399e-2) * args[0] * 1.2360656e-1 + + args[1] * 1.1764706e-2 + 46; + writeScummVar(108, (int32)res); + + res = 640.0 - args[2] * 1.2360656e-1 - args[1] * 1.1588235e-1 - 26; + writeScummVar(109, (int32)res); + + return 1; +} + +int LogicHEfootball::op_1007(int32 *args) { + double res, temp; + + temp = (double)args[1] * 0.32; + + if (temp > 304.0) + res = -args[2] * 0.142; + else + res = args[2] * 0.142; + + res += temp; + + writeScummVar(108, (int32)res); + + res = (1000.0 - args[2]) * 0.48; + + writeScummVar(109, (int32)res); + + return 1; +} + +int LogicHEfootball::op_1010(int32 *args) { + double a1 = (640.0 - (double)args[1] - 26.0) * 8.6294413; + double res; + + res = ((double)args[0] - 46 - a1 * 1.1764706e-2) / + ((1.0 - a1 * 2.9411764e-4 * 5.3050399e-2) * 1.2360656e-1); + writeScummVar(108, (int32)res); + + writeScummVar(109, (int32)a1); + + return 1; +} + +int LogicHEfootball::op_1022(int32 *args) { + double res; + double var10 = args[4] - args[1]; + double var8 = args[5] - args[2]; + double var6 = args[3] - args[0]; + + res = sqrt(var8 * var8 + var6 * var6 + var10 * var10); + + if (res >= (double)args[6]) { + var8 = (double)args[6] * var8 / res; + var10 = (double)args[6] * var10 / res; + res = (double)args[6] * var6 / res; + } + + writeScummVar(108, (int32)res); + writeScummVar(109, (int32)var10); + writeScummVar(110, (int32)var8); + + return 1; +} + +int LogicHEfootball::op_1023(int32 *args) { + double var10, var18, var20, var28, var30, var30_; + double argf[7]; + + for (int i = 0; i < 7; i++) + argf[i] = args[i]; + + var10 = (argf[3] - argf[1]) / (argf[2] - argf[0]); + var28 = var10 * var10 + 1; + var20 = argf[0] * var10; + var18 = (argf[5] + argf[1] + var20) * argf[4] * var10 * 2 + + argf[6] * argf[6] * var28 + argf[4] * argf[4] - + argf[0] * argf[0] * var10 * var10 - + argf[5] * argf[0] * var10 * 2 - + argf[5] * argf[1] * 2 - + argf[1] * argf[1] - argf[5] * argf[5]; + + if (var18 >= 0) { + var18 = sqrt(var18); + + var30_ = argf[4] + argf[5] * var10 + argf[1] * var10 + argf[0] * var10 * var10; + var30 = (var30_ - var18) / var28; + var18 = (var30_ + var18) / var28; + + if ((argf[0] - var30 < 0) && (argf[0] - var18 < 0)) { + var30_ = var30; + var30 = var18; + var18 = var30_; + } + var28 = var18 * var10 - var20 - argf[1]; + var20 = var30 * var10 - var20 - argf[1]; + } else { + var18 = 0; + var20 = 0; + var28 = 0; + var30 = 0; + } + + writeScummVar(108, (int32)var18); + writeScummVar(109, (int32)var28); + writeScummVar(110, (int32)var30); + writeScummVar(111, (int32)var20); + + return 1; +} +int LogicHEfootball::op_1024(int32 *args) { + writeScummVar(108, 0); + writeScummVar(109, 0); + writeScummVar(110, 0); + writeScummVar(111, 0); + + return 1; +} + + +/*********************** + * Backyard Soccer + * + */ + +int LogicHEsoccer::versionID() { + return 1; +} + +int32 LogicHEsoccer::dispatch(int op, int numArgs, int32 *args) { + int res = 0; + + switch (op) { + case 1001: + res = op_1001(args); + break; + + case 1002: + res = op_1002(args); + break; + + case 1004: + res = op_1004(args); + break; + + case 8221968: + // Someone had a fun and used his birthday as opcode number + res = getFromArray(args[0], args[1], args[2]); + break; + + default: + // original range is 1001 - 1021 + LogicHE::dispatch(op, numArgs, args); + warning("Tell sev how to reproduce it"); + } + + return res; +} + +int LogicHEsoccer::op_1001(int32 *args) { + return args[0] * sin(args[1]); +} + +int LogicHEsoccer::op_1002(int32 *args) { + return _vm->VAR(2) * args[0]; +} + +int LogicHEsoccer::op_1004(int32 *args) { + double res, a2, a4, a5; + + a5 = ((double)args[4] - (double)args[1]) / ((double)args[5] - (double)args[2]); + a4 = ((double)args[3] - (double)args[0]) / ((double)args[5] - (double)args[2]); + a2 = (double)args[2] - (double)args[0] * a4 - args[1] * a5; + + res = (double)args[6] * a4 + (double)args[7] * a5 + a2; + writeScummVar(108, (int32)res); + + writeScummVar(109, (int32)a2); + writeScummVar(110, (int32)a5); + writeScummVar(111, (int32)a4); + + return 1; +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/logic_he.h b/engines/scumm/he/logic_he.h new file mode 100644 index 0000000000..59476f2e3b --- /dev/null +++ b/engines/scumm/he/logic_he.h @@ -0,0 +1,124 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#if !defined(LOGIC_HE_H) && !defined(DISABLE_HE) +#define LOGIC_HE_H + +#include "common/stdafx.h" + +namespace Scumm { + +class ScummEngine_v90he; + +class LogicHE { +public: + float *_userData; + double *_userDataD; + ScummEngine_v90he *_vm; + + LogicHE(ScummEngine_v90he *vm); + virtual ~LogicHE(); + + void writeScummVar(int var, int32 value); + int getFromArray(int arg0, int idx2, int idx1); + void putInArray(int arg0, int idx2, int idx1, int val); + + void beforeBootScript(void) {}; + void initOnce() {}; + void startOfFrame() {}; + void endOfFrame() {}; + void processKeyStroke(int keyPressed) {}; + + virtual int versionID(); + virtual int32 dispatch(int op, int numArgs, int32 *args); +}; + +class LogicHErace : public LogicHE { +public: + LogicHErace(ScummEngine_v90he *vm) : LogicHE(vm) {} + + int versionID(); + int32 dispatch(int op, int numArgs, int32 *args); + +private: + int32 op_1003(int32 *args); + int32 op_1004(int32 *args); + int32 op_1100(int32 *args); + int32 op_1101(int32 *args); + int32 op_1102(int32 *args); + int32 op_1103(int32 *args); + int32 op_1110(); + int32 op_1120(int32 *args); + int32 op_1130(int32 *args); + int32 op_1140(int32 *args); + + void op_sub1(float arg); + void op_sub2(float arg); + void op_sub3(float arg); +}; + +class LogicHEfunshop : public LogicHE { +public: + LogicHEfunshop(ScummEngine_v90he *vm) : LogicHE(vm) {} + + int versionID(); + int32 dispatch(int op, int numArgs, int32 *args); + +private: + void op_1004(int32 *args); + void op_1005(int32 *args); + int checkShape(int32 data0, int32 data1, int32 data4, int32 data5, int32 data2, int32 data3, int32 data6, int32 data7, int32 *x, int32 *y); +}; + +class LogicHEfootball : public LogicHE { +public: + LogicHEfootball(ScummEngine_v90he *vm) : LogicHE(vm) {} + + int versionID(); + int32 dispatch(int op, int numArgs, int32 *args); + +private: + int op_1004(int32 *args); + int op_1006(int32 *args); + int op_1007(int32 *args); + int op_1010(int32 *args); + int op_1022(int32 *args); + int op_1023(int32 *args); + int op_1024(int32 *args); +}; + +class LogicHEsoccer : public LogicHE { +public: + LogicHEsoccer(ScummEngine_v90he *vm) : LogicHE(vm) {} + + int versionID(); + int32 dispatch(int op, int numArgs, int32 *args); + +private: + int op_1001(int32 *args); + int op_1002(int32 *args); + int op_1004(int32 *args); +}; + +} // End of namespace Scumm + +#endif diff --git a/engines/scumm/he/palette_he.cpp b/engines/scumm/he/palette_he.cpp new file mode 100644 index 0000000000..85df92cdb7 --- /dev/null +++ b/engines/scumm/he/palette_he.cpp @@ -0,0 +1,317 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "common/system.h" +#include "scumm/scumm.h" +#include "scumm/he/intern_he.h" +#include "scumm/resource.h" +#include "scumm/util.h" + +namespace Scumm { + +void ScummEngine_v70he::remapHEPalette(const uint8 *src, uint8 *dst) { + int r, g, b, sum, bestitem, bestsum; + int ar, ag, ab; + uint8 *palPtr; + src += 30; + + if (_heversion >= 99) { + palPtr = _hePalettes + 1024 + 30; + } else { + palPtr = _currentPalette + 30; + } + + for (int j = 10; j < 246; j++) { + bestitem = 0xFFFF; + bestsum = 0xFFFF; + + r = *src++; + g = *src++; + b = *src++; + + uint8 *curPal = palPtr; + + for (int k = 10; k < 246; k++) { + ar = r - *curPal++; + ag = g - *curPal++; + ab = b - *curPal++; + + sum = (ar * ar) + (ag * ag) + (ab * ab); + + if (bestitem == 0xFFFF || sum <= bestsum) { + bestitem = k; + bestsum = sum; + } + } + + dst[j] = bestitem; + } +} + +uint8 *ScummEngine_v90he::getHEPaletteIndex(int palSlot) { + if (palSlot) { + assert(palSlot >= 1 && palSlot <= _numPalettes); + return _hePalettes + palSlot * 1024; + } else { + return _hePalettes + 1024; + } +} + +int ScummEngine_v90he::getHEPaletteSimilarColor(int palSlot, int red, int green, int start, int end) { + checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); + checkRange(255, 0, start, "Invalid palette slot %d"); + checkRange(255, 0, end, "Invalid palette slot %d"); + + uint8 *pal = _hePalettes + palSlot * 1024 + start * 3; + + int bestsum = 0xFFFFFFFF; + int bestitem = start; + + for (int i = start; i <= end; i++) { + int dr = red - pal[0]; + int dg = green - pal[1]; + int sum = dr * dr + dg * dg * 2; + if (sum == 0) { + return i; + } + if (sum < bestsum) { + bestsum = sum; + bestitem = i; + } + pal += 3; + } + return bestitem; +} + +int ScummEngine_v90he::getHEPaletteColorComponent(int palSlot, int color, int component) { + checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); + checkRange(255, 0, color, "Invalid palette slot %d"); + + return _hePalettes[palSlot * 1024 + color * 3 + component % 3]; +} + +int ScummEngine_v90he::getHEPaletteColor(int palSlot, int color) { + checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); + checkRange(255, 0, color, "Invalid palette slot %d"); + + return _hePalettes[palSlot * 1024 + 768 + color]; +} + +void ScummEngine_v90he::setHEPaletteColor(int palSlot, uint8 color, uint8 r, uint8 g, uint8 b) { + debug(7, "setHEPaletteColor(%d, %d, %d, %d, %d)", palSlot, color, r, g, b); + checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); + uint8 *p = _hePalettes + palSlot * 1024 + color * 3; + *(p + 0) = r; + *(p + 1) = g; + *(p + 2) = b; + _hePalettes[palSlot * 1024 + 768 + color] = color; +} + +void ScummEngine_v90he::setHEPaletteFromPtr(int palSlot, const uint8 *palData) { + checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); + uint8 *pc = _hePalettes + palSlot * 1024; + uint8 *pi = pc + 768; + for (int i = 0; i < 256; ++i) { + *pc++ = *palData++; + *pc++ = *palData++; + *pc++ = *palData++; + *pi++ = i; + } +} + +void ScummEngine_v90he::setHEPaletteFromCostume(int palSlot, int resId) { + debug(7, "setHEPaletteFromCostume(%d, %d)", palSlot, resId); + checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); + const uint8 *data = getResourceAddress(rtCostume, resId); + assert(data); + const uint8 *rgbs = findResourceData(MKID('RGBS'), data); + assert(rgbs); + setHEPaletteFromPtr(palSlot, rgbs); +} + +void ScummEngine_v90he::setHEPaletteFromImage(int palSlot, int resId, int state) { + debug(7, "setHEPaletteFromImage(%d, %d, %d)", palSlot, resId, state); + checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); + uint8 *data = getResourceAddress(rtImage, resId); + assert(data); + const uint8 *rgbs = findWrappedBlock(MKID('RGBS'), data, state, 0); + assert(rgbs); + setHEPaletteFromPtr(palSlot, rgbs); +} + +void ScummEngine_v90he::setHEPaletteFromRoom(int palSlot, int resId, int state) { + debug(7, "setHEPaletteFromRoom(%d, %d, %d)", palSlot, resId, state); + checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); + const uint8 *data = getResourceAddress(rtRoom, resId); + assert(data); + const uint8 *pals = findResourceData(MKID('PALS'), data); + assert(pals); + const uint8 *rgbs = findPalInPals(pals, state); + assert(rgbs); + setHEPaletteFromPtr(palSlot, rgbs); +} + +void ScummEngine_v90he::restoreHEPalette(int palSlot) { + debug(7, "restoreHEPalette(%d)", palSlot); + checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); + if (palSlot != 1) { + memcpy(_hePalettes + palSlot * 1024, _hePalettes + 1024, 1024); + } +} + +void ScummEngine_v90he::copyHEPalette(int dstPalSlot, int srcPalSlot) { + debug(7, "copyHEPalette(%d, %d)", dstPalSlot, srcPalSlot); + assert(dstPalSlot >= 1 && dstPalSlot <= _numPalettes); + assert(srcPalSlot >= 1 && srcPalSlot <= _numPalettes); + if (dstPalSlot != srcPalSlot) { + memcpy(_hePalettes + dstPalSlot * 1024, _hePalettes + srcPalSlot * 1024, 1024); + } +} + +void ScummEngine_v90he::copyHEPaletteColor(int palSlot, uint8 dstColor, uint8 srcColor) { + debug(7, "copyHEPaletteColor(%d, %d, %d)", palSlot, dstColor, srcColor); + checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); + uint8 *dstPal = _hePalettes + palSlot * 1024 + dstColor * 3; + uint8 *srcPal = _hePalettes + 1024 + srcColor * 3; + memcpy(dstPal, srcPal, 3); + _hePalettes[palSlot * 1024 + 768 + dstColor] = srcColor; +} + +void ScummEngine_v99he::setPaletteFromPtr(const byte *ptr, int numcolor) { + int i; + byte *dest, r, g, b; + + if (numcolor < 0) { + numcolor = getResourceDataSize(ptr) / 3; + } + + checkRange(256, 0, numcolor, "Too many colors (%d) in Palette"); + + dest = _hePalettes + 1024; + + for (i = 0; i < numcolor; i++) { + r = *ptr++; + g = *ptr++; + b = *ptr++; + + if (i == 15 || r < 252 || g < 252 || b < 252) { + *dest++ = r; + *dest++ = g; + *dest++ = b; + _hePalettes[1792 + i] = i; + } else { + dest += 3; + } + } + + memcpy(_hePalettes, _hePalettes + 1024, 768); + + for (i = 0; i < 10; ++i) + _hePalettes[1792 + i] = i; + for (i = 246; i < 256; ++i) + _hePalettes[1792 + i] = i; + + setDirtyColors(0, numcolor - 1); +} + +void ScummEngine_v99he::darkenPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor) { + uint8 *src, *dst; + int color, j; + + src = _hePalettes + startColor * 3; + dst = _hePalettes + 1024 + startColor * 3; + for (j = startColor; j <= endColor; j++) { + color = *src++; + color = color * redScale / 0xFF; + if (color > 255) + color = 255; + *dst++ = color; + + color = *src++; + color = color * greenScale / 0xFF; + if (color > 255) + color = 255; + *dst++ = color; + + color = *src++; + color = color * blueScale / 0xFF; + if (color > 255) + color = 255; + *dst++ = color; + + _hePalettes[1792 + j] = j; + setDirtyColors(j, endColor); + } +} + +void ScummEngine_v99he::copyPalColor(int dst, int src) { + byte *dp, *sp; + + if ((uint) dst >= 256 || (uint) src >= 256) + error("copyPalColor: invalid values, %d, %d", dst, src); + + dp = &_hePalettes[1024 + dst * 3]; + sp = &_hePalettes[1024 + src * 3]; + + dp[0] = sp[0]; + dp[1] = sp[1]; + dp[2] = sp[2]; + _hePalettes[1792 + dst] = dst; + + setDirtyColors(dst, dst); +} + +void ScummEngine_v99he::setPalColor(int idx, int r, int g, int b) { + _hePalettes[1024 + idx * 3 + 0] = r; + _hePalettes[1024 + idx * 3 + 1] = g; + _hePalettes[1024 + idx * 3 + 2] = b; + _hePalettes[1792 + idx] = idx; + setDirtyColors(idx, idx); +} + +void ScummEngine_v99he::updatePalette() { + if (_palDirtyMax == -1) + return; + + int num = _palDirtyMax - _palDirtyMin + 1; + int i; + + byte palette_colors[1024]; + byte *p = palette_colors; + + for (i = _palDirtyMin; i <= _palDirtyMax; i++) { + byte *data = _hePalettes + 1024 + i * 3; + + *p++ = data[0]; + *p++ = data[1]; + *p++ = data[2]; + *p++ = 0; + } + + _system->setPalette(palette_colors, _palDirtyMin, num); + + _palDirtyMax = -1; + _palDirtyMin = 256; +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/resource_v7he.cpp b/engines/scumm/he/resource_v7he.cpp new file mode 100644 index 0000000000..95c3c23f2b --- /dev/null +++ b/engines/scumm/he/resource_v7he.cpp @@ -0,0 +1,1912 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004-2006 The ScummVM project + * + * Parts of code heavily based on: + * icoutils - A set of programs dealing with MS Windows icons and cursors. + * Copyright (C) 1998-2001 Oskar Liljeblad + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "scumm/scumm.h" +#include "scumm/he/intern_he.h" +#include "scumm/resource.h" +#include "scumm/he/resource_v7he.h" +#include "scumm/sound.h" +#include "scumm/util.h" +#include "sound/wave.h" + +#include "common/stream.h" +#include "common/system.h" + +namespace Scumm { + +ResExtractor::ResExtractor(ScummEngine_v70he *scumm) + : _vm(scumm) { + + _fileName[0] = 0; + memset(_cursorCache, 0, sizeof(_cursorCache)); +} + +ResExtractor::~ResExtractor() { + for (int i = 0; i < MAX_CACHED_CURSORS; ++i) { + CachedCursor *cc = &_cursorCache[i]; + if (cc->valid) { + free(cc->bitmap); + free(cc->palette); + } + } + memset(_cursorCache, 0, sizeof(_cursorCache)); +} + +ResExtractor::CachedCursor *ResExtractor::findCachedCursor(int id) { + for (int i = 0; i < MAX_CACHED_CURSORS; ++i) { + CachedCursor *cc = &_cursorCache[i]; + if (cc->valid && cc->id == id) { + return cc; + } + } + return NULL; +} + +ResExtractor::CachedCursor *ResExtractor::getCachedCursorSlot() { + uint32 min_last_used = 0; + CachedCursor *r = NULL; + for (int i = 0; i < MAX_CACHED_CURSORS; ++i) { + CachedCursor *cc = &_cursorCache[i]; + if (!cc->valid) { + return cc; + } else { + if (min_last_used == 0 || cc->last_used < min_last_used) { + min_last_used = cc->last_used; + r = cc; + } + } + } + assert(r); + free(r->bitmap); + free(r->palette); + memset(r, 0, sizeof(CachedCursor)); + return r; +} + +void ResExtractor::setCursor(int id) { + byte *cursorRes = 0; + int cursorsize; + int keycolor = 0; + CachedCursor *cc = findCachedCursor(id); + if (cc != NULL) { + debug(7, "Found cursor %d in cache slot %d", id, cc - _cursorCache); + } else { + cc = getCachedCursorSlot(); + assert(cc && !cc->valid); + cursorsize = extractResource(id, &cursorRes); + convertIcons(cursorRes, cursorsize, &cc->bitmap, &cc->w, &cc->h, &cc->hotspot_x, &cc->hotspot_y, &keycolor, &cc->palette, &cc->palSize); + debug(7, "Adding cursor %d to cache slot %d", id, cc - _cursorCache); + free(cursorRes); + cc->valid = true; + cc->id = id; + cc->last_used = g_system->getMillis(); + } + + if (_vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette) && cc->palette) + _vm->_system->setCursorPalette(cc->palette, 0, cc->palSize); + + _vm->setCursorHotspot(cc->hotspot_x, cc->hotspot_y); + _vm->setCursorFromBuffer(cc->bitmap, cc->w, cc->h, cc->w); +} + + +/* + * Static variables + */ +const char *res_types[] = { + /* 0x01: */ + "cursor", "bitmap", "icon", "menu", "dialog", "string", + "fontdir", "font", "accelerator", "rcdata", "messagelist", + "group_cursor", NULL, "group_icon", NULL, + /* the following are not defined in winbase.h, but found in wrc. */ + /* 0x10: */ + "version", "dlginclude", NULL, "plugplay", "vxd", + "anicursor", "aniicon" +}; +#define RES_TYPE_COUNT (sizeof(res_types)/sizeof(char *)) + +Win32ResExtractor::Win32ResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) { +} + +int Win32ResExtractor::extractResource(int resId, byte **data) { + char buf[20]; + + snprintf(buf, sizeof(buf), "%d", resId); + + return extractResource_("group_cursor", buf, data); +} + +int Win32ResExtractor::extractResource_(const char *resType, char *resName, byte **data) { + char *arg_language = NULL; + const char *arg_type = resType; + char *arg_name = resName; + int arg_action = ACTION_LIST; + int ressize = 0; + + _arg_raw = false; + + /* translate --type option from resource type string to integer */ + arg_type = res_type_string_to_id(arg_type); + + WinLibrary fi; + + /* initiate stuff */ + fi.memory = NULL; + fi.file = new Common::File; + + if (!_fileName[0]) { // We are running for the first time + snprintf(_fileName, 256, "%s.he3", _vm->getBaseName()); + + if (_vm->_substResFileNameIndex > 0) { + char buf1[128]; + + _vm->generateSubstResFileName(_fileName, buf1, sizeof(buf1)); + strcpy(_fileName, buf1); + } + } + + + /* get file size */ + fi.file->open(_fileName); + if (!fi.file->isOpen()) { + error("Cannot open file %s", _fileName); + } + + fi.total_size = fi.file->size(); + if (fi.total_size == -1) { + error("Cannot get size of file %s", fi.file->name()); + goto cleanup; + } + if (fi.total_size == 0) { + error("%s: file has a size of 0", fi.file->name()); + goto cleanup; + } + + /* read all of file */ + fi.memory = (byte *)malloc(fi.total_size); + if (fi.file->read(fi.memory, fi.total_size) == 0) { + error("Cannot read from file %s", fi.file->name()); + goto cleanup; + } + + /* identify file and find resource table */ + if (!read_library(&fi)) { + /* error reported by read_library */ + goto cleanup; + } + + // verbose_printf("file is a %s\n", + // fi.is_PE_binary ? "Windows NT `PE' binary" : "Windows 3.1 `NE' binary"); + + /* errors will be printed by the callback */ + ressize = do_resources(&fi, arg_type, arg_name, arg_language, arg_action, data); + + /* free stuff and close file */ + cleanup: + if (fi.file != NULL) + fi.file->close(); + if (fi.memory != NULL) + free(fi.memory); + + return ressize; +} + + +/* res_type_id_to_string: + * Translate a numeric resource type to it's corresponding string type. + * (For informative-ness.) + */ +const char *Win32ResExtractor::res_type_id_to_string(int id) { + if (id == 241) + return "toolbar"; + if (id > 0 && id <= (int)RES_TYPE_COUNT) + return res_types[id-1]; + return NULL; +} + +/* res_type_string_to_id: + * Translate a resource type string to integer. + * (Used to convert the --type option.) + */ +const char *Win32ResExtractor::res_type_string_to_id(const char *type) { + static const char *res_type_ids[] = { + "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9", "-10", + "-11", "-12", NULL, "-14", NULL, "-16", "-17", NULL, "-19", + "-20", "-21", "-22" + }; + int c; + + if (type == NULL) + return NULL; + + for (c = 0 ; c < (int)RES_TYPE_COUNT ; c++) { + if (res_types[c] != NULL && !scumm_stricmp(type, res_types[c])) + return res_type_ids[c]; + } + + return type; +} + +int Win32ResExtractor::extract_resources(WinLibrary *fi, WinResource *wr, + WinResource *type_wr, WinResource *name_wr, + WinResource *lang_wr, byte **data) { + int size; + bool free_it; + const char *type; + int32 id; + + if (*data) { + error("Win32ResExtractor::extract_resources() more than one cursor"); + return 0; + } + + *data = extract_resource(fi, wr, &size, &free_it, type_wr->id, (lang_wr == NULL ? NULL : lang_wr->id), _arg_raw); + + if (data == NULL) { + error("Win32ResExtractor::extract_resources() problem with resource extraction"); + return 0; + } + + /* get named resource type if possible */ + type = NULL; + if ((id = strtol(type_wr->id, 0, 10)) != 0) + type = res_type_id_to_string(id); + + debugC(DEBUG_RESOURCE, "extractCursor(). Found cursor name: %s%s%s [size=%d]", + get_resource_id_quoted(name_wr), + (lang_wr->id[0] != '\0' ? " language: " : ""), + get_resource_id_quoted(lang_wr), size); + + return size; +} + +/* extract_resource: + * Extract a resource, returning pointer to data. + */ +byte *Win32ResExtractor::extract_resource(WinLibrary *fi, WinResource *wr, int *size, + bool *free_it, char *type, char *lang, bool raw) { + char *str; + int32 intval; + + /* just return pointer to data if raw */ + if (raw) { + *free_it = false; + /* get_resource_entry will print possible error */ + return get_resource_entry(fi, wr, size); + } + + /* find out how to extract */ + str = type; + if (str != NULL && (intval = strtol(STRIP_RES_ID_FORMAT(str), 0, 10))) { + if (intval == (int)RT_GROUP_ICON) { + *free_it = true; + return extract_group_icon_cursor_resource(fi, wr, lang, size, true); + } + if (intval == (int)RT_GROUP_CURSOR) { + *free_it = true; + return extract_group_icon_cursor_resource(fi, wr, lang, size, false); + } + } + + return NULL; +} + +/* extract_group_icon_resource: + * Create a complete RT_GROUP_ICON resource, that can be written to + * an `.ico' file without modifications. Returns an allocated + * memory block that should be freed with free() once used. + * + * `root' is the offset in file that specifies the resource. + * `base' is the offset that string pointers are calculated from. + * `ressize' should point to an integer variable where the size of + * the returned memory block will be placed. + * `is_icon' indicates whether resource to be extracted is icon + * or cursor group. + */ +byte *Win32ResExtractor::extract_group_icon_cursor_resource(WinLibrary *fi, WinResource *wr, char *lang, + int *ressize, bool is_icon) { + Win32CursorIconDir *icondir; + Win32CursorIconFileDir *fileicondir; + byte *memory; + int c, offset, skipped; + int size; + + /* get resource data and size */ + icondir = (Win32CursorIconDir *)get_resource_entry(fi, wr, &size); + if (icondir == NULL) { + /* get_resource_entry will print error */ + return NULL; + } + + /* calculate total size of output file */ + RETURN_IF_BAD_POINTER(NULL, icondir->count); + skipped = 0; + for (c = 0 ; c < icondir->count ; c++) { + int level; + int iconsize; + char name[14]; + WinResource *fwr; + + RETURN_IF_BAD_POINTER(NULL, icondir->entries[c]); + /*printf("%d. bytes_in_res=%d width=%d height=%d planes=%d bit_count=%d\n", c, + icondir->entries[c].bytes_in_res, + (is_icon ? icondir->entries[c].res_info.icon.width : icondir->entries[c].res_info.cursor.width), + (is_icon ? icondir->entries[c].res_info.icon.height : icondir->entries[c].res_info.cursor.height), + icondir->entries[c].plane_count, + icondir->entries[c].bit_count);*/ + + /* find the corresponding icon resource */ + snprintf(name, sizeof(name)/sizeof(char), "-%d", icondir->entries[c].res_id); + fwr = find_resource(fi, (is_icon ? "-3" : "-1"), name, lang, &level); + if (fwr == NULL) { + error("%s: could not find `%s' in `%s' resource.", + fi->file->name(), &name[1], (is_icon ? "group_icon" : "group_cursor")); + return NULL; + } + + if (get_resource_entry(fi, fwr, &iconsize) != NULL) { + if (iconsize == 0) { + debugC(DEBUG_RESOURCE, "%s: icon resource `%s' is empty, skipping", fi->file->name(), name); + skipped++; + continue; + } + if ((uint32)iconsize != icondir->entries[c].bytes_in_res) { + debugC(DEBUG_RESOURCE, "%s: mismatch of size in icon resource `%s' and group (%d != %d)", + fi->file->name(), name, iconsize, icondir->entries[c].bytes_in_res); + } + size += iconsize; /* size += icondir->entries[c].bytes_in_res; */ + + /* cursor resources have two additional WORDs that contain + * hotspot info */ + if (!is_icon) + size -= sizeof(uint16)*2; + } + } + offset = sizeof(Win32CursorIconFileDir) + (icondir->count-skipped) * sizeof(Win32CursorIconFileDirEntry); + size += offset; + *ressize = size; + + /* allocate that much memory */ + memory = (byte *)malloc(size); + fileicondir = (Win32CursorIconFileDir *)memory; + + /* transfer Win32CursorIconDir structure members */ + fileicondir->reserved = icondir->reserved; + fileicondir->type = icondir->type; + fileicondir->count = icondir->count - skipped; + + /* transfer each cursor/icon: Win32CursorIconDirEntry and data */ + skipped = 0; + for (c = 0 ; c < icondir->count ; c++) { + int level; + char name[14]; + WinResource *fwr; + byte *data; + + /* find the corresponding icon resource */ + snprintf(name, sizeof(name)/sizeof(char), "-%d", icondir->entries[c].res_id); + fwr = find_resource(fi, (is_icon ? "-3" : "-1"), name, lang, &level); + if (fwr == NULL) { + error("%s: could not find `%s' in `%s' resource.", + fi->file->name(), &name[1], (is_icon ? "group_icon" : "group_cursor")); + return NULL; + } + + /* get data and size of that resource */ + data = (byte *)get_resource_entry(fi, fwr, &size); + if (data == NULL) { + /* get_resource_entry has printed error */ + return NULL; + } + if (size == 0) { + skipped++; + continue; + } + + /* copy ICONDIRENTRY (not including last dwImageOffset) */ + memcpy(&fileicondir->entries[c-skipped], &icondir->entries[c], + sizeof(Win32CursorIconFileDirEntry)-sizeof(uint32)); + + /* special treatment for cursors */ + if (!is_icon) { + fileicondir->entries[c-skipped].width = icondir->entries[c].res_info.cursor.width; + fileicondir->entries[c-skipped].height = icondir->entries[c].res_info.cursor.height / 2; + fileicondir->entries[c-skipped].color_count = 0; + fileicondir->entries[c-skipped].reserved = 0; + } + + /* set image offset and increase it */ + fileicondir->entries[c-skipped].dib_offset = offset; + + /* transfer resource into file memory */ + if (is_icon) { + memcpy(&memory[offset], data, icondir->entries[c].bytes_in_res); + } else { + fileicondir->entries[c-skipped].hotspot_x = ((uint16 *) data)[0]; + fileicondir->entries[c-skipped].hotspot_y = ((uint16 *) data)[1]; + memcpy(&memory[offset], data+sizeof(uint16)*2, + icondir->entries[c].bytes_in_res-sizeof(uint16)*2); + offset -= sizeof(uint16)*2; + } + + /* increase the offset pointer */ + offset += icondir->entries[c].bytes_in_res; + } + + return memory; +} + +/* check_offset: + * Check if a chunk of data (determined by offset and size) + * is within the bounds of the WinLibrary file. + * Usually not called directly. + */ +bool Win32ResExtractor::check_offset(byte *memory, int total_size, const char *name, void *offset, int size) { + int need_size = (int)((byte *)offset - memory + size); + + debugC(DEBUG_RESOURCE, "check_offset: size=%x vs %x offset=%x size=%x", + need_size, total_size, (byte *)offset - memory, size); + + if (need_size < 0 || need_size > total_size) { + error("%s: premature end", name); + return false; + } + + return true; +} + + +/* do_resources: + * Do something for each resource matching type, name and lang. + */ +int Win32ResExtractor::do_resources(WinLibrary *fi, const char *type, char *name, char *lang, int action, byte **data) { + WinResource *type_wr; + WinResource *name_wr; + WinResource *lang_wr; + int size; + + type_wr = (WinResource *)calloc(sizeof(WinResource)*3, 1); + name_wr = type_wr + 1; + lang_wr = type_wr + 2; + + size = do_resources_recurs(fi, NULL, type_wr, name_wr, lang_wr, type, name, lang, action, data); + + free(type_wr); + + return size; +} + +/* what is each entry in this directory level for? type, name or language? */ +#define WINRESOURCE_BY_LEVEL(x) ((x)==0 ? type_wr : ((x)==1 ? name_wr : lang_wr)) + +/* does the id of this entry match the specified id? */ +#define LEVEL_MATCHES(x) (x == NULL || x ## _wr->id[0] == '\0' || compare_resource_id(x ## _wr, x)) + +int Win32ResExtractor::do_resources_recurs(WinLibrary *fi, WinResource *base, + WinResource *type_wr, WinResource *name_wr, WinResource *lang_wr, + const char *type, char *name, char *lang, int action, byte **data) { + int c, rescnt; + WinResource *wr; + uint32 size = 0; + + /* get a list of all resources at this level */ + wr = list_resources(fi, base, &rescnt); + if (wr == NULL) + if (size != 0) + return size; + else + return 0; + + /* process each resource listed */ + for (c = 0 ; c < rescnt ; c++) { + /* (over)write the corresponding WinResource holder with the current */ + memcpy(WINRESOURCE_BY_LEVEL(wr[c].level), wr+c, sizeof(WinResource)); + + /* go deeper unless there is something that does NOT match */ + if (LEVEL_MATCHES(type) && LEVEL_MATCHES(name) && LEVEL_MATCHES(lang)) { + if (wr->is_directory) + size = do_resources_recurs(fi, wr+c, type_wr, name_wr, lang_wr, type, name, lang, action, data); + else + size = extract_resources(fi, wr+c, type_wr, name_wr, lang_wr, data); + } + } + + /* since we're moving back one level after this, unset the + * WinResource holder used on this level */ + memset(WINRESOURCE_BY_LEVEL(wr[0].level), 0, sizeof(WinResource)); + + return size; +} + +/* return the resource id quoted if it's a string, otherwise just return it */ +char *Win32ResExtractor::get_resource_id_quoted(WinResource *wr) { + static char tmp[WINRES_ID_MAXLEN+2]; + + if (wr->numeric_id || wr->id[0] == '\0') + return wr->id; + + sprintf(tmp, "'%s'", wr->id); + return tmp; +} + +bool Win32ResExtractor::compare_resource_id(WinResource *wr, const char *id) { + if (wr->numeric_id) { + int32 cmp1, cmp2; + if (id[0] == '+') + return false; + if (id[0] == '-') + id++; + if (!(cmp1 = strtol(wr->id, 0, 10)) || !(cmp2 = strtol(id, 0, 10)) || cmp1 != cmp2) + return false; + } else { + if (id[0] == '-') + return false; + if (id[0] == '+') + id++; + if (strcmp(wr->id, id)) + return false; + } + + return true; +} + +bool Win32ResExtractor::decode_pe_resource_id(WinLibrary *fi, WinResource *wr, uint32 value) { + if (value & IMAGE_RESOURCE_NAME_IS_STRING) { /* numeric id */ + int c, len; + uint16 *mem = (uint16 *) + (fi->first_resource + (value & ~IMAGE_RESOURCE_NAME_IS_STRING)); + + /* copy each char of the string, and terminate it */ + RETURN_IF_BAD_POINTER(false, *mem); + len = mem[0]; + RETURN_IF_BAD_OFFSET(false, &mem[1], sizeof(uint16) * len); + + len = MIN(mem[0], (uint16)WINRES_ID_MAXLEN); + for (c = 0 ; c < len ; c++) + wr->id[c] = mem[c+1] & 0x00FF; + wr->id[len] = '\0'; + } else { /* Unicode string id */ + /* translate id into a string */ + snprintf(wr->id, WINRES_ID_MAXLEN, "%d", value); + } + + wr->numeric_id = (value & IMAGE_RESOURCE_NAME_IS_STRING ? false:true); + return true; +} + +byte *Win32ResExtractor::get_resource_entry(WinLibrary *fi, WinResource *wr, int *size) { + if (fi->is_PE_binary) { + Win32ImageResourceDataEntry *dataent; + + dataent = (Win32ImageResourceDataEntry *) wr->children; + RETURN_IF_BAD_POINTER(NULL, *dataent); + *size = dataent->size; + RETURN_IF_BAD_OFFSET(NULL, fi->memory + dataent->offset_to_data, *size); + + return fi->memory + dataent->offset_to_data; + } else { + Win16NENameInfo *nameinfo; + int sizeshift; + + nameinfo = (Win16NENameInfo *) wr->children; + sizeshift = *((uint16 *) fi->first_resource - 1); + *size = nameinfo->length << sizeshift; + RETURN_IF_BAD_OFFSET(NULL, fi->memory + (nameinfo->offset << sizeshift), *size); + + return fi->memory + (nameinfo->offset << sizeshift); + } +} + +bool Win32ResExtractor::decode_ne_resource_id(WinLibrary *fi, WinResource *wr, uint16 value) { + if (value & NE_RESOURCE_NAME_IS_NUMERIC) { /* numeric id */ + /* translate id into a string */ + snprintf(wr->id, WINRES_ID_MAXLEN, "%d", value & ~NE_RESOURCE_NAME_IS_NUMERIC); + } else { /* ASCII string id */ + int len; + char *mem = (char *)NE_HEADER(fi->memory) + + NE_HEADER(fi->memory)->rsrctab + + value; + + /* copy each char of the string, and terminate it */ + RETURN_IF_BAD_POINTER(false, *mem); + len = mem[0]; + RETURN_IF_BAD_OFFSET(false, &mem[1], sizeof(char) * len); + memcpy(wr->id, &mem[1], len); + wr->id[len] = '\0'; + } + + wr->numeric_id = (value & NE_RESOURCE_NAME_IS_NUMERIC ? true:false); + return true; +} + +Win32ResExtractor::WinResource *Win32ResExtractor::list_pe_resources(WinLibrary *fi, Win32ImageResourceDirectory *pe_res, int level, int *count) { + WinResource *wr; + int c, rescnt; + Win32ImageResourceDirectoryEntry *dirent + = (Win32ImageResourceDirectoryEntry *)(pe_res + 1); + + /* count number of `type' resources */ + RETURN_IF_BAD_POINTER(NULL, *dirent); + rescnt = pe_res->number_of_named_entries + pe_res->number_of_id_entries; + *count = rescnt; + + /* allocate WinResource's */ + wr = (WinResource *)malloc(sizeof(WinResource) * rescnt); + + /* fill in the WinResource's */ + for (c = 0 ; c < rescnt ; c++) { + RETURN_IF_BAD_POINTER(NULL, dirent[c]); + wr[c].this_ = pe_res; + wr[c].level = level; + wr[c].is_directory = (dirent[c].u2.s.data_is_directory); + wr[c].children = fi->first_resource + dirent[c].u2.s.offset_to_directory; + + /* fill in wr->id, wr->numeric_id */ + if (!decode_pe_resource_id (fi, wr + c, dirent[c].u1.name)) + return NULL; + } + + return wr; +} + +Win32ResExtractor::WinResource *Win32ResExtractor::list_ne_name_resources(WinLibrary *fi, WinResource *typeres, int *count) { + int c, rescnt; + WinResource *wr; + Win16NETypeInfo *typeinfo = (Win16NETypeInfo *) typeres->this_; + Win16NENameInfo *nameinfo = (Win16NENameInfo *) typeres->children; + + /* count number of `type' resources */ + RETURN_IF_BAD_POINTER(NULL, typeinfo->count); + *count = rescnt = typeinfo->count; + + /* allocate WinResource's */ + wr = (WinResource *)malloc(sizeof(WinResource) * rescnt); + + /* fill in the WinResource's */ + for (c = 0 ; c < rescnt ; c++) { + RETURN_IF_BAD_POINTER(NULL, nameinfo[c]); + wr[c].this_ = nameinfo+c; + wr[c].is_directory = false; + wr[c].children = nameinfo+c; + wr[c].level = 1; + + /* fill in wr->id, wr->numeric_id */ + if (!decode_ne_resource_id(fi, wr + c, (nameinfo+c)->id)) + return NULL; + } + + return wr; +} + +Win32ResExtractor::WinResource *Win32ResExtractor::list_ne_type_resources(WinLibrary *fi, int *count) { + int c, rescnt; + WinResource *wr; + Win16NETypeInfo *typeinfo; + + /* count number of `type' resources */ + typeinfo = (Win16NETypeInfo *) fi->first_resource; + RETURN_IF_BAD_POINTER(NULL, *typeinfo); + for (rescnt = 0 ; typeinfo->type_id != 0 ; rescnt++) { + typeinfo = NE_TYPEINFO_NEXT(typeinfo); + RETURN_IF_BAD_POINTER(NULL, *typeinfo); + } + *count = rescnt; + + /* allocate WinResource's */ + wr = (WinResource *)malloc(sizeof(WinResource) * rescnt); + + /* fill in the WinResource's */ + typeinfo = (Win16NETypeInfo *) fi->first_resource; + for (c = 0 ; c < rescnt ; c++) { + wr[c].this_ = typeinfo; + wr[c].is_directory = (typeinfo->count != 0); + wr[c].children = typeinfo+1; + wr[c].level = 0; + + /* fill in wr->id, wr->numeric_id */ + if (!decode_ne_resource_id(fi, wr + c, typeinfo->type_id)) + return NULL; + + typeinfo = NE_TYPEINFO_NEXT(typeinfo); + } + + return wr; +} + +/* list_resources: + * Return an array of WinResource's in the current + * resource level specified by res. + */ +Win32ResExtractor::WinResource *Win32ResExtractor::list_resources(WinLibrary *fi, WinResource *res, int *count) { + if (res != NULL && !res->is_directory) + return NULL; + + if (fi->is_PE_binary) { + return list_pe_resources(fi, (Win32ImageResourceDirectory *) + (res == NULL ? fi->first_resource : res->children), + (res == NULL ? 0 : res->level+1), + count); + } else { + return (res == NULL + ? list_ne_type_resources(fi, count) + : list_ne_name_resources(fi, res, count)); + } +} + +/* read_library: + * Read header and get resource directory offset in a Windows library + * (AKA module). + * + */ +bool Win32ResExtractor::read_library(WinLibrary *fi) { + /* check for DOS header signature `MZ' */ + RETURN_IF_BAD_POINTER(false, MZ_HEADER(fi->memory)->magic); + if (MZ_HEADER(fi->memory)->magic == IMAGE_DOS_SIGNATURE) { + DOSImageHeader *mz_header = MZ_HEADER(fi->memory); + + RETURN_IF_BAD_POINTER(false, mz_header->lfanew); + if (mz_header->lfanew < sizeof(DOSImageHeader)) { + error("%s: not a Windows library", fi->file->name()); + return false; + } + } + + /* check for OS2 (Win16) header signature `NE' */ + RETURN_IF_BAD_POINTER(false, NE_HEADER(fi->memory)->magic); + if (NE_HEADER(fi->memory)->magic == IMAGE_OS2_SIGNATURE) { + OS2ImageHeader *header = NE_HEADER(fi->memory); + + RETURN_IF_BAD_POINTER(false, header->rsrctab); + RETURN_IF_BAD_POINTER(false, header->restab); + if (header->rsrctab >= header->restab) { + error("%s: no resource directory found", fi->file->name()); + return false; + } + + fi->is_PE_binary = false; + fi->first_resource = (byte *) NE_HEADER(fi->memory) + + header->rsrctab + sizeof(uint16); + RETURN_IF_BAD_POINTER(false, *(Win16NETypeInfo *) fi->first_resource); + + return true; + } + + /* check for NT header signature `PE' */ + RETURN_IF_BAD_POINTER(false, PE_HEADER(fi->memory)->signature); + if (PE_HEADER(fi->memory)->signature == IMAGE_NT_SIGNATURE) { + Win32ImageSectionHeader *pe_sec; + Win32ImageDataDirectory *dir; + Win32ImageNTHeaders *pe_header; + int d; + + /* allocate new memory */ + fi->total_size = calc_vma_size(fi); + if (fi->total_size == 0) { + /* calc_vma_size has reported error */ + return false; + } + fi->memory = (byte *)realloc(fi->memory, fi->total_size); + + /* relocate memory, start from last section */ + pe_header = PE_HEADER(fi->memory); + RETURN_IF_BAD_POINTER(false, pe_header->file_header.number_of_sections); + + /* we don't need to do OFFSET checking for the sections. + * calc_vma_size has already done that */ + for (d = pe_header->file_header.number_of_sections - 1; d >= 0 ; d--) { + pe_sec = PE_SECTIONS(fi->memory) + d; + + if (pe_sec->characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) + continue; + + //if (pe_sec->virtual_address + pe_sec->size_of_raw_data > fi->total_size) + + RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->virtual_address, pe_sec->size_of_raw_data); + RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->pointer_to_raw_data, pe_sec->size_of_raw_data); + if (pe_sec->virtual_address != pe_sec->pointer_to_raw_data) { + memmove(fi->memory + pe_sec->virtual_address, + fi->memory + pe_sec->pointer_to_raw_data, + pe_sec->size_of_raw_data); + } + } + + /* find resource directory */ + RETURN_IF_BAD_POINTER(false, pe_header->optional_header.data_directory[IMAGE_DIRECTORY_ENTRY_RESOURCE]); + dir = pe_header->optional_header.data_directory + IMAGE_DIRECTORY_ENTRY_RESOURCE; + if (dir->size == 0) { + error("%s: file contains no resources", fi->file->name()); + return false; + } + + fi->first_resource = fi->memory + dir->virtual_address; + fi->is_PE_binary = true; + return true; + } + + /* other (unknown) header signature was found */ + error("%s: not a Windows library", fi->file->name()); + return false; +} + +/* calc_vma_size: + * Calculate the total amount of memory needed for a 32-bit Windows + * module. Returns -1 if file was too small. + */ +int Win32ResExtractor::calc_vma_size(WinLibrary *fi) { + Win32ImageSectionHeader *seg; + int c, segcount, size; + + size = 0; + RETURN_IF_BAD_POINTER(-1, PE_HEADER(fi->memory)->file_header.number_of_sections); + segcount = PE_HEADER(fi->memory)->file_header.number_of_sections; + + /* If there are no segments, just process file like it is. + * This is (probably) not the right thing to do, but problems + * will be delt with later anyway. + */ + if (segcount == 0) + return fi->total_size; + + seg = PE_SECTIONS(fi->memory); + RETURN_IF_BAD_POINTER(-1, *seg); + for (c = 0 ; c < segcount ; c++) { + RETURN_IF_BAD_POINTER(0, *seg); + + size = MAX((uint32)size, seg->virtual_address + seg->size_of_raw_data); + /* I have no idea what misc.virtual_size is for... */ + size = MAX((uint32)size, seg->virtual_address + seg->misc.virtual_size); + seg++; + } + + return size; +} + +Win32ResExtractor::WinResource *Win32ResExtractor::find_with_resource_array(WinLibrary *fi, WinResource *wr, const char *id) { + int c, rescnt; + WinResource *return_wr; + + wr = list_resources(fi, wr, &rescnt); + if (wr == NULL) + return NULL; + + for (c = 0 ; c < rescnt ; c++) { + if (compare_resource_id(&wr[c], id)) { + /* duplicate WinResource and return it */ + return_wr = (WinResource *)malloc(sizeof(WinResource)); + memcpy(return_wr, &wr[c], sizeof(WinResource)); + + /* free old WinResource */ + free(wr); + return return_wr; + } + } + + return NULL; +} + +Win32ResExtractor::WinResource *Win32ResExtractor::find_resource(WinLibrary *fi, const char *type, const char *name, const char *language, int *level) { + WinResource *wr; + + *level = 0; + if (type == NULL) + return NULL; + wr = find_with_resource_array(fi, NULL, type); + if (wr == NULL || !wr->is_directory) + return wr; + + *level = 1; + if (name == NULL) + return wr; + wr = find_with_resource_array(fi, wr, name); + if (wr == NULL || !wr->is_directory) + return wr; + + *level = 2; + if (language == NULL) + return wr; + wr = find_with_resource_array(fi, wr, language); + return wr; +} + +#define ROW_BYTES(bits) ((((bits) + 31) >> 5) << 2) + + +int Win32ResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, + int *hotspot_x, int *hotspot_y, int *keycolor, byte **pal, int *palSize) { + Win32CursorIconFileDir dir; + Win32CursorIconFileDirEntry *entries = NULL; + uint32 offset; + uint32 c, d; + int completed; + int matched = 0; + MemoryReadStream *in = new MemoryReadStream(data, datasize); + + if (!in->read(&dir, sizeof(Win32CursorIconFileDir)- sizeof(Win32CursorIconFileDirEntry))) + goto cleanup; + fix_win32_cursor_icon_file_dir_endian(&dir); + + if (dir.reserved != 0) { + error("not an icon or cursor file (reserved non-zero)"); + goto cleanup; + } + if (dir.type != 1 && dir.type != 2) { + error("not an icon or cursor file (wrong type)"); + goto cleanup; + } + + entries = (Win32CursorIconFileDirEntry *)malloc(dir.count * sizeof(Win32CursorIconFileDirEntry)); + for (c = 0; c < dir.count; c++) { + if (!in->read(&entries[c], sizeof(Win32CursorIconFileDirEntry))) + goto cleanup; + fix_win32_cursor_icon_file_dir_entry_endian(&entries[c]); + if (entries[c].reserved != 0) + error("reserved is not zero"); + } + + offset = sizeof(Win32CursorIconFileDir) + (dir.count - 1) * (sizeof(Win32CursorIconFileDirEntry)); + + for (completed = 0; completed < dir.count; ) { + uint32 min_offset = 0x7fffffff; + int previous = completed; + + for (c = 0; c < dir.count; c++) { + if (entries[c].dib_offset == offset) { + Win32BitmapInfoHeader bitmap; + Win32RGBQuad *palette = NULL; + uint32 palette_count = 0; + uint32 image_size, mask_size; + uint32 width, height; + byte *image_data = NULL, *mask_data = NULL; + byte *row = NULL; + + if (!in->read(&bitmap, sizeof(Win32BitmapInfoHeader))) + goto local_cleanup; + + fix_win32_bitmap_info_header_endian(&bitmap); + if (bitmap.size < sizeof(Win32BitmapInfoHeader)) { + error("bitmap header is too short"); + goto local_cleanup; + } + if (bitmap.compression != 0) { + error("compressed image data not supported"); + goto local_cleanup; + } + if (bitmap.x_pels_per_meter != 0) + error("x_pels_per_meter field in bitmap should be zero"); + if (bitmap.y_pels_per_meter != 0) + error("y_pels_per_meter field in bitmap should be zero"); + if (bitmap.clr_important != 0) + error("clr_important field in bitmap should be zero"); + if (bitmap.planes != 1) + error("planes field in bitmap should be one"); + if (bitmap.size != sizeof(Win32BitmapInfoHeader)) { + uint32 skip = bitmap.size - sizeof(Win32BitmapInfoHeader); + error("skipping %d bytes of extended bitmap header", skip); + in->seek(skip, SEEK_CUR); + } + offset += bitmap.size; + + if (bitmap.clr_used != 0 || bitmap.bit_count < 24) { + palette_count = (bitmap.clr_used != 0 ? bitmap.clr_used : 1 << bitmap.bit_count); + palette = (Win32RGBQuad *)malloc(sizeof(Win32RGBQuad) * palette_count); + if (!in->read(palette, sizeof(Win32RGBQuad) * palette_count)) + goto local_cleanup; + offset += sizeof(Win32RGBQuad) * palette_count; + } + + width = bitmap.width; + height = ABS(bitmap.height)/2; + + image_size = height * ROW_BYTES(width * bitmap.bit_count); + mask_size = height * ROW_BYTES(width); + + if (entries[c].dib_size != bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad)) + debugC(DEBUG_RESOURCE, "incorrect total size of bitmap (%d specified; %d real)", + entries[c].dib_size, + bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad) + ); + + image_data = (byte *)malloc(image_size); + if (!in->read(image_data, image_size)) + goto local_cleanup; + + mask_data = (byte *)malloc(mask_size); + if (!in->read(mask_data, mask_size)) + goto local_cleanup; + + offset += image_size; + offset += mask_size; + completed++; + matched++; + + *hotspot_x = entries[c].hotspot_x; + *hotspot_y = entries[c].hotspot_y; + *w = width; + *h = height; + *keycolor = 0; + *cursor = (byte *)malloc(width * height); + + row = (byte *)malloc(width * 4); + + for (d = 0; d < height; d++) { + uint32 x; + uint32 y = (bitmap.height < 0 ? d : height - d - 1); + uint32 imod = y * (image_size / height) * 8 / bitmap.bit_count; + //uint32 mmod = y * (mask_size / height) * 8; + + for (x = 0; x < width; x++) { + + uint32 color = simple_vec(image_data, x + imod, bitmap.bit_count); + + // FIXME?: This works only with b/w cursors and white index may be + // different. But now it's enough. + if (color) { + cursor[0][width * d + x] = 15; // white in SCUMM + } else { + cursor[0][width * d + x] = 255; // transparent + } + /* + + if (bitmap.bit_count <= 16) { + if (color >= palette_count) { + error("color out of range in image data"); + goto local_cleanup; + } + row[4*x+0] = palette[color].red; + row[4*x+1] = palette[color].green; + row[4*x+2] = palette[color].blue; + + } else { + row[4*x+0] = (color >> 16) & 0xFF; + row[4*x+1] = (color >> 8) & 0xFF; + row[4*x+2] = (color >> 0) & 0xFF; + } + if (bitmap.bit_count == 32) + row[4*x+3] = (color >> 24) & 0xFF; + else + row[4*x+3] = simple_vec(mask_data, x + mmod, 1) ? 0 : 0xFF; + */ + } + + } + + if (row != NULL) + free(row); + if (palette != NULL) + free(palette); + if (image_data != NULL) { + free(image_data); + free(mask_data); + } + continue; + + local_cleanup: + + if (row != NULL) + free(row); + if (palette != NULL) + free(palette); + if (image_data != NULL) { + free(image_data); + free(mask_data); + } + goto cleanup; + } else { + if (entries[c].dib_offset > offset) + min_offset = MIN(min_offset, entries[c].dib_offset); + } + } + + if (previous == completed) { + if (min_offset < offset) { + error("offset of bitmap header incorrect (too low)"); + goto cleanup; + } + debugC(DEBUG_RESOURCE, "skipping %d bytes of garbage at %d", min_offset-offset, offset); + in->seek(min_offset - offset, SEEK_CUR); + offset = min_offset; + } + } + + free(entries); + return matched; + +cleanup: + + free(entries); + return -1; +} + +uint32 Win32ResExtractor::simple_vec(byte *data, uint32 ofs, byte size) { + switch (size) { + case 1: + return (data[ofs/8] >> (7 - ofs%8)) & 1; + case 2: + return (data[ofs/4] >> ((3 - ofs%4) << 1)) & 3; + case 4: + return (data[ofs/2] >> ((1 - ofs%2) << 2)) & 15; + case 8: + return data[ofs]; + case 16: + return data[2*ofs] | data[2*ofs+1] << 8; + case 24: + return data[3*ofs] | data[3*ofs+1] << 8 | data[3*ofs+2] << 16; + case 32: + return data[4*ofs] | data[4*ofs+1] << 8 | data[4*ofs+2] << 16 | data[4*ofs+3] << 24; + } + + return 0; +} + +#define LE16(x) ((x) = TO_LE_16(x)) +#define LE32(x) ((x) = TO_LE_32(x)) + +void Win32ResExtractor::fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj) { + LE16(obj->reserved); + LE16(obj->type); + LE16(obj->count); +} + +void Win32ResExtractor::fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj) { + LE32(obj->size); + LE32(obj->width); + LE32(obj->height); + LE16(obj->planes); + LE16(obj->bit_count); + LE32(obj->compression); + LE32(obj->size_image); + LE32(obj->x_pels_per_meter); + LE32(obj->y_pels_per_meter); + LE32(obj->clr_used); + LE32(obj->clr_important); +} + +void Win32ResExtractor::fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj) { + LE16(obj->hotspot_x); + LE16(obj->hotspot_y); + LE32(obj->dib_size); + LE32(obj->dib_offset); +} + +void Win32ResExtractor::fix_win32_image_section_header(Win32ImageSectionHeader *obj) { + LE32(obj->misc.physical_address); + LE32(obj->virtual_address); + LE32(obj->size_of_raw_data); + LE32(obj->pointer_to_raw_data); + LE32(obj->pointer_to_relocations); + LE32(obj->pointer_to_linenumbers); + LE16(obj->number_of_relocations); + LE16(obj->number_of_linenumbers); + LE32(obj->characteristics); +} + +void Win32ResExtractor::fix_os2_image_header_endian(OS2ImageHeader *obj) { + LE16(obj->magic); + LE16(obj->enttab); + LE16(obj->cbenttab); + LE32(obj->crc); + LE16(obj->flags); + LE16(obj->autodata); + LE16(obj->heap); + LE16(obj->stack); + LE32(obj->csip); + LE32(obj->sssp); + LE16(obj->cseg); + LE16(obj->cmod); + LE16(obj->cbnrestab); + LE16(obj->segtab); + LE16(obj->rsrctab); + LE16(obj->restab); + LE16(obj->modtab); + LE16(obj->imptab); + LE32(obj->nrestab); + LE16(obj->cmovent); + LE16(obj->align); + LE16(obj->cres); + LE16(obj->fastload_offset); + LE16(obj->fastload_length); + LE16(obj->swaparea); + LE16(obj->expver); +} + +/* fix_win32_image_header_endian: + * NOTE: This assumes that the optional header is always available. + */ +void Win32ResExtractor::fix_win32_image_header_endian(Win32ImageNTHeaders *obj) { + LE32(obj->signature); + LE16(obj->file_header.machine); + LE16(obj->file_header.number_of_sections); + LE32(obj->file_header.time_date_stamp); + LE32(obj->file_header.pointer_to_symbol_table); + LE32(obj->file_header.number_of_symbols); + LE16(obj->file_header.size_of_optional_header); + LE16(obj->file_header.characteristics); + LE16(obj->optional_header.magic); + LE32(obj->optional_header.size_of_code); + LE32(obj->optional_header.size_of_initialized_data); + LE32(obj->optional_header.size_of_uninitialized_data); + LE32(obj->optional_header.address_of_entry_point); + LE32(obj->optional_header.base_of_code); + LE32(obj->optional_header.base_of_data); + LE32(obj->optional_header.image_base); + LE32(obj->optional_header.section_alignment); + LE32(obj->optional_header.file_alignment); + LE16(obj->optional_header.major_operating_system_version); + LE16(obj->optional_header.minor_operating_system_version); + LE16(obj->optional_header.major_image_version); + LE16(obj->optional_header.minor_image_version); + LE16(obj->optional_header.major_subsystem_version); + LE16(obj->optional_header.minor_subsystem_version); + LE32(obj->optional_header.win32_version_value); + LE32(obj->optional_header.size_of_image); + LE32(obj->optional_header.size_of_headers); + LE32(obj->optional_header.checksum); + LE16(obj->optional_header.subsystem); + LE16(obj->optional_header.dll_characteristics); + LE32(obj->optional_header.size_of_stack_reserve); + LE32(obj->optional_header.size_of_stack_commit); + LE32(obj->optional_header.size_of_heap_reserve); + LE32(obj->optional_header.size_of_heap_commit); + LE32(obj->optional_header.loader_flags); + LE32(obj->optional_header.number_of_rva_and_sizes); +} + +void Win32ResExtractor::fix_win32_image_data_directory(Win32ImageDataDirectory *obj) { + LE32(obj->virtual_address); + LE32(obj->size); +} + + +MacResExtractor::MacResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) { + _resOffset = -1; +} + +int MacResExtractor::extractResource(int id, byte **buf) { + Common::File in; + int size; + + if (!_fileName[0]) // We are running for the first time + if (_vm->_substResFileNameIndex > 0) { + char buf1[128]; + + snprintf(buf1, 128, "%s.he3", _vm->getBaseName()); + _vm->generateSubstResFileName(buf1, _fileName, sizeof(buf1)); + + // Some programs write it as .bin. Try that too + if (!in.exists(_fileName)) { + strcpy(buf1, _fileName); + snprintf(_fileName, 128, "%s.bin", buf1); + + if (!in.exists(_fileName)) { + // And finally check if we have dumped resource fork + snprintf(_fileName, 128, "%s.rsrc", buf1); + if (!in.exists(_fileName)) { + error("Cannot open file any of files '%s', '%s.bin', '%s.rsrc", + buf1, buf1, buf1); + } + } + } + } + + in.open(_fileName); + if (!in.isOpen()) { + error("Cannot open file %s", _fileName); + } + + // we haven't calculated it + if (_resOffset == -1) { + if (!init(in)) + error("Resource fork is missing in file '%s'", _fileName); + in.close(); + in.open(_fileName); + } + + *buf = getResource(in, "crsr", 1000 + id, &size); + + in.close(); + + if (*buf == NULL) + error("There is no cursor ID #%d", 1000 + id); + + return size; +} + +#define MBI_INFOHDR 128 +#define MBI_ZERO1 0 +#define MBI_NAMELEN 1 +#define MBI_ZERO2 74 +#define MBI_ZERO3 82 +#define MBI_DFLEN 83 +#define MBI_RFLEN 87 +#define MAXNAMELEN 63 + +bool MacResExtractor::init(Common::File in) { + byte infoHeader[MBI_INFOHDR]; + int32 data_size, rsrc_size; + int32 data_size_pad, rsrc_size_pad; + int filelen; + + filelen = in.size(); + in.read(infoHeader, MBI_INFOHDR); + + // Maybe we have MacBinary? + if (infoHeader[MBI_ZERO1] == 0 && infoHeader[MBI_ZERO2] == 0 && + infoHeader[MBI_ZERO3] == 0 && infoHeader[MBI_NAMELEN] <= MAXNAMELEN) { + + // Pull out fork lengths + data_size = READ_BE_UINT32(infoHeader + MBI_DFLEN); + rsrc_size = READ_BE_UINT32(infoHeader + MBI_RFLEN); + + data_size_pad = (((data_size + 127) >> 7) << 7); + rsrc_size_pad = (((rsrc_size + 127) >> 7) << 7); + + // Length check + int sumlen = MBI_INFOHDR + data_size_pad + rsrc_size_pad; + + if (sumlen == filelen) + _resOffset = MBI_INFOHDR + data_size_pad; + } + + if (_resOffset == -1) // MacBinary check is failed + _resOffset = 0; // Maybe we have dumped fork? + + in.seek(_resOffset); + + _dataOffset = in.readUint32BE() + _resOffset; + _mapOffset = in.readUint32BE() + _resOffset; + _dataLength = in.readUint32BE(); + _mapLength = in.readUint32BE(); + + // do sanity check + if (_dataOffset >= filelen || _mapOffset >= filelen || + _dataLength + _mapLength > filelen) { + _resOffset = -1; + return false; + } + + debug(7, "got header: data %d [%d] map %d [%d]", + _dataOffset, _dataLength, _mapOffset, _mapLength); + + readMap(in); + + return true; +} + +byte *MacResExtractor::getResource(Common::File in, const char *typeID, int16 resID, int *size) { + int i; + int typeNum = -1; + int resNum = -1; + byte *buf; + int len; + + for (i = 0; i < _resMap.numTypes; i++) + if (strcmp(_resTypes[i].id, typeID) == 0) { + typeNum = i; + break; + } + + if (typeNum == -1) + return NULL; + + for (i = 0; i < _resTypes[typeNum].items; i++) + if (_resLists[typeNum][i].id == resID) { + resNum = i; + break; + } + + if (resNum == -1) + return NULL; + + in.seek(_dataOffset + _resLists[typeNum][resNum].dataOffset); + + len = in.readUint32BE(); + buf = (byte *)malloc(len); + + in.read(buf, len); + + *size = len; + + return buf; +} + +void MacResExtractor::readMap(Common::File in) { + int i, j, len; + + in.seek(_mapOffset + 22); + + _resMap.resAttr = in.readUint16BE(); + _resMap.typeOffset = in.readUint16BE(); + _resMap.nameOffset = in.readUint16BE(); + _resMap.numTypes = in.readUint16BE(); + _resMap.numTypes++; + + in.seek(_mapOffset + _resMap.typeOffset + 2); + _resTypes = new ResType[_resMap.numTypes]; + + for (i = 0; i < _resMap.numTypes; i++) { + in.read(_resTypes[i].id, 4); + _resTypes[i].id[4] = 0; + _resTypes[i].items = in.readUint16BE(); + _resTypes[i].offset = in.readUint16BE(); + _resTypes[i].items++; + } + + _resLists = new ResPtr[_resMap.numTypes]; + + for (i = 0; i < _resMap.numTypes; i++) { + _resLists[i] = new Resource[_resTypes[i].items]; + in.seek(_resTypes[i].offset + _mapOffset + _resMap.typeOffset); + + for (j = 0; j < _resTypes[i].items; j++) { + ResPtr resPtr = _resLists[i] + j; + + resPtr->id = in.readUint16BE(); + resPtr->nameOffset = in.readUint16BE(); + resPtr->dataOffset = in.readUint32BE(); + in.readUint32BE(); + resPtr->name = 0; + + resPtr->attr = resPtr->dataOffset >> 24; + resPtr->dataOffset &= 0xFFFFFF; + } + + for (j = 0; j < _resTypes[i].items; j++) { + if (_resLists[i][j].nameOffset != -1) { + in.seek(_resLists[i][j].nameOffset + _mapOffset + _resMap.nameOffset); + + len = in.readByte(); + _resLists[i][j].name = new byte[len + 1]; + _resLists[i][j].name[len] = 0; + in.read(_resLists[i][j].name, len); + } + } + } +} + +int MacResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, + int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize) { + Common::MemoryReadStream dis(data, datasize); + int i, b; + byte imageByte; + byte *iconData; + int numBytes; + int pixelsPerByte, bpp; + int ctSize; + byte bitmask; + int iconRowBytes, iconBounds[4]; + int ignored; + int iconDataSize; + + dis.readUint16BE(); // type + dis.readUint32BE(); // offset to pixel map + dis.readUint32BE(); // offset to pixel data + dis.readUint32BE(); // expanded cursor data + dis.readUint16BE(); // expanded data depth + dis.readUint32BE(); // reserved + + // Grab B/W icon data + *cursor = (byte *)malloc(16 * 16); + for (i = 0; i < 32; i++) { + imageByte = dis.readByte(); + for (b = 0; b < 8; b++) + cursor[0][i*8+b] = (byte)((imageByte & + (0x80 >> b)) > 0? 0x0F: 0x00); + } + + // Apply mask data + for (i = 0; i < 32; i++) { + imageByte = dis.readByte(); + for (b = 0; b < 8; b++) + if ((imageByte & (0x80 >> b)) == 0) + cursor[0][i*8+b] = 0xff; + } + + *hotspot_y = dis.readUint16BE(); + *hotspot_x = dis.readUint16BE(); + *w = *h = 16; + + // Use b/w cursor on backends which don't support cursor palettes + if (!_vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette)) + return 1; + + dis.readUint32BE(); // reserved + dis.readUint32BE(); // cursorID + + // Color version of cursor + dis.readUint32BE(); // baseAddr + + // Keep only lowbyte for now + dis.readByte(); + iconRowBytes = dis.readByte(); + + if (!iconRowBytes) + return 1; + + iconBounds[0] = dis.readUint16BE(); + iconBounds[1] = dis.readUint16BE(); + iconBounds[2] = dis.readUint16BE(); + iconBounds[3] = dis.readUint16BE(); + + dis.readUint16BE(); // pmVersion + dis.readUint16BE(); // packType + dis.readUint32BE(); // packSize + + dis.readUint32BE(); // hRes + dis.readUint32BE(); // vRes + + dis.readUint16BE(); // pixelType + dis.readUint16BE(); // pixelSize + dis.readUint16BE(); // cmpCount + dis.readUint16BE(); // cmpSize + + dis.readUint32BE(); // planeByte + dis.readUint32BE(); // pmTable + dis.readUint32BE(); // reserved + + // Pixel data for cursor + iconDataSize = iconRowBytes * (iconBounds[3] - iconBounds[1]); + iconData = (byte *)malloc(iconDataSize); + dis.read(iconData, iconDataSize); + + // Color table + dis.readUint32BE(); // ctSeed + dis.readUint16BE(); // ctFlag + ctSize = dis.readUint16BE() + 1; + + *palette = (byte *)malloc(ctSize * 4); + + // Read just high byte of 16-bit color + for (int c = 0; c < ctSize; c++) { + // We just use indices 0..ctSize, so ignore color ID + dis.readUint16BE(); // colorID[c] + + palette[0][c * 4 + 0] = dis.readByte(); + ignored = dis.readByte(); + + palette[0][c * 4 + 1] = dis.readByte(); + ignored = dis.readByte(); + + palette[0][c * 4 + 2] = dis.readByte(); + ignored = dis.readByte(); + + palette[0][c * 4 + 3] = 0; + } + + *palSize = ctSize; + + numBytes = + (iconBounds[2] - iconBounds[0]) * + (iconBounds[3] - iconBounds[1]); + + pixelsPerByte = (iconBounds[2] - iconBounds[0]) / iconRowBytes; + bpp = 8 / pixelsPerByte; + + // build a mask to make sure the pixels are properly shifted out + bitmask = 0; + for (int m = 0; m < bpp; m++) { + bitmask <<= 1; + bitmask |= 1; + } + + // Extract pixels from bytes + for (int j = 0; j < iconDataSize; j++) + for (b = 0; b < pixelsPerByte; b++) { + int idx = j * pixelsPerByte + (pixelsPerByte - 1 - b); + + if (cursor[0][idx] != 0xff) // if mask is not there + cursor[0][idx] = (byte)((iconData[j] >> (b * bpp)) & bitmask); + } + + free(iconData); + + assert(datasize - dis.pos() == 0); + + return 1; +} + + + +void ScummEngine_v70he::readRoomsOffsets() { + int num, i; + byte *ptr; + + debug(9, "readRoomOffsets()"); + + num = READ_LE_UINT16(_heV7RoomOffsets); + ptr = _heV7RoomOffsets + 2; + for (i = 0; i < num; i++) { + res.roomoffs[rtRoom][i] = READ_LE_UINT32(ptr); + ptr += 4; + } +} + +void ScummEngine_v70he::readGlobalObjects() { + int num = _fileHandle->readUint16LE(); + assert(num == _numGlobalObjects); + + _fileHandle->read(_objectStateTable, num); + _fileHandle->read(_objectOwnerTable, num); + _fileHandle->read(_objectRoomTable, num); + + _fileHandle->read(_classData, num * sizeof(uint32)); + +#if defined(SCUMM_BIG_ENDIAN) + // Correct the endianess if necessary + for (int i = 0; i != num; i++) + _classData[i] = FROM_LE_32(_classData[i]); +#endif +} + +void ScummEngine_v99he::readMAXS(int blockSize) { + debug(0, "ScummEngine_v99he readMAXS: MAXS has blocksize %d", blockSize); + + _numVariables = _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _numRoomVariables = _fileHandle->readUint16LE(); + _numLocalObjects = _fileHandle->readUint16LE(); + _numArray = _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _numFlObject = _fileHandle->readUint16LE(); + _numInventory = _fileHandle->readUint16LE(); + _numRooms = _fileHandle->readUint16LE(); + _numScripts = _fileHandle->readUint16LE(); + _numSounds = _fileHandle->readUint16LE(); + _numCharsets = _fileHandle->readUint16LE(); + _numCostumes = _fileHandle->readUint16LE(); + _numGlobalObjects = _fileHandle->readUint16LE(); + _numImages = _fileHandle->readUint16LE(); + _numSprites = _fileHandle->readUint16LE(); + _numLocalScripts = _fileHandle->readUint16LE(); + _HEHeapSize = _fileHandle->readUint16LE(); + _numPalettes = _fileHandle->readUint16LE(); + _numUnk = _fileHandle->readUint16LE(); + _numTalkies = _fileHandle->readUint16LE(); + _numNewNames = 10; + + _objectRoomTable = (byte *)calloc(_numGlobalObjects, 1); + _numGlobalScripts = 2048; +} + +void ScummEngine_v90he::readMAXS(int blockSize) { + debug(0, "ScummEngine_v90he readMAXS: MAXS has blocksize %d", blockSize); + + _numVariables = _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _numRoomVariables = _fileHandle->readUint16LE(); + _numLocalObjects = _fileHandle->readUint16LE(); + _numArray = _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _numFlObject = _fileHandle->readUint16LE(); + _numInventory = _fileHandle->readUint16LE(); + _numRooms = _fileHandle->readUint16LE(); + _numScripts = _fileHandle->readUint16LE(); + _numSounds = _fileHandle->readUint16LE(); + _numCharsets = _fileHandle->readUint16LE(); + _numCostumes = _fileHandle->readUint16LE(); + _numGlobalObjects = _fileHandle->readUint16LE(); + _numImages = _fileHandle->readUint16LE(); + _numSprites = _fileHandle->readUint16LE(); + _numLocalScripts = _fileHandle->readUint16LE(); + _HEHeapSize = _fileHandle->readUint16LE(); + _numNewNames = 10; + + _objectRoomTable = (byte *)calloc(_numGlobalObjects, 1); + if (_features & GF_HE_985) + _numGlobalScripts = 2048; + else + _numGlobalScripts = 200; +} + +void ScummEngine_v72he::readMAXS(int blockSize) { + debug(0, "ScummEngine_v72he readMAXS: MAXS has blocksize %d", blockSize); + + _numVariables = _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _numBitVariables = _numRoomVariables = _fileHandle->readUint16LE(); + _numLocalObjects = _fileHandle->readUint16LE(); + _numArray = _fileHandle->readUint16LE(); + _fileHandle->readUint16LE(); + _numVerbs = _fileHandle->readUint16LE(); + _numFlObject = _fileHandle->readUint16LE(); + _numInventory = _fileHandle->readUint16LE(); + _numRooms = _fileHandle->readUint16LE(); + _numScripts = _fileHandle->readUint16LE(); + _numSounds = _fileHandle->readUint16LE(); + _numCharsets = _fileHandle->readUint16LE(); + _numCostumes = _fileHandle->readUint16LE(); + _numGlobalObjects = _fileHandle->readUint16LE(); + _numImages = _fileHandle->readUint16LE(); + _numNewNames = 10; + + _objectRoomTable = (byte *)calloc(_numGlobalObjects, 1); + _numGlobalScripts = 200; +} + +byte *ScummEngine_v72he::getStringAddress(int i) { + byte *addr = getResourceAddress(rtString, i); + if (addr == NULL) + return NULL; + return ((ScummEngine_v72he::ArrayHeader *)addr)->data; +} + +int ScummEngine_v72he::getSoundResourceSize(int id) { + const byte *ptr; + int offs, size; + + if (id > _numSounds) { + if (!_sound->getHEMusicDetails(id, offs, size)) { + debug(0, "getSoundResourceSize: musicID %d not found", id); + return 0; + } + } else { + ptr = getResourceAddress(rtSound, id); + if (!ptr) + return 0; + + if (READ_UINT32(ptr) == MKID('RIFF')) { + byte flags; + int rate; + + size = READ_BE_UINT32(ptr + 4); + Common::MemoryReadStream stream(ptr, size); + + if (!loadWAVFromStream(stream, size, rate, flags)) { + error("getSoundResourceSize: Not a valid WAV file"); + } + } else { + ptr += 8 + READ_BE_UINT32(ptr + 12); + if (READ_UINT32(ptr) == MKID('SBNG')) { + ptr += READ_BE_UINT32(ptr + 4); + } + + assert(READ_UINT32(ptr) == MKID('SDAT')); + size = READ_BE_UINT32(ptr + 4) - 8; + } + } + + return size; +} + +void ScummEngine_v80he::createSound(int snd1id, int snd2id) { + debug(0, "createSound: snd1id %d snd2id %d", snd1id, snd2id); + + byte *snd1Ptr, *snd2Ptr; + byte *sbng1Ptr, *sbng2Ptr; + byte *sdat1Ptr, *sdat2Ptr; + byte *src, *dst, *tmp; + int len, offs, size; + int sdat1size, sdat2size; + + if (snd2id == -1) { + _sndPtrOffs = 0; + _sndTmrOffs = 0; + return; + } + + if (snd1id != _curSndId) { + _curSndId = snd1id; + _sndPtrOffs = 0; + _sndTmrOffs = 0; + } + + snd1Ptr = getResourceAddress(rtSound, snd1id); + assert(snd1Ptr); + snd2Ptr = getResourceAddress(rtSound, snd2id); + assert(snd2Ptr); + + int i; + int chan = -1; + for (i = 0; i < ARRAYSIZE(_sound->_heChannel); i++) { + if (_sound->_heChannel[i].sound == snd1id) + chan = i; + } + + sbng1Ptr = heFindResource(MKID('SBNG'), snd1Ptr); + sbng2Ptr = heFindResource(MKID('SBNG'), snd2Ptr); + + if (sbng1Ptr != NULL && sbng2Ptr != NULL) { + if (chan != -1 && _sound->_heChannel[chan].codeOffs > 0) { + int curOffs = _sound->_heChannel[chan].codeOffs; + + src = snd1Ptr + curOffs; + dst = sbng1Ptr + 8; + size = READ_BE_UINT32(sbng1Ptr + 4); + len = sbng1Ptr - snd1Ptr + size - curOffs; + + byte *data = (byte *)malloc(len); + memcpy(data, src, len); + memcpy(dst, data, len); + free(data); + + dst = sbng1Ptr + 8; + while ((size = READ_LE_UINT16(dst)) != 0) + dst += size; + } else { + dst = sbng1Ptr + 8; + } + + _sound->_heChannel[chan].codeOffs = sbng1Ptr - snd1Ptr + 8; + + tmp = sbng2Ptr + 8; + while ((offs = READ_LE_UINT16(tmp)) != 0) { + tmp += offs; + } + + src = sbng2Ptr + 8; + len = tmp - sbng2Ptr - 6; + memcpy(dst, src, len); + + int32 time; + while ((size = READ_LE_UINT16(dst)) != 0) { + time = READ_LE_UINT32(dst + 2); + time += _sndTmrOffs; + WRITE_LE_UINT32(dst + 2, time); + dst += size; + } + } + + sdat1Ptr = heFindResource(MKID('SDAT'), snd1Ptr); + assert(sdat1Ptr); + sdat2Ptr = heFindResource(MKID('SDAT'), snd2Ptr); + assert(sdat2Ptr); + + sdat1size = READ_BE_UINT32(sdat1Ptr + 4) - 8 - _sndPtrOffs; + sdat2size = READ_BE_UINT32(sdat2Ptr + 4) - 8; + + debug(0, "SDAT size1 %d size2 %d", sdat1size, sdat2size); + if (sdat2size < sdat1size) { + src = sdat2Ptr + 8; + dst = sdat1Ptr + 8 + _sndPtrOffs; + len = sdat2size; + + memcpy(dst, src, len); + + _sndPtrOffs += sdat2size; + _sndTmrOffs += sdat2size; + } else { + src = sdat2Ptr + 8; + dst = sdat1Ptr + 8 + _sndPtrOffs; + len = sdat1size; + + memcpy(dst, src, len); + + if (sdat2size != sdat1size) { + src = sdat2Ptr + 8 + sdat1size; + dst = sdat1Ptr + 8; + len = sdat2size - sdat1size; + + memcpy(dst, src, len); + } + + _sndPtrOffs = sdat2size - sdat1size; + _sndTmrOffs += sdat2size; + } +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/resource_v7he.h b/engines/scumm/he/resource_v7he.h new file mode 100644 index 0000000000..1496aa3d7f --- /dev/null +++ b/engines/scumm/he/resource_v7he.h @@ -0,0 +1,556 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004-2006 The ScummVM project + * + * Parts of code heavily based on: + * icoutils - A set of programs dealing with MS Windows icons and cursors. + * Copyright (C) 1998-2001 Oskar Liljeblad + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#if !defined(RESOURCE_V7HE_H) && !defined(DISABLE_HE) +#define RESOURCE_V7HE_H + +namespace Scumm { + +#define WINRES_ID_MAXLEN (256) + +/* + * Definitions + */ + +#define ACTION_LIST 1 /* command: list resources */ +#define ACTION_EXTRACT 2 /* command: extract resources */ +#define CALLBACK_STOP 0 /* results of ResourceCallback */ +#define CALLBACK_CONTINUE 1 +#define CALLBACK_CONTINUE_RECURS 2 + +#define MZ_HEADER(x) ((DOSImageHeader *)(x)) +#define NE_HEADER(x) ((OS2ImageHeader *)PE_HEADER(x)) +#define NE_TYPEINFO_NEXT(x) ((Win16NETypeInfo *)((byte *)(x) + sizeof(Win16NETypeInfo) + \ + ((Win16NETypeInfo *)x)->count * sizeof(Win16NENameInfo))) +#define NE_RESOURCE_NAME_IS_NUMERIC (0x8000) + +#define STRIP_RES_ID_FORMAT(x) (x != NULL && (x[0] == '-' || x[0] == '+') ? ++x : x) + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 +#define IMAGE_SIZEOF_SHORT_NAME 8 + +#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 +#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 + +#define PE_HEADER(module) \ + ((Win32ImageNTHeaders*)((byte *)(module) + \ + (((DOSImageHeader*)(module))->lfanew))) + +#define PE_SECTIONS(module) \ + ((Win32ImageSectionHeader *)((byte *) &PE_HEADER(module)->optional_header + \ + PE_HEADER(module)->file_header.size_of_optional_header)) + +#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ +#define IMAGE_OS2_SIGNATURE 0x454E /* NE */ +#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */ +#define IMAGE_OS2_SIGNATURE_LX 0x584C /* LX */ +#define IMAGE_VXD_SIGNATURE 0x454C /* LE */ +#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ + +#if !defined (WIN32) +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 +#endif + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* (MIPS GP) */ +#define IMAGE_DIRECTORY_ENTRY_TLS 9 +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 +#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 + +#if !defined (WIN32) +#define RT_CURSOR 1 +#define RT_BITMAP 2 +#define RT_ICON 3 +#define RT_MENU 4 +#define RT_DIALOG 5 +#define RT_STRING 6 +#define RT_FONTDIR 7 +#define RT_FONT 8 +#define RT_ACCELERATOR 9 +#define RT_RCDATA 10 +#define RT_MESSAGELIST 11 +#define RT_GROUP_CURSOR 12 +#define RT_GROUP_ICON 14 +#endif + +#define RETURN_IF_BAD_POINTER(r, x) \ + if (!check_offset(fi->memory, fi->total_size, fi->file->name(), &(x), sizeof(x))) \ + return (r); +#define RETURN_IF_BAD_OFFSET(r, x, s) \ + if (!check_offset(fi->memory, fi->total_size, fi->file->name(), x, s)) \ + return (r); + +class ScummEngine_v70he; + +class ResExtractor { +public: + ResExtractor(ScummEngine_v70he *scumm); + virtual ~ResExtractor(); + + void setCursor(int id); + + virtual int extractResource(int id, byte **buf) { return 0; }; + virtual int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, + int *hotspot_x, int *hotspot_y, int *keycolor, + byte **palette, int *palSize) { return 0; }; + + enum { + MAX_CACHED_CURSORS = 10 + }; + + struct CachedCursor { + bool valid; + int id; + byte *bitmap; + int w, h; + int hotspot_x, hotspot_y; + uint32 last_used; + byte *palette; + int palSize; + }; + + ScummEngine_v70he *_vm; + + ResExtractor::CachedCursor *findCachedCursor(int id); + ResExtractor::CachedCursor *getCachedCursorSlot(); + + bool _arg_raw; + char _fileName[256]; + CachedCursor _cursorCache[MAX_CACHED_CURSORS]; + + typedef Common::MemoryReadStream MemoryReadStream; + +}; + +class Win32ResExtractor : public ResExtractor { + public: + Win32ResExtractor(ScummEngine_v70he *scumm); + ~Win32ResExtractor() {}; + int extractResource(int id, byte **data); + void setCursor(int id); + int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, + int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize); + + private: + int extractResource_(const char *resType, char *resName, byte **data); +/* + * Structures + */ + +#if !defined(__GNUC__) + #pragma START_PACK_STRUCTS +#endif + + struct WinLibrary { + Common::File *file; + byte *memory; + byte *first_resource; + bool is_PE_binary; + int total_size; + }; + + struct WinResource { + char id[256]; + void *this_; + void *children; + int level; + bool numeric_id; + bool is_directory; + }; + + + struct Win32IconResDir { + byte width; + byte height; + byte color_count; + byte reserved; + }; + + struct Win32CursorDir { + uint16 width; + uint16 height; + }; + + struct Win32CursorIconDirEntry { + union { + Win32IconResDir icon; + Win32CursorDir cursor; + } res_info; + uint16 plane_count; + uint16 bit_count; + uint32 bytes_in_res; + uint16 res_id; + }; + + struct Win32CursorIconDir { + uint16 reserved; + uint16 type; + uint16 count; + Win32CursorIconDirEntry entries[1] GCC_PACK; + }; + + struct Win32CursorIconFileDirEntry { + byte width; + byte height; + byte color_count; + byte reserved; + uint16 hotspot_x; + uint16 hotspot_y; + uint32 dib_size; + uint32 dib_offset; + }; + + struct Win32CursorIconFileDir { + uint16 reserved; + uint16 type; + uint16 count; + Win32CursorIconFileDirEntry entries[1]; + }; + + struct Win32BitmapInfoHeader { + uint32 size; + int32 width; + int32 height; + uint16 planes; + uint16 bit_count; + uint32 compression; + uint32 size_image; + int32 x_pels_per_meter; + int32 y_pels_per_meter; + uint32 clr_used; + uint32 clr_important; + }; + + struct Win32RGBQuad { + byte blue; + byte green; + byte red; + byte reserved; + }; + + struct Win32ImageResourceDirectoryEntry { + union { + struct { + #ifdef SCUMM_BIGENDIAN + unsigned name_is_string:1; + unsigned name_offset:31; + #else + unsigned name_offset:31; + unsigned name_is_string:1; + #endif + } s1; + uint32 name; + struct { + #ifdef SCUMM_BIG_ENDIAN + uint16 __pad; + uint16 id; + #else + uint16 id; + uint16 __pad; + #endif + } s2; + } u1; + union { + uint32 offset_to_data; + struct { + #ifdef SCUMM_BIG_ENDIAN + unsigned data_is_directory:1; + unsigned offset_to_directory:31; + #else + unsigned offset_to_directory:31; + unsigned data_is_directory:1; + #endif + } s; + } u2; + }; + + struct Win16NETypeInfo { + uint16 type_id; + uint16 count; + uint32 resloader; // FARPROC16 - smaller? uint16? + }; + + struct Win16NENameInfo { + uint16 offset; + uint16 length; + uint16 flags; + uint16 id; + uint16 handle; + uint16 usage; + }; + + struct OS2ImageHeader { + uint16 magic; + byte ver; + byte rev; + uint16 enttab; + uint16 cbenttab; + int32 crc; + uint16 flags; + uint16 autodata; + uint16 heap; + uint16 stack; + uint32 csip; + uint32 sssp; + uint16 cseg; + uint16 cmod; + uint16 cbnrestab; + uint16 segtab; + uint16 rsrctab; + uint16 restab; + uint16 modtab; + uint16 imptab; + uint32 nrestab; + uint16 cmovent; + uint16 align; + uint16 cres; + byte exetyp; + byte flagsothers; + uint16 fastload_offset; + uint16 fastload_length; + uint16 swaparea; + uint16 expver; + }; + + struct DOSImageHeader { + uint16 magic; + uint16 cblp; + uint16 cp; + uint16 crlc; + uint16 cparhdr; + uint16 minalloc; + uint16 maxalloc; + uint16 ss; + uint16 sp; + uint16 csum; + uint16 ip; + uint16 cs; + uint16 lfarlc; + uint16 ovno; + uint16 res[4]; + uint16 oemid; + uint16 oeminfo; + uint16 res2[10]; + uint32 lfanew; + }; + + struct Win32ImageFileHeader { + uint16 machine; + uint16 number_of_sections; + uint32 time_date_stamp; + uint32 pointer_to_symbol_table; + uint32 number_of_symbols; + uint16 size_of_optional_header; + uint16 characteristics; + }; + + struct Win32ImageDataDirectory { + uint32 virtual_address; + uint32 size; + }; + + struct Win32ImageOptionalHeader { + uint16 magic; + byte major_linker_version; + byte minor_linker_version; + uint32 size_of_code; + uint32 size_of_initialized_data; + uint32 size_of_uninitialized_data; + uint32 address_of_entry_point; + uint32 base_of_code; + uint32 base_of_data; + uint32 image_base; + uint32 section_alignment; + uint32 file_alignment; + uint16 major_operating_system_version; + uint16 minor_operating_system_version; + uint16 major_image_version; + uint16 minor_image_version; + uint16 major_subsystem_version; + uint16 minor_subsystem_version; + uint32 win32_version_value; + uint32 size_of_image; + uint32 size_of_headers; + uint32 checksum; + uint16 subsystem; + uint16 dll_characteristics; + uint32 size_of_stack_reserve; + uint32 size_of_stack_commit; + uint32 size_of_heap_reserve; + uint32 size_of_heap_commit; + uint32 loader_flags; + uint32 number_of_rva_and_sizes; + Win32ImageDataDirectory data_directory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + }; + + struct Win32ImageNTHeaders { + uint32 signature; + Win32ImageFileHeader file_header; + Win32ImageOptionalHeader optional_header; + }; + + struct Win32ImageSectionHeader { + byte name[IMAGE_SIZEOF_SHORT_NAME]; + union { + uint32 physical_address; + uint32 virtual_size; + } misc; + uint32 virtual_address; + uint32 size_of_raw_data; + uint32 pointer_to_raw_data; + uint32 pointer_to_relocations; + uint32 pointer_to_linenumbers; + uint16 number_of_relocations; + uint16 number_of_linenumbers; + uint32 characteristics; + }; + + struct Win32ImageResourceDataEntry { + uint32 offset_to_data; + uint32 size; + uint32 code_page; + uint32 resource_handle; + }; + + struct Win32ImageResourceDirectory { + uint32 characteristics; + uint32 time_date_stamp; + uint16 major_version; + uint16 minor_version; + uint16 number_of_named_entries; + uint16 number_of_id_entries; + }; + +#if !defined(__GNUC__) + #pragma END_PACK_STRUCTS +#endif + +/* + * Function Prototypes + */ + + WinResource *list_resources(WinLibrary *, WinResource *, int *); + bool read_library(WinLibrary *); + WinResource *find_resource(WinLibrary *, const char *, const char *, const char *, int *); + byte *get_resource_entry(WinLibrary *, WinResource *, int *); + int do_resources(WinLibrary *, const char *, char *, char *, int, byte **); + bool compare_resource_id(WinResource *, const char *); + const char *res_type_string_to_id(const char *); + + const char *res_type_id_to_string(int); + char *get_destination_name(WinLibrary *, char *, char *, char *); + + byte *extract_resource(WinLibrary *, WinResource *, int *, bool *, char *, char *, bool); + int extract_resources(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *, byte **); + byte *extract_group_icon_cursor_resource(WinLibrary *, WinResource *, char *, int *, bool); + + bool decode_pe_resource_id(WinLibrary *, WinResource *, uint32); + bool decode_ne_resource_id(WinLibrary *, WinResource *, uint16); + WinResource *list_ne_type_resources(WinLibrary *, int *); + WinResource *list_ne_name_resources(WinLibrary *, WinResource *, int *); + WinResource *list_pe_resources(WinLibrary *, Win32ImageResourceDirectory *, int, int *); + int calc_vma_size(WinLibrary *); + int do_resources_recurs(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *, const char *, char *, char *, int, byte **); + char *get_resource_id_quoted(WinResource *); + WinResource *find_with_resource_array(WinLibrary *, WinResource *, const char *); + + bool check_offset(byte *, int, const char *, void *, int); + + uint32 simple_vec(byte *data, uint32 ofs, byte size); + + void fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj); + void fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj); + void fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj); + void fix_win32_image_section_header(Win32ImageSectionHeader *obj); + void fix_os2_image_header_endian(OS2ImageHeader *obj); + void fix_win32_image_header_endian(Win32ImageNTHeaders *obj); + void fix_win32_image_data_directory(Win32ImageDataDirectory *obj); +}; + +class MacResExtractor : public ResExtractor { + +public: + MacResExtractor(ScummEngine_v70he *scumm); + ~MacResExtractor() { } + void setCursor(int id) ; + +private: + int extractResource(int id, byte **buf); + bool init(Common::File in); + void readMap(Common::File in); + byte *getResource(Common::File in, const char *typeID, int16 resID, int *size); + int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, + int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize); + + struct ResMap { + int16 resAttr; + int16 typeOffset; + int16 nameOffset; + int16 numTypes; + }; + + struct ResType { + char id[5]; + int16 items; + int16 offset; + }; + + struct Resource { + int16 id; + int16 nameOffset; + byte attr; + int32 dataOffset; + byte *name; + }; + + typedef Resource *ResPtr; + +private: + int _resOffset; + int32 _dataOffset; + int32 _dataLength; + int32 _mapOffset; + int32 _mapLength; + ResMap _resMap; + ResType *_resTypes; + ResPtr *_resLists; +}; + +} // End of namespace Scumm + +#endif diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp new file mode 100644 index 0000000000..c9bfeade67 --- /dev/null +++ b/engines/scumm/he/script_v100he.cpp @@ -0,0 +1,2978 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" + +#include "common/system.h" + +#include "scumm/actor.h" +#include "scumm/charset.h" +#include "scumm/he/intern_he.h" +#include "scumm/object.h" +#include "scumm/resource.h" +#include "scumm/he/resource_v7he.h" +#include "scumm/scumm.h" +#include "scumm/sound.h" +#include "scumm/he/sprite_he.h" +#include "scumm/util.h" + +namespace Scumm { + +#define OPCODE(x) _OPCODE(ScummEngine_v100he, x) + +void ScummEngine_v100he::setupOpcodes() { + static const OpcodeEntryV100he opcodes[256] = { + /* 00 */ + OPCODE(o100_actorOps), + OPCODE(o6_add), + OPCODE(o6_faceActor), + OPCODE(o90_sortArray), + /* 04 */ + OPCODE(o100_arrayOps), + OPCODE(o6_band), + OPCODE(o6_bor), + OPCODE(o6_breakHere), + /* 08 */ + OPCODE(o6_delayFrames), + OPCODE(o90_shl), + OPCODE(o90_shr), + OPCODE(o90_xor), + /* 0C */ + OPCODE(o6_setCameraAt), + OPCODE(o6_actorFollowCamera), + OPCODE(o6_loadRoom), + OPCODE(o6_panCameraTo), + /* 10 */ + OPCODE(o72_captureWizImage), + OPCODE(o100_jumpToScript), + OPCODE(o6_setClass), + OPCODE(o60_closeFile), + /* 14 */ + OPCODE(o6_loadRoomWithEgo), + OPCODE(o6_invalid), + OPCODE(o72_setFilePath), + OPCODE(o100_createSound), + /* 18 */ + OPCODE(o6_cutscene), + OPCODE(o6_pop), + OPCODE(o72_traceStatus), + OPCODE(o6_wordVarDec), + /* 1C */ + OPCODE(o6_wordArrayDec), + OPCODE(o72_deleteFile), + OPCODE(o100_dim2dimArray), + OPCODE(o100_dimArray), + /* 20 */ + OPCODE(o6_div), + OPCODE(o6_animateActor), + OPCODE(o6_doSentence), + OPCODE(o6_drawBox), + /* 24 */ + OPCODE(o72_drawWizImage), + OPCODE(o80_drawWizPolygon), + OPCODE(o100_drawLine), + OPCODE(o100_drawObject), + /* 28 */ + OPCODE(o6_dup), + OPCODE(o90_dup_n), + OPCODE(o6_endCutscene), + OPCODE(o6_stopObjectCode), + /* 2C */ + OPCODE(o6_stopObjectCode), + OPCODE(o6_eq), + OPCODE(o100_floodFill), + OPCODE(o6_freezeUnfreeze), + /* 30 */ + OPCODE(o6_ge), + OPCODE(o6_getDateTime), + OPCODE(o100_setSpriteGroupInfo), + OPCODE(o6_gt), + /* 34 */ + OPCODE(o100_resourceRoutines), + OPCODE(o6_if), + OPCODE(o6_ifNot), + OPCODE(o100_wizImageOps), + /* 38 */ + OPCODE(o72_isAnyOf), + OPCODE(o6_wordVarInc), + OPCODE(o6_wordArrayInc), + OPCODE(o6_jump), + /* 3C */ + OPCODE(o90_kernelSetFunctions), + OPCODE(o6_land), + OPCODE(o6_le), + OPCODE(o60_localizeArrayToScript), + /* 40 */ + OPCODE(o6_wordArrayRead), + OPCODE(o6_wordArrayIndexedRead), + OPCODE(o6_lor), + OPCODE(o6_lt), + /* 44 */ + OPCODE(o90_mod), + OPCODE(o6_mul), + OPCODE(o6_neq), + OPCODE(o100_dim2dim2Array), + /* 48 */ + OPCODE(o6_setObjectName), + OPCODE(o100_redim2dimArray), + OPCODE(o6_not), + OPCODE(o6_invalid), + /* 4C */ + OPCODE(o6_beginOverride), + OPCODE(o6_endOverride), + OPCODE(o72_resetCutscene), + OPCODE(o6_setOwner), + /* 50 */ + OPCODE(o100_paletteOps), + OPCODE(o70_pickupObject), + OPCODE(o70_polygonOps), + OPCODE(o6_pop), + /* 54 */ + OPCODE(o6_printDebug), + OPCODE(o72_printWizImage), + OPCODE(o6_printLine), + OPCODE(o6_printSystem), + /* 58 */ + OPCODE(o6_printText), + OPCODE(o100_jumpToScriptUnk), + OPCODE(o100_startScriptUnk), + OPCODE(o6_pseudoRoom), + /* 5C */ + OPCODE(o6_pushByte), + OPCODE(o72_pushDWord), + OPCODE(o72_getScriptString), + OPCODE(o6_pushWord), + /* 60 */ + OPCODE(o6_pushWordVar), + OPCODE(o6_putActorAtObject), + OPCODE(o6_putActorAtXY), + OPCODE(o6_invalid), + /* 64 */ + OPCODE(o100_redimArray), + OPCODE(o72_rename), + OPCODE(o6_stopObjectCode), + OPCODE(o80_localizeArrayToRoom), + /* 68 */ + OPCODE(o100_roomOps), + OPCODE(o6_printActor), + OPCODE(o6_printEgo), + OPCODE(o72_talkActor), + /* 6C */ + OPCODE(o72_talkEgo), + OPCODE(o6_invalid), + OPCODE(o70_seekFilePos), + OPCODE(o6_setBoxFlags), + /* 70 */ + OPCODE(o6_invalid), + OPCODE(o6_setBoxSet), + OPCODE(o100_setSystemMessage), + OPCODE(o6_shuffle), + /* 74 */ + OPCODE(o6_delay), + OPCODE(o6_delayMinutes), + OPCODE(o6_delaySeconds), + OPCODE(o100_startSound), + /* 78 */ + OPCODE(o80_sourceDebug), + OPCODE(o100_setSpriteInfo), + OPCODE(o6_stampObject), + OPCODE(o72_startObject), + /* 7C */ + OPCODE(o100_startScript), + OPCODE(o6_startScriptQuick), + OPCODE(o80_setState), + OPCODE(o6_stopObjectScript), + /* 80 */ + OPCODE(o6_stopScript), + OPCODE(o6_stopSentence), + OPCODE(o6_stopSound), + OPCODE(o6_stopTalking), + /* 84 */ + OPCODE(o6_writeWordVar), + OPCODE(o6_wordArrayWrite), + OPCODE(o6_wordArrayIndexedWrite), + OPCODE(o6_sub), + /* 88 */ + OPCODE(o100_systemOps), + OPCODE(o6_invalid), + OPCODE(o72_setTimer), + OPCODE(o100_cursorCommand), + /* 8C */ + OPCODE(o100_videoOps), + OPCODE(o100_wait), + OPCODE(o6_walkActorToObj), + OPCODE(o6_walkActorTo), + /* 90 */ + OPCODE(o100_writeFile), + OPCODE(o72_writeINI), + OPCODE(o80_writeConfigFile), + OPCODE(o6_abs), + /* 94 */ + OPCODE(o6_getActorWalkBox), + OPCODE(o6_getActorCostume), + OPCODE(o6_getActorElevation), + OPCODE(o6_getObjectOldDir), + /* 98 */ + OPCODE(o6_getActorMoving), + OPCODE(o90_getActorData), + OPCODE(o6_getActorRoom), + OPCODE(o6_getActorScaleX), + /* 9C */ + OPCODE(o6_getAnimateVariable), + OPCODE(o6_getActorWidth), + OPCODE(o6_getObjectX), + OPCODE(o6_getObjectY), + /* A0 */ + OPCODE(o90_atan2), + OPCODE(o90_getSegmentAngle), + OPCODE(o90_getActorAnimProgress), + OPCODE(o90_getDistanceBetweenPoints), + /* A4 */ + OPCODE(o6_ifClassOfIs), + OPCODE(o6_invalid), + OPCODE(o90_cond), + OPCODE(o90_cos), + /* A8 */ + OPCODE(o6_invalid), + OPCODE(o80_getFileSize), + OPCODE(o6_getActorFromXY), + OPCODE(o72_findAllObjects), + /* AC */ + OPCODE(o90_findAllObjectsWithClassOf), + OPCODE(o6_invalid), + OPCODE(o6_findInventory), + OPCODE(o72_findObject), + /* B0 */ + OPCODE(o72_findObjectWithClassOf), + OPCODE(o70_polygonHit), + OPCODE(o90_getLinesIntersectionPoint), + OPCODE(o90_fontUnk), + /* B4 */ + OPCODE(o72_getNumFreeArrays), + OPCODE(o72_getArrayDimSize), + OPCODE(o100_isResourceLoaded), + OPCODE(o100_getResourceSize), + /* B8 */ + OPCODE(o100_getSpriteGroupInfo), + OPCODE(o6_invalid), + OPCODE(o100_getWizData), + OPCODE(o6_isActorInBox), + /* BC */ + OPCODE(o6_isAnyOf), + OPCODE(o6_getInventoryCount), + OPCODE(o90_kernelGetFunctions), + OPCODE(o90_max), + /* C0 */ + OPCODE(o90_min), + OPCODE(o72_getObjectImageX), + OPCODE(o72_getObjectImageY), + OPCODE(o6_isRoomScriptRunning), + /* C4 */ + OPCODE(o90_getObjectData), + OPCODE(o72_openFile), + OPCODE(o90_getPolygonOverlap), + OPCODE(o6_getOwner), + /* C8 */ + OPCODE(o100_getPaletteData), + OPCODE(o6_pickOneOf), + OPCODE(o6_pickOneOfDefault), + OPCODE(o80_pickVarRandom), + /* CC */ + OPCODE(o72_getPixel), + OPCODE(o6_distObjectObject), + OPCODE(o6_distObjectPt), + OPCODE(o6_distPtPt), + /* D0 */ + OPCODE(o6_getRandomNumber), + OPCODE(o6_getRandomNumberRange), + OPCODE(o6_invalid), + OPCODE(o100_readFile), + /* D4 */ + OPCODE(o72_readINI), + OPCODE(o80_readConfigFile), + OPCODE(o6_isScriptRunning), + OPCODE(o90_sin), + /* D8 */ + OPCODE(o72_getSoundPosition), + OPCODE(o6_isSoundRunning), + OPCODE(o80_getSoundVar), + OPCODE(o100_getSpriteInfo), + /* DC */ + OPCODE(o90_sqrt), + OPCODE(o6_startObjectQuick), + OPCODE(o6_startScriptQuick2), + OPCODE(o6_getState), + /* E0 */ + OPCODE(o70_compareString), + OPCODE(o70_copyString), + OPCODE(o70_appendString), + OPCODE(o70_concatString), + /* E4 */ + OPCODE(o70_getStringLen), + OPCODE(o70_getStringLenForWidth), + OPCODE(o80_stringToInt), + OPCODE(o70_getCharIndexInString), + /* E8 */ + OPCODE(o70_getStringWidth), + OPCODE(o60_readFilePos), + OPCODE(o72_getTimer), + OPCODE(o6_getVerbEntrypoint), + /* EC */ + OPCODE(o100_getVideoData), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* F0 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* F4 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* F8 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* FC */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + }; + + _opcodesV100he = opcodes; +} + +void ScummEngine_v100he::executeOpcode(byte i) { + OpcodeProcV100he op = _opcodesV100he[i].proc; + (this->*op) (); +} + +const char *ScummEngine_v100he::getOpcodeDesc(byte i) { + return _opcodesV100he[i].desc; +} + +void ScummEngine_v100he::o100_actorOps() { + Actor *a; + int i, j, k; + int args[32]; + byte string[256]; + + byte subOp = fetchScriptByte(); + if (subOp == 129) { + _curActor = pop(); + return; + } + + a = derefActorSafe(_curActor, "o100_actorOps"); + if (!a) + return; + + switch (subOp) { + case 0: + // freddicove Ru Updated + // FIXME: check stack parameters + debug(0,"o100_actorOps: case 0 UNHANDLED"); + break; + case 3: + pop(); + pop(); + pop(); + break; + case 4: // SO_ANIMATION_SPEED + a->setAnimSpeed(pop()); + break; + case 6: + j = pop(); + i = pop(); + a->putActor(i, j, a->_room); + break; + case 8: + a->_drawToBackBuf = false; + a->_needRedraw = true; + a->_needBgReset = true; + break; + case 9: + a->drawActorToBackBuf(a->_pos.x, a->_pos.y); + break; + case 14: + a->_charset = pop(); + break; + case 18: + a->_clipOverride.bottom = pop(); + a->_clipOverride.right = pop(); + a->_clipOverride.top = pop(); + a->_clipOverride.left = pop(); + break; + case 22: + k = getStackList(args, ARRAYSIZE(args)); + for (i = 0; i < k; ++i) { + a->setUserCondition(args[i] & 0x7F, args[i] & 0x80); + } + break; + case 25: // SO_COSTUME + a->setActorCostume(pop()); + break; + case 27: // SO_DEFAULT + a->initActor(0); + break; + case 32: + i = pop(); + debug(0,"o100_actorOps: case 32 (%d)", i); + break; + case 52: // SO_ACTOR_NAME + copyScriptString(string, sizeof(string)); + loadPtrToResource(rtActorName, a->_number, string); + break; + case 53: // SO_ACTOR_NEW + a->initActor(2); + break; + case 57: // SO_PALETTE + j = pop(); + i = pop(); + checkRange(255, 0, i, "o100_actorOps: Illegal palette slot %d"); + a->remapActorPaletteColor(i, j); + a->_needRedraw = true; + break; + case 59: + // HE games use reverse order of layering, so we adjust + a->_layer = -pop(); + a->_needRedraw = true; + break; + case 63: + a->_hePaletteNum = pop(); + a->_needRedraw = true; + break; + case 65: // SO_SCALE + i = pop(); + a->setScale(i, i); + break; + case 70: // SO_SHADOW + a->_heXmapNum = pop(); + a->_needRedraw = true; + break; + case 74: // SO_STEP_DIST + j = pop(); + i = pop(); + a->setActorWalkSpeed(i, j); + break; + case 78: + { + copyScriptString(string, sizeof(string)); + int slot = pop(); + + int len = resStrLen(string) + 1; + memcpy(a->_heTalkQueue[slot].sentence, string, len); + + a->_heTalkQueue[slot].posX = a->_talkPosX; + a->_heTalkQueue[slot].posY = a->_talkPosY; + a->_heTalkQueue[slot].color = a->_talkColor; + } + break; + case 83: // SO_ACTOR_VARIABLE + i = pop(); + a->setAnimVar(pop(), i); + break; + case 87: // SO_ALWAYS_ZCLIP + a->_forceClip = pop(); + break; + case 89: // SO_NEVER_ZCLIP + a->_forceClip = 0; + break; + case 128: + _actorClipOverride.bottom = pop(); + _actorClipOverride.right = pop(); + _actorClipOverride.top = pop(); + _actorClipOverride.left = pop(); + break; + case 130: // SO_SOUND + k = getStackList(args, ARRAYSIZE(args)); + for (i = 0; i < k; i++) + a->_sound[i] = args[i]; + break; + case 131: // SO_ACTOR_WIDTH + a->_width = pop(); + break; + case 132: // SO_ANIMATION_DEFAULT + a->_initFrame = 1; + a->_walkFrame = 2; + a->_standFrame = 3; + a->_talkStartFrame = 4; + a->_talkStopFrame = 5; + break; + case 133: // SO_ELEVATION + a->setElevation(pop()); + break; + case 134: // SO_FOLLOW_BOXES + a->_ignoreBoxes = 0; + a->_forceClip = 0; + if (a->isInCurrentRoom()) + a->putActor(a->_pos.x, a->_pos.y, a->_room); + break; + case 135: // SO_IGNORE_BOXES + a->_ignoreBoxes = 1; + a->_forceClip = 0; + if (a->isInCurrentRoom()) + a->putActor(a->_pos.x, a->_pos.y, a->_room); + break; + case 136: // SO_ACTOR_IGNORE_TURNS_OFF + a->_ignoreTurns = false; + break; + case 137: // SO_ACTOR_IGNORE_TURNS_ON + a->_ignoreTurns = true; + break; + case 138: // SO_INIT_ANIMATION + a->_initFrame = pop(); + break; + case 139: // SO_STAND_ANIMATION + a->_standFrame = pop(); + break; + case 140: // SO_TALK_ANIMATION + a->_talkStopFrame = pop(); + a->_talkStartFrame = pop(); + break; + case 141: // SO_TALK_COLOR + a->_talkColor = pop(); + break; + case 142: + k = pop(); + if (k == 0) + k = _rnd.getRandomNumberRng(1, 10); + a->_heNoTalkAnimation = 1; + a->setTalkCondition(k); + break; + case 143: // SO_TEXT_OFFSET + a->_talkPosY = pop(); + a->_talkPosX = pop(); + break; + case 144: // SO_WALK_ANIMATION + a->_walkFrame = pop(); + break; + default: + error("o100_actorOps: default case %d", subOp); + } +} + +void ScummEngine_v100he::o100_arrayOps() { + ArrayHeader *ah; + byte string[1024]; + int dim1end, dim1start, dim2end, dim2start; + int id, len, b, c, list[128]; + int offs, tmp, tmp2; + uint tmp3; + + byte subOp = fetchScriptByte(); + int array = fetchScriptWord(); + debug(9,"o100_arrayOps: array %d case %d", array, subOp); + + switch (subOp) { + case 35: + decodeScriptString(string); + len = resStrLen(string); + ah = defineArray(array, kStringArray, 0, 0, 0, len); + memcpy(ah->data, string, len); + break; + case 77: // SO_ASSIGN_STRING + copyScriptString(string, sizeof(string)); + len = resStrLen(string); + ah = defineArray(array, kStringArray, 0, 0, 0, len); + memcpy(ah->data, string, len); + break; + + case 128: // SO_ASSIGN_2DIM_LIST + len = getStackList(list, ARRAYSIZE(list)); + id = readVar(array); + if (id == 0) + error("Must DIM a two dimensional array before assigning"); + c = pop(); + while (--len >= 0) { + writeArray(array, c, len, list[len]); + } + break; + case 129: // SO_ASSIGN_INT_LIST + b = pop(); + c = pop(); + id = readVar(array); + if (id == 0) { + defineArray(array, kDwordArray, 0, 0, 0, b + c - 1); + } + while (c--) { + writeArray(array, 0, b + c, pop()); + } + break; + case 130: + len = getStackList(list, ARRAYSIZE(list)); + dim1end = pop(); + dim1start = pop(); + dim2end = pop(); + dim2start = pop(); + id = readVar(array); + if (id == 0) { + defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end); + } + tmp2 = 0; + while (dim2start <= dim2end) { + tmp = dim1start; + while (tmp <= dim1end) { + writeArray(array, dim2start, tmp, list[tmp2++]); + if (tmp2 == len) + tmp2 = 0; + tmp++; + } + dim2start++; + } + break; + case 131: + { + int a2_dim1end = pop(); + int a2_dim1start = pop(); + int a2_dim2end = pop(); + int a2_dim2start = pop(); + int array2 = fetchScriptWord(); + int a1_dim1end = pop(); + int a1_dim1start = pop(); + int a1_dim2end = pop(); + int a1_dim2start = pop(); + if (a1_dim1end - a1_dim1start != a2_dim1end - a2_dim1start || a2_dim2end - a2_dim2start != a1_dim2end - a1_dim2start) { + error("Source and dest ranges size are mismatched"); + } + copyArray(array, a1_dim2start, a1_dim2end, a1_dim1start, a1_dim1end, array2, a2_dim2start, a2_dim2end, a2_dim1start, a2_dim1end); + } + break; + case 133: + b = pop(); + c = pop(); + dim1end = pop(); + dim1start = pop(); + dim2end = pop(); + dim2start = pop(); + id = readVar(array); + if (id == 0) { + defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end); + } + + offs = (b >= c) ? 1 : -1; + tmp2 = c; + tmp3 = c - b + 1; + while (dim2start <= dim2end) { + tmp = dim1start; + while (tmp <= dim1end) { + writeArray(array, dim2start, tmp, tmp2); + if (--tmp3 == 0) { + tmp2 = c; + tmp3 = c - b + 1; + } else { + tmp2 += offs; + } + tmp++; + } + dim2start++; + } + break; + default: + error("o100_arrayOps: default case %d (array %d)", subOp, array); + } +} + +void ScummEngine_v100he::o100_jumpToScript() { + int args[25]; + int script; + byte flags; + + getStackList(args, ARRAYSIZE(args)); + script = pop(); + flags = fetchScriptByte(); + stopObjectCode(); + runScript(script, (flags == 128 || flags == 129), (flags == 130 || flags == 129), args); +} + +void ScummEngine_v100he::o100_createSound() { + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 0: + _heSndResId = pop(); + break; + case 53: + createSound(_heSndResId, -1); + break; + case 92: + // dummy case + break; + case 128: + createSound(_heSndResId, pop()); + break; + default: + error("o100_createSound: default case %d", subOp); + } +} + +void ScummEngine_v100he::o100_dim2dimArray() { + int data, dim1end, dim2end; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 41: // SO_BIT_ARRAY + data = kBitArray; + break; + case 42: // SO_INT_ARRAY + data = kIntArray; + break; + case 43: + data = kDwordArray; + break; + case 44: // SO_NIBBLE_ARRAY + data = kNibbleArray; + break; + case 45: // SO_BYTE_ARRAY + data = kByteArray; + break; + case 77: // SO_STRING_ARRAY + data = kStringArray; + break; + default: + error("o100_dim2dimArray: default case %d", subOp); + } + + dim1end = pop(); + dim2end = pop(); + defineArray(fetchScriptWord(), data, 0, dim2end, 0, dim1end); +} + +void ScummEngine_v100he::o100_dimArray() { + int data; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 41: // SO_BIT_ARRAY + data = kBitArray; + break; + case 42: // SO_INT_ARRAY + data = kIntArray; + break; + case 43: + data = kDwordArray; + break; + case 44: // SO_NIBBLE_ARRAY + data = kNibbleArray; + break; + case 45: // SO_BYTE_ARRAY + data = kByteArray; + break; + case 77: // SO_STRING_ARRAY + data = kStringArray; + break; + case 135: // SO_UNDIM_ARRAY + nukeArray(fetchScriptWord()); + return; + default: + error("o100_dimArray: default case %d", subOp); + } + + defineArray(fetchScriptWord(), data, 0, 0, 0, pop()); +} + +void ScummEngine_v100he::o100_drawLine() { + int id, unk1, unk2, x, x1, y1; + + unk2 = pop(); + id = pop(); + unk1 = pop(); + x = pop(); + y1 = pop(); + x1 = pop(); + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 1: + drawLine(x1, y1, x, unk1, unk2, 2, id); + break; + case 20: + drawLine(x1, y1, x, unk1, unk2, 1, id); + break; + case 40: + drawLine(x1, y1, x, unk1, unk2, 3, id); + break; + default: + error("o100_drawLine: default case %d", subOp); + } +} + +void ScummEngine_v100he::o100_drawObject() { + int state, y, x; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 6: + state = 1; + y = pop(); + x = pop(); + break; + case 7: + state = pop(); + y = pop(); + x = pop(); + break; + case 40: + state = pop(); + if (state == 0) + state = 1; + y = x = -100; + break; + default: + error("o100_drawObject: default case %d", subOp); + } + + int object = pop(); + int objnum = getObjectIndex(object); + if (objnum == -1) + return; + + if (y != -100 && x != -100) { + _objs[objnum].x_pos = x * 8; + _objs[objnum].y_pos = y * 8; + } + + if (state != -1) { + addObjectToDrawQue(objnum); + putState(object, state); + } +} + +void ScummEngine_v100he::o100_floodFill() { + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 0: + memset(&_floodFillParams, 0, sizeof(_floodFillParams)); + _floodFillParams.box.left = 0; + _floodFillParams.box.top = 0; + _floodFillParams.box.right = 639; + _floodFillParams.box.bottom = 479; + break; + case 6: + _floodFillParams.y = pop(); + _floodFillParams.x = pop(); + break; + case 18: + _floodFillParams.box.bottom = pop(); + _floodFillParams.box.right = pop(); + _floodFillParams.box.top = pop(); + _floodFillParams.box.left = pop(); + break; + case 20: + _floodFillParams.flags = pop(); + break; + case 67: + pop(); + break; + case 92: + floodFill(&_floodFillParams, this); + break; + default: + error("o100_floodFill: Unknown case %d", subOp); + } +} + +void ScummEngine_v100he::o100_setSpriteGroupInfo() { + byte string[260]; + int type, value1, value2, value3, value4; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 0: + _curSpriteGroupId = pop(); + break; + case 6: + value2 = pop(); + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupPosition(_curSpriteGroupId, value1, value2); + break; + case 18: + value4 = pop(); + value3 = pop(); + value2 = pop(); + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupBounds(_curSpriteGroupId, value1, value2, value3, value4); + break; + case 38: + type = pop() - 1; + switch (type) { + case 0: + value2 = pop(); + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->moveGroupMembers(_curSpriteGroupId, value1, value2); + break; + case 1: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupMembersPriority(_curSpriteGroupId, value1); + break; + case 2: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupMembersGroup(_curSpriteGroupId, value1); + break; + case 3: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupMembersUpdateType(_curSpriteGroupId, value1); + break; + case 4: + if (!_curSpriteGroupId) + break; + + _sprite->setGroupMembersResetSprite(_curSpriteGroupId); + break; + case 5: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupMembersAnimationSpeed(_curSpriteGroupId, value1); + break; + case 6: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupMembersAutoAnimFlag(_curSpriteGroupId, value1); + break; + case 7: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupMembersShadow(_curSpriteGroupId, value1); + break; + default: + error("o100_setSpriteGroupInfo subOp 38: Unknown case %d", subOp); + } + break; + case 40: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupImage(_curSpriteGroupId, value1); + break; + case 49: + value2 = pop(); + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->moveGroup(_curSpriteGroupId, value1, value2); + break; + case 52: + copyScriptString(string, sizeof(string)); + break; + case 53: + if (!_curSpriteGroupId) + break; + + _sprite->resetGroup(_curSpriteGroupId); + break; + case 54: + // dummy case + pop(); + pop(); + break; + case 59: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupPriority(_curSpriteGroupId, value1); + break; + case 60: + type = pop(); + value1 = pop(); + if (!_curSpriteGroupId) + break; + + switch (type) { + case 0: + _sprite->setGroupXMul(_curSpriteGroupId, value1); + break; + case 1: + _sprite->setGroupXDiv(_curSpriteGroupId, value1); + break; + case 2: + _sprite->setGroupYMul(_curSpriteGroupId, value1); + break; + case 3: + _sprite->setGroupYDiv(_curSpriteGroupId, value1); + break; + default: + error("o100_setSpriteGroupInfo subOp 60: Unknown case %d", subOp); + } + break; + case 89: + if (!_curSpriteGroupId) + break; + + _sprite->resetGroupBounds(_curSpriteGroupId); + break; + default: + error("o100_setSpriteGroupInfo: Unknown case %d", subOp); + } +} + +void ScummEngine_v100he::o100_resourceRoutines() { + int objidx, room; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 14: + _heResType = rtCharset; + _heResId = pop(); + break; + case 25: + _heResType = rtCostume; + _heResId = pop(); + break; + case 34: + _heResType = rtFlObject; + _heResId = pop(); + break; + case 40: + _heResType = rtImage; + _heResId = pop(); + break; + case 47: + if (_heResType == rtFlObject) { + room = getObjectRoom(_heResId); + loadFlObject(_heResId, room); + } else if (_heResType == rtCharset) { + loadCharset(_heResId); + } else { + ensureResourceLoaded(_heResType, _heResId); + } + break; + case 62: + _heResType = rtRoom; + _heResId = pop(); + break; + case 66: + _heResType = rtScript; + _heResId = pop(); + break; + case 72: + _heResType = rtSound; + _heResId = pop(); + break; + case 128: + break; + case 132: + if (_heResType == rtScript && _heResId >= _numGlobalScripts) + break; + + if (_heResType == rtFlObject) { + objidx = getObjectIndex(_heResId); + if (objidx == -1) + break; + res.lock(rtFlObject, _objs[objidx].fl_object_index); + } else { + res.lock(_heResType, _heResId); + } + break; + case 133: + if (_heResType == rtCharset) + nukeCharset(_heResId); + else + res.nukeResource(_heResType, _heResId); + break; + case 134: + case 135: + // Heap related + break; + case 136: + if (_heResType == rtScript && _heResId >= _numGlobalScripts) + break; + + //queueLoadResource(_heResType, _heResId); + break; + case 137: + if (_heResType == rtScript && _heResId >= _numGlobalScripts) + break; + + if (_heResType == rtFlObject) { + objidx = getObjectIndex(_heResId); + if (objidx == -1) + break; + res.unlock(rtFlObject, _objs[objidx].fl_object_index); + } else { + res.unlock(_heResType, _heResId); + } + break; + default: + error("o100_resourceRoutines: default case %d", subOp); + } +} + +void ScummEngine_v100he::o100_wizImageOps() { + int a, b; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 0: + _wizParams.img.resNum = pop(); + _wizParams.processMode = 0; + _wizParams.processFlags = 0; + _wizParams.remapNum = 0; + _wizParams.img.flags = 0; + _wizParams.field_184 = 0; + _wizParams.field_180 = 0; + _wizParams.spriteId = 0; + _wizParams.spriteGroup = 0; + break; + case 2: + _wizParams.processFlags |= kWPFRotate; + _wizParams.angle = pop(); + break; + case 6: + case 132: + _wizParams.processFlags |= kWPFSetPos; + _wizParams.img.y1 = pop(); + _wizParams.img.x1 = pop(); + break; + case 7: + _wizParams.processFlags |= kWPFMaskImg; + _wizParams.sourceImage = pop(); + break; + case 11: + _wizParams.processFlags |= kWPFClipBox | 0x100; + _wizParams.processMode = 2; + _wizParams.box.bottom = pop(); + _wizParams.box.right = pop(); + _wizParams.box.top = pop(); + _wizParams.box.left = pop(); + _wizParams.compType = pop(); + break; + case 18: + _wizParams.processFlags |= kWPFClipBox; + _wizParams.box.bottom = pop(); + _wizParams.box.right = pop(); + _wizParams.box.top = pop(); + _wizParams.box.left = pop(); + break; + case 21: + b = pop(); + a = pop(); + _wizParams.processFlags |= kWPFRemapPalette; + _wizParams.processMode = 6; + if (_wizParams.remapNum == 0) { + memset(_wizParams.remapIndex, 0, sizeof(_wizParams.remapIndex)); + } else { + assert(_wizParams.remapNum < ARRAYSIZE(_wizParams.remapIndex)); + _wizParams.remapIndex[_wizParams.remapNum] = a; + _wizParams.remapColor[a] = b; + ++_wizParams.remapNum; + } + break; + case 29: + _wizParams.processMode = 1; + break; + case 36: + _wizParams.box.bottom = pop(); + _wizParams.box.right = pop(); + _wizParams.box.top = pop(); + _wizParams.box.left = pop(); + break; + case 37: + // Dummy case + pop(); + break; + case 39: + _wizParams.processFlags |= kWPFUseDefImgHeight; + _wizParams.resDefImgH = pop(); + break; + case 47: + _wizParams.processFlags |= kWPFUseFile; + _wizParams.processMode = 3; + copyScriptString(_wizParams.filename, sizeof(_wizParams.filename)); + break; + case 53: + _wizParams.processMode = 8; + break; + case 54: + _wizParams.processFlags |= 0x100000; + _wizParams.field_180 = pop(); + _wizParams.field_184 = pop(); + break; + case 55: + _wizParams.img.flags = pop(); + _wizParams.img.state = pop(); + _wizParams.img.y1 = pop(); + _wizParams.img.x1 = pop(); + _wizParams.spriteId = 0; + _wizParams.spriteGroup = 0; + _wizParams.img.resNum = pop(); + _wiz->displayWizImage(&_wizParams.img); + break; + case 57: + _wizParams.processFlags |= kWPFPaletteNum; + _wizParams.img.palette = pop(); + break; + case 58: + _wizParams.processFlags |= 0x1000 | 0x100 | 0x2; + _wizParams.processMode = 7; + _wizParams.field_168 = pop(); + _wizParams.field_164 = pop(); + _wizParams.compType = pop(); + break; + case 64: + _wizParams.processFlags |= kWPFUseFile; + _wizParams.processMode = 4; + copyScriptString(_wizParams.filename, sizeof(_wizParams.filename)); + _wizParams.fileWriteMode = pop(); + break; + case 65: + _wizParams.processFlags |= kWPFScaled; + _wizParams.scale = pop(); + break; + case 67: + _wizParams.processFlags |= kWPFNewFlags; + _wizParams.img.flags |= pop(); + break; + case 68: + _wizParams.processFlags |= kWPFNewFlags | kWPFSetPos | 2; + _wizParams.img.flags |= kWIFIsPolygon; + _wizParams.field_164 = _wizParams.img.y1 = _wizParams.img.x1 = pop(); + break; + case 70: + _wizParams.processFlags |= kWPFShadow; + _wizParams.img.shadow = pop(); + break; + case 73: + _wizParams.processFlags |= kWPFNewState; + _wizParams.img.state = pop(); + break; + case 84: + _wizParams.processFlags |= kWPFUseDefImgWidth; + _wizParams.resDefImgW = pop(); + break; + case 92: + if (_wizParams.img.resNum) + _wiz->processWizImage(&_wizParams); + break; + case 128: + _wizParams.field_239D = pop(); + _wizParams.field_2399 = pop(); + _wizParams.field_23A5 = pop(); + _wizParams.field_23A1 = pop(); + copyScriptString(_wizParams.string2, sizeof(_wizParams.string2)); + _wizParams.processMode = 15; + break; + case 129: + _wizParams.processMode = 14; + break; + case 130: + _wizParams.processMode = 16; + _wizParams.field_23AD = pop(); + _wizParams.field_23A9 = pop(); + copyScriptString(_wizParams.string1, sizeof(_wizParams.string1)); + break; + case 131: + _wizParams.processMode = 13; + break; + case 133: + _wizParams.processMode = 17; + _wizParams.field_23CD = pop(); + _wizParams.field_23C9 = pop(); + _wizParams.field_23C5 = pop(); + _wizParams.field_23C1 = pop(); + _wizParams.field_23BD = pop(); + _wizParams.field_23B9 = pop(); + _wizParams.field_23B5 = pop(); + _wizParams.field_23B1 = pop(); + break; + case 134: + _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; + _wizParams.processMode = 12; + _wizParams.fillColor = pop(); + _wizParams.box2.top = _wizParams.box2.bottom = pop(); + _wizParams.box2.left = _wizParams.box2.right = pop(); + break; + case 135: + _wizParams.processFlags |= kWPFDstResNum; + _wizParams.dstResNum = pop(); + break; + case 136: + _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; + _wizParams.processMode = 10; + _wizParams.fillColor = pop(); + _wizParams.box2.bottom = pop(); + _wizParams.box2.right = pop(); + _wizParams.box2.top = pop(); + _wizParams.box2.left = pop(); + break; + case 137: + _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; + _wizParams.processMode = 11; + _wizParams.fillColor = pop(); + _wizParams.box2.top = _wizParams.box2.bottom = pop(); + _wizParams.box2.left = _wizParams.box2.right = pop(); + break; + case 138: + _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; + _wizParams.processMode = 9; + _wizParams.fillColor = pop(); + _wizParams.box2.bottom = pop(); + _wizParams.box2.right = pop(); + _wizParams.box2.top = pop(); + _wizParams.box2.left = pop(); + break; + default: + error("o100_wizImageOps: Unknown case %d", subOp); + } +} + +void ScummEngine_v100he::o100_dim2dim2Array() { + int data, dim1start, dim1end, dim2start, dim2end; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 41: // SO_BIT_ARRAY + data = kBitArray; + break; + case 42: // SO_INT_ARRAY + data = kIntArray; + break; + case 43: + data = kDwordArray; + break; + case 44: // SO_NIBBLE_ARRAY + data = kNibbleArray; + break; + case 45: // SO_BYTE_ARRAY + data = kByteArray; + break; + case 77: // SO_STRING_ARRAY + data = kStringArray; + break; + default: + error("o100_dim2dim2Array: default case %d", subOp); + } + + if (pop() == 2) { + dim1end = pop(); + dim1start = pop(); + dim2end = pop(); + dim2start = pop(); + } else { + dim2end = pop(); + dim2start = pop(); + dim1end = pop(); + dim1start = pop(); + } + + defineArray(fetchScriptWord(), data, dim2start, dim2end, dim1start, dim1end); +} + +void ScummEngine_v100he::o100_redim2dimArray() { + int a, b, c, d; + d = pop(); + c = pop(); + b = pop(); + a = pop(); + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 42: + redimArray(fetchScriptWord(), a, b, c, d, kIntArray); + break; + case 43: + redimArray(fetchScriptWord(), a, b, c, d, kDwordArray); + break; + case 45: + redimArray(fetchScriptWord(), a, b, c, d, kByteArray); + break; + default: + error("o100_redim2dimArray: default type %d", subOp); + } +} + +void ScummEngine_v100he::o100_paletteOps() { + int a, b, c, d, e; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 0: + _hePaletteNum = pop(); + break; + case 20: + e = pop(); + d = pop(); + c = pop(); + b = pop(); + a = pop(); + if (_hePaletteNum != 0) { + for (; a <= b; ++a) { + setHEPaletteColor(_hePaletteNum, a, c, d, e); + } + } + break; + case 25: + a = pop(); + if (_hePaletteNum != 0) { + setHEPaletteFromCostume(_hePaletteNum, a); + } + break; + case 40: + b = pop(); + a = pop(); + if (_hePaletteNum != 0) { + setHEPaletteFromImage(_hePaletteNum, a, b); + } + break; + case 53: + if (_hePaletteNum != 0) { + restoreHEPalette(_hePaletteNum); + } + break; + case 57: + a = pop(); + if (_hePaletteNum != 0) { + copyHEPalette(_hePaletteNum, a); + } + break; + case 63: + b = pop(); + a = pop(); + if (_hePaletteNum != 0) { + setHEPaletteFromRoom(_hePaletteNum, a, b); + } + break; + case 81: + c = pop(); + b = pop(); + a = pop(); + if (_hePaletteNum) { + for (; a <= b; ++a) { + copyHEPaletteColor(_hePaletteNum, a, c); + } + } + break; + case 92: + _hePaletteNum = 0; + break; + default: + error("o100_paletteOps: Unknown case %d", subOp); + } +} + +void ScummEngine_v100he::o100_jumpToScriptUnk() { + int args[25]; + int script, cycle; + byte flags; + + getStackList(args, ARRAYSIZE(args)); + cycle = pop(); + script = pop(); + flags = fetchScriptByte(); + stopObjectCode(); + runScript(script, (flags == 128 || flags == 129), (flags == 130 || flags == 129), args, cycle); +} + +void ScummEngine_v100he::o100_startScriptUnk() { + int args[25]; + int script, cycle; + byte flags; + + getStackList(args, ARRAYSIZE(args)); + cycle = pop(); + script = pop(); + flags = fetchScriptByte(); + runScript(script, (flags == 128 || flags == 129), (flags == 130 || flags == 129), args, cycle); +} + +void ScummEngine_v100he::o100_redimArray() { + int newX, newY; + newY = pop(); + newX = pop(); + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 42: + redimArray(fetchScriptWord(), 0, newX, 0, newY, kIntArray); + break; + case 43: + redimArray(fetchScriptWord(), 0, newX, 0, newY, kDwordArray); + break; + case 45: + redimArray(fetchScriptWord(), 0, newX, 0, newY, kByteArray); + break; + default: + error("o100_redimArray: default type %d", subOp); + } +} + +void ScummEngine_v100he::o100_roomOps() { + int a, b, c, d, e; + byte filename[100]; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 63: // SO_ROOM_PALETTE + d = pop(); + c = pop(); + b = pop(); + a = pop(); + setPalColor(d, a, b, c); + break; + + case 129: + b = pop(); + a = pop(); + swapObjects(a, b); + break; + + case 130: + a = pop(); + b = pop(); + copyPalColor(a, b); + break; + + case 131: // SO_ROOM_FADE + // Defaults to 1 but doesn't use fade effects + a = pop(); + break; + + case 132: // SO_ROOM_INTENSITY + c = pop(); + b = pop(); + a = pop(); + darkenPalette(a, a, a, b, c); + break; + + case 133: // SO_RGB_ROOM_INTENSITY + e = pop(); + d = pop(); + c = pop(); + b = pop(); + a = pop(); + darkenPalette(a, b, c, d, e); + break; + + case 134: // SO_ROOM_NEW_PALETTE + a = pop(); + setPalette(a); + break; + + case 135: + b = pop(); + a = pop(); + setRoomPalette(a, b); + break; + + case 136: // SO_ROOM_SAVEGAME + _saveTemporaryState = true; + _saveLoadSlot = pop(); + _saveLoadFlag = pop(); + break; + + case 137: + copyScriptString(filename, sizeof(filename)); + _saveLoadFlag = pop(); + _saveLoadSlot = 1; + _saveTemporaryState = true; + break; + + case 138: // SO_ROOM_SCREEN + b = pop(); + a = pop(); + initScreens(a, _screenHeight); + break; + + case 139: // SO_ROOM_SCROLL + b = pop(); + a = pop(); + if (a < (_screenWidth / 2)) + a = (_screenWidth / 2); + if (b < (_screenWidth / 2)) + b = (_screenWidth / 2); + if (a > _roomWidth - (_screenWidth / 2)) + a = _roomWidth - (_screenWidth / 2); + if (b > _roomWidth - (_screenWidth / 2)) + b = _roomWidth - (_screenWidth / 2); + VAR(VAR_CAMERA_MIN_X) = a; + VAR(VAR_CAMERA_MAX_X) = b; + break; + + default: + error("o100_roomOps: default case %d", subOp); + } +} + +void ScummEngine_v100he::o100_setSystemMessage() { + byte name[1024]; + + copyScriptString(name, sizeof(name)); + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 80: // Set Window Caption + _system->setWindowCaption((const char *)name); + break; + case 131: // Set Version + debug(1,"o100_setSystemMessage: (%d) %s", subOp, name); + break; + default: + error("o100_setSystemMessage: default case %d", subOp); + } +} + +void ScummEngine_v100he::o100_startSound() { + byte filename[260]; + int var, value; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 6: + _heSndFlags |= 16; + _heSndOffset = pop(); + break; + case 47: + copyScriptString(filename, sizeof(filename)); + _heSndSoundId = pop(); + if (_heSndSoundId) + debug(0, "Load sound %d from file %s\n", _heSndSoundId, filename); + break; + case 55: + _heSndFlags |= 8; + break; + case 83: + value = pop(); + var = pop(); + _heSndSoundId = pop(); + _sound->setSoundVar(_heSndSoundId, var, value); + break; + case 92: + _sound->addSoundToQueue(_heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags); + break; + case 128: + _heSndFlags |= 2; + break; + case 129: + _heSndChannel = pop(); + break; + case 130: + _heSndFlags |= 64; + pop(); + break; + case 131: + _heSndFlags |= 1; + break; + case 132: // Music + case 134: // Sound + _heSndSoundId = pop(); + _heSndOffset = 0; + _heSndSoundFreq = 11025; + _heSndChannel = VAR(VAR_SOUND_CHANNEL); + _heSndFlags = 0; + break; + case 133: + _heSndFlags |= 128; + pop(); + break; + case 135: + _heSndFlags |= 4; + break; + case 136: + _heSndFlags |= 32; + pop(); + break; + default: + error("o100_startSound invalid case %d", subOp); + } +} + +void ScummEngine_v100he::o100_setSpriteInfo() { + int args[16]; + int spriteId, n; + int32 tmp[2]; + byte string[80]; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 0: + _curMaxSpriteId = pop(); + _curSpriteId = pop(); + + if (_curSpriteId > _curMaxSpriteId) + SWAP(_curSpriteId, _curMaxSpriteId); + break; + case 2: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteAngle(spriteId, args[0]); + break; + case 3: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteFlagAutoAnim(spriteId, args[0]); + break; + case 4: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteAnimSpeed(spriteId, args[0]); + break; + case 6: + args[1] = pop(); + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpritePosition(spriteId, args[0], args[1]); + break; + case 7: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteSourceImage(spriteId, args[0]); + break; + case 16: + n = getStackList(args, ARRAYSIZE(args)); + if (_curSpriteId != 0 && _curMaxSpriteId != 0 && n != 0) { + int *p = &args[n - 1]; + do { + int code = *p; + if (code == 0) { + for (int i = _curSpriteId; i <= _curMaxSpriteId; ++i) { + _sprite->setSpriteResetClass(i); + } + } else if (code & 0x80) { + for (int i = _curSpriteId; i <= _curMaxSpriteId; ++i) { + _sprite->setSpriteSetClass(i, code & 0x7F, 1); + } + } else { + for (int i = _curSpriteId; i <= _curMaxSpriteId; ++i) { + _sprite->setSpriteSetClass(i, code & 0x7F, 0); + } + } + --p; + } while (--n); + } + break; + case 32: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteFlagEraseType(spriteId, args[0]); + break; + case 38: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteGroup(spriteId, args[0]); + break; + case 40: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteImage(spriteId, args[0]); + break; + case 48: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteMaskImage(spriteId, args[0]); + break; + case 49: + args[1] = pop(); + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->moveSprite(spriteId, args[0], args[1]); + break; + case 52: + copyScriptString(string, sizeof(string)); + break; + case 53: + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->resetSprite(spriteId); + break; + case 54: + args[1] = pop(); + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteGeneralProperty(spriteId, args[0], args[1]); + break; + case 57: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpritePalette(spriteId, args[0]); + break; + case 59: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpritePriority(spriteId, args[0]); + break; + case 60: + args[1] = pop(); + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + switch(args[1]) { + case 0: + _sprite->setSpriteFlagXFlipped(spriteId, args[0]); + break; + case 1: + _sprite->setSpriteFlagYFlipped(spriteId, args[0]); + break; + case 2: + _sprite->setSpriteFlagActive(spriteId, args[0]); + break; + case 3: + _sprite->setSpriteFlagDoubleBuffered(spriteId, args[0]); + break; + case 4: + _sprite->setSpriteFlagRemapPalette(spriteId, args[0]); + break; + default: + break; + } + break; + case 61: + _sprite->resetTables(true); + break; + case 65: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteScale(spriteId, args[0]); + break; + case 70: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteShadow(spriteId, args[0]); + break; + case 73: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteImageState(spriteId, args[0]); + break; + case 74: + args[1] = pop(); + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteDist(spriteId, args[0], args[1]); + break; + case 75: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) { + _sprite->getSpriteDist(spriteId, tmp[0], tmp[1]); + _sprite->setSpriteDist(spriteId, args[0], tmp[1]); + } + break; + case 76: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) { + _sprite->getSpriteDist(spriteId, tmp[0], tmp[1]); + _sprite->setSpriteDist(spriteId, tmp[0], args[0]); + } + break; + case 82: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteFlagUpdateType(spriteId, args[0]); + break; + case 83: + args[1] = pop(); + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteUserValue(spriteId, args[0], args[1]); + break; + case 88: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteField84(spriteId, args[0]); + break; + case 89: + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteField84(spriteId, 0); + break; + default: + error("o100_setSpriteInfo: Unknown case %d", subOp); + } +} + +void ScummEngine_v100he::o100_startScript() { + int args[25]; + int script; + byte flags; + + getStackList(args, ARRAYSIZE(args)); + script = pop(); + flags = fetchScriptByte(); + runScript(script, (flags == 128 || flags == 129), (flags == 130 || flags == 129), args); +} + +void ScummEngine_v100he::o100_systemOps() { + byte string[1024]; + + byte subOp = fetchScriptByte(); + subOp -= 61; + + switch (subOp) { + case 0: + restart(); + break; + case 67: + clearDrawObjectQueue(); + break; + case 71: + // Confirm shutdown + shutDown(); + break; + case 72: + shutDown(); + break; + case 73: + copyScriptString(string, sizeof(string)); + debug(0, "Start game (%s)", string); + break; + case 74: + copyScriptString(string, sizeof(string)); + debug(0, "Start executable (%s)", string); + break; + case 75: + gdi.copyVirtScreenBuffers(Common::Rect(_screenWidth, _screenHeight)); + updatePalette(); + break; + default: + error("o100_systemOps invalid case %d", subOp); + } +} + +void ScummEngine_v100he::o100_cursorCommand() { + int a, i; + int args[16]; + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 0xE: // SO_CHARSET_SET + initCharset(pop()); + break; + case 0xF: // SO_CHARSET_COLOR + getStackList(args, ARRAYSIZE(args)); + for (i = 0; i < 16; i++) + _charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i]; + break; + case 0x80: + case 0x81: + a = pop(); + _wiz->loadWizCursor(a); + break; + case 0x82: + pop(); + a = pop(); + _wiz->loadWizCursor(a); + break; + case 0x86: // SO_CURSOR_ON Turn cursor on + _cursor.state = 1; + break; + case 0x87: // SO_CURSOR_OFF Turn cursor off + _cursor.state = 0; + break; + case 0x88: // SO_CURSOR_SOFT_ON Turn soft cursor on + _cursor.state++; + if (_cursor.state > 1) + error("o100_cursorCommand: Cursor state greater than 1 in script"); + break; + + case 0x89: // SO_CURSOR_SOFT_OFF Turn soft cursor off + _cursor.state--; + break; + case 0x8B: // SO_USERPUT_ON + _userPut = 1; + break; + case 0x8C: // SO_USERPUT_OFF + _userPut = 0; + break; + case 0x8D: // SO_USERPUT_SOFT_ON + _userPut++; + break; + case 0x8E: // SO_USERPUT_SOFT_OFF + _userPut--; + break; + default: + error("o100_cursorCommand: default case %x", subOp); + } + + VAR(VAR_CURSORSTATE) = _cursor.state; + VAR(VAR_USERPUT) = _userPut; +} + +void ScummEngine_v100he::o100_videoOps() { + // Uses Bink video + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 0: + memset(_videoParams.filename, 0, sizeof(_videoParams.filename)); + _videoParams.unk2 = pop(); + break; + case 19: + _videoParams.status = 19; + break; + case 40: + _videoParams.wizResNum = pop(); + if (_videoParams.wizResNum) + _videoParams.flags |= 2; + break; + case 47: + copyScriptString(_videoParams.filename, sizeof(_videoParams.filename)); + _videoParams.status = 47; + break; + case 67: + _videoParams.flags |= pop(); + break; + case 92: + if (_videoParams.status == 47) { + // Start video + if (_videoParams.flags == 0) + _videoParams.flags = 4; + + if (_videoParams.flags == 2) { + // result = startVideo(_videoParams.filename, _videoParams.flags, _videoParams.wizResNum); + // VAR(119) = result; + } else { + // result = startVideo(_videoParams.filename, _videoParams.flags); + // VAR(119) = result; + } + } else if (_videoParams.status == 19) { + // Stop video + } + break; + default: + error("o100_videoOps: unhandled case %d", subOp); + } + + debug(1,"o100_videoOps stub (%d)", subOp); +} + +void ScummEngine_v100he::o100_wait() { + int actnum; + int offs = -2; + Actor *a; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 128: // SO_WAIT_FOR_ACTOR Wait for actor + offs = fetchScriptWordSigned(); + actnum = pop(); + a = derefActor(actnum, "o100_wait:168"); + if (a->_moving) + break; + return; + case 129: // SO_WAIT_FOR_CAMERA Wait for camera + if (camera._cur.x / 8 != camera._dest.x / 8) + break; + return; + case 130: // SO_WAIT_FOR_MESSAGE Wait for message + if (VAR(VAR_HAVE_MSG)) + break; + return; + case 131: // SO_WAIT_FOR_SENTENCE + if (_sentenceNum) { + if (_sentence[_sentenceNum - 1].freezeCount && !isScriptInUse(VAR(VAR_SENTENCE_SCRIPT))) + return; + break; + } + if (!isScriptInUse(VAR(VAR_SENTENCE_SCRIPT))) + return; + break; + default: + error("o100_wait: default case 0x%x", subOp); + } + + _scriptPointer += offs; + o6_breakHere(); +} + +void ScummEngine_v100he::o100_writeFile() { + int32 resID = pop(); + int slot = pop(); + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 5: + fetchScriptByte(); + writeFileFromArray(slot, resID); + break; + case 42: + _hFileTable[slot].writeUint16LE(resID); + break; + case 43: + _hFileTable[slot].writeUint32LE(resID); + break; + case 45: + _hFileTable[slot].writeByte(resID); + break; + default: + error("o100_writeFile: default case %d", subOp); + } +} + +void ScummEngine_v100he::o100_isResourceLoaded() { + // Reports percentage of resource loaded by queue + int type; + + byte subOp = fetchScriptByte(); + /* int idx = */ pop(); + + switch (subOp) { + case 25: + type = rtCostume; + break; + case 40: + type = rtImage; + break; + case 62: + type = rtRoom; + break; + case 66: + type = rtScript; + break; + case 72: + type = rtSound; + break; + default: + error("o100_isResourceLoaded: default case %d", subOp); + } + + push(100); +} + +void ScummEngine_v100he::o100_getResourceSize() { + const byte *ptr; + int size, type; + + int resid = pop(); + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 25: + type = rtCostume; + break; + case 40: + type = rtImage; + break; + case 62: + type = rtRoomImage; + break; + case 66: + type = rtScript; + break; + case 72: + push (getSoundResourceSize(resid)); + return; + default: + error("o100_getResourceSize: default type %d", subOp); + } + + ptr = getResourceAddress(type, resid); + assert(ptr); + size = READ_BE_UINT32(ptr + 4) - 8; + push(size); +} + +void ScummEngine_v100he::o100_getSpriteGroupInfo() { + int32 tx, ty; + int spriteGroupId, type; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 5: + spriteGroupId = pop(); + if (spriteGroupId) + push(getGroupSpriteArray(spriteGroupId)); + else + push(0); + break; + case 40: + spriteGroupId = pop(); + if (spriteGroupId) + push(_sprite->getGroupDstResNum(spriteGroupId)); + else + push(0); + break; + case 54: + // TODO: U32 related + pop(); + pop(); + push(0); + break; + case 59: + spriteGroupId = pop(); + if (spriteGroupId) + push(_sprite->getGroupPriority(spriteGroupId)); + else + push(0); + break; + case 60: + type = pop(); + spriteGroupId = pop(); + if (spriteGroupId) { + switch(type) { + case 0: + push(_sprite->getGroupXMul(spriteGroupId)); + break; + case 1: + push(_sprite->getGroupXDiv(spriteGroupId)); + break; + case 2: + push(_sprite->getGroupYMul(spriteGroupId)); + break; + case 3: + push(_sprite->getGroupYDiv(spriteGroupId)); + break; + default: + push(0); + } + } else { + push(0); + } + break; + case 85: + spriteGroupId = pop(); + if (spriteGroupId) { + _sprite->getGroupPosition(spriteGroupId, tx, ty); + push(tx); + } else { + push(0); + } + break; + case 86: + spriteGroupId = pop(); + if (spriteGroupId) { + _sprite->getGroupPosition(spriteGroupId, tx, ty); + push(ty); + } else { + push(0); + } + break; + default: + error("o100_getSpriteGroupInfo: Unknown case %d", subOp); + } +} + +void ScummEngine_v100he::o100_getWizData() { + byte filename[4096]; + int resId, state, type; + int32 w, h; + int32 x, y; + + byte subOp = fetchScriptByte(); + subOp -= 20; + + switch (subOp) { + case 0: + y = pop(); + x = pop(); + state = pop(); + resId = pop(); + push(_wiz->getWizPixelColor(resId, state, x, y, 0)); + break; + case 6: + resId = pop(); + push(_wiz->getWizImageStates(resId)); + break; + case 13: + y = pop(); + x = pop(); + state = pop(); + resId = pop(); + push(_wiz->isWizPixelNonTransparent(resId, state, x, y, 0)); + break; + case 19: + state = pop(); + resId = pop(); + _wiz->getWizImageDim(resId, state, w, h); + push(h); + break; + case 34: + type = pop(); + state = pop(); + resId = pop(); + push(_wiz->getWizImageData(resId, state, type)); + break; + case 64: + state = pop(); + resId = pop(); + _wiz->getWizImageDim(resId, state, w, h); + push(w); + break; + case 65: + state = pop(); + resId = pop(); + _wiz->getWizImageSpot(resId, state, x, y); + push(x); + break; + case 66: + state = pop(); + resId = pop(); + _wiz->getWizImageSpot(resId, state, x, y); + push(y); + break; + case 111: + pop(); + copyScriptString(filename, sizeof(filename)); + pop(); + push(0); + debug(0, "o100_getWizData() case 111 unhandled"); + break; + case 112: + h = pop(); + w = pop(); + y = pop(); + x = pop(); + state = pop(); + resId = pop(); + if (x == -1 && y == -1 && w == -1 && h == -1) { + _wiz->getWizImageDim(resId, state, w, h); + x = 0; + y = 0; + } + push(computeWizHistogram(resId, state, x, y, w, h)); + break; + default: + error("o100_getWizData: Unknown case %d", subOp); + } +} + +void ScummEngine_v100he::o100_getPaletteData() { + int b, c, d, e; + int palSlot, color; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 13: + c = pop(); + b = pop(); + push(getHEPaletteColorComponent(1, b, c)); + break; + case 20: + color = pop(); + palSlot = pop(); + push(getHEPaletteColor(palSlot, color)); + break; + case 33: + e = pop(); + d = pop(); + palSlot = pop(); + pop(); + c = pop(); + b = pop(); + push(getHEPaletteSimilarColor(palSlot, b, c, d, e)); + break; + case 53: + pop(); + c = pop(); + c = MAX(0, c); + c = MIN(c, 255); + b = pop(); + b = MAX(0, b); + b = MIN(b, 255); + push(getHEPaletteSimilarColor(1, b, c, 10, 245)); + break; + case 73: + c = pop(); + b = pop(); + palSlot = pop(); + push(getHEPaletteColorComponent(palSlot, b, c)); + break; + default: + error("o100_getPaletteData: Unknown case %d", subOp); + } +} + +void ScummEngine_v100he::o100_readFile() { + int slot, val; + int32 size; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 5: + fetchScriptByte(); + size = pop(); + slot = pop(); + val = readFileToArray(slot, size); + push(val); + break; + case 42: + slot = pop(); + val = _hFileTable[slot].readUint16LE(); + push(val); + break; + case 43: + slot = pop(); + val = _hFileTable[slot].readUint32LE(); + push(val); + break; + case 45: + slot = pop(); + val = _hFileTable[slot].readByte(); + push(val); + break; + default: + error("o100_readFile: default case %d", subOp); + } +} + +void ScummEngine_v100he::o100_getSpriteInfo() { + int args[16]; + int spriteId, flags, groupId, type; + int32 x, y; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 3: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteFlagAutoAnim(spriteId)); + else + push(0); + break; + case 4: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteAnimSpeed(spriteId)); + else + push(1); + break; + case 7: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteSourceImage(spriteId)); + else + push(0); + break; + case 16: + flags = getStackList(args, ARRAYSIZE(args)); + spriteId = pop(); + if (spriteId) { + push(_sprite->getSpriteClass(spriteId, flags, args)); + } else { + push(0); + } + break; + case 26: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteImageStateCount(spriteId)); + else + push(0); + break; + case 30: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteDisplayX(spriteId)); + else + push(0); + break; + case 31: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteDisplayY(spriteId)); + else + push(0); + break; + case 32: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteFlagEraseType(spriteId)); + else + push(1); + break; + case 33: + flags = getStackList(args, ARRAYSIZE(args)); + type = pop(); + groupId = pop(); + y = pop(); + x = pop(); + push(_sprite->findSpriteWithClassOf(x, y, groupId, type, flags, args)); + break; + case 38: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteGroup(spriteId)); + else + push(0); + break; + case 39: + spriteId = pop(); + if (spriteId) { + _sprite->getSpriteImageDim(spriteId, x, y); + push(y); + } else { + push(0); + } + break; + case 40: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteImage(spriteId)); + else + push(0); + break; + case 48: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteMaskImage(spriteId)); + else + push(0); + break; + case 54: + flags = pop(); + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteGeneralProperty(spriteId, flags)); + else + push(0); + break; + case 57: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpritePalette(spriteId)); + else + push(0); + break; + case 59: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpritePriority(spriteId)); + else + push(0); + break; + case 60: + flags = pop(); + spriteId = pop(); + if (spriteId) { + switch(flags) { + case 0: + push(_sprite->getSpriteFlagXFlipped(spriteId)); + break; + case 1: + push(_sprite->getSpriteFlagYFlipped(spriteId)); + break; + case 2: + push(_sprite->getSpriteFlagActive(spriteId)); + break; + case 3: + push(_sprite->getSpriteFlagDoubleBuffered(spriteId)); + break; + case 4: + push(_sprite->getSpriteFlagRemapPalette(spriteId)); + break; + default: + push(0); + } + } else { + push(0); + } + break; + case 65: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteScale(spriteId)); + else + push(0); + break; + case 70: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteShadow(spriteId)); + else + push(0); + break; + case 73: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteImageState(spriteId)); + else + push(0); + break; + case 75: + spriteId = pop(); + if (spriteId) { + _sprite->getSpriteDist(spriteId, x, y); + push(x); + } else { + push(0); + } + break; + case 76: + spriteId = pop(); + if (spriteId) { + _sprite->getSpriteDist(spriteId, x, y); + push(y); + } else { + push(0); + } + break; + case 82: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteFlagUpdateType(spriteId)); + else + push(0); + break; + case 83: + pop(); + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteUserValue(spriteId)); + else + push(0); + break; + case 84: + spriteId = pop(); + if (spriteId) { + _sprite->getSpriteImageDim(spriteId, x, y); + push(x); + } else { + push(0); + } + break; + case 85: + spriteId = pop(); + if (spriteId) { + _sprite->getSpritePosition(spriteId, x, y); + push(x); + } else { + push(0); + } + break; + case 86: + spriteId = pop(); + if (spriteId) { + _sprite->getSpritePosition(spriteId, x, y); + push(y); + } else { + push(0); + } + break; + default: + error("o100_getSpriteInfo: Unknown case %d", subOp); + } +} + +void ScummEngine_v100he::o100_getVideoData() { + // Uses Bink video + byte subOp = fetchScriptByte(); + subOp -= 26; + + switch (subOp) { + case 0: + pop(); + break; + case 13: + pop(); + break; + case 14: + pop(); + break; + case 28: + pop(); + pop(); + break; + case 47: + pop(); + break; + case 58: + pop(); + break; + default: + error("o100_getVideoData: unhandled case %d", subOp); + } + + push(-1); + debug(1,"o100_getVideoData stub (%d)", subOp); +} + +void ScummEngine_v100he::decodeParseString(int m, int n) { + Actor *a; + int i, colors, size; + int args[31]; + byte name[1024]; + + byte b = fetchScriptByte(); + + switch (b) { + case 6: // SO_AT + _string[m].ypos = pop(); + _string[m].xpos = pop(); + _string[m].overhead = false; + break; + case 12: // SO_CENTER + _string[m].center = true; + _string[m].overhead = false; + break; + case 18: // SO_CLIPPED + _string[m].right = pop(); + break; + case 20: // SO_COLOR + _string[m].color = pop(); + break; + case 21: + colors = pop(); + if (colors == 1) { + _string[m].color = pop(); + } else { + push(colors); + getStackList(args, ARRAYSIZE(args)); + for (i = 0; i < 16; i++) + _charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i]; + _string[m].color = _charsetColorMap[0]; + } + break; + case 35: + decodeScriptString(name, true); + printString(m, name); + break; + case 46: // SO_LEFT + _string[m].center = false; + _string[m].overhead = false; + break; + case 51: // SO_MUMBLE + _string[m].no_talk_anim = true; + break; + case 56: // SO_OVERHEAD + _string[m].overhead = true; + _string[m].no_talk_anim = false; + break; + case 78: + { + byte *dataPtr = getResourceAddress(rtTalkie, pop()); + byte *text = findWrappedBlock(MKID('TEXT'), dataPtr, 0, 0); + size = getResourceDataSize(text); + memcpy(name, text, size); + printString(m, name); + } + break; + case 79: // SO_TEXTSTRING + printString(m, _scriptPointer); + _scriptPointer += resStrLen(_scriptPointer) + 1; + break; + case 91: + _string[m].loadDefault(); + if (n) { + _actorToPrintStrFor = pop(); + if (_actorToPrintStrFor != 0xFF) { + a = derefActor(_actorToPrintStrFor, "decodeParseString"); + _string[0].color = a->_talkColor; + } + } + break; + case 92: + _string[m].saveDefault(); + break; + default: + error("decodeParseString: default case %d", b); + } +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/script_v6he.cpp b/engines/scumm/he/script_v6he.cpp new file mode 100644 index 0000000000..9d7de59450 --- /dev/null +++ b/engines/scumm/he/script_v6he.cpp @@ -0,0 +1,1276 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "common/savefile.h" + +#include "scumm/actor.h" +#include "scumm/charset.h" +#include "scumm/imuse.h" +#include "scumm/he/intern_he.h" +#include "scumm/object.h" +#include "scumm/resource.h" +#include "scumm/scumm.h" +#include "scumm/sound.h" +#include "scumm/usage_bits.h" +#include "scumm/util.h" +#include "scumm/verbs.h" + +namespace Scumm { + +struct vsUnpackCtx { + uint8 size; + uint8 type; + uint8 b; + uint8 *ptr; +}; + +struct vsPackCtx { + int size; + uint8 buf[256]; +}; + +static void virtScreenSavePackBuf(vsPackCtx *ctx, uint8 *&dst, int len); +static void virtScreenSavePackByte(vsPackCtx *ctx, uint8 *&dst, int len, uint8 b); +static uint8 virtScreenLoadUnpack(vsUnpackCtx *ctx, byte *data); +static int virtScreenSavePack(byte *dst, byte *src, int len, int unk); + +// Compatibility notes: +// +// FBEAR (fbear, fbeardemo) +// transparency in akos.cpp +// negative size in file read/write + +#define OPCODE(x) _OPCODE(ScummEngine_v60he, x) + +void ScummEngine_v60he::setupOpcodes() { + static const OpcodeEntryv60he opcodes[256] = { + /* 00 */ + OPCODE(o6_pushByte), + OPCODE(o6_pushWord), + OPCODE(o6_pushByteVar), + OPCODE(o6_pushWordVar), + /* 04 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayRead), + OPCODE(o6_wordArrayRead), + /* 08 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayIndexedRead), + OPCODE(o6_wordArrayIndexedRead), + /* 0C */ + OPCODE(o6_dup), + OPCODE(o6_not), + OPCODE(o6_eq), + OPCODE(o6_neq), + /* 10 */ + OPCODE(o6_gt), + OPCODE(o6_lt), + OPCODE(o6_le), + OPCODE(o6_ge), + /* 14 */ + OPCODE(o6_add), + OPCODE(o6_sub), + OPCODE(o6_mul), + OPCODE(o6_div), + /* 18 */ + OPCODE(o6_land), + OPCODE(o6_lor), + OPCODE(o6_pop), + OPCODE(o6_invalid), + /* 1C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 20 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 24 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 28 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 2C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 30 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 34 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 38 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 3C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 40 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_writeByteVar), + OPCODE(o6_writeWordVar), + /* 44 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayWrite), + OPCODE(o6_wordArrayWrite), + /* 48 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayIndexedWrite), + OPCODE(o6_wordArrayIndexedWrite), + /* 4C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteVarInc), + OPCODE(o6_wordVarInc), + /* 50 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayInc), + OPCODE(o6_wordArrayInc), + /* 54 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteVarDec), + OPCODE(o6_wordVarDec), + /* 58 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayDec), + OPCODE(o6_wordArrayDec), + /* 5C */ + OPCODE(o6_if), + OPCODE(o6_ifNot), + OPCODE(o6_startScript), + OPCODE(o6_startScriptQuick), + /* 60 */ + OPCODE(o6_startObject), + OPCODE(o6_drawObject), + OPCODE(o6_drawObjectAt), + OPCODE(o6_invalid), + /* 64 */ + OPCODE(o6_invalid), + OPCODE(o6_stopObjectCode), + OPCODE(o6_stopObjectCode), + OPCODE(o6_endCutscene), + /* 68 */ + OPCODE(o6_cutscene), + OPCODE(o6_stopMusic), + OPCODE(o6_freezeUnfreeze), + OPCODE(o6_cursorCommand), + /* 6C */ + OPCODE(o6_breakHere), + OPCODE(o6_ifClassOfIs), + OPCODE(o6_setClass), + OPCODE(o6_getState), + /* 70 */ + OPCODE(o60_setState), + OPCODE(o6_setOwner), + OPCODE(o6_getOwner), + OPCODE(o6_jump), + /* 74 */ + OPCODE(o6_startSound), + OPCODE(o6_stopSound), + OPCODE(o6_startMusic), + OPCODE(o6_stopObjectScript), + /* 78 */ + OPCODE(o6_panCameraTo), + OPCODE(o6_actorFollowCamera), + OPCODE(o6_setCameraAt), + OPCODE(o6_loadRoom), + /* 7C */ + OPCODE(o6_stopScript), + OPCODE(o6_walkActorToObj), + OPCODE(o6_walkActorTo), + OPCODE(o6_putActorAtXY), + /* 80 */ + OPCODE(o6_putActorAtObject), + OPCODE(o6_faceActor), + OPCODE(o6_animateActor), + OPCODE(o6_doSentence), + /* 84 */ + OPCODE(o6_pickupObject), + OPCODE(o6_loadRoomWithEgo), + OPCODE(o6_invalid), + OPCODE(o6_getRandomNumber), + /* 88 */ + OPCODE(o6_getRandomNumberRange), + OPCODE(o6_invalid), + OPCODE(o6_getActorMoving), + OPCODE(o6_isScriptRunning), + /* 8C */ + OPCODE(o6_getActorRoom), + OPCODE(o6_getObjectX), + OPCODE(o6_getObjectY), + OPCODE(o6_getObjectOldDir), + /* 90 */ + OPCODE(o6_getActorWalkBox), + OPCODE(o6_getActorCostume), + OPCODE(o6_findInventory), + OPCODE(o6_getInventoryCount), + /* 94 */ + OPCODE(o6_getVerbFromXY), + OPCODE(o6_beginOverride), + OPCODE(o6_endOverride), + OPCODE(o6_setObjectName), + /* 98 */ + OPCODE(o6_isSoundRunning), + OPCODE(o6_setBoxFlags), + OPCODE(o6_invalid), + OPCODE(o6_resourceRoutines), + /* 9C */ + OPCODE(o60_roomOps), + OPCODE(o60_actorOps), + OPCODE(o6_verbOps), + OPCODE(o6_getActorFromXY), + /* A0 */ + OPCODE(o6_findObject), + OPCODE(o6_pseudoRoom), + OPCODE(o6_getActorElevation), + OPCODE(o6_getVerbEntrypoint), + /* A4 */ + OPCODE(o6_arrayOps), + OPCODE(o6_saveRestoreVerbs), + OPCODE(o6_drawBox), + OPCODE(o6_pop), + /* A8 */ + OPCODE(o6_getActorWidth), + OPCODE(o6_wait), + OPCODE(o6_getActorScaleX), + OPCODE(o6_getActorAnimCounter1), + /* AC */ + OPCODE(o6_invalid), + OPCODE(o6_isAnyOf), + OPCODE(o6_systemOps), + OPCODE(o6_isActorInBox), + /* B0 */ + OPCODE(o6_delay), + OPCODE(o6_delaySeconds), + OPCODE(o6_delayMinutes), + OPCODE(o6_stopSentence), + /* B4 */ + OPCODE(o6_printLine), + OPCODE(o6_printText), + OPCODE(o6_printDebug), + OPCODE(o6_printSystem), + /* B8 */ + OPCODE(o6_printActor), + OPCODE(o6_printEgo), + OPCODE(o6_talkActor), + OPCODE(o6_talkEgo), + /* BC */ + OPCODE(o6_dimArray), + OPCODE(o6_stopObjectCode), + OPCODE(o6_startObjectQuick), + OPCODE(o6_startScriptQuick2), + /* C0 */ + OPCODE(o6_dim2dimArray), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* C4 */ + OPCODE(o6_abs), + OPCODE(o6_distObjectObject), + OPCODE(o6_distObjectPt), + OPCODE(o6_distPtPt), + /* C8 */ + OPCODE(o60_kernelGetFunctions), + OPCODE(o60_kernelSetFunctions), + OPCODE(o6_delayFrames), + OPCODE(o6_pickOneOf), + /* CC */ + OPCODE(o6_pickOneOfDefault), + OPCODE(o6_stampObject), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* D0 */ + OPCODE(o6_getDateTime), + OPCODE(o6_stopTalking), + OPCODE(o6_getAnimateVariable), + OPCODE(o6_invalid), + /* D4 */ + OPCODE(o6_shuffle), + OPCODE(o6_jumpToScript), + OPCODE(o6_band), + OPCODE(o6_bor), + /* D8 */ + OPCODE(o6_isRoomScriptRunning), + OPCODE(o60_closeFile), + OPCODE(o60_openFile), + OPCODE(o60_readFile), + /* DC */ + OPCODE(o60_writeFile), + OPCODE(o6_findAllObjects), + OPCODE(o60_deleteFile), + OPCODE(o60_rename), + /* E0 */ + OPCODE(o60_soundOps), + OPCODE(o6_getPixel), + OPCODE(o60_localizeArrayToScript), + OPCODE(o6_pickVarRandom), + /* E4 */ + OPCODE(o6_setBoxSet), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* E8 */ + OPCODE(o6_invalid), + OPCODE(o60_seekFilePos), + OPCODE(o60_redimArray), + OPCODE(o60_readFilePos), + /* EC */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* F0 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* F4 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* F8 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* FC */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + }; + + _opcodesv60he = opcodes; +} + +void ScummEngine_v60he::executeOpcode(byte i) { + OpcodeProcv60he op = _opcodesv60he[i].proc; + (this->*op) (); +} + +const char *ScummEngine_v60he::getOpcodeDesc(byte i) { + return _opcodesv60he[i].desc; +} + +void ScummEngine_v60he::o60_setState() { + int state = pop(); + int obj = pop(); + + if (state & 0x8000) { + state &= 0x7FFF; + putState(obj, state); + if (_heversion >= 72) + removeObjectFromDrawQue(obj); + } else { + putState(obj, state); + markObjectRectAsDirty(obj); + if (_bgNeedsRedraw) + clearDrawObjectQueue(); + } +} + +void ScummEngine_v60he::o60_roomOps() { + int a, b, c, d, e; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 172: // SO_ROOM_SCROLL + b = pop(); + a = pop(); + if (a < (_screenWidth / 2)) + a = (_screenWidth / 2); + if (b < (_screenWidth / 2)) + b = (_screenWidth / 2); + if (a > _roomWidth - (_screenWidth / 2)) + a = _roomWidth - (_screenWidth / 2); + if (b > _roomWidth - (_screenWidth / 2)) + b = _roomWidth - (_screenWidth / 2); + VAR(VAR_CAMERA_MIN_X) = a; + VAR(VAR_CAMERA_MAX_X) = b; + break; + + case 174: // SO_ROOM_SCREEN + b = pop(); + a = pop(); + if (_heversion >= 71) + initScreens(a, _screenHeight); + else + initScreens(a, b); + break; + + case 175: // SO_ROOM_PALETTE + d = pop(); + c = pop(); + b = pop(); + a = pop(); + setPalColor(d, a, b, c); + break; + + case 176: // SO_ROOM_SHAKE_ON + setShake(1); + break; + + case 177: // SO_ROOM_SHAKE_OFF + setShake(0); + break; + + case 179: // SO_ROOM_INTENSITY + c = pop(); + b = pop(); + a = pop(); + darkenPalette(a, a, a, b, c); + break; + + case 180: // SO_ROOM_SAVEGAME + _saveTemporaryState = true; + _saveLoadSlot = pop(); + _saveLoadFlag = pop(); + break; + + case 181: // SO_ROOM_FADE + a = pop(); + if (_heversion >= 70) { + // Defaults to 1 but doesn't use fade effects + } else if (a) { + _switchRoomEffect = (byte)(a & 0xFF); + _switchRoomEffect2 = (byte)(a >> 8); + } else { + fadeIn(_newEffect); + } + break; + + case 182: // SO_RGB_ROOM_INTENSITY + e = pop(); + d = pop(); + c = pop(); + b = pop(); + a = pop(); + darkenPalette(a, b, c, d, e); + break; + + case 183: // SO_ROOM_SHADOW + e = pop(); + d = pop(); + c = pop(); + b = pop(); + a = pop(); + if (_heversion == 60) + setupShadowPalette(a, b, c, d, e, 0, 256); + break; + + case 186: // SO_ROOM_TRANSFORM + d = pop(); + c = pop(); + b = pop(); + a = pop(); + palManipulateInit(a, b, c, d); + break; + + case 187: // SO_CYCLE_SPEED + b = pop(); + a = pop(); + checkRange(16, 1, a, "o60_roomOps: 187: color cycle out of range (%d)"); + _colorCycle[a - 1].delay = (b != 0) ? 0x4000 / (b * 0x4C) : 0; + break; + + case 213: // SO_ROOM_NEW_PALETTE + a = pop(); + setPalette(a); + break; + case 220: + a = pop(); + b = pop(); + copyPalColor(a, b); + break; + case 221: + int len; + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + _saveLoadFlag = pop(); + _saveLoadSlot = 1; + _saveTemporaryState = true; + break; + case 234: // HE 7.2 + b = pop(); + a = pop(); + swapObjects(a, b); + break; + case 236: // HE 7.2 + b = pop(); + a = pop(); + setRoomPalette(a, b); + break; + default: + error("o60_roomOps: default case %d", subOp); + } +} + +void ScummEngine_v60he::swapObjects(int object1, int object2) { + int idx1 = -1, idx2 = -1; + + for (int i = 0; i < _numLocalObjects; i++) { + if (_objs[i].obj_nr == object1) + idx1 = i; + + if (_objs[i].obj_nr == object2) + idx2 = i; + } + + if (idx1 == -1 || idx2 == -1 || idx1 <= idx2) + return; + + stopObjectScript(object1); + stopObjectScript(object2); + + ObjectData tmpOd; + + memcpy(&tmpOd, &_objs[idx1], sizeof(tmpOd)); + memcpy(&_objs[idx1], &_objs[idx2], sizeof(tmpOd)); + memcpy(&_objs[idx2], &tmpOd, sizeof(tmpOd)); +} + +void ScummEngine_v60he::o60_actorOps() { + Actor *a; + int i, j, k; + int args[8]; + + byte subOp = fetchScriptByte(); + if (subOp == 197) { + _curActor = pop(); + return; + } + + a = derefActorSafe(_curActor, "o60_actorOps"); + if (!a) + return; + + switch (subOp) { + case 30: + // _heversion >= 70 + _actorClipOverride.bottom = pop(); + _actorClipOverride.right = pop(); + _actorClipOverride.top = pop(); + _actorClipOverride.left = pop(); + break; + case 76: // SO_COSTUME + a->setActorCostume(pop()); + break; + case 77: // SO_STEP_DIST + j = pop(); + i = pop(); + a->setActorWalkSpeed(i, j); + break; + case 78: // SO_SOUND + k = getStackList(args, ARRAYSIZE(args)); + for (i = 0; i < k; i++) + a->_sound[i] = args[i]; + break; + case 79: // SO_WALK_ANIMATION + a->_walkFrame = pop(); + break; + case 80: // SO_TALK_ANIMATION + a->_talkStopFrame = pop(); + a->_talkStartFrame = pop(); + break; + case 81: // SO_STAND_ANIMATION + a->_standFrame = pop(); + break; + case 82: // SO_ANIMATION + // dummy case in scumm6 + pop(); + pop(); + pop(); + break; + case 83: // SO_DEFAULT + a->initActor(0); + break; + case 84: // SO_ELEVATION + a->setElevation(pop()); + break; + case 85: // SO_ANIMATION_DEFAULT + a->_initFrame = 1; + a->_walkFrame = 2; + a->_standFrame = 3; + a->_talkStartFrame = 4; + a->_talkStopFrame = 5; + break; + case 86: // SO_PALETTE + j = pop(); + i = pop(); + checkRange(255, 0, i, "Illegal palette slot %d"); + a->remapActorPaletteColor(i, j); + a->_needRedraw = true; + break; + case 87: // SO_TALK_COLOR + a->_talkColor = pop(); + break; + case 88: // SO_ACTOR_NAME + loadPtrToResource(rtActorName, a->_number, NULL); + break; + case 89: // SO_INIT_ANIMATION + a->_initFrame = pop(); + break; + case 91: // SO_ACTOR_WIDTH + a->_width = pop(); + break; + case 92: // SO_SCALE + i = pop(); + a->setScale(i, i); + break; + case 93: // SO_NEVER_ZCLIP + a->_forceClip = 0; + break; + case 94: // SO_ALWAYS_ZCLIP + a->_forceClip = pop(); + break; + case 95: // SO_IGNORE_BOXES + a->_ignoreBoxes = 1; + a->_forceClip = 0; + if (a->isInCurrentRoom()) + a->putActor(a->_pos.x, a->_pos.y, a->_room); + break; + case 96: // SO_FOLLOW_BOXES + a->_ignoreBoxes = 0; + a->_forceClip = 0; + if (a->isInCurrentRoom()) + a->putActor(a->_pos.x, a->_pos.y, a->_room); + break; + case 97: // SO_ANIMATION_SPEED + a->setAnimSpeed(pop()); + break; + case 98: // SO_SHADOW + a->_shadowMode = pop(); + a->_needRedraw = true; + break; + case 99: // SO_TEXT_OFFSET + a->_talkPosY = pop(); + a->_talkPosX = pop(); + break; + case 156: // HE 7.2 + a->_charset = pop(); + break; + case 198: // SO_ACTOR_VARIABLE + i = pop(); + a->setAnimVar(pop(), i); + break; + case 215: // SO_ACTOR_IGNORE_TURNS_ON + a->_ignoreTurns = true; + break; + case 216: // SO_ACTOR_IGNORE_TURNS_OFF + a->_ignoreTurns = false; + break; + case 217: // SO_ACTOR_NEW + a->initActor(2); + break; + case 218: + a->drawActorToBackBuf(a->_pos.x, a->_pos.y); + break; + case 219: + a->_drawToBackBuf = false; + a->_needRedraw = true; + a->_needBgReset = true; + break; + case 225: + { + byte string[128]; + copyScriptString(string); + int slot = pop(); + + int len = resStrLen(string) + 1; + convertMessageToString(string, a->_heTalkQueue[slot].sentence, len); + + a->_heTalkQueue[slot].posX = a->_talkPosX; + a->_heTalkQueue[slot].posY = a->_talkPosY; + a->_heTalkQueue[slot].color = a->_talkColor; + break; + } + default: + error("o60_actorOps: default case %d", subOp); + } +} + +void ScummEngine_v60he::o60_kernelSetFunctions() { + int args[29]; + int num; + + num = getStackList(args, ARRAYSIZE(args)); + + switch (args[0]) { + case 1: + // Used to restore images when decorating cake in + // Fatty Bear's Birthday Surprise + virtScreenLoad(args[1], args[2], args[3], args[4], args[5]); + break; + case 3: + case 4: + case 5: + case 6: + case 8: + //Used before mini games in 3DO versions, seems safe to ignore. + break; + default: + error("o60_kernelSetFunctions: default case %d (param count %d)", args[0], num); + } +} + +void ScummEngine_v60he::virtScreenLoad(int resIdx, int x1, int y1, int x2, int y2) { + vsUnpackCtx ctx; + memset(&ctx, 0, sizeof(ctx)); + VirtScreen &vs = virtscr[kMainVirtScreen]; + + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resIdx); + virtScreenLoadUnpack(&ctx, ah->data); + for (int j = y1; j <= y2; ++j) { + uint8 *p1 = vs.getPixels(x1, j - vs.topline); + uint8 *p2 = vs.getBackPixels(x1, j - vs.topline); + if (x2 >= x1) { + uint32 w = x2 - x1 + 1; + while (w--) { + uint8 decByte = virtScreenLoadUnpack(&ctx, 0); + *p1++ = decByte; + *p2++ = decByte; + } + } + } + markRectAsDirty(kMainVirtScreen, x1, x2, y1, y2 + 1, USAGE_BIT_RESTORED); +} + +uint8 virtScreenLoadUnpack(vsUnpackCtx *ctx, byte *data) { + uint8 decByte; + if (data != 0) { + ctx->type = 0; + ctx->ptr = data; + decByte = 0; + } else { + uint8 a; + if (ctx->type == 0) { + a = *(ctx->ptr)++; + if (a & 1) { + ctx->type = 1; + ctx->b = *(ctx->ptr)++; + } else { + ctx->type = 2; + } + ctx->size = a; + a = (a >> 1) + 1; + } else { + a = ctx->size; + } + if (ctx->type == 2) { + ctx->b = *(ctx->ptr)++; + } + ctx->size = a - 1; + if (ctx->size == 0) { + ctx->type = 0; + } + decByte = ctx->b; + } + return decByte; +} + + +void ScummEngine_v60he::o60_kernelGetFunctions() { + int args[29]; + ArrayHeader *ah; + getStackList(args, ARRAYSIZE(args)); + + switch (args[0]) { + case 1: + // Used to store images when decorating cake in + // Fatty Bear's Birthday Surprise + writeVar(0, 0); + ah = defineArray(0, kByteArray, 0, virtScreenSave(0, args[1], args[2], args[3], args[4])); + virtScreenSave(ah->data, args[1], args[2], args[3], args[4]); + push(readVar(0)); + break; + default: + error("o60_kernelGetFunctions: default case %d", args[0]); + } +} + +int ScummEngine_v60he::virtScreenSave(byte *dst, int x1, int y1, int x2, int y2) { + int packedSize = 0; + VirtScreen &vs = virtscr[kMainVirtScreen]; + + for (int j = y1; j <= y2; ++j) { + uint8 *p = vs.getBackPixels(x1, j - vs.topline); + + int size = virtScreenSavePack(dst, p, x2 - x1 + 1, 0); + if (dst != 0) { + dst += size; + } + packedSize += size; + } + return packedSize; +} + +int virtScreenSavePack(byte *dst, byte *src, int len, int unk) { + vsPackCtx ctx; + memset(&ctx, 0, sizeof(ctx)); + + uint8 prevByte, curByte; + + ctx.buf[0] = prevByte = *src++; + int flag = 0; + int iend = 1; + int ibeg = 0; + + for (--len; len != 0; --len, prevByte = curByte) { + bool pass = false; + + assert(iend < 0x100); + ctx.buf[iend] = curByte = *src++; + ++iend; + + if (flag == 0) { + if (iend > 0x80) { + virtScreenSavePackBuf(&ctx, dst, iend - 1); + ctx.buf[0] = curByte; + iend = 1; + ibeg = 0; + continue; + } + if (prevByte != curByte) { + ibeg = iend - 1; + continue; + } + if (iend - ibeg < 3) { + if (ibeg != 0) { + pass = true; + } else { + flag = 1; + } + } else { + if (ibeg > 0) { + virtScreenSavePackBuf(&ctx, dst, ibeg); + } + flag = 1; + } + } + if (flag == 1 || pass) { + if (prevByte != curByte || iend - ibeg > 0x80) { + virtScreenSavePackByte(&ctx, dst, iend - ibeg - 1, prevByte); + ctx.buf[0] = curByte; + iend = 1; + ibeg = 0; + flag = 0; + } + } + } + + if (flag == 0) { + virtScreenSavePackBuf(&ctx, dst, iend); + } else if (flag == 1) { + virtScreenSavePackByte(&ctx, dst, iend - ibeg, prevByte); + } + return ctx.size; +} + +void virtScreenSavePackBuf(vsPackCtx *ctx, uint8 *&dst, int len) { + if (dst) { + *dst++ = (len - 1) * 2; + } + ++ctx->size; + if (len > 0) { + ctx->size += len; + if (dst) { + memcpy(dst, ctx->buf, len); + dst += len; + } + } +} + +void virtScreenSavePackByte(vsPackCtx *ctx, uint8 *&dst, int len, uint8 b) { + if (dst) { + *dst++ = ((len - 1) * 2) | 1; + } + ++ctx->size; + if (dst) { + *dst++ = b; + } + ++ctx->size; +} + +void ScummEngine_v60he::o60_openFile() { + int mode, len, slot, l, r; + byte filename[100]; + + convertMessageToString(_scriptPointer, filename, sizeof(filename)); + + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + for (r = strlen((char*)filename); r != 0; r--) { + if (filename[r - 1] == '\\') + break; + } + + mode = pop(); + slot = -1; + for (l = 0; l < 17; l++) { + if (_hFileTable[l].isOpen() == false) { + slot = l; + break; + } + } + + if (slot != -1) { + switch(mode) { + case 1: + _hFileTable[slot].open((char*)filename + r, Common::File::kFileReadMode, _saveFileMan->getSavePath()); + if (_hFileTable[slot].isOpen() == false) + _hFileTable[slot].open((char*)filename + r, Common::File::kFileReadMode); + break; + case 2: + _hFileTable[slot].open((char*)filename + r, Common::File::kFileWriteMode, _saveFileMan->getSavePath()); + break; + default: + error("o60_openFile(): wrong open file mode %d", mode); + } + + if (_hFileTable[slot].isOpen() == false) + slot = -1; + + } + push(slot); +} + +void ScummEngine_v60he::o60_closeFile() { + int slot = pop(); + if (slot != -1) + _hFileTable[slot].close(); +} + +void ScummEngine_v60he::o60_deleteFile() { + int len, r; + byte filename[100]; + + convertMessageToString(_scriptPointer, filename, sizeof(filename)); + + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + for (r = strlen((char*)filename); r != 0; r--) { + if (filename[r - 1] == '\\') + break; + } + + debug(1, "stub o60_deleteFile(\"%s\")", filename + r); +} + +void ScummEngine_v60he::o60_rename() { + int len, r1, r2; + byte filename[100],filename2[100]; + + convertMessageToString(_scriptPointer, filename, sizeof(filename)); + + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + for (r1 = strlen((char*)filename); r1 != 0; r1--) { + if (filename[r1 - 1] == '\\') + break; + } + + convertMessageToString(_scriptPointer, filename2, sizeof(filename2)); + + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + for (r2 = strlen((char*)filename2); r2 != 0; r2--) { + if (filename2[r2 - 1] == '\\') + break; + } + + debug(1, "stub o60_rename(\"%s\" to \"%s\")", filename + r1, filename2 + r2); +} + +int ScummEngine_v60he::readFileToArray(int slot, int32 size) { + if (size == 0) + size = _hFileTable[slot].size() - _hFileTable[slot].pos(); + + writeVar(0, 0); + + ArrayHeader *ah = defineArray(0, kByteArray, 0, size); + _hFileTable[slot].read(ah->data, size); + + return readVar(0); +} + +void ScummEngine_v60he::o60_readFile() { + int32 size = pop(); + int slot = pop(); + int val; + + // Fatty Bear uses positive values + if ((_platform == Common::kPlatformPC) && (_gameId == GID_FBEAR)) + size = -size; + + if (size == -2) { + val = _hFileTable[slot].readUint16LE(); + push(val); + } else if (size == -1) { + val = _hFileTable[slot].readByte(); + push(val); + } else { + val = readFileToArray(slot, size); + push(val); + } +} + +void ScummEngine_v60he::writeFileFromArray(int slot, int resID) { + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resID); + int32 size = FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2); + + _hFileTable[slot].write(ah->data, size); +} + +void ScummEngine_v60he::o60_writeFile() { + int32 size = pop(); + int16 resID = pop(); + int slot = pop(); + + // Fatty Bear uses positive values + if ((_platform == Common::kPlatformPC) && (_gameId == GID_FBEAR)) + size = -size; + + if (size == -2) { + _hFileTable[slot].writeUint16LE(resID); + } else if (size == -1) { + _hFileTable[slot].writeByte(resID); + } else { + writeFileFromArray(slot, resID); + } +} + +void ScummEngine_v60he::o60_soundOps() { + byte subOp = fetchScriptByte(); + int arg = pop(); + + switch (subOp) { + case 0xde: + _imuse->setMusicVolume(arg); + break; + case 0xdf: + // Used in fbear introduction + break; + case 0xe0: + // Fatty Bear's Birthday surprise uses this when playing the + // piano, but only when using one of the digitized instruments. + // See also o6_startSound(). + _sound->setOverrideFreq(arg); + break; + default: + error("o60_soundOps: default case 0x%x", subOp); + } +} + +void ScummEngine_v60he::localizeArray(int slot, byte scriptSlot) { + if (_heversion >= 80) + slot &= ~0x33539000; + + if (slot >= _numArray) + error("o60_localizeArrayToScript(%d): array slot out of range", slot); + + _arraySlot[slot] = scriptSlot; +} + +void ScummEngine_v60he::o60_localizeArrayToScript() { + int slot = pop(); + localizeArray(slot, _currentScript); +} + +void ScummEngine_v60he::o60_seekFilePos() { + int mode, offset, slot; + + mode = pop(); + offset = pop(); + slot = pop(); + + if (slot == -1) + return; + + switch (mode) { + case 1: + _hFileTable[slot].seek(offset, SEEK_SET); + break; + case 2: + _hFileTable[slot].seek(offset, SEEK_CUR); + break; + case 3: + _hFileTable[slot].seek(offset, SEEK_END); + break; + default: + error("o60_seekFilePos: default case %d", mode); + } +} + +void ScummEngine_v60he::o60_readFilePos() { + int slot = pop(); + + if (slot == -1) { + push(0); + return; + } + + push(_hFileTable[slot].pos()); +} + +void ScummEngine_v60he::o60_redimArray() { + int newX, newY; + newY = pop(); + newX = pop(); + + if (newY == 0) + SWAP(newX, newY); + + byte subOp = fetchScriptByte(); + switch (subOp) { + case 199: + redimArray(fetchScriptWord(), newX, newY, kIntArray); + break; + case 202: + redimArray(fetchScriptWord(), newX, newY, kByteArray); + break; + default: + error("o60_redimArray: default type %d", subOp); + } +} + +void ScummEngine_v60he::redimArray(int arrayId, int newX, int newY, int type) { + // Used in mini game at Cosmic Dust Diner in puttmoon + int newSize, oldSize; + + if (readVar(arrayId) == 0) + error("redimArray: Reference to zeroed array pointer"); + + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(arrayId)); + + if (!ah) + error("redimArray: Invalid array (%d) reference", readVar(arrayId)); + + newSize = (type == kIntArray) ? 2 : 1; + oldSize = (ah->type == kIntArray) ? 2 : 1; + + newSize *= (newX + 1) * (newY + 1); + oldSize *= FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2); + + if (newSize != oldSize) + error("redimArray: array %d redim mismatch", readVar(arrayId)); + + ah->type = TO_LE_16(type); + ah->dim1 = TO_LE_16(newY + 1); + ah->dim2 = TO_LE_16(newX + 1); +} + +void ScummEngine_v60he::decodeParseString(int m, int n) { + int i, colors; + int args[31]; + + byte b = fetchScriptByte(); + + switch (b) { + case 65: // SO_AT + _string[m].ypos = pop(); + _string[m].xpos = pop(); + _string[m].overhead = false; + break; + case 66: // SO_COLOR + _string[m].color = pop(); + break; + case 67: // SO_CLIPPED + _string[m].right = pop(); + break; + case 69: // SO_CENTER + _string[m].center = true; + _string[m].overhead = false; + break; + case 71: // SO_LEFT + _string[m].center = false; + _string[m].overhead = false; + break; + case 72: // SO_OVERHEAD + _string[m].overhead = true; + _string[m].no_talk_anim = false; + break; + case 74: // SO_MUMBLE + _string[m].no_talk_anim = true; + break; + case 75: // SO_TEXTSTRING + printString(m, _scriptPointer); + _scriptPointer += resStrLen(_scriptPointer) + 1; + break; + case 0xF9: + colors = pop(); + if (colors == 1) { + _string[m].color = pop(); + } else { + push(colors); + getStackList(args, ARRAYSIZE(args)); + for (i = 0; i < 16; i++) + _charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i]; + _string[m].color = _charsetColorMap[0]; + } + break; + case 0xFE: + _string[m].loadDefault(); + if (n) + _actorToPrintStrFor = pop(); + break; + case 0xFF: + _string[m].saveDefault(); + break; + default: + error("decodeParseString: default case 0x%x", b); + } +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp new file mode 100644 index 0000000000..b94cc06b40 --- /dev/null +++ b/engines/scumm/he/script_v72he.cpp @@ -0,0 +1,2368 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" + +#include "common/config-manager.h" +#include "common/savefile.h" +#include "common/system.h" + +#include "scumm/actor.h" +#include "scumm/charset.h" +#include "scumm/he/intern_he.h" +#include "scumm/object.h" +#include "scumm/resource.h" +#include "scumm/he/resource_v7he.h" +#include "scumm/scumm.h" +#include "scumm/sound.h" +#include "scumm/util.h" +#include "scumm/verbs.h" + +namespace Scumm { + +#define OPCODE(x) _OPCODE(ScummEngine_v72he, x) + +void ScummEngine_v72he::setupOpcodes() { + static const OpcodeEntryV72he opcodes[256] = { + /* 00 */ + OPCODE(o6_pushByte), + OPCODE(o6_pushWord), + OPCODE(o72_pushDWord), + OPCODE(o6_pushWordVar), + /* 04 */ + OPCODE(o72_getScriptString), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_wordArrayRead), + /* 08 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_wordArrayIndexedRead), + /* 0C */ + OPCODE(o6_dup), + OPCODE(o6_not), + OPCODE(o6_eq), + OPCODE(o6_neq), + /* 10 */ + OPCODE(o6_gt), + OPCODE(o6_lt), + OPCODE(o6_le), + OPCODE(o6_ge), + /* 14 */ + OPCODE(o6_add), + OPCODE(o6_sub), + OPCODE(o6_mul), + OPCODE(o6_div), + /* 18 */ + OPCODE(o6_land), + OPCODE(o6_lor), + OPCODE(o6_pop), + OPCODE(o72_isAnyOf), + /* 1C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 20 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 24 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 28 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 2C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 30 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 34 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 38 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 3C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 40 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_writeWordVar), + /* 44 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_wordArrayWrite), + /* 48 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_wordArrayIndexedWrite), + /* 4C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_wordVarInc), + /* 50 */ + OPCODE(o72_resetCutscene), + OPCODE(o6_invalid), + OPCODE(o72_findObjectWithClassOf), + OPCODE(o6_wordArrayInc), + /* 54 */ + OPCODE(o72_getObjectImageX), + OPCODE(o72_getObjectImageY), + OPCODE(o72_captureWizImage), + OPCODE(o6_wordVarDec), + /* 58 */ + OPCODE(o72_getTimer), + OPCODE(o72_setTimer), + OPCODE(o72_getSoundPosition), + OPCODE(o6_wordArrayDec), + /* 5C */ + OPCODE(o6_if), + OPCODE(o6_ifNot), + OPCODE(o72_startScript), + OPCODE(o6_startScriptQuick), + /* 60 */ + OPCODE(o72_startObject), + OPCODE(o72_drawObject), + OPCODE(o72_printWizImage), + OPCODE(o72_getArrayDimSize), + /* 64 */ + OPCODE(o72_getNumFreeArrays), + OPCODE(o6_stopObjectCode), + OPCODE(o6_stopObjectCode), + OPCODE(o6_endCutscene), + /* 68 */ + OPCODE(o6_cutscene), + OPCODE(o6_stopMusic), + OPCODE(o6_freezeUnfreeze), + OPCODE(o6_cursorCommand), + /* 6C */ + OPCODE(o6_breakHere), + OPCODE(o6_ifClassOfIs), + OPCODE(o6_setClass), + OPCODE(o6_getState), + /* 70 */ + OPCODE(o60_setState), + OPCODE(o6_setOwner), + OPCODE(o6_getOwner), + OPCODE(o6_jump), + /* 74 */ + OPCODE(o70_startSound), + OPCODE(o6_stopSound), + OPCODE(o6_startMusic), + OPCODE(o6_stopObjectScript), + /* 78 */ + OPCODE(o6_panCameraTo), + OPCODE(o6_actorFollowCamera), + OPCODE(o6_setCameraAt), + OPCODE(o6_loadRoom), + /* 7C */ + OPCODE(o6_stopScript), + OPCODE(o6_walkActorToObj), + OPCODE(o6_walkActorTo), + OPCODE(o6_putActorAtXY), + /* 80 */ + OPCODE(o6_putActorAtObject), + OPCODE(o6_faceActor), + OPCODE(o6_animateActor), + OPCODE(o6_doSentence), + /* 84 */ + OPCODE(o70_pickupObject), + OPCODE(o6_loadRoomWithEgo), + OPCODE(o6_invalid), + OPCODE(o6_getRandomNumber), + /* 88 */ + OPCODE(o6_getRandomNumberRange), + OPCODE(o6_invalid), + OPCODE(o6_getActorMoving), + OPCODE(o6_isScriptRunning), + /* 8C */ + OPCODE(o70_getActorRoom), + OPCODE(o6_getObjectX), + OPCODE(o6_getObjectY), + OPCODE(o6_getObjectOldDir), + /* 90 */ + OPCODE(o6_getActorWalkBox), + OPCODE(o6_getActorCostume), + OPCODE(o6_findInventory), + OPCODE(o6_getInventoryCount), + /* 94 */ + OPCODE(o6_getVerbFromXY), + OPCODE(o6_beginOverride), + OPCODE(o6_endOverride), + OPCODE(o6_setObjectName), + /* 98 */ + OPCODE(o6_isSoundRunning), + OPCODE(o6_setBoxFlags), + OPCODE(o6_invalid), + OPCODE(o70_resourceRoutines), + /* 9C */ + OPCODE(o72_roomOps), + OPCODE(o72_actorOps), + OPCODE(o72_verbOps), + OPCODE(o6_getActorFromXY), + /* A0 */ + OPCODE(o72_findObject), + OPCODE(o6_pseudoRoom), + OPCODE(o6_getActorElevation), + OPCODE(o6_getVerbEntrypoint), + /* A4 */ + OPCODE(o72_arrayOps), + OPCODE(o6_saveRestoreVerbs), + OPCODE(o6_drawBox), + OPCODE(o6_pop), + /* A8 */ + OPCODE(o6_getActorWidth), + OPCODE(o6_wait), + OPCODE(o6_getActorScaleX), + OPCODE(o6_getActorAnimCounter1), + /* AC */ + OPCODE(o6_invalid), + OPCODE(o6_isAnyOf), + OPCODE(o72_systemOps), + OPCODE(o6_isActorInBox), + /* B0 */ + OPCODE(o6_delay), + OPCODE(o6_delaySeconds), + OPCODE(o6_delayMinutes), + OPCODE(o6_stopSentence), + /* B4 */ + OPCODE(o6_printLine), + OPCODE(o6_printText), + OPCODE(o6_printDebug), + OPCODE(o6_printSystem), + /* B8 */ + OPCODE(o6_printActor), + OPCODE(o6_printEgo), + OPCODE(o72_talkActor), + OPCODE(o72_talkEgo), + /* BC */ + OPCODE(o72_dimArray), + OPCODE(o6_stopObjectCode), + OPCODE(o6_startObjectQuick), + OPCODE(o6_startScriptQuick2), + /* C0 */ + OPCODE(o72_dim2dimArray), + OPCODE(o72_traceStatus), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* C4 */ + OPCODE(o6_abs), + OPCODE(o6_distObjectObject), + OPCODE(o6_distObjectPt), + OPCODE(o6_distPtPt), + /* C8 */ + OPCODE(o72_kernelGetFunctions), + OPCODE(o70_kernelSetFunctions), + OPCODE(o6_delayFrames), + OPCODE(o6_pickOneOf), + /* CC */ + OPCODE(o6_pickOneOfDefault), + OPCODE(o6_stampObject), + OPCODE(o72_drawWizImage), + OPCODE(o72_debugInput), + /* D0 */ + OPCODE(o6_getDateTime), + OPCODE(o6_stopTalking), + OPCODE(o6_getAnimateVariable), + OPCODE(o6_invalid), + /* D4 */ + OPCODE(o6_shuffle), + OPCODE(o72_jumpToScript), + OPCODE(o6_band), + OPCODE(o6_bor), + /* D8 */ + OPCODE(o6_isRoomScriptRunning), + OPCODE(o60_closeFile), + OPCODE(o72_openFile), + OPCODE(o72_readFile), + /* DC */ + OPCODE(o72_writeFile), + OPCODE(o72_findAllObjects), + OPCODE(o72_deleteFile), + OPCODE(o72_rename), + /* E0 */ + OPCODE(o60_soundOps), + OPCODE(o72_getPixel), + OPCODE(o60_localizeArrayToScript), + OPCODE(o72_pickVarRandom), + /* E4 */ + OPCODE(o6_setBoxSet), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* E8 */ + OPCODE(o6_invalid), + OPCODE(o70_seekFilePos), + OPCODE(o72_redimArray), + OPCODE(o60_readFilePos), + /* EC */ + OPCODE(o70_copyString), + OPCODE(o70_getStringWidth), + OPCODE(o70_getStringLen), + OPCODE(o70_appendString), + /* F0 */ + OPCODE(o70_concatString), + OPCODE(o70_compareString), + OPCODE(o70_isResourceLoaded), + OPCODE(o72_readINI), + /* F4 */ + OPCODE(o72_writeINI), + OPCODE(o70_getStringLenForWidth), + OPCODE(o70_getCharIndexInString), + OPCODE(o6_invalid), + /* F8 */ + OPCODE(o72_getResourceSize), + OPCODE(o72_setFilePath), + OPCODE(o72_setSystemMessage), + OPCODE(o70_polygonOps), + /* FC */ + OPCODE(o70_polygonHit), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + }; + + _opcodesV72he = opcodes; +} + +void ScummEngine_v72he::executeOpcode(byte i) { + OpcodeProcV72he op = _opcodesV72he[i].proc; + (this->*op) (); +} + +const char *ScummEngine_v72he::getOpcodeDesc(byte i) { + return _opcodesV72he[i].desc; +} + +static const int arrayDataSizes[] = { 0, 1, 4, 8, 8, 16, 32 }; + +ScummEngine_v72he::ArrayHeader *ScummEngine_v72he::defineArray(int array, int type, int dim2start, int dim2end, + int dim1start, int dim1end) { + int id; + int size; + ArrayHeader *ah; + + assert(dim2start >= 0 && dim2start <= dim2end); + assert(dim1start >= 0 && dim1start <= dim1end); + assert(0 <= type && type <= 6); + + + if (type == kBitArray || type == kNibbleArray) + type = kByteArray; + + nukeArray(array); + + id = findFreeArrayId(); + + debug(9,"defineArray (array %d, dim2start %d, dim2end %d dim1start %d dim1end %d", id, dim2start, dim2end, dim1start, dim1end); + + if (array & 0x80000000) { + error("Can't define bit variable as array pointer"); + } + + size = arrayDataSizes[type]; + + if (_heversion >= 80) + id |= 0x33539000; + + writeVar(array, id); + + if (_heversion >= 80) + id &= ~0x33539000; + + size *= dim2end - dim2start + 1; + size *= dim1end - dim1start + 1; + size >>= 3; + + ah = (ArrayHeader *)res.createResource(rtString, id, size + sizeof(ArrayHeader)); + + ah->type = TO_LE_32(type); + ah->dim1start = TO_LE_32(dim1start); + ah->dim1end = TO_LE_32(dim1end); + ah->dim2start = TO_LE_32(dim2start); + ah->dim2end = TO_LE_32(dim2end); + + return ah; +} + +int ScummEngine_v72he::readArray(int array, int idx2, int idx1) { + debug(9, "readArray (array %d, idx2 %d, idx1 %d)", readVar(array), idx2, idx1); + + if (readVar(array) == 0) + error("readArray: Reference to zeroed array pointer"); + + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array)); + + if (ah == NULL || ah->data == NULL) + error("readArray: invalid array %d (%d)", array, readVar(array)); + + if (idx2 < (int)FROM_LE_32(ah->dim2start) || idx2 > (int)FROM_LE_32(ah->dim2end) || + idx1 < (int)FROM_LE_32(ah->dim1start) || idx1 > (int)FROM_LE_32(ah->dim1end)) { + error("readArray: array %d out of bounds: [%d, %d] exceeds [%d..%d, %d..%d]", + array, idx1, idx2, FROM_LE_32(ah->dim1start), FROM_LE_32(ah->dim1end), + FROM_LE_32(ah->dim2start), FROM_LE_32(ah->dim2end)); + } + + const int offset = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) * + (idx2 - FROM_LE_32(ah->dim2start)) - FROM_LE_32(ah->dim1start) + idx1; + + switch (FROM_LE_32(ah->type)) { + case kByteArray: + case kStringArray: + return ah->data[offset]; + + case kIntArray: + return (int16)READ_LE_UINT16(ah->data + offset * 2); + + case kDwordArray: + return (int32)READ_LE_UINT32(ah->data + offset * 4); + } + + return 0; +} + +void ScummEngine_v72he::writeArray(int array, int idx2, int idx1, int value) { + debug(9, "writeArray (array %d, idx2 %d, idx1 %d, value %d)", readVar(array), idx2, idx1, value); + + if (readVar(array) == 0) + error("writeArray: Reference to zeroed array pointer"); + + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array)); + + if (!ah) + error("writeArray: Invalid array (%d) reference", readVar(array)); + + if (idx2 < (int)FROM_LE_32(ah->dim2start) || idx2 > (int)FROM_LE_32(ah->dim2end) || + idx1 < (int)FROM_LE_32(ah->dim1start) || idx1 > (int)FROM_LE_32(ah->dim1end)) { + error("writeArray: array %d out of bounds: [%d, %d] exceeds [%d..%d, %d..%d]", + array, idx1, idx2, FROM_LE_32(ah->dim1start), FROM_LE_32(ah->dim1end), + FROM_LE_32(ah->dim2start), FROM_LE_32(ah->dim2end)); + } + + const int offset = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) * + (idx2 - FROM_LE_32(ah->dim2start)) - FROM_LE_32(ah->dim1start) + idx1; + + switch (FROM_LE_32(ah->type)) { + case kByteArray: + case kStringArray: + ah->data[offset] = value; + break; + + case kIntArray: + WRITE_LE_UINT16(ah->data + offset * 2, value); + break; + + case kDwordArray: + WRITE_LE_UINT32(ah->data + offset * 4, value); + break; + } +} + +int ScummEngine_v72he::setupStringArray(int size) { + writeVar(0, 0); + defineArray(0, kStringArray, 0, 0, 0, size + 1); + writeArray(0, 0, 0, 0); + return readVar(0); +} + +void ScummEngine_v72he::readArrayFromIndexFile() { + int num; + int a, b, c; + + while ((num = _fileHandle->readUint16LE()) != 0) { + a = _fileHandle->readUint16LE(); + b = _fileHandle->readUint16LE(); + c = _fileHandle->readUint16LE(); + + if (c == 1) + defineArray(num, kBitArray, 0, a, 0, b); + else + defineArray(num, kDwordArray, 0, a, 0, b); + } +} + +int ScummEngine_v72he::convertFilePath(byte *dst, bool setFilePath) { + debug(1, "convertFilePath: original filePath is %s", dst); + + // Switch all \ to / for portablity + int len = resStrLen(dst) + 1; + for (int i = 0; i < len; i++) { + if (dst[i] == '\\') + dst[i] = '/'; + } + + // Strip path + int r = 0; + if (dst[0] == '.' && dst[1] == '/') { + r = 2; + } else if (dst[0] == 'c' && dst[1] == ':') { + for (r = len; r != 0; r--) { + if (dst[r - 1] == '/') + break; + } + } + + if (setFilePath) { + char filePath[256]; + sprintf(filePath, "%s%s", _gameDataPath.c_str(), dst + r); + if (!Common::File::exists(filePath)) { + sprintf(filePath, "%s%s", _saveFileMan->getSavePath(), dst + r); + } + strcpy((char *)dst, filePath); + debug(1, "convertFilePath: filePath is %s", dst); + } + + return r; +} + +void ScummEngine_v72he::copyScriptString(byte *dst, int dstSize) { + byte string[1024]; + byte chr; + int pos = 0; + + int array = pop(); + if (array == -1) { + if (_stringLength == 1) + error("String stack underflow"); + + _stringLength -= 2; + while ((chr = _stringBuffer[_stringLength]) != 0) { + string[pos] = chr; + pos++; + + if (pos > dstSize) + error("String too long to pop"); + + _stringLength--; + } + + string[pos] = 0; + _stringLength++; + + // Reverse string + int len = resStrLen(string); + while (len--) + *dst++ = string[len]; + } else { + writeVar(0, array); + while ((chr = readArray(0, 0, pos)) != 0) { + *dst++ = chr; + pos++; + } + } + *dst = 0; +} + +void ScummEngine_v72he::decodeScriptString(byte *dst, bool scriptString) { + const byte *src; + int args[31]; + int num, len, val; + byte chr, string[1024]; + memset(args, 0, sizeof(args)); + memset(string, 0, sizeof(string)); + + // Get stack list, plus one + num = pop(); + for (int i = num; i >= 0; i--) + args[i] = pop(); + + // Get string + if (scriptString) { + len = resStrLen(_scriptPointer) + 1; + memcpy(string, _scriptPointer, len); + _scriptPointer += len; + } else { + copyScriptString(string, sizeof(string)); + len = resStrLen(string) + 1; + } + + // Decode string + num = 0; + val = 0; + while (len--) { + chr = string[num++]; + if (chr == '%') { + chr = string[num++]; + switch(chr) { + case 'b': + //dst += sprintf((char *)dst, "%b", args[val++]); + break; + case 'c': + *dst++ = args[val++]; + break; + case 'd': + dst += sprintf((char *)dst, "%d", args[val++]); + break; + case 's': + src = getStringAddress(args[val++]); + if (src) { + while (*src != 0) + *dst++ = *src++; + } + break; + case 'x': + dst += sprintf((char *)dst, "%x", args[val++]); + break; + default: + *dst++ = '%'; + num--; + break; + } + } else { + *dst++ = chr; + } + } + *dst = 0; +} + +byte *ScummEngine_v70he::heFindResourceData(uint32 tag, byte *ptr) { + ptr = heFindResource(tag, ptr); + + if (ptr == NULL) + return NULL; + return ptr + _resourceHeaderSize; +} + +byte *ScummEngine_v70he::heFindResource(uint32 tag, byte *searchin) { + uint32 curpos, totalsize, size; + + debugC(DEBUG_RESOURCE, "heFindResource(%s, %lx)", tag2str(tag), searchin); + + assert(searchin); + searchin += 4; + _resourceLastSearchSize = totalsize = READ_BE_UINT32(searchin); + curpos = 8; + searchin += 4; + + while (curpos < totalsize) { + if (READ_UINT32(searchin) == tag) { + return searchin; + } + + size = READ_BE_UINT32(searchin + 4); + if ((int32)size <= 0) { + error("(%s) Not found in %d... illegal block len %d", tag2str(tag), 0, size); + return NULL; + } + + curpos += size; + searchin += size; + } + + return NULL; +} + +byte *ScummEngine_v70he::findWrappedBlock(uint32 tag, byte *ptr, int state, bool errorFlag) { + if (READ_UINT32(ptr) == MKID('MULT')) { + byte *offs, *wrap; + uint32 size; + + wrap = heFindResource(MKID('WRAP'), ptr); + if (wrap == NULL) + return NULL; + + offs = heFindResourceData(MKID('OFFS'), wrap); + if (offs == NULL) + return NULL; + + size = getResourceDataSize(offs) / 4; + assert((uint32)state <= (uint32)size); + + + offs += READ_LE_UINT32(offs + state * sizeof(uint32)); + offs = heFindResourceData(tag, offs - 8); + if (offs) + return offs; + + offs = heFindResourceData(MKID('DEFA'), ptr); + if (offs == NULL) + return NULL; + + return heFindResourceData(tag, offs - 8); + } else { + return heFindResourceData(tag, ptr); + } +} + +int ScummEngine_v72he::findObject(int x, int y, int num, int *args) { + int b, cls, i, result; + + for (i = 1; i < _numLocalObjects; i++) { + result = 0; + if ((_objs[i].obj_nr < 1) || getClass(_objs[i].obj_nr, kObjectClassUntouchable)) + continue; + + // Check polygon bounds + if (_wiz->polygonDefined(_objs[i].obj_nr)) { + if (_wiz->polygonHit(_objs[i].obj_nr, x, y)) + result = _objs[i].obj_nr; + else if (VAR_POLYGONS_ONLY != 0xFF && VAR(VAR_POLYGONS_ONLY)) + continue; + } + + if (!result) { + // Check object bounds + if (_objs[i].x_pos <= x && _objs[i].width + _objs[i].x_pos > x && + _objs[i].y_pos <= y && _objs[i].height + _objs[i].y_pos > y) + result = _objs[i].obj_nr; + } + + if (result) { + if (!num) + return result; + + // Check object class + cls = args[0]; + b = getClass(_objs[i].obj_nr, cls); + if ((cls & 0x80 && b) || (!(cls & 0x80) && !b)) + return result; + } + } + + return 0; +} + +void ScummEngine_v72he::o72_pushDWord() { + push(fetchScriptDWordSigned()); +} + +void ScummEngine_v72he::o72_getScriptString() { + byte chr; + + while ((chr = fetchScriptByte()) != 0) { + _stringBuffer[_stringLength] = chr; + _stringLength++; + + if (_stringLength >= 4096) + error("String stack overflow"); + } + + _stringBuffer[_stringLength] = 0; + _stringLength++; +} + +void ScummEngine_v72he::o72_isAnyOf() { + int args[128]; + int num, value; + + num = getStackList(args, ARRAYSIZE(args)); + value = pop(); + + for (int i = 0; i < num; i++) { + if (args[i] == value) { + push(1); + return; + } + } + + push(0); +} + +void ScummEngine_v72he::o72_resetCutscene() { + int idx; + + idx = vm.cutSceneStackPointer; + vm.cutSceneStackPointer = 0; + vm.cutScenePtr[idx] = 0; + vm.cutSceneScript[idx] = 0; + + VAR(VAR_OVERRIDE) = 0; +} + +void ScummEngine_v72he::o72_findObjectWithClassOf() { + int args[16], num; + + num = getStackList(args, ARRAYSIZE(args)); + int y = pop(); + int x = pop(); + int r = findObject(x, y, num, args); + push(r); +} + +void ScummEngine_v72he::o72_getObjectImageX() { + int object = pop(); + int objnum = getObjectIndex(object); + + if (objnum == -1) { + push(0); + return; + } + + push(_objs[objnum].x_pos / 8); +} + +void ScummEngine_v72he::o72_getObjectImageY() { + int object = pop(); + int objnum = getObjectIndex(object); + + if (objnum == -1) { + push(0); + return; + } + + push(_objs[objnum].y_pos / 8); +} + +void ScummEngine_v72he::o72_captureWizImage() { + Common::Rect grab; + grab.bottom = pop() + 1; + grab.right = pop() + 1; + grab.top = pop(); + grab.left = pop(); + _wiz->captureWizImage(pop(), grab, false, true); +} + +void ScummEngine_v72he::o72_getTimer() { + int timer = pop(); + byte cmd = fetchScriptByte(); + + if (cmd == 10 || cmd == 50) { + push(getHETimer(timer)); + } else { + push(0); + } +} + +void ScummEngine_v72he::o72_setTimer() { + int timer = pop(); + byte cmd = fetchScriptByte(); + + if (cmd == 158 || cmd == 61) { + setHETimer(timer); + } else { + error("TIMER command %d?", cmd); + } +} + +void ScummEngine_v72he::o72_getSoundPosition() { + int snd = pop(); + push(_sound->getSoundPos(snd)); +} + +void ScummEngine_v72he::o72_startScript() { + int args[25]; + int script; + byte flags; + + getStackList(args, ARRAYSIZE(args)); + script = pop(); + flags = fetchScriptByte(); + runScript(script, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args); +} + +void ScummEngine_v72he::o72_startObject() { + int args[25]; + int script, entryp; + byte flags; + + getStackList(args, ARRAYSIZE(args)); + entryp = pop(); + script = pop(); + flags = fetchScriptByte(); + runObjectScript(script, entryp, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args); +} + +void ScummEngine_v72he::o72_drawObject() { + byte subOp = fetchScriptByte(); + int state, y, x; + + switch (subOp) { + case 62: + state = pop(); + y = pop(); + x = pop(); + break; + case 63: + state = pop(); + if (state == 0) + state = 1; + y = x = -100; + break; + case 65: + state = 1; + y = pop(); + x = pop(); + break; + default: + error("o72_drawObject: default case %d", subOp); + } + + int object = pop(); + int objnum = getObjectIndex(object); + if (objnum == -1) + return; + + if (y != -100 && x != -100) { + _objs[objnum].x_pos = x * 8; + _objs[objnum].y_pos = y * 8; + } + + if (state != -1) { + addObjectToDrawQue(objnum); + putState(object, state); + } +} + +void ScummEngine_v72he::o72_printWizImage() { + WizImage wi; + wi.resNum = pop(); + wi.x1 = wi.y1 = 0; + wi.state = 0; + wi.flags = kWIFPrint; + _wiz->displayWizImage(&wi); +} + +void ScummEngine_v72he::o72_getArrayDimSize() { + byte subOp = fetchScriptByte(); + int32 val1, val2; + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(fetchScriptWord())); + if (!ah) { + push(0); + return; + } + + switch (subOp) { + case 1: + case 3: + val1 = FROM_LE_32(ah->dim1end); + val2 = FROM_LE_32(ah->dim1start); + push(val1 - val2 + 1); + break; + case 2: + val1 = FROM_LE_32(ah->dim2end); + val2 = FROM_LE_32(ah->dim2start); + push(val1 - val2 + 1); + break; + case 4: + push(FROM_LE_32(ah->dim1start)); + break; + case 5: + push(FROM_LE_32(ah->dim1end)); + break; + case 6: + push(FROM_LE_32(ah->dim2start)); + break; + case 7: + push(FROM_LE_32(ah->dim2end)); + break; + default: + error("o72_getArrayDimSize: default case %d", subOp); + } +} + +void ScummEngine_v72he::o72_getNumFreeArrays() { + byte **addr = res.address[rtString]; + int i, num = 0; + + for (i = 1; i < _numArray; i++) { + if (!addr[i]) + num++; + } + + push (num); +} + +void ScummEngine_v72he::o72_roomOps() { + int a, b, c, d, e; + byte filename[100]; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 172: // SO_ROOM_SCROLL + b = pop(); + a = pop(); + if (a < (_screenWidth / 2)) + a = (_screenWidth / 2); + if (b < (_screenWidth / 2)) + b = (_screenWidth / 2); + if (a > _roomWidth - (_screenWidth / 2)) + a = _roomWidth - (_screenWidth / 2); + if (b > _roomWidth - (_screenWidth / 2)) + b = _roomWidth - (_screenWidth / 2); + VAR(VAR_CAMERA_MIN_X) = a; + VAR(VAR_CAMERA_MAX_X) = b; + break; + + case 174: // SO_ROOM_SCREEN + b = pop(); + a = pop(); + initScreens(a, _screenHeight); + break; + + case 175: // SO_ROOM_PALETTE + d = pop(); + c = pop(); + b = pop(); + a = pop(); + setPalColor(d, a, b, c); + break; + + case 179: // SO_ROOM_INTENSITY + c = pop(); + b = pop(); + a = pop(); + darkenPalette(a, a, a, b, c); + break; + + case 180: // SO_ROOM_SAVEGAME + _saveTemporaryState = true; + _saveLoadSlot = pop(); + _saveLoadFlag = pop(); + break; + + case 181: // SO_ROOM_FADE + // Defaults to 1 but doesn't use fade effects + a = pop(); + break; + + case 182: // SO_RGB_ROOM_INTENSITY + e = pop(); + d = pop(); + c = pop(); + b = pop(); + a = pop(); + darkenPalette(a, b, c, d, e); + break; + + case 213: // SO_ROOM_NEW_PALETTE + a = pop(); + setPalette(a); + break; + + case 220: + a = pop(); + b = pop(); + copyPalColor(a, b); + break; + + case 221: + copyScriptString(filename, sizeof(filename)); + _saveLoadFlag = pop(); + _saveLoadSlot = 1; + _saveTemporaryState = true; + break; + + case 234: + b = pop(); + a = pop(); + swapObjects(a, b); + break; + + case 236: + b = pop(); + a = pop(); + setRoomPalette(a, b); + break; + + default: + error("o72_roomOps: default case %d", subOp); + } +} + +void ScummEngine_v72he::o72_actorOps() { + Actor *a; + int i, j, k; + int args[32]; + byte string[256]; + + byte subOp = fetchScriptByte(); + if (subOp == 197) { + _curActor = pop(); + return; + } + + a = derefActorSafe(_curActor, "o72_actorOps"); + if (!a) + return; + + switch (subOp) { + case 21: // HE 80+ + k = getStackList(args, ARRAYSIZE(args)); + for (i = 0; i < k; ++i) { + a->setUserCondition(args[i] & 0x7F, args[i] & 0x80); + } + break; + case 24: // HE 80+ + k = pop(); + if (k == 0) + k = _rnd.getRandomNumberRng(1, 10); + a->_heNoTalkAnimation = 1; + a->setTalkCondition(k); + break; + case 43: // HE 90+ + // HE games use reverse order of layering, so we adjust + a->_layer = -pop(); + a->_needRedraw = true; + break; + case 64: + _actorClipOverride.bottom = pop(); + _actorClipOverride.right = pop(); + _actorClipOverride.top = pop(); + _actorClipOverride.left = pop(); + break; + case 67: // HE 99+ + a->_clipOverride.bottom = pop(); + a->_clipOverride.right = pop(); + a->_clipOverride.top = pop(); + a->_clipOverride.left = pop(); + break; + case 65: // HE 98+ + j = pop(); + i = pop(); + a->putActor(i, j, a->_room); + break; + case 68: // HE 90+ + k = pop(); + debug(0,"o72_actorOps: case 68 (%d)", k); + break; + case 76: // SO_COSTUME + a->setActorCostume(pop()); + break; + case 77: // SO_STEP_DIST + j = pop(); + i = pop(); + a->setActorWalkSpeed(i, j); + break; + case 78: // SO_SOUND + k = getStackList(args, ARRAYSIZE(args)); + for (i = 0; i < k; i++) + a->_sound[i] = args[i]; + break; + case 79: // SO_WALK_ANIMATION + a->_walkFrame = pop(); + break; + case 80: // SO_TALK_ANIMATION + a->_talkStopFrame = pop(); + a->_talkStartFrame = pop(); + break; + case 81: // SO_STAND_ANIMATION + a->_standFrame = pop(); + break; + case 82: // SO_ANIMATION + // dummy case in scumm6 + pop(); + pop(); + pop(); + break; + case 83: // SO_DEFAULT + a->initActor(0); + break; + case 84: // SO_ELEVATION + a->setElevation(pop()); + break; + case 85: // SO_ANIMATION_DEFAULT + a->_initFrame = 1; + a->_walkFrame = 2; + a->_standFrame = 3; + a->_talkStartFrame = 4; + a->_talkStopFrame = 5; + break; + case 86: // SO_PALETTE + j = pop(); + i = pop(); + checkRange(255, 0, i, "Illegal palette slot %d"); + a->remapActorPaletteColor(i, j); + a->_needRedraw = true; + break; + case 87: // SO_TALK_COLOR + a->_talkColor = pop(); + break; + case 88: // SO_ACTOR_NAME + copyScriptString(string, sizeof(string)); + loadPtrToResource(rtActorName, a->_number, string); + break; + case 89: // SO_INIT_ANIMATION + a->_initFrame = pop(); + break; + case 91: // SO_ACTOR_WIDTH + a->_width = pop(); + break; + case 92: // SO_SCALE + i = pop(); + a->setScale(i, i); + break; + case 93: // SO_NEVER_ZCLIP + a->_forceClip = 0; + break; + case 94: // SO_ALWAYS_ZCLIP + a->_forceClip = pop(); + break; + case 95: // SO_IGNORE_BOXES + a->_ignoreBoxes = 1; + a->_forceClip = 0; + if (a->isInCurrentRoom()) + a->putActor(a->_pos.x, a->_pos.y, a->_room); + break; + case 96: // SO_FOLLOW_BOXES + a->_ignoreBoxes = 0; + a->_forceClip = 0; + if (a->isInCurrentRoom()) + a->putActor(a->_pos.x, a->_pos.y, a->_room); + break; + case 97: // SO_ANIMATION_SPEED + a->setAnimSpeed(pop()); + break; + case 98: // SO_SHADOW + a->_heXmapNum = pop(); + a->_needRedraw = true; + break; + case 99: // SO_TEXT_OFFSET + a->_talkPosY = pop(); + a->_talkPosX = pop(); + break; + case 156: // HE 72+ + a->_charset = pop(); + break; + case 175: // HE 99+ + a->_hePaletteNum = pop(); + a->_needRedraw = true; + break; + case 198: // SO_ACTOR_VARIABLE + i = pop(); + a->setAnimVar(pop(), i); + break; + case 215: // SO_ACTOR_IGNORE_TURNS_ON + a->_ignoreTurns = true; + break; + case 216: // SO_ACTOR_IGNORE_TURNS_OFF + a->_ignoreTurns = false; + break; + case 217: // SO_ACTOR_NEW + a->initActor(2); + break; + case 218: + a->drawActorToBackBuf(a->_pos.x, a->_pos.y); + break; + case 219: + a->_drawToBackBuf = false; + a->_needRedraw = true; + a->_needBgReset = true; + break; + case 225: + { + copyScriptString(string, sizeof(string)); + int slot = pop(); + + int len = resStrLen(string) + 1; + memcpy(a->_heTalkQueue[slot].sentence, string, len); + + a->_heTalkQueue[slot].posX = a->_talkPosX; + a->_heTalkQueue[slot].posY = a->_talkPosY; + a->_heTalkQueue[slot].color = a->_talkColor; + break; + } + default: + error("o72_actorOps: default case %d", subOp); + } +} + +void ScummEngine_v72he::o72_verbOps() { + int slot, a, b; + VerbSlot *vs; + byte name[200]; + + byte subOp = fetchScriptByte(); + if (subOp == 196) { + _curVerb = pop(); + _curVerbSlot = getVerbSlot(_curVerb, 0); + checkRange(_numVerbs - 1, 0, _curVerbSlot, "Illegal new verb slot %d"); + return; + } + vs = &_verbs[_curVerbSlot]; + slot = _curVerbSlot; + switch (subOp) { + case 124: // SO_VERB_IMAGE + a = pop(); + if (_curVerbSlot) { + setVerbObject(_roomResource, a, slot); + vs->type = kImageVerbType; + vs->imgindex = a; + } + break; + case 125: // SO_VERB_NAME + copyScriptString(name, sizeof(name)); + loadPtrToResource(rtVerb, slot, name); + vs->type = kTextVerbType; + vs->imgindex = 0; + break; + case 126: // SO_VERB_COLOR + vs->color = pop(); + break; + case 127: // SO_VERB_HICOLOR + vs->hicolor = pop(); + break; + case 128: // SO_VERB_AT + vs->curRect.top = pop(); + vs->curRect.left = pop(); + break; + case 129: // SO_VERB_ON + vs->curmode = 1; + break; + case 130: // SO_VERB_OFF + vs->curmode = 0; + break; + case 131: // SO_VERB_DELETE + slot = getVerbSlot(pop(), 0); + killVerb(slot); + break; + case 132: // SO_VERB_NEW + slot = getVerbSlot(_curVerb, 0); + if (slot == 0) { + for (slot = 1; slot < _numVerbs; slot++) { + if (_verbs[slot].verbid == 0) + break; + } + if (slot == _numVerbs) + error("Too many verbs"); + _curVerbSlot = slot; + } + vs = &_verbs[slot]; + vs->verbid = _curVerb; + vs->color = 2; + vs->hicolor = 0; + vs->dimcolor = 8; + vs->type = kTextVerbType; + vs->charset_nr = _string[0]._default.charset; + vs->curmode = 0; + vs->saveid = 0; + vs->key = 0; + vs->center = 0; + vs->imgindex = 0; + break; + case 133: // SO_VERB_DIMCOLOR + vs->dimcolor = pop(); + break; + case 134: // SO_VERB_DIM + vs->curmode = 2; + break; + case 135: // SO_VERB_KEY + vs->key = pop(); + break; + case 136: // SO_VERB_CENTER + vs->center = 1; + break; + case 137: // SO_VERB_NAME_STR + a = pop(); + if (a == 0) { + loadPtrToResource(rtVerb, slot, (const byte *)""); + } else { + loadPtrToResource(rtVerb, slot, getStringAddress(a)); + } + vs->type = kTextVerbType; + vs->imgindex = 0; + break; + case 139: // SO_VERB_IMAGE_IN_ROOM + b = pop(); + a = pop(); + + if (slot && a != vs->imgindex) { + setVerbObject(b, a, slot); + vs->type = kImageVerbType; + vs->imgindex = a; + } + break; + case 140: // SO_VERB_BAKCOLOR + vs->bkcolor = pop(); + break; + case 255: + drawVerb(slot, 0); + verbMouseOver(0); + break; + default: + error("o72_verbops: default case %d", subOp); + } +} + +void ScummEngine_v72he::o72_findObject() { + int y = pop(); + int x = pop(); + int r = findObject(x, y, 0, 0); + push(r); +} + +void ScummEngine_v72he::o72_arrayOps() { + ArrayHeader *ah; + byte string[1024]; + int dim1end, dim1start, dim2end, dim2start; + int id, len, b, c, list[128]; + int offs, tmp, tmp2; + uint tmp3; + + byte subOp = fetchScriptByte(); + int array = fetchScriptWord(); + debug(9,"o72_arrayOps: array %d case %d", array, subOp); + + switch (subOp) { + case 7: // SO_ASSIGN_STRING + copyScriptString(string, sizeof(string)); + len = resStrLen(string); + ah = defineArray(array, kStringArray, 0, 0, 0, len); + memcpy(ah->data, string, len); + break; + + case 126: + len = getStackList(list, ARRAYSIZE(list)); + dim1end = pop(); + dim1start = pop(); + dim2end = pop(); + dim2start = pop(); + id = readVar(array); + if (id == 0) { + defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end); + } + tmp2 = 0; + while (dim2start <= dim2end) { + tmp = dim1start; + while (tmp <= dim1end) { + writeArray(array, dim2start, tmp, list[tmp2++]); + if (tmp2 == len) + tmp2 = 0; + tmp++; + } + dim2start++; + } + break; + case 127: + { + int a2_dim1end = pop(); + int a2_dim1start = pop(); + int a2_dim2end = pop(); + int a2_dim2start = pop(); + int array2 = fetchScriptWord(); + int a1_dim1end = pop(); + int a1_dim1start = pop(); + int a1_dim2end = pop(); + int a1_dim2start = pop(); + if (a1_dim1end - a1_dim1start != a2_dim1end - a2_dim1start || a2_dim2end - a2_dim2start != a1_dim2end - a1_dim2start) { + error("Source and dest ranges size are mismatched"); + } + copyArray(array, a1_dim2start, a1_dim2end, a1_dim1start, a1_dim1end, array2, a2_dim2start, a2_dim2end, a2_dim1start, a2_dim1end); + } + break; + case 128: + b = pop(); + c = pop(); + dim1end = pop(); + dim1start = pop(); + dim2end = pop(); + dim2start = pop(); + id = readVar(array); + if (id == 0) { + defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end); + } + + offs = (b >= c) ? 1 : -1; + tmp2 = c; + tmp3 = c - b + 1; + while (dim2start <= dim2end) { + tmp = dim1start; + while (tmp <= dim1end) { + writeArray(array, dim2start, tmp, tmp2); + if (--tmp3 == 0) { + tmp2 = c; + tmp3 = c - b + 1; + } else { + tmp2 += offs; + } + tmp++; + } + dim2start++; + } + break; + case 194: + decodeScriptString(string); + len = resStrLen(string); + ah = defineArray(array, kStringArray, 0, 0, 0, len); + memcpy(ah->data, string, len); + break; + case 208: // SO_ASSIGN_INT_LIST + b = pop(); + c = pop(); + id = readVar(array); + if (id == 0) { + defineArray(array, kDwordArray, 0, 0, 0, b + c - 1); + } + while (c--) { + writeArray(array, 0, b + c, pop()); + } + break; + case 212: // SO_ASSIGN_2DIM_LIST + len = getStackList(list, ARRAYSIZE(list)); + id = readVar(array); + if (id == 0) + error("Must DIM a two dimensional array before assigning"); + c = pop(); + while (--len >= 0) { + writeArray(array, c, len, list[len]); + } + break; + default: + error("o72_arrayOps: default case %d (array %d)", subOp, array); + } +} + +void ScummEngine_v72he::o72_systemOps() { + byte string[1024]; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 22: // HE80+ + clearDrawObjectQueue(); + break; + case 26: // HE80+ + gdi.copyVirtScreenBuffers(Common::Rect(_screenWidth, _screenHeight)); + updatePalette(); + break; + case 158: + restart(); + break; + case 160: + // Confirm shutdown + shutDown(); + break; + case 244: + shutDown(); + break; + case 251: + copyScriptString(string, sizeof(string)); + debug(0, "Start executable (%s)", string); + break; + case 252: + copyScriptString(string, sizeof(string)); + debug(0, "Start game (%s)", string); + break; + default: + error("o72_systemOps invalid case %d", subOp); + } +} + +void ScummEngine_v72he::o72_talkActor() { + Actor *a; + + int act = pop(); + + _string[0].loadDefault(); + + // A value of 225 can occur when examining the gold in the mine of pajama, after mining the gold. + // This is a script bug, the script should set the subtitle color, not actor number. + // This script bug was fixed in the updated version of pajama. + if (act == 225) { + _string[0].color = act; + } else { + _actorToPrintStrFor = act; + if (_actorToPrintStrFor != 0xFF) { + a = derefActor(_actorToPrintStrFor, "o72_talkActor"); + _string[0].color = a->_talkColor; + } + } + + actorTalk(_scriptPointer); + + _scriptPointer += resStrLen(_scriptPointer) + 1; +} + +void ScummEngine_v72he::o72_talkEgo() { + push(VAR(VAR_EGO)); + o72_talkActor(); +} + +void ScummEngine_v72he::o72_dimArray() { + int data; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 2: // SO_BIT_ARRAY + data = kBitArray; + break; + case 3: // SO_NIBBLE_ARRAY + data = kNibbleArray; + break; + case 4: // SO_BYTE_ARRAY + data = kByteArray; + break; + case 5: // SO_INT_ARRAY + data = kIntArray; + break; + case 6: + data = kDwordArray; + break; + case 7: // SO_STRING_ARRAY + data = kStringArray; + break; + case 204: // SO_UNDIM_ARRAY + nukeArray(fetchScriptWord()); + return; + default: + error("o72_dimArray: default case %d", subOp); + } + + defineArray(fetchScriptWord(), data, 0, 0, 0, pop()); +} + + +void ScummEngine_v72he::o72_dim2dimArray() { + int data, dim1end, dim2end; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 2: // SO_BIT_ARRAY + data = kBitArray; + break; + case 3: // SO_NIBBLE_ARRAY + data = kNibbleArray; + break; + case 4: // SO_BYTE_ARRAY + data = kByteArray; + break; + case 5: // SO_INT_ARRAY + data = kIntArray; + break; + case 6: + data = kDwordArray; + break; + case 7: // SO_STRING_ARRAY + data = kStringArray; + break; + default: + error("o72_dim2dimArray: default case %d", subOp); + } + + dim1end = pop(); + dim2end = pop(); + defineArray(fetchScriptWord(), data, 0, dim2end, 0, dim1end); +} + +void ScummEngine_v72he::o72_traceStatus() { + byte string[80]; + + copyScriptString(string, sizeof(string)); + pop(); +} + +void ScummEngine_v72he::o72_kernelGetFunctions() { + int args[29]; + ArrayHeader *ah; + getStackList(args, ARRAYSIZE(args)); + + switch (args[0]) { + case 1: + writeVar(0, 0); + ah = defineArray(0, kByteArray, 0, 0, 0, virtScreenSave(0, args[1], args[2], args[3], args[4])); + virtScreenSave(ah->data, args[1], args[2], args[3], args[4]); + push(readVar(0)); + break; + default: + error("o72_kernelGetFunctions: default case %d", args[0]); + } +} + +void ScummEngine_v72he::o72_drawWizImage() { + WizImage wi; + wi.flags = pop(); + wi.y1 = pop(); + wi.x1 = pop(); + wi.resNum = pop(); + wi.state = 0; + _wiz->displayWizImage(&wi); +} + +void ScummEngine_v72he::o72_debugInput() { + byte string[255]; + + copyScriptString(string, sizeof(string)); + int len = resStrLen(string) + 1; + + writeVar(0, 0); + ArrayHeader *ah = defineArray(0, kStringArray, 0, 0, 0, len); + memcpy(ah->data, string, len); + push(readVar(0)); + debug(1,"o72_debugInput: String %s", string); +} + +void ScummEngine_v72he::o72_jumpToScript() { + int args[25]; + int script; + byte flags; + + getStackList(args, ARRAYSIZE(args)); + script = pop(); + flags = fetchScriptByte(); + stopObjectCode(); + runScript(script, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args); +} + +void ScummEngine_v72he::o72_openFile() { + int mode, slot, i; + byte filename[256]; + + mode = pop(); + copyScriptString(filename, sizeof(filename)); + + debug(1,"Original filename %s", filename); + + // There are Macintosh specific versions of HE7.2 games. + if (_heversion >= 80 && _platform == Common::kPlatformMacintosh) { + // Work around for filename difference in HE7 file, needs to + // open 'Water (7)' instead of 'Water Worries (7)'. + if (_gameId == GID_WATER && _heversion == 99 && !strcmp((char *)filename, "Water.he7")) { + strcpy((char *)filename, "Water (7)"); + } else { + char buf1[128]; + buf1[0] = '\0'; + generateSubstResFileName((char *)filename, buf1, sizeof(buf1)); + if (buf1[0]) { + strcpy((char *)filename, buf1); + } + } + } + + int r = convertFilePath(filename); + debug(1,"Final filename to %s", filename + r); + + slot = -1; + for (i = 1; i < 17; i++) { + if (_hFileTable[i].isOpen() == false) { + slot = i; + break; + } + } + + if (slot != -1) { + switch(mode) { + case 1: + _hFileTable[slot].open((char*)filename + r, Common::File::kFileReadMode, _saveFileMan->getSavePath()); + if (_hFileTable[slot].isOpen() == false) + _hFileTable[slot].open((char*)filename + r, Common::File::kFileReadMode, _gameDataPath.c_str()); + break; + case 2: + _hFileTable[slot].open((char*)filename + r, Common::File::kFileWriteMode, _saveFileMan->getSavePath()); + break; + default: + error("o72_openFile(): wrong open file mode %d", mode); + } + + if (_hFileTable[slot].isOpen() == false) + slot = -1; + + } + debug(1, "o72_openFile: slot %d, mode %d", slot, mode); + push(slot); +} + +int ScummEngine_v72he::readFileToArray(int slot, int32 size) { + if (size == 0) + size = _hFileTable[slot].size() - _hFileTable[slot].pos(); + + writeVar(0, 0); + ArrayHeader *ah = defineArray(0, kByteArray, 0, 0, 0, size); + + if (_hFileTable[slot].isOpen()) + _hFileTable[slot].read(ah->data, size + 1); + + return readVar(0); +} + +void ScummEngine_v72he::o72_readFile() { + int slot, val; + int32 size; + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 4: + slot = pop(); + val = _hFileTable[slot].readByte(); + push(val); + break; + case 5: + slot = pop(); + val = _hFileTable[slot].readUint16LE(); + push(val); + break; + case 6: + slot = pop(); + val = _hFileTable[slot].readUint32LE(); + push(val); + break; + case 8: + fetchScriptByte(); + size = pop(); + slot = pop(); + val = readFileToArray(slot, size); + push(val); + break; + default: + error("o72_readFile: default case %d", subOp); + } +} + +void ScummEngine_v72he::writeFileFromArray(int slot, int32 resID) { + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resID); + int32 size = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) * + (FROM_LE_32(ah->dim2end) - FROM_LE_32(ah->dim2start) + 1); + + _hFileTable[slot].write(ah->data, size); +} + +void ScummEngine_v72he::o72_writeFile() { + int32 resID = pop(); + int slot = pop(); + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 4: + _hFileTable[slot].writeByte(resID); + break; + case 5: + _hFileTable[slot].writeUint16LE(resID); + break; + case 6: + _hFileTable[slot].writeUint32LE(resID); + break; + case 8: + fetchScriptByte(); + writeFileFromArray(slot, resID); + break; + default: + error("o72_writeFile: default case %d", subOp); + } +} + +void ScummEngine_v72he::o72_findAllObjects() { + int room = pop(); + int i; + + if (room != _currentRoom) + error("o72_findAllObjects: current room is not %d", room); + + writeVar(0, 0); + defineArray(0, kDwordArray, 0, 0, 0, _numLocalObjects); + writeArray(0, 0, 0, _numLocalObjects); + + for (i = 1; i < _numLocalObjects; i++) { + writeArray(0, 0, i, _objs[i].obj_nr); + } + + push(readVar(0)); +} + +void ScummEngine_v72he::o72_deleteFile() { + byte filename[256]; + + copyScriptString(filename, sizeof(filename)); + debug(1, "stub o72_deleteFile(%s)", filename); +} + +void ScummEngine_v72he::o72_rename() { + byte oldFilename[100],newFilename[100]; + + copyScriptString(newFilename, sizeof(newFilename)); + copyScriptString(oldFilename, sizeof(oldFilename)); + + debug(1, "stub o72_rename(%s to %s)", oldFilename, newFilename); +} + +void ScummEngine_v72he::o72_getPixel() { + byte area; + + int y = pop(); + int x = pop(); + byte subOp = fetchScriptByte(); + + VirtScreen *vs = findVirtScreen(y); + if (vs == NULL || x > _screenWidth - 1 || x < 0) { + push(-1); + return; + } + + switch (subOp) { + case 9: // HE 100 + case 218: + area = *vs->getBackPixels(x, y - vs->topline); + break; + case 8: // HE 100 + case 219: + area = *vs->getPixels(x, y - vs->topline); + break; + default: + error("o72_getPixel: default case %d", subOp); + } + push(area); +} + +void ScummEngine_v72he::o72_pickVarRandom() { + int num; + int args[100]; + int32 dim1end; + + num = getStackList(args, ARRAYSIZE(args)); + int value = fetchScriptWord(); + + if (readVar(value) == 0) { + defineArray(value, kDwordArray, 0, 0, 0, num); + if (num > 0) { + int16 counter = 0; + do { + writeArray(value, 0, counter + 1, args[counter]); + } while (++counter < num); + } + + shuffleArray(value, 1, num); + writeArray(value, 0, 0, 2); + push(readArray(value, 0, 1)); + return; + } + + num = readArray(value, 0, 0); + + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(value)); + dim1end = FROM_LE_32(ah->dim1end); + + if (dim1end < num) { + int32 var_2 = readArray(value, 0, num - 1); + shuffleArray(value, 1, dim1end); + if (readArray(value, 0, 1) == var_2) { + num = 2; + } else { + num = 1; + } + } + + writeArray(value, 0, 0, num + 1); + push(readArray(value, 0, num)); +} + +void ScummEngine_v72he::o72_redimArray() { + int newX, newY; + newY = pop(); + newX = pop(); + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 5: + redimArray(fetchScriptWord(), 0, newX, 0, newY, kIntArray); + break; + case 4: + redimArray(fetchScriptWord(), 0, newX, 0, newY, kByteArray); + break; + case 6: + redimArray(fetchScriptWord(), 0, newX, 0, newY, kDwordArray); + break; + default: + error("o72_redimArray: default type %d", subOp); + } +} + +void ScummEngine_v72he::redimArray(int arrayId, int newDim2start, int newDim2end, + int newDim1start, int newDim1end, int type) { + int newSize, oldSize; + + if (readVar(arrayId) == 0) + error("redimArray: Reference to zeroed array pointer"); + + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(arrayId)); + + if (!ah) + error("redimArray: Invalid array (%d) reference", readVar(arrayId)); + + newSize = arrayDataSizes[type]; + oldSize = arrayDataSizes[FROM_LE_32(ah->type)]; + + newSize *= (newDim1end - newDim1start + 1) * (newDim2end - newDim2start + 1); + oldSize *= (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) * + (FROM_LE_32(ah->dim2end) - FROM_LE_32(ah->dim2start) + 1); + + newSize >>= 3; + oldSize >>= 3; + + if (newSize != oldSize) + error("redimArray: array %d redim mismatch", readVar(arrayId)); + + ah->type = TO_LE_32(type); + ah->dim1start = TO_LE_32(newDim1start); + ah->dim1end = TO_LE_32(newDim1end); + ah->dim2start = TO_LE_32(newDim2start); + ah->dim2end = TO_LE_32(newDim2end); +} + +void ScummEngine_v72he::checkArrayLimits(int array, int dim2start, int dim2end, int dim1start, int dim1end) { + if (dim1end < dim1start) { + error("Across max %d smaller than min %d", dim1end, dim1start); + } + if (dim2end < dim2start) { + error("Down max %d smaller than min %d", dim2end, dim2start); + } + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array)); + assert(ah); + if (ah->dim2start > dim2start || ah->dim2end < dim2end || ah->dim1start > dim1start || ah->dim1end < dim1end) { + error("Invalid array access (%d,%d,%d,%d) limit (%d,%d,%d,%d)", dim2start, dim2end, dim1start, dim1end, ah->dim2start, ah->dim2end, ah->dim1start, ah->dim1end); + } +} + +void ScummEngine_v72he::copyArray(int array1, int a1_dim2start, int a1_dim2end, int a1_dim1start, int a1_dim1end, + int array2, int a2_dim2start, int a2_dim2end, int a2_dim1start, int a2_dim1end) +{ + byte *dst, *src; + int dstPitch, srcPitch; + int rowSize; + checkArrayLimits(array1, a1_dim2start, a1_dim2end, a1_dim1start, a1_dim1end); + checkArrayLimits(array2, a2_dim2start, a2_dim2end, a2_dim1start, a2_dim1end); + int a12_num = a1_dim2end - a1_dim2start + 1; + int a11_num = a1_dim1end - a1_dim1start + 1; + int a22_num = a2_dim2end - a2_dim2start + 1; + int a21_num = a2_dim1end - a2_dim1start + 1; + if (a22_num != a12_num || a21_num != a11_num) { + error("Operation size mismatch (%d vs %d)(%d vs %d)", a12_num, a22_num, a11_num, a21_num); + } + + if (array1 != array2) { + ArrayHeader *ah1 = (ArrayHeader *)getResourceAddress(rtString, readVar(array1)); + assert(ah1); + ArrayHeader *ah2 = (ArrayHeader *)getResourceAddress(rtString, readVar(array2)); + assert(ah2); + if (FROM_LE_32(ah1->type) == FROM_LE_32(ah2->type)) { + copyArrayHelper(ah1, a1_dim2start, a1_dim1start, a1_dim1end, &dst, &dstPitch, &rowSize); + copyArrayHelper(ah2, a2_dim2start, a2_dim1start, a2_dim1end, &src, &srcPitch, &rowSize); + for (; a1_dim2start <= a1_dim2end; ++a1_dim2start) { + memcpy(dst, src, rowSize); + dst += dstPitch; + src += srcPitch; + } + } else { + for (; a1_dim2start <= a1_dim2end; ++a1_dim2start, ++a2_dim2start) { + int a2dim1 = a2_dim1start; + int a1dim1 = a1_dim1start; + for (; a1dim1 <= a1_dim1end; ++a1dim1, ++a2dim1) { + int val = readArray(array2, a2_dim2start, a2dim1); + writeArray(array1, a1_dim2start, a1dim1, val); + } + } + } + } else { + if (a2_dim2start != a1_dim2start || a2_dim1start != a1_dim1start) { + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array1)); + assert(ah); + if (a2_dim2start > a1_dim2start) { + copyArrayHelper(ah, a1_dim2start, a1_dim1start, a1_dim1end, &dst, &dstPitch, &rowSize); + copyArrayHelper(ah, a2_dim2start, a2_dim1start, a2_dim1end, &src, &srcPitch, &rowSize); + } else { + copyArrayHelper(ah, a1_dim2end, a1_dim1start, a1_dim1end, &dst, &dstPitch, &rowSize); + copyArrayHelper(ah, a2_dim2end, a2_dim1start, a2_dim1end, &src, &srcPitch, &rowSize); + } + for (; a1_dim2start <= a1_dim2end; ++a1_dim2start) { + memcpy(dst, src, rowSize); + dst += dstPitch; + src += srcPitch; + } + } + } +} + +void ScummEngine_v72he::copyArrayHelper(ArrayHeader *ah, int idx2, int idx1, int len1, byte **data, int *size, int *num) { + const int pitch = FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1; + const int offset = pitch * (idx2 - FROM_LE_32(ah->dim2start)) + idx1 - FROM_LE_32(ah->dim1start); + + switch (FROM_LE_32(ah->type)) { + case kByteArray: + case kStringArray: + *num = len1 - idx1 + 1; + *size = pitch; + *data = ah->data + offset; + break; + case kIntArray: + *num = (len1 - idx1) * 2 + 2; + *size = pitch * 2; + *data = ah->data + offset * 2; + break; + case kDwordArray: + *num = (len1 - idx1) * 4 + 4; + *size = pitch * 4; + *data = ah->data + offset * 4; + break; + default: + error("Invalid array type", FROM_LE_32(ah->type)); + } +} + +void ScummEngine_v72he::o72_readINI() { + byte option[128]; + ArrayHeader *ah; + const char *entry; + int len; + + copyScriptString(option, sizeof(option)); + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 43: // HE 100 + case 6: // number + if (!strcmp((char *)option, "NoPrinting")) { + push(1); + } else if (!strcmp((char *)option, "TextOn")) { + push(ConfMan.getBool("subtitles")); + } else { + push(ConfMan.getInt((char *)option)); + } + break; + case 77: // HE 100 + case 7: // string + entry = (ConfMan.get((char *)option).c_str()); + + writeVar(0, 0); + len = resStrLen((const byte *)entry); + ah = defineArray(0, kStringArray, 0, 0, 0, len); + memcpy(ah->data, entry, len); + + push(readVar(0)); + break; + default: + error("o72_readINI: default type %d", subOp); + } + + debug(1, "o72_readINI: Option %s", option); +} + +void ScummEngine_v72he::o72_writeINI() { + int value; + byte option[256], string[1024]; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 43: // HE 100 + case 6: // number + value = pop(); + copyScriptString(option, sizeof(option)); + ConfMan.set((char *)option, value); + debug(1, "o72_writeINI: Option %s Value %d", option, value); + break; + case 77: // HE 100 + case 7: // string + copyScriptString(string, sizeof(string)); + copyScriptString(option, sizeof(option)); + + // Filter out useless setting + if (!strcmp((char *)option, "HETest")) + return; + + // Filter out confusing subtitle setting + if (!strcmp((char *)option, "TextOn")) + return; + + // Filter out confusing path settings + if (!strcmp((char *)option, "DownLoadPath") || !strcmp((char *)option, "GameResourcePath") || !strcmp((char *)option, "SaveGamePath")) + return; + + ConfMan.set((char *)option, (char *)string); + debug(1, "o72_writeINI: Option %s String %s", option, string); + break; + default: + error("o72_writeINI: default type %d", subOp); + } + + ConfMan.flushToDisk(); +} + +void ScummEngine_v72he::o72_getResourceSize() { + const byte *ptr; + int size, type; + + int resid = pop(); + if (_heversion == 72) { + push(getSoundResourceSize(resid)); + return; + } + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 13: + push (getSoundResourceSize(resid)); + return; + case 14: + type = rtRoomImage; + break; + case 15: + type = rtImage; + break; + case 16: + type = rtCostume; + break; + case 17: + type = rtScript; + break; + default: + error("o72_getResourceSize: default type %d", subOp); + } + + ptr = getResourceAddress(type, resid); + assert(ptr); + size = READ_BE_UINT32(ptr + 4) - 8; + push(size); +} + +void ScummEngine_v72he::o72_setFilePath() { + byte filename[255]; + + copyScriptString(filename, sizeof(filename)); + debug(1,"o72_setFilePath: %s", filename); +} + +void ScummEngine_v72he::o72_setSystemMessage() { + byte name[1024]; + + copyScriptString(name, sizeof(name)); + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 240: + debug(1,"o72_setSystemMessage: (%d) %s", subOp, name); + break; + case 241: // Set Version + debug(1,"o72_setSystemMessage: (%d) %s", subOp, name); + break; + case 242: + debug(1,"o72_setSystemMessage: (%d) %s", subOp, name); + break; + case 243: // Set Window Caption + _system->setWindowCaption((const char *)name); + break; + default: + error("o72_setSystemMessage: default case %d", subOp); + } +} + +void ScummEngine_v72he::decodeParseString(int m, int n) { + Actor *a; + int i, colors, size; + int args[31]; + byte name[1024]; + + byte b = fetchScriptByte(); + + switch (b) { + case 65: // SO_AT + _string[m].ypos = pop(); + _string[m].xpos = pop(); + _string[m].overhead = false; + break; + case 66: // SO_COLOR + _string[m].color = pop(); + break; + case 67: // SO_CLIPPED + _string[m].right = pop(); + break; + case 69: // SO_CENTER + _string[m].center = true; + _string[m].overhead = false; + break; + case 71: // SO_LEFT + _string[m].center = false; + _string[m].overhead = false; + break; + case 72: // SO_OVERHEAD + _string[m].overhead = true; + _string[m].no_talk_anim = false; + break; + case 73: // SO_SAY_VOICE + error("decodeParseString: case 73"); + break; + case 74: // SO_MUMBLE + _string[m].no_talk_anim = true; + break; + case 75: // SO_TEXTSTRING + printString(m, _scriptPointer); + _scriptPointer += resStrLen(_scriptPointer) + 1; + break; + case 194: + decodeScriptString(name, true); + printString(m, name); + break; + case 0xE1: + { + byte *dataPtr = getResourceAddress(rtTalkie, pop()); + byte *text = findWrappedBlock(MKID('TEXT'), dataPtr, 0, 0); + size = getResourceDataSize(text); + memcpy(name, text, size); + printString(m, name); + } + break; + case 0xF9: + colors = pop(); + if (colors == 1) { + _string[m].color = pop(); + } else { + push(colors); + getStackList(args, ARRAYSIZE(args)); + for (i = 0; i < 16; i++) + _charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i]; + _string[m].color = _charsetColorMap[0]; + } + break; + case 0xFE: + _string[m].loadDefault(); + if (n) { + _actorToPrintStrFor = pop(); + if (_actorToPrintStrFor != 0xFF) { + a = derefActor(_actorToPrintStrFor, "decodeParseString"); + _string[0].color = a->_talkColor; + } + } + break; + case 0xFF: + _string[m].saveDefault(); + break; + default: + error("decodeParseString: default case 0x%x", b); + } +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/script_v7he.cpp b/engines/scumm/he/script_v7he.cpp new file mode 100644 index 0000000000..400e7c0ad0 --- /dev/null +++ b/engines/scumm/he/script_v7he.cpp @@ -0,0 +1,1153 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" + +#include "common/config-manager.h" +#include "common/system.h" + +#include "scumm/actor.h" +#include "scumm/charset.h" +#include "scumm/he/intern_he.h" +#include "scumm/object.h" +#include "scumm/resource.h" +#include "scumm/he/resource_v7he.h" +#include "scumm/scumm.h" +#include "scumm/sound.h" +#include "scumm/verbs.h" + +namespace Scumm { + +#define OPCODE(x) _OPCODE(ScummEngine_v70he, x) + +void ScummEngine_v70he::setupOpcodes() { + static const OpcodeEntryv70he opcodes[256] = { + /* 00 */ + OPCODE(o6_pushByte), + OPCODE(o6_pushWord), + OPCODE(o6_pushByteVar), + OPCODE(o6_pushWordVar), + /* 04 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayRead), + OPCODE(o6_wordArrayRead), + /* 08 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayIndexedRead), + OPCODE(o6_wordArrayIndexedRead), + /* 0C */ + OPCODE(o6_dup), + OPCODE(o6_not), + OPCODE(o6_eq), + OPCODE(o6_neq), + /* 10 */ + OPCODE(o6_gt), + OPCODE(o6_lt), + OPCODE(o6_le), + OPCODE(o6_ge), + /* 14 */ + OPCODE(o6_add), + OPCODE(o6_sub), + OPCODE(o6_mul), + OPCODE(o6_div), + /* 18 */ + OPCODE(o6_land), + OPCODE(o6_lor), + OPCODE(o6_pop), + OPCODE(o6_invalid), + /* 1C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 20 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 24 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 28 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 2C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 30 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 34 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 38 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 3C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 40 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_writeByteVar), + OPCODE(o6_writeWordVar), + /* 44 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayWrite), + OPCODE(o6_wordArrayWrite), + /* 48 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayIndexedWrite), + OPCODE(o6_wordArrayIndexedWrite), + /* 4C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteVarInc), + OPCODE(o6_wordVarInc), + /* 50 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayInc), + OPCODE(o6_wordArrayInc), + /* 54 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteVarDec), + OPCODE(o6_wordVarDec), + /* 58 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_byteArrayDec), + OPCODE(o6_wordArrayDec), + /* 5C */ + OPCODE(o6_if), + OPCODE(o6_ifNot), + OPCODE(o6_startScript), + OPCODE(o6_startScriptQuick), + /* 60 */ + OPCODE(o6_startObject), + OPCODE(o6_drawObject), + OPCODE(o6_drawObjectAt), + OPCODE(o6_invalid), + /* 64 */ + OPCODE(o6_invalid), + OPCODE(o6_stopObjectCode), + OPCODE(o6_stopObjectCode), + OPCODE(o6_endCutscene), + /* 68 */ + OPCODE(o6_cutscene), + OPCODE(o6_stopMusic), + OPCODE(o6_freezeUnfreeze), + OPCODE(o6_cursorCommand), + /* 6C */ + OPCODE(o6_breakHere), + OPCODE(o6_ifClassOfIs), + OPCODE(o6_setClass), + OPCODE(o6_getState), + /* 70 */ + OPCODE(o60_setState), + OPCODE(o6_setOwner), + OPCODE(o6_getOwner), + OPCODE(o6_jump), + /* 74 */ + OPCODE(o70_startSound), + OPCODE(o6_stopSound), + OPCODE(o6_startMusic), + OPCODE(o6_stopObjectScript), + /* 78 */ + OPCODE(o6_panCameraTo), + OPCODE(o6_actorFollowCamera), + OPCODE(o6_setCameraAt), + OPCODE(o6_loadRoom), + /* 7C */ + OPCODE(o6_stopScript), + OPCODE(o6_walkActorToObj), + OPCODE(o6_walkActorTo), + OPCODE(o6_putActorAtXY), + /* 80 */ + OPCODE(o6_putActorAtObject), + OPCODE(o6_faceActor), + OPCODE(o6_animateActor), + OPCODE(o6_doSentence), + /* 84 */ + OPCODE(o70_pickupObject), + OPCODE(o6_loadRoomWithEgo), + OPCODE(o6_invalid), + OPCODE(o6_getRandomNumber), + /* 88 */ + OPCODE(o6_getRandomNumberRange), + OPCODE(o6_invalid), + OPCODE(o6_getActorMoving), + OPCODE(o6_isScriptRunning), + /* 8C */ + OPCODE(o70_getActorRoom), + OPCODE(o6_getObjectX), + OPCODE(o6_getObjectY), + OPCODE(o6_getObjectOldDir), + /* 90 */ + OPCODE(o6_getActorWalkBox), + OPCODE(o6_getActorCostume), + OPCODE(o6_findInventory), + OPCODE(o6_getInventoryCount), + /* 94 */ + OPCODE(o6_getVerbFromXY), + OPCODE(o6_beginOverride), + OPCODE(o6_endOverride), + OPCODE(o6_setObjectName), + /* 98 */ + OPCODE(o6_isSoundRunning), + OPCODE(o6_setBoxFlags), + OPCODE(o6_invalid), + OPCODE(o70_resourceRoutines), + /* 9C */ + OPCODE(o60_roomOps), + OPCODE(o60_actorOps), + OPCODE(o6_verbOps), + OPCODE(o6_getActorFromXY), + /* A0 */ + OPCODE(o6_findObject), + OPCODE(o6_pseudoRoom), + OPCODE(o6_getActorElevation), + OPCODE(o6_getVerbEntrypoint), + /* A4 */ + OPCODE(o6_arrayOps), + OPCODE(o6_saveRestoreVerbs), + OPCODE(o6_drawBox), + OPCODE(o6_pop), + /* A8 */ + OPCODE(o6_getActorWidth), + OPCODE(o6_wait), + OPCODE(o6_getActorScaleX), + OPCODE(o6_getActorAnimCounter1), + /* AC */ + OPCODE(o6_invalid), + OPCODE(o6_isAnyOf), + OPCODE(o70_systemOps), + OPCODE(o6_isActorInBox), + /* B0 */ + OPCODE(o6_delay), + OPCODE(o6_delaySeconds), + OPCODE(o6_delayMinutes), + OPCODE(o6_stopSentence), + /* B4 */ + OPCODE(o6_printLine), + OPCODE(o6_printText), + OPCODE(o6_printDebug), + OPCODE(o6_printSystem), + /* B8 */ + OPCODE(o6_printActor), + OPCODE(o6_printEgo), + OPCODE(o6_talkActor), + OPCODE(o6_talkEgo), + /* BC */ + OPCODE(o6_dimArray), + OPCODE(o6_stopObjectCode), + OPCODE(o6_startObjectQuick), + OPCODE(o6_startScriptQuick2), + /* C0 */ + OPCODE(o6_dim2dimArray), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* C4 */ + OPCODE(o6_abs), + OPCODE(o6_distObjectObject), + OPCODE(o6_distObjectPt), + OPCODE(o6_distPtPt), + /* C8 */ + OPCODE(o60_kernelGetFunctions), + OPCODE(o70_kernelSetFunctions), + OPCODE(o6_delayFrames), + OPCODE(o6_pickOneOf), + /* CC */ + OPCODE(o6_pickOneOfDefault), + OPCODE(o6_stampObject), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* D0 */ + OPCODE(o6_getDateTime), + OPCODE(o6_stopTalking), + OPCODE(o6_getAnimateVariable), + OPCODE(o6_invalid), + /* D4 */ + OPCODE(o6_shuffle), + OPCODE(o6_jumpToScript), + OPCODE(o6_band), + OPCODE(o6_bor), + /* D8 */ + OPCODE(o6_isRoomScriptRunning), + OPCODE(o60_closeFile), + OPCODE(o60_openFile), + OPCODE(o60_readFile), + /* DC */ + OPCODE(o60_writeFile), + OPCODE(o6_findAllObjects), + OPCODE(o60_deleteFile), + OPCODE(o60_rename), + /* E0 */ + OPCODE(o60_soundOps), + OPCODE(o6_getPixel), + OPCODE(o60_localizeArrayToScript), + OPCODE(o6_pickVarRandom), + /* E4 */ + OPCODE(o6_setBoxSet), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* E8 */ + OPCODE(o6_invalid), + OPCODE(o70_seekFilePos), + OPCODE(o60_redimArray), + OPCODE(o60_readFilePos), + /* EC */ + OPCODE(o70_copyString), + OPCODE(o70_getStringWidth), + OPCODE(o70_getStringLen), + OPCODE(o70_appendString), + /* F0 */ + OPCODE(o70_concatString), + OPCODE(o70_compareString), + OPCODE(o70_isResourceLoaded), + OPCODE(o70_readINI), + /* F4 */ + OPCODE(o70_writeINI), + OPCODE(o70_getStringLenForWidth), + OPCODE(o70_getCharIndexInString), + OPCODE(o6_invalid), + /* F8 */ + OPCODE(o6_invalid), + OPCODE(o70_setFilePath), + OPCODE(o70_setSystemMessage), + OPCODE(o70_polygonOps), + /* FC */ + OPCODE(o70_polygonHit), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + }; + + _opcodesv70he = opcodes; +} + +void ScummEngine_v70he::executeOpcode(byte i) { + OpcodeProcv70he op = _opcodesv70he[i].proc; + (this->*op) (); +} + +const char *ScummEngine_v70he::getOpcodeDesc(byte i) { + return _opcodesv70he[i].desc; +} + +int ScummEngine_v70he::getStringCharWidth(byte chr) { + int charset = _string[0]._default.charset; + + byte *ptr = getResourceAddress(rtCharset, charset); + assert(ptr); + ptr += 29; + + int spacing = 0; + + int offs = READ_LE_UINT32(ptr + chr * 4 + 4); + if (offs) { + spacing = ptr[offs] + (signed char)ptr[offs + 2]; + } + + return spacing; +} + +int ScummEngine_v70he::setupStringArray(int size) { + writeVar(0, 0); + defineArray(0, kStringArray, 0, size + 1); + writeArray(0, 0, 0, 0); + return readVar(0); +} + +void ScummEngine_v70he::appendSubstring(int dst, int src, int srcOffs, int len) { + int dstOffs, value; + int i = 0; + + if (len == -1) { + len = resStrLen(getStringAddress(src)); + srcOffs = 0; + } + + dstOffs = resStrLen(getStringAddress(dst)); + + len -= srcOffs; + len++; + + while (i < len) { + writeVar(0, src); + value = readArray(0, 0, srcOffs + i); + writeVar(0, dst); + writeArray(0, 0, dstOffs + i, value); + i++; + } + + writeArray(0, 0, dstOffs + i, 0); +} + +void ScummEngine_v70he::o70_startSound() { + int var, value; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 9: + _heSndFlags |= 4; + break; + case 23: + value = pop(); + var = pop(); + _heSndSoundId = pop(); + _sound->setSoundVar(_heSndSoundId, var, value); + break; + case 25: + value = pop(); + _heSndSoundId = pop(); + _sound->addSoundToQueue(_heSndSoundId, 0, 0, 8); + case 56: + _heSndFlags |= 16; + break; + case 164: + _heSndFlags |= 2; + break; + case 224: + _heSndSoundFreq = pop(); + break; + case 230: + _heSndChannel = pop(); + break; + case 231: + _heSndOffset = pop(); + break; + case 232: + _heSndSoundId = pop(); + _heSndOffset = 0; + _heSndSoundFreq = 11025; + _heSndChannel = VAR(VAR_SOUND_CHANNEL); + break; + case 245: + _heSndFlags |= 1; + break; + case 255: + _sound->addSoundToQueue(_heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags); + _heSndFlags = 0; + break; + + default: + error("o70_startSound invalid case %d", subOp); + } +} + +void ScummEngine_v70he::o70_pickupObject() { + int obj, room; + + room = pop(); + obj = pop(); + if (room == 0) + room = getObjectRoom(obj); + + addObjectToInventory(obj, room); + putOwner(obj, VAR(VAR_EGO)); + if (_heversion <= 70) { + putClass(obj, kObjectClassUntouchable, 1); + putState(obj, 1); + markObjectRectAsDirty(obj); + clearDrawObjectQueue(); + } + runInventoryScript(obj); /* Difference */ +} + +void ScummEngine_v70he::o70_getActorRoom() { + int act = pop(); + + if (act < _numActors) { + Actor *a = derefActor(act, "o70_getActorRoom"); + push(a->_room); + } else + push(getObjectRoom(act)); +} + +void ScummEngine_v70he::o70_resourceRoutines() { + int objidx, resid; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 100: // SO_LOAD_SCRIPT + resid = pop(); + ensureResourceLoaded(rtScript, resid); + break; + case 101: // SO_LOAD_SOUND + resid = pop(); + ensureResourceLoaded(rtSound, resid); + break; + case 102: // SO_LOAD_COSTUME + resid = pop(); + ensureResourceLoaded(rtCostume, resid); + break; + case 103: // SO_LOAD_ROOM + resid = pop(); + ensureResourceLoaded(rtRoomImage, resid); + ensureResourceLoaded(rtRoom, resid); + break; + case 104: // SO_NUKE_SCRIPT + resid = pop(); + res.nukeResource(rtScript, resid); + break; + case 105: // SO_NUKE_SOUND + resid = pop(); + res.nukeResource(rtSound, resid); + break; + case 106: // SO_NUKE_COSTUME + resid = pop(); + res.nukeResource(rtCostume, resid); + break; + case 107: // SO_NUKE_ROOM + resid = pop(); + res.nukeResource(rtRoom, resid); + res.nukeResource(rtRoomImage, resid); + break; + case 108: // SO_LOCK_SCRIPT + resid = pop(); + if (resid >= _numGlobalScripts) + break; + res.lock(rtScript, resid); + break; + case 109: // SO_LOCK_SOUND + resid = pop(); + res.lock(rtSound, resid); + break; + case 110: // SO_LOCK_COSTUME + resid = pop(); + res.lock(rtCostume, resid); + break; + case 111: // SO_LOCK_ROOM + resid = pop(); + if (_heversion <= 71 && resid > 0x7F) + resid = _resourceMapper[resid & 0x7F]; + res.lock(rtRoom, resid); + res.lock(rtRoomImage, resid); + break; + case 112: // SO_UNLOCK_SCRIPT + resid = pop(); + if (resid >= _numGlobalScripts) + break; + res.unlock(rtScript, resid); + break; + case 113: // SO_UNLOCK_SOUND + resid = pop(); + res.unlock(rtSound, resid); + break; + case 114: // SO_UNLOCK_COSTUME + resid = pop(); + res.unlock(rtCostume, resid); + break; + case 115: // SO_UNLOCK_ROOM + resid = pop(); + if (_heversion <= 71 && resid > 0x7F) + resid = _resourceMapper[resid & 0x7F]; + res.unlock(rtRoom, resid); + res.unlock(rtRoomImage, resid); + break; + case 116: + break; + case 117: // SO_LOAD_CHARSET + resid = pop(); + loadCharset(resid); + break; + case 118: // SO_NUKE_CHARSET + resid = pop(); + nukeCharset(resid); + break; + case 119: // SO_LOAD_OBJECT + { + int obj = pop(); + int room = getObjectRoom(obj); + loadFlObject(obj, room); + break; + } + case 120: + resid = pop(); + if (resid >= _numGlobalScripts) + break; + //queueLoadResource(rtScript, resid); + break; + case 121: + resid = pop(); + //queueLoadResource(rtSound, resid); + break; + case 122: + resid = pop(); + //queueLoadResource(rtCostume, resid); + break; + case 123: + resid = pop(); + //queueLoadResource(rtRoomImage, resid); + break; + case 159: + resid = pop(); + res.unlock(rtImage, resid); + break; + case 192: + resid = pop(); + res.nukeResource(rtImage, resid); + break; + case 201: + resid = pop(); + ensureResourceLoaded(rtImage, resid); + break; + case 202: + resid = pop(); + res.lock(rtImage, resid); + break; + case 203: + resid = pop(); + //queueLoadResource(rtImage, resid); + break; + case 233: + resid = pop(); + objidx = getObjectIndex(resid); + if (objidx == -1) + break; + res.lock(rtFlObject, _objs[objidx].fl_object_index); + break; + case 235: + resid = pop(); + objidx = getObjectIndex(resid); + if (objidx == -1) + break; + res.unlock(rtFlObject, _objs[objidx].fl_object_index); + break; + case 239: + // Used in airport + break; + default: + error("o70_resourceRoutines: default case %d", subOp); + } +} + +void ScummEngine_v70he::o70_systemOps() { + byte *src, string[256]; + int id, len; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 158: + restart(); + break; + case 160: + // Confirm shutdown + shutDown(); + break; + case 244: + shutDown(); + break; + case 250: + id = pop(); + src = getStringAddress(id); + len = resStrLen(src) + 1; + memcpy(string, src, len); + debug(0, "Start executable (%s)", string); + break; + case 251: + convertMessageToString(_scriptPointer, string, sizeof(string)); + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + debug(0, "Start executable (%s)", string); + break; + case 252: + convertMessageToString(_scriptPointer, string, sizeof(string)); + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + debug(0, "Start game (%s)", string); + break; + case 253: + id = pop(); + src = getStringAddress(id); + len = resStrLen(src) + 1; + memcpy(string, src, len); + debug(0, "Start game (%s)", string); + break; + default: + error("o70_systemOps invalid case %d", subOp); + } +} + +void ScummEngine_v70he::o70_seekFilePos() { + int mode, offset, slot; + mode = pop(); + offset = pop(); + slot = pop(); + + if (slot == -1) + return; + + switch (mode) { + case 1: + _hFileTable[slot].seek(offset, SEEK_SET); + break; + case 2: + _hFileTable[slot].seek(offset, SEEK_CUR); + break; + case 3: + _hFileTable[slot].seek(offset, SEEK_END); + break; + default: + error("o70_seekFilePos: default case 0x%x", mode); + } +} + +void ScummEngine_v70he::o70_copyString() { + int dst, size; + int src = pop(); + + size = resStrLen(getStringAddress(src)) + 1; + dst = setupStringArray(size); + + appendSubstring(dst, src, -1, -1); + + push(dst); +} + +void ScummEngine_v70he::o70_getStringWidth() { + int array, pos, len; + int chr, width = 0; + + len = pop(); + pos = pop(); + array = pop(); + + if (len == -1) { + pos = 0; + len = resStrLen(getStringAddress(array)); + } + + writeVar(0, array); + while (pos <= len) { + chr = readArray(0, 0, pos); + if (chr == 0) + break; + width += getStringCharWidth(chr); + pos++; + } + + push(width); +} + +void ScummEngine_v70he::o70_kernelSetFunctions() { + int args[29]; + int num; + Actor *a; + + num = getStackList(args, ARRAYSIZE(args)); + + switch (args[0]) { + case 1: + // Used to restore images when decorating cake in + // Fatty Bear's Birthday Surprise + virtScreenLoad(args[1], args[2], args[3], args[4], args[5]); + break; + case 20: // HE72+ + a = derefActor(args[1], "o70_kernelSetFunctions: 20"); + ((ScummEngine_v71he *)this)->queueAuxBlock(a); + break; + case 21: + _skipDrawObject = 1; + break; + case 22: + _skipDrawObject = 0; + break; + case 23: + _charset->clearCharsetMask(); + _fullRedraw = true; + break; + case 24: + _skipProcessActors = 1; + redrawAllActors(); + break; + case 25: + _skipProcessActors = 0; + redrawAllActors(); + break; + case 26: + a = derefActor(args[1], "o70_kernelSetFunctions: 26"); + a->_auxBlock.r.left = 0; + a->_auxBlock.r.right = -1; + a->_auxBlock.r.top = 0; + a->_auxBlock.r.bottom = -2; + break; + case 30: + a = derefActor(args[1], "o70_kernelSetFunctions: 30"); + a->_clipOverride.bottom = args[2]; + break; + case 42: + _wiz->_rectOverrideEnabled = true; + _wiz->_rectOverride.left = args[1]; + _wiz->_rectOverride.top = args[2]; + _wiz->_rectOverride.right = args[3]; + _wiz->_rectOverride.bottom = args[4]; + break; + case 43: + _wiz->_rectOverrideEnabled = false; + break; + default: + error("o70_kernelSetFunctions: default case %d (param count %d)", args[0], num); + } +} + +void ScummEngine_v70he::o70_getStringLen() { + int id, len; + byte *addr; + + id = pop(); + + addr = getStringAddress(id); + if (!addr) + error("o70_getStringLen: Reference to zeroed array pointer (%d)", id); + + len = resStrLen(getStringAddress(id)); + push(len); +} + +void ScummEngine_v70he::o70_appendString() { + int dst, size; + + int len = pop(); + int srcOffs = pop(); + int src = pop(); + + size = len - srcOffs + 2; + dst = setupStringArray(size); + + appendSubstring(dst, src, srcOffs, len); + + push(dst); +} + +void ScummEngine_v70he::o70_concatString() { + int dst, size; + + int src2 = pop(); + int src1 = pop(); + + size = resStrLen(getStringAddress(src1)); + size += resStrLen(getStringAddress(src2)) + 1; + dst = setupStringArray(size); + + appendSubstring(dst, src1, 0, -1); + appendSubstring(dst, src2, 0, -1); + + push(dst); +} + +void ScummEngine_v70he::o70_compareString() { + int result; + + int array1 = pop(); + int array2 = pop(); + + byte *string1 = getStringAddress(array1); + if (!string1) + error("o70_compareString: Reference to zeroed array pointer (%d)", array1); + + byte *string2 = getStringAddress(array2); + if (!string2) + error("o70_compareString: Reference to zeroed array pointer (%d)", array2); + + while (*string1 == *string2) { + if (*string2 == 0) { + push(0); + return; + } + + string1++; + string2++; + } + + result = (*string1 > *string2) ? -1 : 1; + push(result); +} + +void ScummEngine_v70he::o70_isResourceLoaded() { + // Reports percentage of resource loaded by queue + int type; + + byte subOp = fetchScriptByte(); + /* int idx = */ pop(); + + switch (subOp) { + case 18: + type = rtImage; + break; + case 226: + type = rtRoom; + break; + case 227: + type = rtCostume; + break; + case 228: + type = rtSound; + break; + case 229: + type = rtScript; + break; + default: + error("o70_isResourceLoaded: default case %d", subOp); + } + + push(100); +} + +void ScummEngine_v70he::o70_readINI() { + byte option[256]; + ArrayHeader *ah; + const char *entry; + int len, type; + + convertMessageToString(_scriptPointer, option, sizeof(option)); + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + type = pop(); + switch (type) { + case 1: // number + if (!strcmp((char *)option, "NoPrinting")) { + push(1); + } else if (!strcmp((char *)option, "TextOn")) { + push(ConfMan.getBool("subtitles")); + } else { + push(ConfMan.getInt((char *)option)); + } + break; + case 2: // string + entry = (ConfMan.get((char *)option).c_str()); + + writeVar(0, 0); + len = resStrLen((const byte *)entry); + ah = defineArray(0, kStringArray, 0, len); + memcpy(ah->data, entry, len); + + push(readVar(0)); + break; + default: + error("o70_readINI: default type %d", type); + } + debug(1, "o70_readINI: Option %s", option); +} + +void ScummEngine_v70he::o70_writeINI() { + int type, value; + byte option[256], string[256]; + int len; + + type = pop(); + value = pop(); + + convertMessageToString(_scriptPointer, option, sizeof(option)); + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + switch (type) { + case 1: // number + ConfMan.set((char *)option, value); + debug(1, "o70_writeINI: Option %s Value %d", option, value); + break; + case 2: // string + convertMessageToString(_scriptPointer, string, sizeof(string)); + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + ConfMan.set((char *)option, (char *)string); + debug(1, "o70_writeINI: Option %s String %s", option, string); + break; + default: + error("o70_writeINI: default type %d", type); + } +} + +void ScummEngine_v70he::o70_getStringLenForWidth() { + int chr, max; + int array, len, pos, width = 0; + + max = pop(); + pos = pop(); + array = pop(); + + len = resStrLen(getStringAddress(array)); + + writeVar(0, array); + while (pos <= len) { + chr = readArray(0, 0, pos); + width += getStringCharWidth(chr); + if (width >= max) { + push(pos); + return; + } + pos++; + } + + push(len); +} + +void ScummEngine_v70he::o70_getCharIndexInString() { + int array, end, len, pos, value; + + value = pop(); + end = pop(); + pos = pop(); + array = pop(); + + if (end >= 0) { + len = resStrLen(getStringAddress(array)); + if (len < end) + end = len; + } else { + end = 0; + } + + if (pos < 0) + pos = 0; + + writeVar(0, array); + if (end > pos) { + while (end >= pos) { + if (readArray(0, 0, pos) == value) { + push(pos); + return; + } + pos++; + } + } else { + while (end <= pos) { + if (readArray(0, 0, pos) == value) { + push(pos); + return; + } + pos--; + } + } + + push(-1); +} + +void ScummEngine_v70he::o70_setFilePath() { + int len; + byte filename[100]; + + convertMessageToString(_scriptPointer, filename, sizeof(filename)); + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + debug(1,"stub o70_setFilePath(%s)", filename); +} + +void ScummEngine_v70he::o70_setSystemMessage() { + int len; + byte name[255]; + + byte subOp = fetchScriptByte(); + + convertMessageToString(_scriptPointer, name, sizeof(name)); + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + switch (subOp) { + case 240: + debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); + break; + case 241: // Set Version + debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); + break; + case 242: + debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); + break; + case 243: // Set Window Caption + _system->setWindowCaption((const char *)name); + break; + default: + error("o70_setSystemMessage: default case %d", subOp); + } +} + +void ScummEngine_v70he::o70_polygonOps() { + int vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y; + int id, fromId, toId; + bool flag; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 68: // HE 100 + case 69: // HE 100 + case 246: + case 248: + vert4y = pop(); + vert4x = pop(); + vert3y = pop(); + vert3x = pop(); + vert2y = pop(); + vert2x = pop(); + vert1y = pop(); + vert1x = pop(); + flag = (subOp == 69 || subOp == 248); + id = pop(); + _wiz->polygonStore(id, flag, vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y); + break; + case 28: // HE 100 + case 247: + toId = pop(); + fromId = pop(); + _wiz->polygonErase(fromId, toId); + break; + default: + error("o70_polygonOps: default case %d", subOp); + } +} + +void ScummEngine_v70he::o70_polygonHit() { + int y = pop(); + int x = pop(); + push(_wiz->polygonHit(0, x, y)); +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/script_v80he.cpp b/engines/scumm/he/script_v80he.cpp new file mode 100644 index 0000000000..f82aebe050 --- /dev/null +++ b/engines/scumm/he/script_v80he.cpp @@ -0,0 +1,811 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" + +#include "common/config-file.h" +#include "common/config-manager.h" +#include "common/str.h" + +#include "scumm/actor.h" +#include "scumm/charset.h" +#include "scumm/he/intern_he.h" +#include "scumm/object.h" +#include "scumm/resource.h" +#include "scumm/he/resource_v7he.h" +#include "scumm/scumm.h" +#include "scumm/sound.h" +#include "scumm/util.h" + +namespace Scumm { + +#define OPCODE(x) _OPCODE(ScummEngine_v80he, x) + +void ScummEngine_v80he::setupOpcodes() { + static const OpcodeEntryV80he opcodes[256] = { + /* 00 */ + OPCODE(o6_pushByte), + OPCODE(o6_pushWord), + OPCODE(o72_pushDWord), + OPCODE(o6_pushWordVar), + /* 04 */ + OPCODE(o72_getScriptString), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_wordArrayRead), + /* 08 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_wordArrayIndexedRead), + /* 0C */ + OPCODE(o6_dup), + OPCODE(o6_not), + OPCODE(o6_eq), + OPCODE(o6_neq), + /* 10 */ + OPCODE(o6_gt), + OPCODE(o6_lt), + OPCODE(o6_le), + OPCODE(o6_ge), + /* 14 */ + OPCODE(o6_add), + OPCODE(o6_sub), + OPCODE(o6_mul), + OPCODE(o6_div), + /* 18 */ + OPCODE(o6_land), + OPCODE(o6_lor), + OPCODE(o6_pop), + OPCODE(o72_isAnyOf), + /* 1C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 20 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 24 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 28 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 2C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 30 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 34 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 38 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 3C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 40 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_writeWordVar), + /* 44 */ + OPCODE(o6_invalid), + OPCODE(o80_createSound), + OPCODE(o80_getFileSize), + OPCODE(o6_wordArrayWrite), + /* 48 */ + OPCODE(o80_stringToInt), + OPCODE(o80_getSoundVar), + OPCODE(o80_localizeArrayToRoom), + OPCODE(o6_wordArrayIndexedWrite), + /* 4C */ + OPCODE(o80_sourceDebug), + OPCODE(o80_readConfigFile), + OPCODE(o80_writeConfigFile), + OPCODE(o6_wordVarInc), + /* 50 */ + OPCODE(o72_resetCutscene), + OPCODE(o6_invalid), + OPCODE(o72_findObjectWithClassOf), + OPCODE(o6_wordArrayInc), + /* 54 */ + OPCODE(o72_getObjectImageX), + OPCODE(o72_getObjectImageY), + OPCODE(o72_captureWizImage), + OPCODE(o6_wordVarDec), + /* 58 */ + OPCODE(o72_getTimer), + OPCODE(o72_setTimer), + OPCODE(o72_getSoundPosition), + OPCODE(o6_wordArrayDec), + /* 5C */ + OPCODE(o6_if), + OPCODE(o6_ifNot), + OPCODE(o72_startScript), + OPCODE(o6_startScriptQuick), + /* 60 */ + OPCODE(o72_startObject), + OPCODE(o72_drawObject), + OPCODE(o72_printWizImage), + OPCODE(o72_getArrayDimSize), + /* 64 */ + OPCODE(o72_getNumFreeArrays), + OPCODE(o6_stopObjectCode), + OPCODE(o6_stopObjectCode), + OPCODE(o6_endCutscene), + /* 68 */ + OPCODE(o6_cutscene), + OPCODE(o6_invalid), + OPCODE(o6_freezeUnfreeze), + OPCODE(o80_cursorCommand), + /* 6C */ + OPCODE(o6_breakHere), + OPCODE(o6_ifClassOfIs), + OPCODE(o6_setClass), + OPCODE(o6_getState), + /* 70 */ + OPCODE(o80_setState), + OPCODE(o6_setOwner), + OPCODE(o6_getOwner), + OPCODE(o6_jump), + /* 74 */ + OPCODE(o70_startSound), + OPCODE(o6_stopSound), + OPCODE(o6_invalid), + OPCODE(o6_stopObjectScript), + /* 78 */ + OPCODE(o6_panCameraTo), + OPCODE(o6_actorFollowCamera), + OPCODE(o6_setCameraAt), + OPCODE(o6_loadRoom), + /* 7C */ + OPCODE(o6_stopScript), + OPCODE(o6_walkActorToObj), + OPCODE(o6_walkActorTo), + OPCODE(o6_putActorAtXY), + /* 80 */ + OPCODE(o6_putActorAtObject), + OPCODE(o6_faceActor), + OPCODE(o6_animateActor), + OPCODE(o6_doSentence), + /* 84 */ + OPCODE(o70_pickupObject), + OPCODE(o6_loadRoomWithEgo), + OPCODE(o6_invalid), + OPCODE(o6_getRandomNumber), + /* 88 */ + OPCODE(o6_getRandomNumberRange), + OPCODE(o6_invalid), + OPCODE(o6_getActorMoving), + OPCODE(o6_isScriptRunning), + /* 8C */ + OPCODE(o70_getActorRoom), + OPCODE(o6_getObjectX), + OPCODE(o6_getObjectY), + OPCODE(o6_getObjectOldDir), + /* 90 */ + OPCODE(o6_getActorWalkBox), + OPCODE(o6_getActorCostume), + OPCODE(o6_findInventory), + OPCODE(o6_getInventoryCount), + /* 94 */ + OPCODE(o6_invalid), + OPCODE(o6_beginOverride), + OPCODE(o6_endOverride), + OPCODE(o6_setObjectName), + /* 98 */ + OPCODE(o6_isSoundRunning), + OPCODE(o6_setBoxFlags), + OPCODE(o6_invalid), + OPCODE(o70_resourceRoutines), + /* 9C */ + OPCODE(o72_roomOps), + OPCODE(o72_actorOps), + OPCODE(o6_invalid), + OPCODE(o6_getActorFromXY), + /* A0 */ + OPCODE(o72_findObject), + OPCODE(o6_pseudoRoom), + OPCODE(o6_getActorElevation), + OPCODE(o6_getVerbEntrypoint), + /* A4 */ + OPCODE(o72_arrayOps), + OPCODE(o6_invalid), + OPCODE(o6_drawBox), + OPCODE(o6_pop), + /* A8 */ + OPCODE(o6_getActorWidth), + OPCODE(o6_wait), + OPCODE(o6_getActorScaleX), + OPCODE(o6_getActorAnimCounter1), + /* AC */ + OPCODE(o80_drawWizPolygon), + OPCODE(o6_isAnyOf), + OPCODE(o72_systemOps), + OPCODE(o6_isActorInBox), + /* B0 */ + OPCODE(o6_delay), + OPCODE(o6_delaySeconds), + OPCODE(o6_delayMinutes), + OPCODE(o6_stopSentence), + /* B4 */ + OPCODE(o6_printLine), + OPCODE(o6_printText), + OPCODE(o6_printDebug), + OPCODE(o6_printSystem), + /* B8 */ + OPCODE(o6_printActor), + OPCODE(o6_printEgo), + OPCODE(o72_talkActor), + OPCODE(o72_talkEgo), + /* BC */ + OPCODE(o72_dimArray), + OPCODE(o6_stopObjectCode), + OPCODE(o6_startObjectQuick), + OPCODE(o6_startScriptQuick2), + /* C0 */ + OPCODE(o72_dim2dimArray), + OPCODE(o72_traceStatus), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* C4 */ + OPCODE(o6_abs), + OPCODE(o6_distObjectObject), + OPCODE(o6_distObjectPt), + OPCODE(o6_distPtPt), + /* C8 */ + OPCODE(o72_kernelGetFunctions), + OPCODE(o70_kernelSetFunctions), + OPCODE(o6_delayFrames), + OPCODE(o6_pickOneOf), + /* CC */ + OPCODE(o6_pickOneOfDefault), + OPCODE(o6_stampObject), + OPCODE(o72_drawWizImage), + OPCODE(o72_debugInput), + /* D0 */ + OPCODE(o6_getDateTime), + OPCODE(o6_stopTalking), + OPCODE(o6_getAnimateVariable), + OPCODE(o6_invalid), + /* D4 */ + OPCODE(o6_shuffle), + OPCODE(o72_jumpToScript), + OPCODE(o6_band), + OPCODE(o6_bor), + /* D8 */ + OPCODE(o6_isRoomScriptRunning), + OPCODE(o60_closeFile), + OPCODE(o72_openFile), + OPCODE(o72_readFile), + /* DC */ + OPCODE(o72_writeFile), + OPCODE(o72_findAllObjects), + OPCODE(o72_deleteFile), + OPCODE(o72_rename), + /* E0 */ + OPCODE(o80_drawLine), + OPCODE(o72_getPixel), + OPCODE(o60_localizeArrayToScript), + OPCODE(o80_pickVarRandom), + /* E4 */ + OPCODE(o6_setBoxSet), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* E8 */ + OPCODE(o6_invalid), + OPCODE(o70_seekFilePos), + OPCODE(o72_redimArray), + OPCODE(o60_readFilePos), + /* EC */ + OPCODE(o70_copyString), + OPCODE(o70_getStringWidth), + OPCODE(o70_getStringLen), + OPCODE(o70_appendString), + /* F0 */ + OPCODE(o70_concatString), + OPCODE(o70_compareString), + OPCODE(o70_isResourceLoaded), + OPCODE(o72_readINI), + /* F4 */ + OPCODE(o72_writeINI), + OPCODE(o70_getStringLenForWidth), + OPCODE(o70_getCharIndexInString), + OPCODE(o6_invalid), + /* F8 */ + OPCODE(o72_getResourceSize), + OPCODE(o72_setFilePath), + OPCODE(o72_setSystemMessage), + OPCODE(o70_polygonOps), + /* FC */ + OPCODE(o70_polygonHit), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + }; + + _opcodesV80he = opcodes; +} + +void ScummEngine_v80he::executeOpcode(byte i) { + OpcodeProcV80he op = _opcodesV80he[i].proc; + (this->*op) (); +} + +const char *ScummEngine_v80he::getOpcodeDesc(byte i) { + return _opcodesV80he[i].desc; +} + +void ScummEngine_v80he::o80_createSound() { + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 27: + createSound(_heSndResId, pop()); + break; + case 217: + createSound(_heSndResId, -1); + break; + case 232: + _heSndResId = pop(); + break; + case 255: + // dummy case + break; + default: + error("o80_createSound: default case %d", subOp); + } +} + +void ScummEngine_v80he::o80_getFileSize() { + byte filename[256]; + + copyScriptString(filename, sizeof(filename)); + + Common::File f; + if (!f.open((char *)filename)) { + push(-1); + } else { + push(f.size()); + f.close(); + } +} + +void ScummEngine_v80he::o80_stringToInt() { + int id, len, val; + byte *addr; + char string[100]; + + id = pop(); + + addr = getStringAddress(id); + if (!addr) + error("o80_stringToInt: Reference to zeroed array pointer (%d)", id); + + len = resStrLen(getStringAddress(id)) + 1; + memcpy(string, addr, len); + val = atoi(string); + push(val); +} + +void ScummEngine_v80he::o80_getSoundVar() { + int var = pop(); + int snd = pop(); + push(_sound->getSoundVar(snd, var)); +} + +void ScummEngine_v80he::o80_localizeArrayToRoom() { + int slot = pop(); + localizeArray(slot, 0xFF); +} + +void ScummEngine_v80he::o80_sourceDebug() { + fetchScriptDWord(); + fetchScriptDWord(); +} + +void ScummEngine_v80he::o80_readConfigFile() { + byte option[128], section[128], filename[256]; + ArrayHeader *ah; + Common::String entry; + int len; + + copyScriptString(option, sizeof(option)); + copyScriptString(section, sizeof(section)); + copyScriptString(filename, sizeof(filename)); + convertFilePath(filename, true); + + Common::ConfigFile ConfFile; + ConfFile.loadFromFile((const char *)filename); + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 43: // HE 100 + case 6: // number + ConfFile.getKey((const char *)option, (const char *)section, entry); + + push(atoi(entry.c_str())); + break; + case 77: // HE 100 + case 7: // string + ConfFile.getKey((const char *)option, (const char *)section, entry); + + writeVar(0, 0); + len = resStrLen((const byte *)entry.c_str()); + ah = defineArray(0, kStringArray, 0, 0, 0, len); + memcpy(ah->data, entry.c_str(), len); + push(readVar(0)); + break; + default: + error("o80_readConfigFile: default type %d", subOp); + } + + debug(1, "o80_readConfigFile: Filename %s Section %s Option %s Value %s", filename, section, option, entry.c_str()); +} + +void ScummEngine_v80he::o80_writeConfigFile() { + byte filename[256], section[256], option[256], string[1024]; + int value; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 43: // HE 100 + case 6: // number + value = pop(); + sprintf((char *)string, "%d", value); + copyScriptString(option, sizeof(option)); + copyScriptString(section, sizeof(section)); + copyScriptString(filename, sizeof(filename)); + convertFilePath(filename, true); + break; + case 77: // HE 100 + case 7: // string + copyScriptString(string, sizeof(string)); + copyScriptString(option, sizeof(option)); + copyScriptString(section, sizeof(section)); + copyScriptString(filename, sizeof(filename)); + convertFilePath(filename, true); + break; + default: + error("o80_writeConfigFile: default type %d", subOp); + } + + Common::ConfigFile ConfFile; + ConfFile.loadFromFile((const char *)filename); + ConfFile.setKey((char *)option, (char *)section, (char *)string); + ConfFile.saveToFile((const char *)filename); + debug(1,"o80_writeConfigFile: Filename %s Section %s Option %s String %s", filename, section, option, string); +} + +void ScummEngine_v80he::o80_cursorCommand() { + int a, i; + int args[16]; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 0x13: + case 0x14: + a = pop(); + _wiz->loadWizCursor(a); + break; + case 0x3C: + pop(); + a = pop(); + _wiz->loadWizCursor(a); + break; + case 0x90: // SO_CURSOR_ON Turn cursor on + _cursor.state = 1; + break; + case 0x91: // SO_CURSOR_OFF Turn cursor off + _cursor.state = 0; + break; + case 0x92: // SO_USERPUT_ON + _userPut = 1; + break; + case 0x93: // SO_USERPUT_OFF + _userPut = 0; + break; + case 0x94: // SO_CURSOR_SOFT_ON Turn soft cursor on + _cursor.state++; + if (_cursor.state > 1) + error("Cursor state greater than 1 in script"); + break; + case 0x95: // SO_CURSOR_SOFT_OFF Turn soft cursor off + _cursor.state--; + break; + case 0x96: // SO_USERPUT_SOFT_ON + _userPut++; + break; + case 0x97: // SO_USERPUT_SOFT_OFF + _userPut--; + break; + case 0x9C: // SO_CHARSET_SET + initCharset(pop()); + break; + case 0x9D: // SO_CHARSET_COLOR + getStackList(args, ARRAYSIZE(args)); + for (i = 0; i < 16; i++) + _charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i]; + break; + default: + error("o80_cursorCommand: default case %x", subOp); + } + + VAR(VAR_CURSORSTATE) = _cursor.state; + VAR(VAR_USERPUT) = _userPut; +} + +void ScummEngine_v80he::o80_setState() { + int state = pop(); + int obj = pop(); + + state &= 0x7FFF; + putState(obj, state); + removeObjectFromDrawQue(obj); +} + +void ScummEngine_v80he::o80_drawWizPolygon() { + WizImage wi; + wi.x1 = wi.y1 = pop(); + wi.resNum = pop(); + wi.state = 0; + wi.flags = kWIFIsPolygon; + _wiz->displayWizImage(&wi); +} + +/** + * Draw a 'line' between two points. + * + * @param x1 the starting x coordinate + * @param y1 the starting y coordinate + * @param x the ending x coordinate + * @param y the ending y coordinate + * @param step the step size used to render the line, only ever 'step'th point is drawn + * @param type the line type -- points are rendered by drawing actors (type == 2), + * wiz images (type == 3), or pixels (any other type) + * @param id the id of an actor, wizimage or color (low bit) & flag (high bit) + */ +void ScummEngine_v80he::drawLine(int x1, int y1, int x, int y, int step, int type, int id) { + if (step < 0) { + step = -step; + } + if (step == 0) { + step = 1; + } + + const int dx = x - x1; + const int dy = y - y1; + + const int absDX = ABS(dx); + const int absDY = ABS(dy); + + const int maxDist = MAX(absDX, absDY); + + y = y1; + x = x1; + + + if (type == 2) { + Actor *a = derefActor(id, "drawLine"); + a->drawActorToBackBuf(x, y); + } else if (type == 3) { + WizImage wi; + wi.flags = 0; + wi.y1 = y; + wi.x1 = x; + wi.resNum = id; + wi.state = 0; + _wiz->displayWizImage(&wi); + } else { + drawPixel(x, y, id); + } + + int stepCount = 0; + int tmpX = 0; + int tmpY = 0; + for (int i = 0; i <= maxDist; i++) { + tmpX += absDX; + tmpY += absDY; + + int drawFlag = 0; + + if (tmpX > maxDist) { + drawFlag = 1; + tmpX -= maxDist; + + if (dx >= 0) { + x++; + } else { + x--; + } + } + if (tmpY > maxDist) { + drawFlag = dy; + tmpY -= maxDist; + + if (dy >= 0) { + y++; + } else { + y--; + } + } + + if (drawFlag == 0) + continue; + + if ((stepCount++ % step) != 0 && maxDist != i) + continue; + + if (type == 2) { + Actor *a = derefActor(id, "drawLine"); + a->drawActorToBackBuf(x, y); + } else if (type == 3) { + WizImage wi; + wi.flags = 0; + wi.y1 = y; + wi.x1 = x; + wi.resNum = id; + wi.state = 0; + _wiz->displayWizImage(&wi); + } else { + drawPixel(x, y, id); + } + } +} + +void ScummEngine_v80he::drawPixel(int x, int y, int flags) { + byte *src, *dst; + VirtScreen *vs; + + if (x < 0 || x > 639) + return; + + if (y < 0) + return; + + if ((vs = findVirtScreen(y)) == NULL) + return; + + markRectAsDirty(vs->number, x, y, x, y + 1); + + if ((flags & 0x4000) || (flags & 0x2000000)) { + src = vs->getPixels(x, y); + dst = vs->getBackPixels(x, y); + *dst = *src; + } else if ((flags & 0x2000) || (flags & 4000000)) { + src = vs->getBackPixels(x, y); + dst = vs->getPixels(x, y); + *dst = *src; + } else if (flags & 0x8000000) { + error("drawPixel: unsupported flag 0x%x", flags); + } else { + dst = vs->getPixels(x, y); + *dst = flags; + if ((flags & 0x8000) || (flags & 0x1000000)) { + dst = vs->getBackPixels(x, y); + *dst = flags; + } + } +} + +void ScummEngine_v80he::o80_drawLine() { + int id, step, x, y, x1, y1; + + step = pop(); + id = pop(); + y = pop(); + x = pop(); + y1 = pop(); + x1 = pop(); + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 55: + drawLine(x1, y1, x, y, step, 2, id); + break; + case 63: + drawLine(x1, y1, x, y, step, 3, id); + break; + case 66: + drawLine(x1, y1, x, y, step, 1, id); + break; + default: + error("o80_drawLine: default case %d", subOp); + } + +} + +void ScummEngine_v80he::o80_pickVarRandom() { + int num; + int args[100]; + int32 dim1end; + + num = getStackList(args, ARRAYSIZE(args)); + int value = fetchScriptWord(); + + if (readVar(value) == 0) { + defineArray(value, kDwordArray, 0, 0, 0, num); + if (value & 0x8000) + localizeArray(readVar(value), 0xFF); + else if (value & 0x4000) + localizeArray(readVar(value), _currentScript); + + if (num > 0) { + int16 counter = 0; + do { + writeArray(value, 0, counter + 1, args[counter]); + } while (++counter < num); + } + + shuffleArray(value, 1, num); + writeArray(value, 0, 0, 2); + push(readArray(value, 0, 1)); + return; + } + + num = readArray(value, 0, 0); + + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(value)); + dim1end = FROM_LE_32(ah->dim1end); + + if (dim1end < num) { + int32 var_2 = readArray(value, 0, num - 1); + shuffleArray(value, 1, dim1end); + num = 1; + if (readArray(value, 0, 1) == var_2 && dim1end >= 3) { + int32 tmp = readArray(value, 0, 2); + writeArray(value, 0, num, tmp); + writeArray(value, 0, 2, var_2); + } + } + + writeArray(value, 0, 0, num + 1); + push(readArray(value, 0, num)); +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp new file mode 100644 index 0000000000..899bce8036 --- /dev/null +++ b/engines/scumm/he/script_v90he.cpp @@ -0,0 +1,2636 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" + +#include "scumm/actor.h" +#include "scumm/charset.h" +#include "scumm/he/intern_he.h" +#include "scumm/he/logic_he.h" +#include "scumm/object.h" +#include "scumm/resource.h" +#include "scumm/he/resource_v7he.h" +#include "scumm/scumm.h" +#include "scumm/sound.h" +#include "scumm/he/sprite_he.h" +#include "scumm/util.h" + +namespace Scumm { + +#define OPCODE(x) _OPCODE(ScummEngine_v90he, x) + +void ScummEngine_v90he::setupOpcodes() { + static const OpcodeEntryV90he opcodes[256] = { + /* 00 */ + OPCODE(o6_pushByte), + OPCODE(o6_pushWord), + OPCODE(o72_pushDWord), + OPCODE(o6_pushWordVar), + /* 04 */ + OPCODE(o72_getScriptString), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_wordArrayRead), + /* 08 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o90_dup_n), + OPCODE(o6_wordArrayIndexedRead), + /* 0C */ + OPCODE(o6_dup), + OPCODE(o6_not), + OPCODE(o6_eq), + OPCODE(o6_neq), + /* 10 */ + OPCODE(o6_gt), + OPCODE(o6_lt), + OPCODE(o6_le), + OPCODE(o6_ge), + /* 14 */ + OPCODE(o6_add), + OPCODE(o6_sub), + OPCODE(o6_mul), + OPCODE(o6_div), + /* 18 */ + OPCODE(o6_land), + OPCODE(o6_lor), + OPCODE(o6_pop), + OPCODE(o72_isAnyOf), + /* 1C */ + OPCODE(o90_wizImageOps), + OPCODE(o90_min), + OPCODE(o90_max), + OPCODE(o90_sin), + /* 20 */ + OPCODE(o90_cos), + OPCODE(o90_sqrt), + OPCODE(o90_atan2), + OPCODE(o90_getSegmentAngle), + /* 24 */ + OPCODE(o90_getDistanceBetweenPoints), + OPCODE(o90_getSpriteInfo), + OPCODE(o90_setSpriteInfo), + OPCODE(o90_getSpriteGroupInfo), + /* 28 */ + OPCODE(o90_setSpriteGroupInfo), + OPCODE(o90_getWizData), + OPCODE(o90_getActorData), + OPCODE(o90_startScriptUnk), + /* 2C */ + OPCODE(o90_jumpToScriptUnk), + OPCODE(o90_videoOps), + OPCODE(o90_getVideoData), + OPCODE(o90_floodFill), + /* 30 */ + OPCODE(o90_mod), + OPCODE(o90_shl), + OPCODE(o90_shr), + OPCODE(o90_xor), + /* 34 */ + OPCODE(o90_findAllObjectsWithClassOf), + OPCODE(o90_getPolygonOverlap), + OPCODE(o90_cond), + OPCODE(o90_dim2dim2Array), + /* 38 */ + OPCODE(o90_redim2dimArray), + OPCODE(o90_getLinesIntersectionPoint), + OPCODE(o90_sortArray), + OPCODE(o6_invalid), + /* 3C */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* 40 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_writeWordVar), + /* 44 */ + OPCODE(o90_getObjectData), + OPCODE(o80_createSound), + OPCODE(o80_getFileSize), + OPCODE(o6_wordArrayWrite), + /* 48 */ + OPCODE(o80_stringToInt), + OPCODE(o80_getSoundVar), + OPCODE(o80_localizeArrayToRoom), + OPCODE(o6_wordArrayIndexedWrite), + /* 4C */ + OPCODE(o80_sourceDebug), + OPCODE(o80_readConfigFile), + OPCODE(o80_writeConfigFile), + OPCODE(o6_wordVarInc), + /* 50 */ + OPCODE(o72_resetCutscene), + OPCODE(o6_invalid), + OPCODE(o72_findObjectWithClassOf), + OPCODE(o6_wordArrayInc), + /* 54 */ + OPCODE(o72_getObjectImageX), + OPCODE(o72_getObjectImageY), + OPCODE(o72_captureWizImage), + OPCODE(o6_wordVarDec), + /* 58 */ + OPCODE(o72_getTimer), + OPCODE(o72_setTimer), + OPCODE(o72_getSoundPosition), + OPCODE(o6_wordArrayDec), + /* 5C */ + OPCODE(o6_if), + OPCODE(o6_ifNot), + OPCODE(o72_startScript), + OPCODE(o6_startScriptQuick), + /* 60 */ + OPCODE(o72_startObject), + OPCODE(o72_drawObject), + OPCODE(o72_printWizImage), + OPCODE(o72_getArrayDimSize), + /* 64 */ + OPCODE(o72_getNumFreeArrays), + OPCODE(o6_stopObjectCode), + OPCODE(o6_stopObjectCode), + OPCODE(o6_endCutscene), + /* 68 */ + OPCODE(o6_cutscene), + OPCODE(o6_invalid), + OPCODE(o6_freezeUnfreeze), + OPCODE(o80_cursorCommand), + /* 6C */ + OPCODE(o6_breakHere), + OPCODE(o6_ifClassOfIs), + OPCODE(o6_setClass), + OPCODE(o6_getState), + /* 70 */ + OPCODE(o80_setState), + OPCODE(o6_setOwner), + OPCODE(o6_getOwner), + OPCODE(o6_jump), + /* 74 */ + OPCODE(o70_startSound), + OPCODE(o6_stopSound), + OPCODE(o6_invalid), + OPCODE(o6_stopObjectScript), + /* 78 */ + OPCODE(o6_panCameraTo), + OPCODE(o6_actorFollowCamera), + OPCODE(o6_setCameraAt), + OPCODE(o6_loadRoom), + /* 7C */ + OPCODE(o6_stopScript), + OPCODE(o6_walkActorToObj), + OPCODE(o6_walkActorTo), + OPCODE(o6_putActorAtXY), + /* 80 */ + OPCODE(o6_putActorAtObject), + OPCODE(o6_faceActor), + OPCODE(o6_animateActor), + OPCODE(o6_doSentence), + /* 84 */ + OPCODE(o70_pickupObject), + OPCODE(o6_loadRoomWithEgo), + OPCODE(o6_invalid), + OPCODE(o6_getRandomNumber), + /* 88 */ + OPCODE(o6_getRandomNumberRange), + OPCODE(o6_invalid), + OPCODE(o6_getActorMoving), + OPCODE(o6_isScriptRunning), + /* 8C */ + OPCODE(o70_getActorRoom), + OPCODE(o6_getObjectX), + OPCODE(o6_getObjectY), + OPCODE(o6_getObjectOldDir), + /* 90 */ + OPCODE(o6_getActorWalkBox), + OPCODE(o6_getActorCostume), + OPCODE(o6_findInventory), + OPCODE(o6_getInventoryCount), + /* 94 */ + OPCODE(o90_getPaletteData), + OPCODE(o6_beginOverride), + OPCODE(o6_endOverride), + OPCODE(o6_setObjectName), + /* 98 */ + OPCODE(o6_isSoundRunning), + OPCODE(o6_setBoxFlags), + OPCODE(o6_invalid), + OPCODE(o70_resourceRoutines), + /* 9C */ + OPCODE(o72_roomOps), + OPCODE(o72_actorOps), + OPCODE(o90_paletteOps), + OPCODE(o6_getActorFromXY), + /* A0 */ + OPCODE(o72_findObject), + OPCODE(o6_pseudoRoom), + OPCODE(o6_getActorElevation), + OPCODE(o6_getVerbEntrypoint), + /* A4 */ + OPCODE(o72_arrayOps), + OPCODE(o90_fontUnk), + OPCODE(o6_drawBox), + OPCODE(o6_pop), + /* A8 */ + OPCODE(o6_getActorWidth), + OPCODE(o6_wait), + OPCODE(o6_getActorScaleX), + OPCODE(o90_getActorAnimProgress), + /* AC */ + OPCODE(o80_drawWizPolygon), + OPCODE(o6_isAnyOf), + OPCODE(o72_systemOps), + OPCODE(o6_isActorInBox), + /* B0 */ + OPCODE(o6_delay), + OPCODE(o6_delaySeconds), + OPCODE(o6_delayMinutes), + OPCODE(o6_stopSentence), + /* B4 */ + OPCODE(o6_printLine), + OPCODE(o6_printText), + OPCODE(o6_printDebug), + OPCODE(o6_printSystem), + /* B8 */ + OPCODE(o6_printActor), + OPCODE(o6_printEgo), + OPCODE(o72_talkActor), + OPCODE(o72_talkEgo), + /* BC */ + OPCODE(o72_dimArray), + OPCODE(o6_stopObjectCode), + OPCODE(o6_startObjectQuick), + OPCODE(o6_startScriptQuick2), + /* C0 */ + OPCODE(o72_dim2dimArray), + OPCODE(o72_traceStatus), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* C4 */ + OPCODE(o6_abs), + OPCODE(o6_distObjectObject), + OPCODE(o6_distObjectPt), + OPCODE(o6_distPtPt), + /* C8 */ + OPCODE(o90_kernelGetFunctions), + OPCODE(o90_kernelSetFunctions), + OPCODE(o6_delayFrames), + OPCODE(o6_pickOneOf), + /* CC */ + OPCODE(o6_pickOneOfDefault), + OPCODE(o6_stampObject), + OPCODE(o72_drawWizImage), + OPCODE(o72_debugInput), + /* D0 */ + OPCODE(o6_getDateTime), + OPCODE(o6_stopTalking), + OPCODE(o6_getAnimateVariable), + OPCODE(o6_invalid), + /* D4 */ + OPCODE(o6_shuffle), + OPCODE(o72_jumpToScript), + OPCODE(o6_band), + OPCODE(o6_bor), + /* D8 */ + OPCODE(o6_isRoomScriptRunning), + OPCODE(o60_closeFile), + OPCODE(o72_openFile), + OPCODE(o72_readFile), + /* DC */ + OPCODE(o72_writeFile), + OPCODE(o72_findAllObjects), + OPCODE(o72_deleteFile), + OPCODE(o72_rename), + /* E0 */ + OPCODE(o80_drawLine), + OPCODE(o72_getPixel), + OPCODE(o60_localizeArrayToScript), + OPCODE(o80_pickVarRandom), + /* E4 */ + OPCODE(o6_setBoxSet), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* E8 */ + OPCODE(o6_invalid), + OPCODE(o70_seekFilePos), + OPCODE(o72_redimArray), + OPCODE(o60_readFilePos), + /* EC */ + OPCODE(o70_copyString), + OPCODE(o70_getStringWidth), + OPCODE(o70_getStringLen), + OPCODE(o70_appendString), + /* F0 */ + OPCODE(o70_concatString), + OPCODE(o70_compareString), + OPCODE(o70_isResourceLoaded), + OPCODE(o72_readINI), + /* F4 */ + OPCODE(o72_writeINI), + OPCODE(o70_getStringLenForWidth), + OPCODE(o70_getCharIndexInString), + OPCODE(o6_invalid), + /* F8 */ + OPCODE(o72_getResourceSize), + OPCODE(o72_setFilePath), + OPCODE(o72_setSystemMessage), + OPCODE(o70_polygonOps), + /* FC */ + OPCODE(o70_polygonHit), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + }; + + _opcodesV90he = opcodes; +} + +void ScummEngine_v90he::executeOpcode(byte i) { + OpcodeProcV90he op = _opcodesV90he[i].proc; + (this->*op) (); +} + +const char *ScummEngine_v90he::getOpcodeDesc(byte i) { + return _opcodesV90he[i].desc; +} + +void ScummEngine_v90he::o90_dup_n() { + int num; + int args[16]; + + push(fetchScriptWord()); + num = getStackList(args, ARRAYSIZE(args)); + + for (int i = 0; i < 2; i++) { + for (int j = 0; j < num; j++) + push(args[j]); + } +} + +void ScummEngine_v90he::o90_min() { + int a = pop(); + int b = pop(); + + if (b < a) { + push(b); + } else { + push(a); + } +} + +void ScummEngine_v90he::o90_max() { + int a = pop(); + int b = pop(); + + if (b > a) { + push(b); + } else { + push(a); + } +} + +void ScummEngine_v90he::o90_sin() { + double a = pop() * PI / 180.; + push((int)(sin(a) * 100000)); +} + +void ScummEngine_v90he::o90_cos() { + double a = pop() * PI / 180.; + push((int)(cos(a) * 100000)); +} + +void ScummEngine_v90he::o90_sqrt() { + int i = pop(); + if (i < 2) { + push(i); + } else { + push((int)sqrt((double)(i + 1))); + } +} + +void ScummEngine_v90he::o90_atan2() { + int y = pop(); + int x = pop(); + int a = (int)(atan2((double)y, (double)x) * 180. / PI); + if (a < 0) { + a += 360; + } + push(a); +} + +void ScummEngine_v90he::o90_getSegmentAngle() { + int y1 = pop(); + int x1 = pop(); + int dy = y1 - pop(); + int dx = x1 - pop(); + int a = (int)(atan2((double)dy, (double)dx) * 180. / PI); + if (a < 0) { + a += 360; + } + push(a); +} + +void ScummEngine_v90he::o90_getActorData() { + Actor *a; + + int subOp = pop(); + int val = pop(); + int act = pop(); + + a = derefActor(act, "o90_getActorData"); + + switch (subOp) { + case 1: + push(a->isUserConditionSet(val)); + break; + case 2: + checkRange(15, 0, val, "Limb %d out of range"); + push(a->_cost.frame[val]); + break; + case 3: + push(a->getAnimSpeed()); + break; + case 4: + push(a->_shadowMode); + break; + case 5: + push(a->_layer); + break; + case 6: + push(a->_hePaletteNum); + break; + default: + error("o90_getActorData: Unknown actor property %d", subOp); + } +} + +void ScummEngine_v90he::o90_startScriptUnk() { + int args[25]; + int script, cycle; + byte flags; + + getStackList(args, ARRAYSIZE(args)); + cycle = pop(); + script = pop(); + flags = fetchScriptByte(); + runScript(script, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args, cycle); +} + +void ScummEngine_v90he::o90_jumpToScriptUnk() { + int args[25]; + int script, cycle; + byte flags; + + getStackList(args, ARRAYSIZE(args)); + cycle = pop(); + script = pop(); + flags = fetchScriptByte(); + stopObjectCode(); + runScript(script, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args, cycle); +} + +void ScummEngine_v90he::o90_videoOps() { + // Uses Smacker video + int status = fetchScriptByte(); + int subOp = status - 49; + + switch (subOp) { + case 0: + copyScriptString(_videoParams.filename, sizeof(_videoParams.filename)); + _videoParams.status = status; + break; + case 5: + _videoParams.flags |= pop(); + break; + case 8: + memset(_videoParams.filename, 0, sizeof(_videoParams.filename)); + _videoParams.unk2 = pop(); + break; + case 14: + _videoParams.wizResNum = pop(); + if (_videoParams.wizResNum) + _videoParams.flags |= 2; + break; + case 116: + _videoParams.status = status; + break; + case 206: + if (_videoParams.status == 49) { + // Start video + if (_videoParams.flags == 0) + _videoParams.flags = 4; + + if (_videoParams.flags == 2) { + // result = startVideo(_videoParams.filename, _videoParams.flags, _videoParams.wizResNum); + // VAR(119) = result; + } else { + // result = startVideo(_videoParams.filename, _videoParams.flags); + // VAR(119) = result; + } + } else if (_videoParams.status == 165) { + // Stop video + } + break; + default: + error("o90_videoOps: unhandled case %d", subOp); + } + + debug(1, "o90_videoOps stub (%d)", subOp); +} + +void ScummEngine_v90he::o90_getVideoData() { + // Uses Smacker video + byte subOp = fetchScriptByte(); + subOp -= 32; + + switch (subOp) { + case 0: // Get width + pop(); + break; + case 1: // Get height + pop(); + break; + case 4: // Get frame count + pop(); + break; + case 20: // Get current frame + pop(); + break; + case 31: // Get image number + pop(); + break; + case 107: // Get statistics + pop(); + pop(); + break; + default: + error("o90_getVideoData: unhandled case %d", subOp); + } + + push(-1); + debug(1, "o90_getVideoData stub (%d)", subOp); +} + +void ScummEngine_v90he::o90_wizImageOps() { + int a, b; + + int subOp = fetchScriptByte(); + subOp -= 46; + + switch (subOp) { + case -14: // HE99+ + _wizParams.processFlags |= kWPFUseDefImgWidth; + _wizParams.resDefImgW = pop(); + break; + case -13: // HE99+ + _wizParams.processFlags |= kWPFUseDefImgHeight; + _wizParams.resDefImgH = pop(); + break; + case 0: + // Dummy case + pop(); + break; + case 1: + _wizParams.box.bottom = pop(); + _wizParams.box.right = pop(); + _wizParams.box.top = pop(); + _wizParams.box.left = pop(); + break; + case 2: + _wizParams.processMode = 1; + break; + case 3: + _wizParams.processFlags |= kWPFUseFile; + _wizParams.processMode = 3; + copyScriptString(_wizParams.filename, sizeof(_wizParams.filename)); + break; + case 4: + _wizParams.processFlags |= kWPFUseFile; + _wizParams.processMode = 4; + copyScriptString(_wizParams.filename, sizeof(_wizParams.filename)); + _wizParams.fileWriteMode = pop(); + break; + case 5: + _wizParams.processFlags |= kWPFClipBox | 0x100; + _wizParams.processMode = 2; + _wizParams.box.bottom = pop(); + _wizParams.box.right = pop(); + _wizParams.box.top = pop(); + _wizParams.box.left = pop(); + _wizParams.compType = pop(); + break; + case 6: + _wizParams.processFlags |= kWPFNewState; + _wizParams.img.state = pop(); + break; + case 7: + _wizParams.processFlags |= kWPFRotate; + _wizParams.angle = pop(); + break; + case 8: + _wizParams.processFlags |= kWPFNewFlags; + _wizParams.img.flags |= pop(); + break; + case 10: + _wizParams.img.flags = pop(); + _wizParams.img.state = pop(); + _wizParams.img.y1 = pop(); + _wizParams.img.x1 = pop(); + _wizParams.img.resNum = pop(); + _wiz->displayWizImage(&_wizParams.img); + break; + case 11: + _wizParams.img.resNum = pop(); + _wizParams.processMode = 0; + _wizParams.processFlags = 0; + _wizParams.remapNum = 0; + _wizParams.img.flags = 0; + _wizParams.field_184 = 0; + _wizParams.field_180 = 0; + _wizParams.spriteId = 0; + _wizParams.spriteGroup = 0; + break; + case 16: // HE99+ + _wizParams.processFlags |= kWPFMaskImg; + _wizParams.sourceImage = pop(); + break; + case 19: + case 108: + _wizParams.processFlags |= kWPFSetPos; + _wizParams.img.y1 = pop(); + _wizParams.img.x1 = pop(); + break; + case 20: + case 203: // HE98+ + b = pop(); + a = pop(); + _wizParams.processFlags |= kWPFRemapPalette; + _wizParams.processMode = 6; + if (_wizParams.remapNum == 0) { + memset(_wizParams.remapIndex, 0, sizeof(_wizParams.remapIndex)); + } else { + assert(_wizParams.remapNum < ARRAYSIZE(_wizParams.remapIndex)); + _wizParams.remapIndex[_wizParams.remapNum] = a; + _wizParams.remapColor[a] = b; + ++_wizParams.remapNum; + } + break; + case 21: + _wizParams.processFlags |= kWPFClipBox; + _wizParams.box.bottom = pop(); + _wizParams.box.right = pop(); + _wizParams.box.top = pop(); + _wizParams.box.left = pop(); + break; + case 40: // HE99+ + _wizParams.processFlags |= kWPFPaletteNum; + _wizParams.img.palette = pop(); + break; + case 46: + _wizParams.processFlags |= kWPFScaled; + _wizParams.scale = pop(); + break; + case 52: + _wizParams.processFlags |= kWPFShadow; + _wizParams.img.shadow = pop(); + break; + case 85: // HE99+ + _wizParams.processFlags |= 0x1000 | 0x100 | 0x2; + _wizParams.processMode = 7; + _wizParams.field_168 = pop(); + _wizParams.field_164 = pop(); + _wizParams.compType = pop(); + break; + case 87: // HE99+ + _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; + _wizParams.processMode = 9; + _wizParams.fillColor = pop(); + _wizParams.box2.bottom = pop(); + _wizParams.box2.right = pop(); + _wizParams.box2.top = pop(); + _wizParams.box2.left = pop(); + break; + case 88: // HE99+ + _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; + _wizParams.processMode = 10; + _wizParams.fillColor = pop(); + _wizParams.box2.bottom = pop(); + _wizParams.box2.right = pop(); + _wizParams.box2.top = pop(); + _wizParams.box2.left = pop(); + break; + case 89: // HE99+ + _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; + _wizParams.processMode = 11; + _wizParams.fillColor = pop(); + _wizParams.box2.top = _wizParams.box2.bottom = pop(); + _wizParams.box2.left = _wizParams.box2.right = pop(); + break; + case 90: // HE99+ + _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; + _wizParams.processMode = 12; + _wizParams.fillColor = pop(); + _wizParams.box2.top = _wizParams.box2.bottom = pop(); + _wizParams.box2.left = _wizParams.box2.right = pop(); + break; + case 91: // HE99+ + _wizParams.processFlags |= kWPFDstResNum; + _wizParams.dstResNum = pop(); + break; + case 93: // HE99+ + _wizParams.processFlags |= 0x100000; + _wizParams.field_180 = pop(); + _wizParams.field_184 = pop(); + break; + case 95: // HE99+ + _wizParams.processMode = 13; + break; + case 96: // HE99+ + _wizParams.field_239D = pop(); + _wizParams.field_2399 = pop(); + _wizParams.field_23A5 = pop(); + _wizParams.field_23A1 = pop(); + copyScriptString(_wizParams.string2, sizeof(_wizParams.string2)); + _wizParams.processMode = 15; + break; + case 97: // HE99+ + _wizParams.processMode = 16; + _wizParams.field_23AD = pop(); + _wizParams.field_23A9 = pop(); + copyScriptString(_wizParams.string1, sizeof(_wizParams.string1)); + break; + case 143: // HE99+ + _wizParams.processMode = 17; + _wizParams.field_23CD = pop(); + _wizParams.field_23C9 = pop(); + _wizParams.field_23C5 = pop(); + _wizParams.field_23C1 = pop(); + _wizParams.field_23BD = pop(); + _wizParams.field_23B9 = pop(); + _wizParams.field_23B5 = pop(); + _wizParams.field_23B1 = pop(); + break; + case 150: // HE99+ + _wizParams.processMode = 14; + break; + case 171: // HE99+ + _wizParams.processMode = 8; + break; + case 200: + _wizParams.processFlags |= kWPFNewFlags | kWPFSetPos | 2; + _wizParams.img.flags |= kWIFIsPolygon; + _wizParams.field_164 = _wizParams.img.y1 = _wizParams.img.x1 = pop(); + break; + case 209: + if (_wizParams.img.resNum) + _wiz->processWizImage(&_wizParams); + break; + default: + error("o90_wizImageOps: unhandled case %d", subOp); + } +} + +void ScummEngine_v90he::o90_getDistanceBetweenPoints() { + int x1, y1, z1, x2, y2, z2, dx, dy, dz, d; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 23: // HE100 + case 28: + y2 = pop(); + x2 = pop(); + y1 = pop(); + x1 = pop(); + dx = x2 - x1; + dy = y2 - y1; + d = dx * dx + dy * dy; + if (d < 2) { + push(d); + } else { + push((int)sqrt((double)(d + 1))); + } + break; + case 24: // HE100 + case 29: + z2 = pop(); + y2 = pop(); + x2 = pop(); + z1 = pop(); + y1 = pop(); + x1 = pop(); + dx = x2 - x1; + dy = y2 - y1; + dz = z2 - z1; + d = dx * dx + dy * dy + dz * dz; + if (d < 2) { + push(d); + } else { + push((int)sqrt((double)(d + 1))); + } + break; + default: + error("o90_getDistanceBetweenPoints: Unknown case %d", subOp); + } +} + +void ScummEngine_v90he::o90_getSpriteInfo() { + int args[16]; + int spriteId, flags, groupId, type; + int32 x, y; + + byte subOp = fetchScriptByte(); + subOp -= 30; + + switch (subOp) { + case 0: + spriteId = pop(); + if (spriteId) { + _sprite->getSpritePosition(spriteId, x, y); + push(x); + } else { + push(0); + } + break; + case 1: + spriteId = pop(); + if (spriteId) { + _sprite->getSpritePosition(spriteId, x, y); + push(y); + } else { + push(0); + } + break; + case 2: + spriteId = pop(); + if (spriteId) { + _sprite->getSpriteImageDim(spriteId, x, y); + push(x); + } else { + push(0); + } + break; + case 3: + spriteId = pop(); + if (spriteId) { + _sprite->getSpriteImageDim(spriteId, x, y); + push(y); + } else { + push(0); + } + break; + case 4: + spriteId = pop(); + if (spriteId) { + _sprite->getSpriteDist(spriteId, x, y); + push(x); + } else { + push(0); + } + break; + case 5: + spriteId = pop(); + if (spriteId) { + _sprite->getSpriteDist(spriteId, x, y); + push(y); + } else { + push(0); + } + break; + case 6: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteImageStateCount(spriteId)); + else + push(0); + break; + case 7: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteGroup(spriteId)); + else + push(0); + break; + case 8: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteDisplayX(spriteId)); + else + push(0); + break; + case 9: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteDisplayY(spriteId)); + else + push(0); + break; + case 12: + flags = pop(); + spriteId = pop(); + if (spriteId) { + switch(flags) { + case 0: + push(_sprite->getSpriteFlagXFlipped(spriteId)); + break; + case 1: + push(_sprite->getSpriteFlagYFlipped(spriteId)); + break; + case 2: + push(_sprite->getSpriteFlagActive(spriteId)); + break; + case 3: + push(_sprite->getSpriteFlagDoubleBuffered(spriteId)); + break; + case 4: + push(_sprite->getSpriteFlagRemapPalette(spriteId)); + break; + default: + push(0); + } + } else { + push(0); + } + break; + case 13: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpritePriority(spriteId)); + else + push(0); + break; + case 15: + if (_heversion == 99) { + flags = getStackList(args, ARRAYSIZE(args)); + type = pop(); + groupId = pop(); + y = pop(); + x = pop(); + push(_sprite->findSpriteWithClassOf(x, y, groupId, type, flags, args)); + } else if (_heversion == 98) { + type = pop(); + groupId = pop(); + y = pop(); + x = pop(); + push(_sprite->findSpriteWithClassOf(x, y, groupId, type, 0, 0)); + } else { + groupId = pop(); + y = pop(); + x = pop(); + push(_sprite->findSpriteWithClassOf(x, y, groupId, 0, 0, 0)); + } + break; + case 22: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteImageState(spriteId)); + else + push(0); + break; + case 32: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteSourceImage(spriteId)); + else + push(0); + break; + case 33: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteImage(spriteId)); + else + push(0); + break; + case 38: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteFlagEraseType(spriteId)); + else + push(1); + break; + case 52: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteFlagAutoAnim(spriteId)); + else + push(0); + break; + case 56: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpritePalette(spriteId)); + else + push(0); + break; + case 62: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteScale(spriteId)); + else + push(0); + break; + case 67: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteAnimSpeed(spriteId)); + else + push(1); + break; + case 68: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteShadow(spriteId)); + else + push(0); + break; + case 94: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteFlagUpdateType(spriteId)); + else + push(0); + break; + case 95: + flags = getStackList(args, ARRAYSIZE(args)); + spriteId = pop(); + if (spriteId) { + push(_sprite->getSpriteClass(spriteId, flags, args)); + } else { + push(0); + } + break; + case 109: + flags = pop(); + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteGeneralProperty(spriteId, flags)); + else + push(0); + break; + case 110: + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteMaskImage(spriteId)); + else + push(0); + break; + case 168: + pop(); + spriteId = pop(); + if (spriteId) + push(_sprite->getSpriteUserValue(spriteId)); + else + push(0); + break; + default: + error("o90_getSpriteInfo: Unknown case %d", subOp); + } +} + +void ScummEngine_v90he::o90_setSpriteInfo() { + int args[16]; + int spriteId; + int32 tmp[2]; + int n; + + byte subOp = fetchScriptByte(); + subOp -= 34; + + switch (subOp) { + case 0: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) { + _sprite->getSpriteDist(spriteId, tmp[0], tmp[1]); + _sprite->setSpriteDist(spriteId, args[0], tmp[1]); + } + break; + case 1: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) { + _sprite->getSpriteDist(spriteId, tmp[0], tmp[1]); + _sprite->setSpriteDist(spriteId, tmp[0], args[0]); + } + break; + case 3: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteGroup(spriteId, args[0]); + break; + case 8: + args[1] = pop(); + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + switch(args[1]) { + case 0: + _sprite->setSpriteFlagXFlipped(spriteId, args[0]); + break; + case 1: + _sprite->setSpriteFlagYFlipped(spriteId, args[0]); + break; + case 2: + _sprite->setSpriteFlagActive(spriteId, args[0]); + break; + case 3: + _sprite->setSpriteFlagDoubleBuffered(spriteId, args[0]); + break; + case 4: + _sprite->setSpriteFlagRemapPalette(spriteId, args[0]); + break; + default: + break; + } + break; + case 9: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpritePriority(spriteId, args[0]); + break; + case 10: + args[1] = pop(); + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->moveSprite(spriteId, args[0], args[1]); + break; + case 18: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteImageState(spriteId, args[0]); + break; + case 19: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteAngle(spriteId, args[0]); + break; + case 23: + if (_features & GF_HE_985 || _heversion >= 99) { + _curMaxSpriteId = pop(); + _curSpriteId = pop(); + + if (_curSpriteId > _curMaxSpriteId) + SWAP(_curSpriteId, _curMaxSpriteId); + } else { + _curSpriteId = pop(); + _curMaxSpriteId = _curSpriteId; // to make all functions happy + } + break; + case 28: // HE99+ + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteSourceImage(spriteId, args[0]); + break; + case 29: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteImage(spriteId, args[0]); + break; + case 31: + args[1] = pop(); + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpritePosition(spriteId, args[0], args[1]); + break; + case 34: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteFlagEraseType(spriteId, args[0]); + break; + case 43: + args[1] = pop(); + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteDist(spriteId, args[0], args[1]); + break; + case 48: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteFlagAutoAnim(spriteId, args[0]); + break; + case 52: // HE 98+ + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpritePalette(spriteId, args[0]); + break; + case 58: // HE 99+ + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteScale(spriteId, args[0]); + break; + case 63: // HE 98+ + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteAnimSpeed(spriteId, args[0]); + break; + case 64: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteShadow(spriteId, args[0]); + break; + case 90: + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteFlagUpdateType(spriteId, args[0]); + break; + case 91: + n = getStackList(args, ARRAYSIZE(args)); + if (_curSpriteId != 0 && _curMaxSpriteId != 0 && n != 0) { + int *p = &args[n - 1]; + do { + int code = *p; + if (code == 0) { + for (int i = _curSpriteId; i <= _curMaxSpriteId; ++i) { + _sprite->setSpriteResetClass(i); + } + } else if (code & 0x80) { + for (int i = _curSpriteId; i <= _curMaxSpriteId; ++i) { + _sprite->setSpriteSetClass(i, code & 0x7F, 1); + } + } else { + for (int i = _curSpriteId; i <= _curMaxSpriteId; ++i) { + _sprite->setSpriteSetClass(i, code & 0x7F, 0); + } + } + --p; + } while (--n); + } + break; + case 105: // HE 99+ + args[1] = pop(); + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteGeneralProperty(spriteId, args[0], args[1]); + break; + case 106: // HE 99+ + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteMaskImage(spriteId, args[0]); + break; + case 124: + _sprite->resetTables(true); + break; + case 164: + args[1] = pop(); + args[0] = pop(); + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->setSpriteUserValue(spriteId, args[0], args[1]); + break; + case 183: + if (_curSpriteId > _curMaxSpriteId) + break; + spriteId = _curSpriteId; + if (!spriteId) + spriteId++; + + for (; spriteId <= _curMaxSpriteId; spriteId++) + _sprite->resetSprite(spriteId); + break; + default: + error("o90_setSpriteInfo: Unknown case %d", subOp); + } +} + +void ScummEngine_v90he::o90_getSpriteGroupInfo() { + int32 tx, ty; + int spriteGroupId, type; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 8: // HE 99+ + spriteGroupId = pop(); + if (spriteGroupId) + push(getGroupSpriteArray(spriteGroupId)); + else + push(0); + break; + case 30: + spriteGroupId = pop(); + if (spriteGroupId) { + _sprite->getGroupPosition(spriteGroupId, tx, ty); + push(tx); + } else { + push(0); + } + break; + case 31: + spriteGroupId = pop(); + if (spriteGroupId) { + _sprite->getGroupPosition(spriteGroupId, tx, ty); + push(ty); + } else { + push(0); + } + break; + case 42: // HE 99+ + type = pop(); + spriteGroupId = pop(); + if (spriteGroupId) { + switch(type) { + case 0: + push(_sprite->getGroupXMul(spriteGroupId)); + break; + case 1: + push(_sprite->getGroupXDiv(spriteGroupId)); + break; + case 2: + push(_sprite->getGroupYMul(spriteGroupId)); + break; + case 3: + push(_sprite->getGroupYDiv(spriteGroupId)); + break; + default: + push(0); + } + } else { + push(0); + } + break; + case 43: + spriteGroupId = pop(); + if (spriteGroupId) + push(_sprite->getGroupPriority(spriteGroupId)); + else + push(0); + break; + case 63: // HE 99+ + spriteGroupId = pop(); + if (spriteGroupId) + push(_sprite->getGroupDstResNum(spriteGroupId)); + else + push(0); + break; + case 139: // HE 99+ + // dummy case + pop(); + pop(); + push(0); + break; + default: + error("o90_getSpriteGroupInfo: Unknown case %d", subOp); + } +} + +void ScummEngine_v90he::o90_setSpriteGroupInfo() { + int type, value1, value2, value3, value4; + + byte subOp = fetchScriptByte(); + subOp -= 37; + + switch (subOp) { + case 0: + type = pop() - 1; + switch (type) { + case 0: + value2 = pop(); + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->moveGroupMembers(_curSpriteGroupId, value1, value2); + break; + case 1: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupMembersPriority(_curSpriteGroupId, value1); + break; + case 2: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupMembersGroup(_curSpriteGroupId, value1); + break; + case 3: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupMembersUpdateType(_curSpriteGroupId, value1); + break; + case 4: + if (!_curSpriteGroupId) + break; + + _sprite->setGroupMembersResetSprite(_curSpriteGroupId); + break; + case 5: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupMembersAnimationSpeed(_curSpriteGroupId, value1); + break; + case 6: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupMembersAutoAnimFlag(_curSpriteGroupId, value1); + break; + case 7: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupMembersShadow(_curSpriteGroupId, value1); + break; + default: + error("o90_setSpriteGroupInfo subOp 0: Unknown case %d", subOp); + } + break; + case 5: + type = pop(); + value1 = pop(); + if (!_curSpriteGroupId) + break; + + switch (type) { + case 0: + _sprite->setGroupXMul(_curSpriteGroupId, value1); + break; + case 1: + _sprite->setGroupXDiv(_curSpriteGroupId, value1); + break; + case 2: + _sprite->setGroupYMul(_curSpriteGroupId, value1); + break; + case 3: + _sprite->setGroupYDiv(_curSpriteGroupId, value1); + break; + default: + error("o90_setSpriteGroupInfo subOp 5: Unknown case %d", subOp); + } + break; + case 6: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupPriority(_curSpriteGroupId, value1); + break; + case 7: + value2 = pop(); + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->moveGroup(_curSpriteGroupId, value1, value2); + break; + case 20: + _curSpriteGroupId = pop(); + break; + case 26: + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupImage(_curSpriteGroupId, value1); + break; + case 28: + value2 = pop(); + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupPosition(_curSpriteGroupId, value1, value2); + break; + case 30: + value4 = pop(); + value3 = pop(); + value2 = pop(); + value1 = pop(); + if (!_curSpriteGroupId) + break; + + _sprite->setGroupBounds(_curSpriteGroupId, value1, value2, value3, value4); + break; + case 56: + if (!_curSpriteGroupId) + break; + + _sprite->resetGroupBounds(_curSpriteGroupId); + break; + case 180: + if (!_curSpriteGroupId) + break; + + _sprite->resetGroup(_curSpriteGroupId); + break; + default: + error("o90_setSpriteGroupInfo: Unknown case %d", subOp); + } +} + +void ScummEngine_v90he::o90_getWizData() { + byte filename[4096]; + int state, resId; + int32 w, h; + int32 x, y; + + byte subOp = fetchScriptByte(); + subOp -= 30; + + switch (subOp) { + case 0: + state = pop(); + resId = pop(); + _wiz->getWizImageSpot(resId, state, x, y); + push(x); + break; + case 1: + state = pop(); + resId = pop(); + _wiz->getWizImageSpot(resId, state, x, y); + push(y); + break; + case 2: + state = pop(); + resId = pop(); + _wiz->getWizImageDim(resId, state, w, h); + push(w); + break; + case 3: + state = pop(); + resId = pop(); + _wiz->getWizImageDim(resId, state, w, h); + push(h); + break; + case 6: + resId = pop(); + push(_wiz->getWizImageStates(resId)); + break; + case 15: + y = pop(); + x = pop(); + state = pop(); + resId = pop(); + push(_wiz->isWizPixelNonTransparent(resId, state, x, y, 0)); + break; + case 36: + y = pop(); + x = pop(); + state = pop(); + resId = pop(); + push(_wiz->getWizPixelColor(resId, state, x, y, 0)); + break; + case 100: + h = pop(); + w = pop(); + y = pop(); + x = pop(); + state = pop(); + resId = pop(); + if (x == -1 && y == -1 && w == -1 && h == -1) { + _wiz->getWizImageDim(resId, state, w, h); + x = 0; + y = 0; + } + push(computeWizHistogram(resId, state, x, y, w, h)); + break; + case 109: + pop(); + pop(); + push(0); + break; + case 111: + pop(); + copyScriptString(filename, sizeof(filename)); + pop(); + push(0); + debug(0, "o90_getWizData() case 111 unhandled"); + break; + default: + error("o90_getWizData: Unknown case %d", subOp); + } +} + +void ScummEngine_v90he::o90_floodFill() { + byte subOp = fetchScriptByte(); + subOp -= 54; + + switch (subOp) { + case 0: + pop(); + break; + case 3: + memset(&_floodFillParams, 0, sizeof(_floodFillParams)); + _floodFillParams.box.left = 0; + _floodFillParams.box.top = 0; + _floodFillParams.box.right = 639; + _floodFillParams.box.bottom = 479; + break; + case 11: + _floodFillParams.y = pop(); + _floodFillParams.x = pop(); + break; + case 12: + _floodFillParams.flags = pop(); + break; + case 13: + _floodFillParams.box.bottom = pop(); + _floodFillParams.box.right = pop(); + _floodFillParams.box.top = pop(); + _floodFillParams.box.left = pop(); + break; + case 201: + floodFill(&_floodFillParams, this); + break; + default: + error("o90_floodFill: Unknown case %d", subOp); + } +} + +void ScummEngine_v90he::o90_shl() { + int a = pop(); + push(pop() << a); +} + +void ScummEngine_v90he::o90_shr() { + int a = pop(); + push(pop() >> a); +} + +void ScummEngine_v90he::o90_xor() { + int a = pop(); + push(pop() ^ a); +} + +void ScummEngine_v90he::o90_mod() { + int a = pop(); + if (a == 0) + error("modulus by zero"); + push(pop() % a); +} + +void ScummEngine_v90he::o90_findAllObjectsWithClassOf() { + int args[16]; + int cond, num, cls, tmp; + bool b; + + num = getStackList(args, ARRAYSIZE(args)); + int room = pop(); + int numObjs = 0; + + if (room != _currentRoom) + error("o90_findAllObjectsWithClassOf: current room is not %d", room); + + writeVar(0, 0); + defineArray(0, kDwordArray, 0, 0, 0, _numLocalObjects); + for (int i = 1; i < _numLocalObjects; i++) { + cond = 1; + tmp = num; + while (--tmp >= 0) { + cls = args[tmp]; + b = getClass(_objs[i].obj_nr, cls); + if ((cls & 0x80 && !b) || (!(cls & 0x80) && b)) + cond = 0; + } + + if (cond) { + numObjs++; + writeArray(0, 0, numObjs, _objs[i].obj_nr); + } + } + + writeArray(0, 0, 0, numObjs); + + push(readVar(0)); +} + +void ScummEngine_v90he::o90_getPolygonOverlap() { + int args1[32]; + int args2[32]; + + int n1 = getStackList(args1, ARRAYSIZE(args1)); + int n2 = getStackList(args2, ARRAYSIZE(args2)); + + int subOp = pop(); + + switch (subOp) { + case 1: + { + Common::Rect r(args1[0], args1[1], args1[2] + 1, args1[3] + 1); + Common::Point p(args2[0], args2[1]); + push(r.contains(p) ? 1 : 0); + } + break; + case 2: + { + int dx = args2[0] - args1[0]; + int dy = args2[1] - args1[1]; + int dist = dx * dx + dy * dy; + if (dist >= 2) { + dist = (int)sqrt((double)(dist + 1)); + } + if (_heversion >= 98) { + push((dist <= args1[2]) ? 1 : 0); + } else { + push((dist > args1[2]) ? 1 : 0); + } + } + break; + case 3: + { + Common::Rect r1(args1[0], args1[1], args1[2] + 1, args1[3] + 1); + Common::Rect r2(args2[0], args2[1], args2[2] + 1, args2[3] + 1); + push(r2.intersects(r1) ? 1 : 0); + } + break; + case 4: + { + int dx = args2[0] - args1[0]; + int dy = args2[1] - args1[1]; + int dist = dx * dx + dy * dy; + if (dist >= 2) { + dist = (int)sqrt((double)(dist + 1)); + } + push((dist < args1[2] && dist < args2[2]) ? 1 : 0); + } + break; + case 5: + { + assert((n1 & 1) == 0); + n1 /= 2; + if (n1 == 0) { + push(0); + } else { + WizPolygon wp; + memset(&wp, 0, sizeof(wp)); + wp.numVerts = n1; + assert(n1 < ARRAYSIZE(wp.vert)); + for (int i = 0; i < n1; ++i) { + wp.vert[i].x = args1[i * 2 + 0]; + wp.vert[i].y = args1[i * 2 + 1]; + } + push(_wiz->polygonContains(wp, args2[0], args2[1]) ? 1 : 0); + } + } + break; + // HE 98+ + case 6: + { + Common::Rect r1, r2; + _sprite->getSpriteBounds(args2[0], false, r2); + _sprite->getSpriteBounds(args1[0], false, r1); + if (r2.isValidRect() == false) { + push(0); + break; + } + + if (n2 == 3) { + r2.left += args2[1]; + r2.right += args2[1]; + r2.top += args2[2]; + r2.bottom += args2[2]; + } + if (n1 == 3) { + r1.left += args1[1]; + r1.right += args1[1]; + r1.top += args1[2]; + r1.bottom += args1[2]; + } + push(r2.intersects(r1) ? 1 : 0); + } + break; + case 7: + { + Common::Rect r2; + _sprite->getSpriteBounds(args2[0], false, r2); + Common::Rect r1(args1[0], args1[1], args1[2], args1[3]); + if (r2.isValidRect() == false) { + push(0); + break; + } + + if (n2 == 3) { + r2.left += args2[1]; + r2.right += args2[1]; + r2.top += args2[2]; + r2.bottom += args2[2]; + } + push(r2.intersects(r1) ? 1 : 0); + } + break; + case 8: + case 10: // TODO: Draw sprites to buffer and compare. + { + Common::Rect r1, r2; + _sprite->getSpriteBounds(args2[0], true, r2); + _sprite->getSpriteBounds(args1[0], true, r1); + if (r2.isValidRect() == false) { + push(0); + break; + } + + if (n2 == 3) { + r2.left += args2[1]; + r2.right += args2[1]; + r2.top += args2[2]; + r2.bottom += args2[2]; + } + if (n1 == 3) { + r1.left += args1[1]; + r1.right += args1[1]; + r1.top += args1[2]; + r1.bottom += args1[2]; + } + push(r2.intersects(r1) ? 1 : 0); + } + break; + case 9: + { + Common::Rect r2; + _sprite->getSpriteBounds(args2[0], true, r2); + Common::Rect r1(args1[0], args1[1], args1[2], args1[3]); + if (r2.isValidRect() == false) { + push(0); + break; + } + + if (n2 == 3) { + r2.left += args2[1]; + r2.right += args2[1]; + r2.top += args2[2]; + r2.bottom += args2[2]; + } + push(r2.intersects(r1) ? 1 : 0); + } + break; + default: + error("o90_getPolygonOverlap: default case %d", subOp); + } +} + +void ScummEngine_v90he::o90_cond() { + int a = pop(); + int b = pop(); + int c = pop(); + + if (!c) + b = a; + push(b); +} + +void ScummEngine_v90he::o90_dim2dim2Array() { + int data, dim1start, dim1end, dim2start, dim2end; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 2: // SO_BIT_ARRAY + data = kBitArray; + break; + case 3: // SO_NIBBLE_ARRAY + data = kNibbleArray; + break; + case 4: // SO_BYTE_ARRAY + data = kByteArray; + break; + case 5: // SO_INT_ARRAY + data = kIntArray; + break; + case 6: + data = kDwordArray; + break; + case 7: // SO_STRING_ARRAY + data = kStringArray; + break; + default: + error("o90_dim2dim2Array: default case %d", subOp); + } + + if (pop() == 2) { + dim1end = pop(); + dim1start = pop(); + dim2end = pop(); + dim2start = pop(); + } else { + dim2end = pop(); + dim2start = pop(); + dim1end = pop(); + dim1start = pop(); + } + + defineArray(fetchScriptWord(), data, dim2start, dim2end, dim1start, dim1end); +} + +void ScummEngine_v90he::o90_redim2dimArray() { + int a, b, c, d; + d = pop(); + c = pop(); + b = pop(); + a = pop(); + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 4: + redimArray(fetchScriptWord(), a, b, c, d, kByteArray); + break; + case 5: + redimArray(fetchScriptWord(), a, b, c, d, kIntArray); + break; + case 6: + redimArray(fetchScriptWord(), a, b, c, d, kDwordArray); + break; + default: + error("o90_redim2dimArray: default type %d", subOp); + } +} + +void ScummEngine_v90he::o90_getLinesIntersectionPoint() { + int var_ix = fetchScriptWord(); + int var_iy = fetchScriptWord(); + int line2_y2 = pop(); + int line2_x2 = pop(); + int line2_y1 = pop(); + int line2_x1 = pop(); + int line1_y2 = pop(); + int line1_x2 = pop(); + int line1_y1 = pop(); + int line1_x1 = pop(); + + int result = 0; + int ix = 0; + int iy = 0; + + bool isLine1Point = (line1_x1 == line1_x2 && line1_y1 == line1_y2); + bool isLine2Point = (line2_x1 == line2_x2 && line2_y1 == line2_y2); + + if (isLine1Point) { + if (isLine2Point) { + if (line1_x1 == line2_x1 && line1_y1 == line2_y2) { + ix = line1_x1; + iy = line2_x1; + result = 1; + } + } else { + // 1 point and 1 line + int dx2 = line2_x2 - line2_x1; + if (dx2 != 0) { + int dy2 = line2_y2 - line2_y1; + float y = (float)dy2 / dx2 * (line1_x1 - line2_x1) + line2_y1 + .5f; + if (line1_y1 == (int)y) { + ix = line1_x1; + iy = line1_y1; + result = 1; + } + } else { + // vertical line + if (line1_x1 == line2_x1) { + if (line2_y1 > line2_y2) { + if (line1_y1 >= line2_y2 && line1_y1 <= line2_y1) { + ix = line1_x1; + iy = line1_y1; + result = 1; + } + } else { + if (line1_y1 >= line2_y1 && line1_y1 <= line2_y2) { + ix = line1_x1; + iy = line1_y1; + result = 1; + } + } + } + } + } + } else { + if (isLine2Point) { + // 1 point and 1 line + int dx1 = line1_x2 - line1_x1; + if (dx1 != 0) { + int dy1 = line1_y2 - line1_y1; + float y = (float)dy1 / dx1 * (line2_x1 - line1_x1) + line1_y1 + .5f; + if (line2_y1 == (int)y) { + ix = line2_x1; + iy = line2_y1; + result = 1; + } + } else { + // vertical line + if (line2_x1 == line1_x1) { + if (line1_y1 > line1_y2) { + if (line2_y1 >= line1_y2 && line2_y1 <= line1_y1) { + ix = line2_x1; + iy = line2_y1; + result = 1; + } + } else { + if (line2_y1 >= line1_y1 && line2_y1 <= line1_y2) { + ix = line2_x2; + iy = line2_y1; + result = 1; + } + } + } + } + } else { + // 2 lines + int dy1 = line1_y2 - line1_y1; + int dx1 = line1_x2 - line1_x1; + int dy2 = line2_y2 - line2_y1; + int dx2 = line2_x2 - line2_x1; + int det = dx1 * dy2 - dx2 * dy1; + int cross_p1 = dx1 * (line1_y1 - line2_y1) - dy1 * (line1_x1 - line2_x1); + int cross_p2 = dx2 * (line1_y1 - line2_y1) - dy2 * (line1_x1 - line2_x1); + if (det == 0) { + // parallel lines + if (cross_p2 == 0) { + ix = ABS(line2_x2 + line2_x1) / 2; + iy = ABS(line2_y2 + line2_y1) / 2; + result = 2; + } + } else { + float rcp1 = (float)cross_p1 / det; + float rcp2 = (float)cross_p2 / det; + if (rcp1 >= 0 && rcp1 <= 1 && rcp2 >= 0 && rcp2 <= 1) { + ix = (int)(dx1 * rcp2 + line1_x1 + .5f); + iy = (int)(dy1 * rcp2 + line1_y1 + .5f); + result = 1; + } + } + } + } + + writeVar(var_ix, ix); + writeVar(var_iy, iy); + push(result); +} + +void ScummEngine_v90he::getArrayDim(int array, int *dim2start, int *dim2end, int *dim1start, int *dim1end) { + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array)); + assert(ah); + if (dim2start && *dim2start == -1) { + *dim2start = ah->dim2start; + } + if (dim2end && *dim2end == -1) { + *dim2end = ah->dim2end; + } + if (dim1start && *dim1start == -1) { + *dim1start = ah->dim1start; + } + if (dim1end && *dim1end == -1) { + *dim1end = ah->dim1end; + } +} + +static int sortArrayOffset; + +static int compareByteArray(const void *a, const void *b) { + int va = *((const uint8 *)a + sortArrayOffset); + int vb = *((const uint8 *)a + sortArrayOffset); + return va - vb; +} + +static int compareByteArrayReverse(const void *a, const void *b) { + int va = *((const uint8 *)a + sortArrayOffset); + int vb = *((const uint8 *)a + sortArrayOffset); + return vb - va; +} + +static int compareIntArray(const void *a, const void *b) { + int va = (int16)READ_LE_UINT16((const uint8 *)a + sortArrayOffset * 2); + int vb = (int16)READ_LE_UINT16((const uint8 *)b + sortArrayOffset * 2); + return va - vb; +} + +static int compareIntArrayReverse(const void *a, const void *b) { + int va = (int16)READ_LE_UINT16((const uint8 *)a + sortArrayOffset * 2); + int vb = (int16)READ_LE_UINT16((const uint8 *)b + sortArrayOffset * 2); + return vb - va; +} + +static int compareDwordArray(const void *a, const void *b) { + int va = (int32)READ_LE_UINT32((const uint8 *)a + sortArrayOffset * 4); + int vb = (int32)READ_LE_UINT32((const uint8 *)b + sortArrayOffset * 4); + return va - vb; +} + +static int compareDwordArrayReverse(const void *a, const void *b) { + int va = (int32)READ_LE_UINT32((const uint8 *)a + sortArrayOffset * 4); + int vb = (int32)READ_LE_UINT32((const uint8 *)b + sortArrayOffset * 4); + return vb - va; +} + +void ScummEngine_v90he::sortArray(int array, int dim2start, int dim2end, int dim1start, int dim1end, int sortOrder) { + debug(9, "sortArray(%d, [%d,%d,%d,%d], %d)", array, dim2start, dim2end, dim1start, dim1end, sortOrder); + + assert(dim1start == dim1end); + checkArrayLimits(array, dim2start, dim2end, dim1start, dim1end); + ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array)); + assert(ah); + + const int num = dim2end - dim2start + 1; + const int pitch = FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1; + const int offset = pitch * (dim2start - FROM_LE_32(ah->dim2start)); + sortArrayOffset = dim1start - FROM_LE_32(ah->dim1start); + + switch (FROM_LE_32(ah->type)) { + case kByteArray: + case kStringArray: + if (sortOrder <= 0) { + qsort(ah->data + offset, num, pitch, compareByteArray); + } else { + qsort(ah->data + offset, num, pitch, compareByteArrayReverse); + } + break; + case kIntArray: + if (sortOrder <= 0) { + qsort(ah->data + offset * 2, num, pitch * 2, compareIntArray); + } else { + qsort(ah->data + offset * 2, num, pitch * 2, compareIntArrayReverse); + } + break; + case kDwordArray: + if (sortOrder <= 0) { + qsort(ah->data + offset * 4, num, pitch * 4, compareDwordArray); + } else { + qsort(ah->data + offset * 4, num, pitch * 4, compareDwordArrayReverse); + } + break; + default: + error("Invalid array type", FROM_LE_32(ah->type)); + } +} + +void ScummEngine_v90he::o90_sortArray() { + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 129: + case 134: // HE100 + { + int array = fetchScriptWord(); + int sortOrder = pop(); + int dim1end = pop(); + int dim1start = pop(); + int dim2end = pop(); + int dim2start = pop(); + getArrayDim(array, &dim2start, &dim2end, &dim1start, &dim1end); + sortArray(array, dim2start, dim2end, dim1start, dim1end, sortOrder); + } + break; + default: + error("o90_sortArray: Unknown case %d", subOp); + } +} + +void ScummEngine_v90he::o90_getObjectData() { + byte subOp = fetchScriptByte(); + subOp -= 32; + + switch (subOp) { + case 0: + if (_heObjectNum == -1) + push(0); + else + push(_objs[_heObjectNum].width); + break; + case 1: + if (_heObjectNum == -1) + push(0); + else + push(_objs[_heObjectNum].height); + break; + case 4: + push(getObjectImageCount(_heObject)); + break; + case 6: + if (_heObjectNum == -1) + push(0); + else + push(_objs[_heObjectNum].x_pos); + break; + case 7: + if (_heObjectNum == -1) + push(0); + else + push(_objs[_heObjectNum].y_pos); + break; + case 20: + push(getState(_heObject)); + break; + case 25: + _heObject = pop(); + _heObjectNum = getObjectIndex(_heObject); + break; + case 107: + // Dummy case + pop(); + push(0); + break; + default: + error("o90_getObjectData: Unknown case %d", subOp); + } +} + +void ScummEngine_v90he::o90_getPaletteData() { + int b, c, d, e; + int palSlot, color; + + byte subOp = fetchScriptByte(); + subOp -= 45; + + switch (subOp) { + case 0: + e = pop(); + d = pop(); + palSlot = pop(); + pop(); + c = pop(); + b = pop(); + push(getHEPaletteSimilarColor(palSlot, b, c, d, e)); + break; + case 7: + c = pop(); + b = pop(); + palSlot = pop(); + push(getHEPaletteColorComponent(palSlot, b, c)); + break; + case 21: + color = pop(); + palSlot = pop(); + push(getHEPaletteColor(palSlot, color)); + break; + case 87: + c = pop(); + b = pop(); + push(getHEPaletteColorComponent(1, b, c)); + break; + case 172: + pop(); + c = pop(); + c = MAX(0, c); + c = MIN(c, 255); + b = pop(); + b = MAX(0, b); + b = MIN(b, 255); + push(getHEPaletteSimilarColor(1, b, c, 10, 245)); + break; + default: + error("o90_getPaletteData: Unknown case %d", subOp); + } +} + +void ScummEngine_v90he::o90_paletteOps() { + int a, b, c, d, e; + + byte subOp = fetchScriptByte(); + subOp -= 57; + + switch (subOp) { + case 0: + _hePaletteNum = pop(); + break; + case 6: + b = pop(); + a = pop(); + if (_hePaletteNum != 0) { + setHEPaletteFromImage(_hePaletteNum, a, b); + } + break; + case 9: + e = pop(); + d = pop(); + c = pop(); + b = pop(); + a = pop(); + if (_hePaletteNum != 0) { + for (; a <= b; ++a) { + setHEPaletteColor(_hePaletteNum, a, c, d, e); + } + } + break; + case 13: + c = pop(); + b = pop(); + a = pop(); + if (_hePaletteNum != 0) { + for (; a <= b; ++a) { + copyHEPaletteColor(_hePaletteNum, a, c); + } + } + break; + case 19: //HE99+ + a = pop(); + if (_hePaletteNum != 0) { + setHEPaletteFromCostume(_hePaletteNum, a); + } + break; + case 29: + a = pop(); + if (_hePaletteNum != 0) { + copyHEPalette(_hePaletteNum, a); + } + break; + case 118: + b = pop(); + a = pop(); + if (_hePaletteNum != 0) { + setHEPaletteFromRoom(_hePaletteNum, a, b); + } + break; + case 160: + if (_hePaletteNum != 0) { + restoreHEPalette(_hePaletteNum); + } + break; + case 198: + _hePaletteNum = 0; + break; + default: + error("o90_paletteOps: Unknown case %d", subOp); + } +} + +void ScummEngine_v90he::o90_fontUnk() { + // Font related + byte string[80]; + int a; + + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 60: // HE100 + case 42: + a = pop(); + if (a == 2) { + copyScriptString(string, sizeof(string)); + push(-1); + } else if (a == 1) { + pop(); + writeVar(0, 0); + defineArray(0, kStringArray, 0, 0, 0, 0); + writeArray(0, 0, 0, 0); + push(readVar(0)); + } + break; + case 0: // HE100 + case 57: + push(1); + break; + default: + error("o90_fontUnk: Unknown case %d", subOp); + } + + debug(1, "o90_fontUnk stub (%d)", subOp); +} + +void ScummEngine_v90he::o90_getActorAnimProgress() { + Actor *a = derefActor(pop(), "o90_getActorAnimProgress"); + push(a->getAnimProgress()); +} + +void ScummEngine_v90he::o90_kernelGetFunctions() { + int args[29]; + int num, tmp; + Actor *a; + + num = getStackList(args, ARRAYSIZE(args)); + + switch (args[0]) { + case 1001: + { + double b = args[1] * PI / 180.; + push((int)(sin(b) * 100000)); + } + break; + case 1002: + { + double b = args[1] * PI / 180.; + push((int)(cos(b) * 100000)); + } + break; + case 1969: + a = derefActor(args[1], "o90_kernelGetFunctions: 1969"); + tmp = a->_heCondMask; + tmp &= 0x7FFF0000; + push(tmp); + break; + case 2001: + push(_logicHE->dispatch(args[1], num - 2, (int32 *)&args[2])); + break; + default: + error("o90_kernelGetFunctions: default case %d", args[0]); + } +} + +void ScummEngine_v90he::o90_kernelSetFunctions() { + int args[29]; + int num, tmp; + Actor *a; + + num = getStackList(args, ARRAYSIZE(args)); + + switch (args[0]) { + case 20: + a = derefActor(args[1], "o90_kernelSetFunctions: 20"); + queueAuxBlock(a); + break; + case 21: + _skipDrawObject = 1; + break; + case 22: + _skipDrawObject = 0; + break; + case 23: + _charset->clearCharsetMask(); + _fullRedraw = true; + break; + case 24: + _skipProcessActors = 1; + redrawAllActors(); + break; + case 25: + _skipProcessActors = 0; + redrawAllActors(); + break; + case 27: + // Used in readdemo + break; + case 42: + _wiz->_rectOverrideEnabled = true; + _wiz->_rectOverride.left = args[1]; + _wiz->_rectOverride.top = args[2]; + _wiz->_rectOverride.right = args[3]; + _wiz->_rectOverride.bottom = args[4]; + break; + case 43: + _wiz->_rectOverrideEnabled = false; + break; + case 714: + debug(5, "o90_kernelSetFunctions: case 714: type %d resId %d unk1 %d", args[1], args[2], args[3]); + break; + case 1492: + // Remote start script function + break; + case 1969: + a = derefActor(args[1], "o90_kernelSetFunctions: 1969"); + tmp = a->_heCondMask; + tmp ^= args[2]; + tmp &= 0x7FFF0000; + a->_heCondMask ^= tmp; + break; + case 2001: + _logicHE->dispatch(args[1], num - 2, (int32 *)&args[2]); + break; + default: + error("o90_kernelSetFunctions: default case %d (param count %d)", args[0], num); + } +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/sound_he.cpp b/engines/scumm/he/sound_he.cpp new file mode 100644 index 0000000000..879e34a99e --- /dev/null +++ b/engines/scumm/he/sound_he.cpp @@ -0,0 +1,516 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "scumm/actor.h" +#include "scumm/imuse.h" +#include "scumm/scumm.h" +#include "scumm/sound.h" +#include "scumm/util.h" + +#include "common/config-manager.h" +#include "common/timer.h" +#include "common/util.h" + +#include "sound/adpcm.h" +#include "sound/audiocd.h" +#include "sound/flac.h" +#include "sound/mididrv.h" +#include "sound/mixer.h" +#include "sound/mp3.h" +#include "sound/voc.h" +#include "sound/vorbis.h" +#include "sound/wave.h" + +namespace Scumm { + +int Sound::findFreeSoundChannel() { + int chan, min; + + min = _vm->VAR(_vm->VAR_RESERVED_SOUND_CHANNELS); + if (min == 0) { + _vm->VAR(_vm->VAR_RESERVED_SOUND_CHANNELS) = 8; + return 1; + } + + if (min < 8) { + for (chan = min; chan < ARRAYSIZE(_heChannel); chan++) { + if (_vm->_mixer->isSoundHandleActive(_heSoundChannels[chan]) == 0) + return chan; + } + } else { + return 1; + } + + return min; +} + +int Sound::isSoundCodeUsed(int sound) { + int chan = -1; + for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) { + if (_heChannel[i].sound == sound) + chan = i; + } + + if (chan != -1) { + return _heChannel[chan].sbngBlock; + } else { + return 0; + } +} + +int Sound::getSoundPos(int sound) { + int chan = -1; + for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) { + if (_heChannel[i].sound == sound) + chan = i; + } + + if (chan != -1) { + int time = _vm->getHETimer(chan + 4) * 11025 / 1000; + return time; + } else { + return 0; + } +} + +int Sound::getSoundVar(int sound, int var) { + if (_vm->_heversion >= 90 && var == 26) { + return isSoundCodeUsed(sound); + } + + checkRange(25, 0, var, "Illegal sound variable %d"); + + int chan = -1; + for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) { + if (_heChannel[i].sound == sound) + chan = i; + } + + if (chan != -1) { + debug(5, "getSoundVar: sound %d var %d result %d", sound, var, _heChannel[chan].soundVars[var]); + return _heChannel[chan].soundVars[var]; + } else { + return 0; + } +} + +void Sound::setSoundVar(int sound, int var, int val) { + checkRange(25, 0, var, "Illegal sound variable %d"); + + int chan = -1; + for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) { + if (_heChannel[i].sound == sound) + chan = i; + } + + if (chan != -1) { + debug(5, "setSoundVar: sound %d var %d val %d", sound, var, val); + _heChannel[chan].soundVars[var] = val; + } +} + +void Sound::setOverrideFreq(int freq) { + _overrideFreq = freq; +} + +void Sound::setupHEMusicFile() { + int i, total_size; + char buf[32], buf1[128]; + Common::File musicFile; + + sprintf(buf, "%s.he4", _vm->getBaseName()); + + if (_vm->_substResFileNameIndex > 0) { + _vm->generateSubstResFileName(buf, buf1, sizeof(buf1)); + strcpy(buf, buf1); + } + if (musicFile.open(buf) == true) { + musicFile.seek(4, SEEK_SET); + total_size = musicFile.readUint32BE(); + musicFile.seek(16, SEEK_SET); + _heMusicTracks = musicFile.readUint32LE(); + debug(5, "Total music tracks %d", _heMusicTracks); + + int musicStart = (_vm->_heversion >= 80) ? 56 : 20; + musicFile.seek(musicStart, SEEK_SET); + + _heMusic = (HEMusic *)malloc((_heMusicTracks + 1) * sizeof(HEMusic)); + for (i = 0; i < _heMusicTracks; i++) { + _heMusic[i].id = musicFile.readUint32LE(); + _heMusic[i].offset = musicFile.readUint32LE(); + _heMusic[i].size = musicFile.readUint32LE(); + + if (_vm->_heversion >= 80) { + musicFile.seek(+9, SEEK_CUR); + } else { + musicFile.seek(+13, SEEK_CUR); + } + } + + musicFile.close(); + } +} + +bool Sound::getHEMusicDetails(int id, int &musicOffs, int &musicSize) { + int i; + + for (i = 0; i < _heMusicTracks; i++) { + if (_heMusic[i].id == id) { + musicOffs = _heMusic[i].offset; + musicSize = _heMusic[i].size; + return 1; + } + } + + return 0; +} + +void Sound::processSoundCode() { + byte *codePtr; + int chan, tmr, size, time; + + for (chan = 0; chan < ARRAYSIZE(_heChannel); chan++) { + if (_heChannel[chan].sound == 0) { + continue; + } + + if (_heChannel[chan].codeOffs == -1) { + continue; + } + + tmr = _vm->getHETimer(chan + 4) * 11025 / 1000; + tmr += _vm->VAR(_vm->VAR_SOUNDCODE_TMR); + if (tmr < 0) + tmr = 0; + + if (_heChannel[chan].sound > _vm->_numSounds) { + codePtr = _vm->getResourceAddress(rtSpoolBuffer, chan); + } else { + codePtr = _vm->getResourceAddress(rtSound, _heChannel[chan].sound); + } + assert(codePtr); + codePtr += _heChannel[chan].codeOffs; + + while(1) { + size = READ_LE_UINT16(codePtr); + time = READ_LE_UINT32(codePtr + 2); + + if (size == 0) { + _heChannel[chan].codeOffs = -1; + break; + } + + debug(5, "Channel %d Timer %d Time %d", chan, tmr, time); + if (time >= tmr) + break; + + processSoundOpcodes(_heChannel[chan].sound, codePtr + 6, _heChannel[chan].soundVars); + + codePtr += size; + _heChannel[chan].codeOffs += size; + } + } +} + +void Sound::processSoundOpcodes(int sound, byte *codePtr, int *soundVars) { + int arg, opcode, var, val; + + while(READ_LE_UINT16(codePtr) != 0) { + codePtr += 2; + opcode = READ_LE_UINT16(codePtr); codePtr += 2; + opcode = (opcode & 0xFFF) >> 4; + arg = opcode & 3; + opcode &= ~3; + debug(5, "processSoundOpcodes: sound %d opcode %d", sound, opcode); + switch (opcode) { + case 0: // Continue + break; + case 16: // Set talk state + val = READ_LE_UINT16(codePtr); codePtr += 2; + setSoundVar(sound, 19, val); + break; + case 32: // Set var + var = READ_LE_UINT16(codePtr); codePtr += 2; + val = READ_LE_UINT16(codePtr); codePtr += 2; + if (arg == 2) { + val = getSoundVar(sound, val); + } + setSoundVar(sound, var, val); + break; + case 48: // Add + var = READ_LE_UINT16(codePtr); codePtr += 2; + val = READ_LE_UINT16(codePtr); codePtr += 2; + if (arg == 2) { + val = getSoundVar(sound, val); + } + val = getSoundVar(sound, var) + val; + setSoundVar(sound, var, val); + break; + case 56: // Subtract + var = READ_LE_UINT16(codePtr); codePtr += 2; + val = READ_LE_UINT16(codePtr); codePtr += 2; + if (arg == 2) { + val = getSoundVar(sound, val); + } + val = getSoundVar(sound, var) - val; + setSoundVar(sound, var, val); + break; + case 64: // Multiple + var = READ_LE_UINT16(codePtr); codePtr += 2; + val = READ_LE_UINT16(codePtr); codePtr += 2; + if (arg == 2) { + val = getSoundVar(sound, val); + } + val = getSoundVar(sound, var) * val; + setSoundVar(sound, var, val); + break; + case 80: // Divide + var = READ_LE_UINT16(codePtr); codePtr += 2; + val = READ_LE_UINT16(codePtr); codePtr += 2; + if (arg == 2) { + val = getSoundVar(sound, val); + } + val = getSoundVar(sound, var) / val; + setSoundVar(sound, var, val); + break; + case 96: // Increment + var = READ_LE_UINT16(codePtr); codePtr += 2; + val = getSoundVar(sound, var) + 1; + setSoundVar(sound, var, val); + break; + case 104: // Decrement + var = READ_LE_UINT16(codePtr); codePtr += 2; + val = getSoundVar(sound, var) - 1; + setSoundVar(sound, var, val); + break; + default: + error("Illegal sound %d opcode %d", sound, opcode); + } + } +} + +void Sound::playHESound(int soundID, int heOffset, int heChannel, int heFlags) { + byte *ptr, *spoolPtr; + char *sound; + int size = -1; + int priority, rate; + byte flags = Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE; + + if (heChannel == -1) + heChannel = (_vm->VAR_RESERVED_SOUND_CHANNELS != 0xFF) ? findFreeSoundChannel() : 1; + + debug(5,"playHESound: soundID %d heOffset %d heChannel %d heFlags %d", soundID, heOffset, heChannel, heFlags); + + if (soundID >= 10000) { + // Special codes, used in pjgames + return; + } + + if (soundID > _vm->_numSounds) { + int music_offs; + char buf[32], buf1[128]; + Common::File musicFile; + + sprintf(buf, "%s.he4", _vm->getBaseName()); + + if (_vm->_substResFileNameIndex > 0) { + _vm->generateSubstResFileName(buf, buf1, sizeof(buf1)); + strcpy(buf, buf1); + } + if (musicFile.open(buf) == false) { + warning("playSound: Can't open music file %s", buf); + return; + } + if (!getHEMusicDetails(soundID, music_offs, size)) { + debug(0, "playSound: musicID %d not found", soundID); + return; + } + + musicFile.seek(music_offs, SEEK_SET); + + if (_vm->_heversion == 70) { + spoolPtr = (byte *)malloc(size); + musicFile.read(spoolPtr, size); + } else { + spoolPtr = _vm->res.createResource(rtSpoolBuffer, heChannel, size); + assert(spoolPtr); + musicFile.read(spoolPtr, size); + } + musicFile.close(); + + if (_vm->_heversion == 70) { + _vm->_mixer->stopHandle(_heSoundChannels[heChannel]); + _vm->_mixer->playRaw(&_heSoundChannels[heChannel], spoolPtr, size, 11025, flags, soundID); + return; + } + } + + if (soundID > _vm->_numSounds) { + ptr = _vm->getResourceAddress(rtSpoolBuffer, heChannel); + } else { + ptr = _vm->getResourceAddress(rtSound, soundID); + } + + if (!ptr) { + return; + } + + // TODO: Extra sound flags + if (heFlags & 1) { + flags |= Audio::Mixer::FLAG_LOOP; + } + + // Support for sound in later Backyard sports games + if (READ_UINT32(ptr) == MKID('RIFF') || READ_UINT32(ptr) == MKID('WSOU')) { + uint16 type; + int blockAlign; + + if (READ_UINT32(ptr) == MKID('WSOU')) + ptr += 8; + + size = READ_LE_UINT32(ptr + 4); + Common::MemoryReadStream stream(ptr, size); + + if (!loadWAVFromStream(stream, size, rate, flags, &type, &blockAlign)) { + error("playSound: Not a valid WAV file"); + } + + if (type == 17) { + AudioStream *voxStream = new ADPCMInputStream(&stream, size, kADPCMIma, (flags & Audio::Mixer::FLAG_STEREO) ? 2 : 1, blockAlign); + + sound = (char *)malloc(size * 4); + size = voxStream->readBuffer((int16*)sound, size * 2); + size *= 2; // 16bits. + delete voxStream; + } else { + // Allocate a sound buffer, copy the data into it, and play + sound = (char *)malloc(size); + memcpy(sound, ptr + stream.pos(), size); + } + _vm->_mixer->stopHandle(_heSoundChannels[heChannel]); + _vm->_mixer->playRaw(&_heSoundChannels[heChannel], sound, size, rate, flags, soundID); + } + // Support for sound in Humongous Entertainment games + else if (READ_UINT32(ptr) == MKID('DIGI') || READ_UINT32(ptr) == MKID('TALK')) { + byte *sndPtr = ptr; + + priority = (soundID > _vm->_numSounds) ? 255 : *(ptr + 18); + rate = READ_LE_UINT16(ptr + 22); + ptr += 8 + READ_BE_UINT32(ptr + 12); + + if (_vm->_mixer->isSoundHandleActive(_heSoundChannels[heChannel])) { + int curSnd = _heChannel[heChannel].sound; + if (curSnd == 1 && soundID != 1) + return; + if (curSnd != 0 && curSnd != 1 && soundID != 1 && _heChannel[heChannel].priority > priority) + return; + } + + int codeOffs = -1; + if (READ_UINT32(ptr) == MKID('SBNG')) { + codeOffs = ptr - sndPtr + 8; + ptr += READ_BE_UINT32(ptr + 4); + } + + assert(READ_UINT32(ptr) == MKID('SDAT')); + size = READ_BE_UINT32(ptr+4) - 8; + if (heOffset < 0 || heOffset > size) { + // Occurs when making fireworks in puttmoon + debug(0, "playSound: Invalid sound offset (offset %d, size %d) in sound %d", heOffset, size, soundID); + heOffset = 0; + } + size -= heOffset; + + if (_overrideFreq) { + // Used by the piano in Fatty Bear's Birthday Surprise + rate = _overrideFreq; + _overrideFreq = 0; + } + + // Allocate a sound buffer, copy the data into it, and play + sound = (char *)malloc(size); + memcpy(sound, ptr + heOffset + 8, size); + _vm->_mixer->stopHandle(_heSoundChannels[heChannel]); + _vm->_mixer->playRaw(&_heSoundChannels[heChannel], sound, size, rate, flags, soundID); + + _vm->setHETimer(heChannel + 4); + _heChannel[heChannel].sound = soundID; + _heChannel[heChannel].priority = priority; + _heChannel[heChannel].sbngBlock = (codeOffs != -1) ? 1 : 0; + _heChannel[heChannel].codeOffs = codeOffs; + memset(_heChannel[heChannel].soundVars, 0, sizeof(_heChannel[heChannel].soundVars)); + } + // Support for PCM music in 3DO versions of Humongous Entertainment games + else if (READ_UINT32(ptr) == MKID('MRAW')) { + priority = *(ptr + 18); + rate = READ_LE_UINT16(ptr + 22); + ptr += 8 + READ_BE_UINT32(ptr+12); + + assert(READ_UINT32(ptr) == MKID('SDAT')); + size = READ_BE_UINT32(ptr+4) - 8; + + flags = Audio::Mixer::FLAG_AUTOFREE; + + // Allocate a sound buffer, copy the data into it, and play + sound = (char *)malloc(size); + memcpy(sound, ptr + 8, size); + _vm->_mixer->stopID(_currentMusic); + _currentMusic = soundID; + _vm->_mixer->playRaw(NULL, sound, size, rate, flags, soundID); + } + else if (READ_UINT32(ptr) == MKID('MIDI')) { + if (_vm->_musicEngine) { + _vm->_musicEngine->startSound(soundID); + } + } +} + +void Sound::startHETalkSound(uint32 offset) { + byte *ptr; + int32 size; + + if (ConfMan.getBool("speech_mute")) + return; + + if (!_sfxFile->isOpen()) { + error("startHETalkSound: Speech file is not open"); + return; + } + + _sfxMode |= 2; + _vm->res.nukeResource(rtSound, 1); + + _sfxFile->seek(offset + 4, SEEK_SET); + size = _sfxFile->readUint32BE(); + _sfxFile->seek(offset, SEEK_SET); + + _vm->res.createResource(rtSound, 1, size); + ptr = _vm->getResourceAddress(rtSound, 1); + _sfxFile->read(ptr, size); + + int channel = (_vm->VAR_TALK_CHANNEL != 0xFF) ? _vm->VAR(_vm->VAR_TALK_CHANNEL) : 0; + addSoundToQueue2(1, 0, channel, 0); +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/sprite_he.cpp b/engines/scumm/he/sprite_he.cpp new file mode 100644 index 0000000000..7de5f0742a --- /dev/null +++ b/engines/scumm/he/sprite_he.cpp @@ -0,0 +1,1440 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" + +#include "scumm/he/intern_he.h" +#include "scumm/resource.h" +#include "scumm/saveload.h" +#include "scumm/scumm.h" +#include "scumm/he/sprite_he.h" +#include "scumm/usage_bits.h" +#include "scumm/util.h" +#include "scumm/he/wiz_he.h" + +namespace Scumm { + +Sprite::Sprite(ScummEngine_v90he *vm) : _vm(vm) { +} + +Sprite::~Sprite() { + free(_spriteGroups); + free(_spriteTable); + free(_activeSpritesTable); +} + +void ScummEngine_v90he::allocateArrays() { + ScummEngine::allocateArrays(); + _sprite->allocTables(_numSprites, MAX(64, _numSprites / 4), 64); +} + +void Sprite::getSpriteBounds(int spriteId, bool checkGroup, Common::Rect &bound) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + int32 spr_wiz_x, spr_wiz_y; + int angle, scale, x1, y1; + int32 w, h; + + SpriteInfo *spi = &_spriteTable[spriteId]; + + _vm->_wiz->getWizImageSpot(spi->image, spi->imageState, spr_wiz_x, spr_wiz_y); + if (checkGroup && spi->group) { + SpriteGroup *spg = &_spriteGroups[spi->group]; + + if (spg->scaling) { + x1 = spi->tx * spg->scale_x_ratio_mul / spg->scale_x_ratio_div - spr_wiz_x + spg->tx; + y1 = spi->ty * spg->scale_y_ratio_mul / spg->scale_y_ratio_div - spr_wiz_y + spg->ty; + } else { + x1 = spi->tx - spr_wiz_x + spg->tx; + y1 = spi->ty - spr_wiz_y + spg->ty; + } + } else { + x1 = spi->tx - spr_wiz_x; + y1 = spi->ty - spr_wiz_y; + } + + if (spi->image) { + angle = spi->angle; + scale = spi->scale; + _vm->_wiz->getWizImageDim(spi->image, spi->imageState, w, h); + if (spi->flags & (kSFScaled | kSFRotated)) { + Common::Point pts[4]; + _vm->_wiz->polygonTransform(spi->image, spi->imageState, x1, y1, angle, scale, pts); + _vm->_wiz->polygonCalcBoundBox(pts, 4, bound); + } else { + bound.left = x1; + bound.top = y1; + bound.right = x1 + w; + bound.bottom = y1 + h; + } + } else { + bound.left = 1234; + bound.top = 1234; + bound.right = -1234; + bound.bottom = -1234; + } +} + +// +// spriteInfoGet functions +// +int Sprite::findSpriteWithClassOf(int x_pos, int y_pos, int spriteGroupId, int type, int num, int *args) { + debug(2, "findSprite: x %d, y %d, spriteGroup %d, type %d, num %d", x_pos, y_pos, spriteGroupId, type, num); + Common::Point pos[1]; + bool cond; + int code, classId; + + for (int i = (_numSpritesToProcess - 1); i >= 0; i--) { + SpriteInfo *spi = _activeSpritesTable[i]; + if (!spi->curImage) + continue; + + if (spriteGroupId && spi->group != spriteGroupId) + continue; + + cond = true; + for (int j = 0; j < num; j++) { + code = classId = args[j]; + classId &= 0x7F; + checkRange(32, 1, classId, "class %d out of range in statement"); + if (code & 0x80) { + if (!(spi->classFlags & (1 << (classId - 1)))) + cond = 0; + } else { + if ((spi->classFlags & (1 << (classId - 1)))) + cond = 0; + } + } + if (!cond) + continue; + + if (type) { + if (spi->bbox.left > spi->bbox.right) + continue; + if (spi->bbox.top > spi->bbox.bottom) + continue; + if (spi->bbox.left > x_pos) + continue; + if (spi->bbox.top > y_pos) + continue; + if (spi->bbox.right < x_pos) + continue; + if (spi->bbox.bottom < y_pos) + continue; + return spi->id; + } else { + int image, imageState, angle, scale; + int32 w, h; + + image = spi->curImage; + if (spi->maskImage) { + int32 x1, x2, y1, y2; + + imageState = spi->curImageState % _vm->_wiz->getWizImageStates(spi->maskImage); + + pos[0].x = x_pos - spi->pos.x; + pos[0].y = y_pos - spi->pos.y; + + _vm->_wiz->getWizImageSpot(spi->curImage, imageState, x1, y1); + _vm->_wiz->getWizImageSpot(spi->maskImage, imageState, x2, y2); + + pos[0].x += (x2 - x1); + pos[0].y += (y2 - y1); + } else { + if (spi->bbox.left > spi->bbox.right) + continue; + if (spi->bbox.top > spi->bbox.bottom) + continue; + if (spi->bbox.left > x_pos) + continue; + if (spi->bbox.top > y_pos) + continue; + if (spi->bbox.right < x_pos) + continue; + if (spi->bbox.bottom < y_pos) + continue; + + pos[0].x = x_pos - spi->pos.x; + pos[0].y = y_pos - spi->pos.y; + imageState = spi->curImageState; + } + + angle = spi->curAngle; + scale = spi->curScale; + if ((spi->flags & kSFScaled) || (spi->flags & kSFRotated)) { + if (spi->flags & kSFScaled && scale) { + pos[0].x = pos[0].x * 256 / scale; + pos[0].y = pos[0].y * 256 / scale; + } + if (spi->flags & kSFRotated && angle) { + angle = (360 - angle) % 360; + _vm->_wiz->polygonRotatePoints(pos, 1, angle); + } + + _vm->_wiz->getWizImageDim(image, imageState, w, h); + pos[0].x += w / 2; + pos[0].y += h / 2; + } + + if (_vm->_wiz->isWizPixelNonTransparent(image, imageState, pos[0].x, pos[0].y, spi->curImgFlags)) + return spi->id; + } + } + + return 0; +} + +int Sprite::getSpriteClass(int spriteId, int num, int *args) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + int code, classId; + + if (num == 0) + return _spriteTable[spriteId].classFlags; + + for (int i = 0; i < num; i++) { + code = classId = args[i]; + classId &= 0x7F; + checkRange(32, 1, classId, "class %d out of range in statement"); + if (code & 0x80) { + if (!(_spriteTable[spriteId].classFlags & (1 << (classId - 1)))) + return 0; + } else { + if ((_spriteTable[spriteId].classFlags & (1 << (classId - 1)))) + return 0; + } + } + + return 1; +} + +int Sprite::getSpriteFlagDoubleBuffered(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return ((_spriteTable[spriteId].flags & kSFDoubleBuffered) != 0) ? 1 : 0; +} + +int Sprite::getSpriteFlagYFlipped(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return ((_spriteTable[spriteId].flags & kSFYFlipped) != 0) ? 1 : 0; +} + +int Sprite::getSpriteFlagXFlipped(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return ((_spriteTable[spriteId].flags & kSFXFlipped) != 0) ? 1 : 0; +} + +int Sprite::getSpriteFlagActive(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return ((_spriteTable[spriteId].flags & kSFActive) != 0) ? 1 : 0; +} + +int Sprite::getSpriteFlagRemapPalette(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return ((_spriteTable[spriteId].flags & kSFRemapPalette) != 0) ? 1 : 0; +} + +int Sprite::getSpriteFlagAutoAnim(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return ((_spriteTable[spriteId].flags & kSFAutoAnim) != 0) ? 1 : 0; +} + +int Sprite::getSpriteFlagUpdateType(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return ((_spriteTable[spriteId].flags & kSFMarkDirty) != 0) ? 1 : 0; +} + +int Sprite::getSpriteFlagEraseType(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return ((_spriteTable[spriteId].flags & kSFImageless) != 0) ? 1 : 0; +} + +int Sprite::getSpriteImage(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return _spriteTable[spriteId].image; +} + +int Sprite::getSpriteImageState(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return _spriteTable[spriteId].imageState; +} + +int Sprite::getSpriteGroup(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return _spriteTable[spriteId].group; +} + +int Sprite::getSpritePalette(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return _spriteTable[spriteId].palette; +} + +int Sprite::getSpritePriority(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return _spriteTable[spriteId].priority; +} + +int Sprite::getSpriteDisplayX(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + if (_spriteTable[spriteId].group) + return _spriteTable[spriteId].tx + _spriteGroups[_spriteTable[spriteId].group].tx; + else + return _spriteTable[spriteId].tx; +} + +int Sprite::getSpriteDisplayY(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + if (_spriteTable[spriteId].group) + return _spriteTable[spriteId].ty + _spriteGroups[_spriteTable[spriteId].group].ty; + else + return _spriteTable[spriteId].ty; +} + +int Sprite::getSpriteUserValue(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return _spriteTable[spriteId].userValue; +} + +int Sprite::getSpriteShadow(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return _spriteTable[spriteId].shadow; +} + +int Sprite::getSpriteImageStateCount(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return _spriteTable[spriteId].imageStateCount; +} + +int Sprite::getSpriteScale(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return _spriteTable[spriteId].scale; +} + +int Sprite::getSpriteAnimSpeed(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return _spriteTable[spriteId].animSpeed; +} + +int Sprite::getSpriteSourceImage(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return _spriteTable[spriteId].sourceImage; +} + +int Sprite::getSpriteMaskImage(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + return _spriteTable[spriteId].maskImage; +} + +int Sprite::getSpriteGeneralProperty(int spriteId, int type) { + debug(0, "getSpriteGeneralProperty: spriteId %d type 0x%x", spriteId, type); + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + // XXX U32 related check + + switch(type) { + case 0x7B: + return _spriteTable[spriteId].imgFlags; + case 0x7D: + return _spriteTable[spriteId].field_90; + case 0x7E: + return _spriteTable[spriteId].animProgress; + default: + error("getSpriteGeneralProperty: Invalid type %d", type); + } +} + +void Sprite::getSpriteImageDim(int spriteId, int32 &w, int32 &h) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + if (_spriteTable[spriteId].image) { + _vm->_wiz->getWizImageDim(_spriteTable[spriteId].image, _spriteTable[spriteId].imageState, w, h); + } else { + w = 0; + h = 0; + } +} + +void Sprite::getSpritePosition(int spriteId, int32 &tx, int32 &ty) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + tx = _spriteTable[spriteId].tx; + ty = _spriteTable[spriteId].ty; +} + +void Sprite::getSpriteDist(int spriteId, int32 &dx, int32 &dy) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + dx = _spriteTable[spriteId].dx; + dy = _spriteTable[spriteId].dy; +} + +// +// spriteGroupGet functions +// +int ScummEngine_v90he::getGroupSpriteArray(int spriteGroupId) { + int i, numSprites = 0; + + checkRange(_sprite->_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + for (i = (_sprite->_varNumSprites - 1); i > 0; i--) { + if (_sprite->_spriteTable[i].group == spriteGroupId) + numSprites++; + } + + if (!numSprites) + return 0; + + writeVar(0, 0); + defineArray(0, kDwordArray, 0, 0, 0, numSprites); + writeArray(0, 0, 0, numSprites); + + numSprites = 1; + for (i = (_sprite->_varNumSprites - 1); i > 0; i--) { + if (_sprite->_spriteTable[i].group == spriteGroupId) { + writeArray(0, 0, numSprites, i); + numSprites++; + } + } + + return readVar(0); +} + +int Sprite::getGroupPriority(int spriteGroupId) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + return _spriteGroups[spriteGroupId].priority; +} + +int Sprite::getGroupDstResNum(int spriteGroupId) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + return _spriteGroups[spriteGroupId].image; +} + +int Sprite::getGroupXMul(int spriteGroupId) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + return _spriteGroups[spriteGroupId].scale_x_ratio_mul; +} + +int Sprite::getGroupXDiv(int spriteGroupId) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + return _spriteGroups[spriteGroupId].scale_x_ratio_div; +} + +int Sprite::getGroupYMul(int spriteGroupId) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + return _spriteGroups[spriteGroupId].scale_y_ratio_mul; +} + +int Sprite::getGroupYDiv(int spriteGroupId) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + return _spriteGroups[spriteGroupId].scale_y_ratio_div; +} + +void Sprite::getGroupPosition(int spriteGroupId, int32 &tx, int32 &ty) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + tx = _spriteGroups[spriteGroupId].tx; + ty = _spriteGroups[spriteGroupId].ty; +} + +// +// spriteInfoSet functions +// +void Sprite::setSpritePalette(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + if (_spriteTable[spriteId].palette != value) { + _spriteTable[spriteId].palette = value; + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; + } +} + +void Sprite::setSpriteSourceImage(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + if (_spriteTable[spriteId].sourceImage != value) { + _spriteTable[spriteId].sourceImage = value; + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; + } +} + +void Sprite::setSpriteMaskImage(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + _spriteTable[spriteId].maskImage = value; +} + +void Sprite::setSpriteImageState(int spriteId, int state) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + if (_spriteTable[spriteId].image) { + int imageStateCount = _spriteTable[spriteId].imageStateCount - 1; + state = MAX(0, state); + state = MIN(state, imageStateCount); + + if (_spriteTable[spriteId].imageState != state) { + _spriteTable[spriteId].imageState = state; + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; + } + } +} + +void Sprite::setSpritePosition(int spriteId, int tx, int ty) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + if (_spriteTable[spriteId].tx != tx || _spriteTable[spriteId].ty != ty) { + _spriteTable[spriteId].tx = tx; + _spriteTable[spriteId].ty = ty; + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; + } +} + +void Sprite::setSpriteGroup(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + checkRange(_varNumSpriteGroups, 0, value, "Invalid sprite group %d"); + + _spriteTable[spriteId].group = value; + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; +} + +void Sprite::setSpriteDist(int spriteId, int value1, int value2) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + _spriteTable[spriteId].dx = value1; + _spriteTable[spriteId].dy = value2; +} + +void Sprite::setSpriteShadow(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + _spriteTable[spriteId].shadow = value; + if (_spriteTable[spriteId].image) + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; +} + +void Sprite::setSpriteUserValue(int spriteId, int value1, int value2) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + _spriteTable[spriteId].userValue = value2; +} + +void Sprite::setSpritePriority(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + _spriteTable[spriteId].priority = value; +} + +void Sprite::moveSprite(int spriteId, int value1, int value2) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + _spriteTable[spriteId].tx += value1; + _spriteTable[spriteId].ty += value2; + + if (value1 || value2) + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; +} + +void Sprite::setSpriteScale(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + _spriteTable[spriteId].flags |= kSFScaled; + + if (_spriteTable[spriteId].scale != value) { + _spriteTable[spriteId].scale = value; + + if (_spriteTable[spriteId].image) + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; + } +} + +void Sprite::setSpriteAngle(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + _spriteTable[spriteId].flags |= kSFRotated; + + if (_spriteTable[spriteId].angle != value) { + _spriteTable[spriteId].angle = value; + + if (_spriteTable[spriteId].image) + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; + } +} + +void Sprite::setSpriteFlagDoubleBuffered(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + int oldFlags = _spriteTable[spriteId].flags; + if (value) + _spriteTable[spriteId].flags |= kSFDoubleBuffered; + else + _spriteTable[spriteId].flags &= ~kSFDoubleBuffered; + + if (_spriteTable[spriteId].image && _spriteTable[spriteId].flags != oldFlags) + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; +} + +void Sprite::setSpriteFlagYFlipped(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + int oldFlags = _spriteTable[spriteId].flags; + if (value) + _spriteTable[spriteId].flags |= kSFYFlipped; + else + _spriteTable[spriteId].flags &= ~kSFYFlipped; + + if (_spriteTable[spriteId].image && _spriteTable[spriteId].flags != oldFlags) + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; +} + +void Sprite::setSpriteFlagXFlipped(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + int oldFlags = _spriteTable[spriteId].flags; + if (value) + _spriteTable[spriteId].flags |= kSFXFlipped; + else + _spriteTable[spriteId].flags &= ~kSFXFlipped; + + if (_spriteTable[spriteId].image && _spriteTable[spriteId].flags != oldFlags) + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; +} + +void Sprite::setSpriteFlagActive(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + if (value) + _spriteTable[spriteId].flags |= kSFActive; + else + _spriteTable[spriteId].flags &= ~kSFActive; +} + +void Sprite::setSpriteFlagRemapPalette(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + int oldFlags = _spriteTable[spriteId].flags; + if (value) + _spriteTable[spriteId].flags |= kSFRemapPalette; + else + _spriteTable[spriteId].flags &= ~kSFRemapPalette; + + if (_spriteTable[spriteId].image && _spriteTable[spriteId].flags != oldFlags) + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; +} + +void Sprite::setSpriteFlagAutoAnim(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + if (value) + _spriteTable[spriteId].flags |= kSFAutoAnim; + else + _spriteTable[spriteId].flags &= ~kSFAutoAnim; +} + +void Sprite::setSpriteFlagUpdateType(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + switch(value) { + case 2: + _spriteTable[spriteId].flags &= ~(kSFMarkDirty); + _spriteTable[spriteId].flags |= kSFBlitDirectly; + break; + case 1: + _spriteTable[spriteId].flags |= kSFMarkDirty | kSFBlitDirectly; + break; + case 0: + _spriteTable[spriteId].flags &= ~(kSFMarkDirty | kSFBlitDirectly); + break; + default: + error("setSpriteFlagUpdateType: Invalid value %d", value); + } +} + +void Sprite::setSpriteFlagEraseType(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + // Note that condition is inverted + if (!value) + _spriteTable[spriteId].flags |= kSFImageless; + else + _spriteTable[spriteId].flags &= ~kSFImageless; +} + +void Sprite::setSpriteAnimSpeed(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + _spriteTable[spriteId].animSpeed = value; + _spriteTable[spriteId].animProgress = value; +} + +void Sprite::setSpriteSetClass(int spriteId, int classId, int toggle) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + checkRange(32, 1, classId, "class %d out of range in statement"); + + if (toggle) { + _spriteTable[spriteId].classFlags |= (1 << (classId - 1)); + } else { + _spriteTable[spriteId].classFlags &= ~(1 << (classId - 1)); + } +} + +void Sprite::setSpriteResetClass(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + _spriteTable[spriteId].classFlags = 0; +} + +void Sprite::setSpriteField84(int spriteId, int value) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + _spriteTable[spriteId].field_84 = value; +} + +void Sprite::setSpriteGeneralProperty(int spriteId, int type, int value) { + debug(0, "setSpriteGeneralProperty: spriteId %d type 0x%x", spriteId, type); + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + int32 delay; + + // XXX U32 related check + + switch(type) { + case 0x7B: + _spriteTable[spriteId].imgFlags = value; + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; + break; + case 0x7D: + _spriteTable[spriteId].field_90 = value; + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; + break; + case 0x7E: + delay = MAX(0, value); + delay = MIN(delay, _spriteTable[spriteId].animSpeed); + + _spriteTable[spriteId].animProgress = delay; + break; + default: + error("setSpriteGeneralProperty: Invalid value %d", type); + } +} + +void Sprite::resetSprite(int spriteId) { + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + _spriteTable[spriteId].angle = 0; + _spriteTable[spriteId].scale = 0; + + setSpriteImage(spriteId, 0); + + _spriteTable[spriteId].shadow = 0; + _spriteTable[spriteId].tx = 0; + _spriteTable[spriteId].ty = 0; + + _spriteTable[spriteId].flags &= ~(kSFYFlipped | kSFXFlipped); + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; + _spriteTable[spriteId].dx = 0; + _spriteTable[spriteId].dy = 0; + _spriteTable[spriteId].userValue = 0; + _spriteTable[spriteId].group = 0; + _spriteTable[spriteId].animSpeed = 0; + _spriteTable[spriteId].animProgress = 0; + _spriteTable[spriteId].classFlags = 0; + _spriteTable[spriteId].palette = 0; + _spriteTable[spriteId].sourceImage = 0; + _spriteTable[spriteId].maskImage = 0; + _spriteTable[spriteId].priority = 0; + _spriteTable[spriteId].field_84 = 0; + _spriteTable[spriteId].imgFlags = 0; + _spriteTable[spriteId].field_90 = 0; +} + +void Sprite::setSpriteImage(int spriteId, int imageNum) { + int origResId, origResWizStates; + + checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); + + origResId = _spriteTable[spriteId].image; + origResWizStates = _spriteTable[spriteId].imageStateCount; + + _spriteTable[spriteId].image = imageNum; + _spriteTable[spriteId].field_74 = 0; + _spriteTable[spriteId].imageState = 0; + + if (_spriteTable[spriteId].image) { + _spriteTable[spriteId].imageStateCount = _vm->_wiz->getWizImageStates(_spriteTable[spriteId].image); + _spriteTable[spriteId].flags |= kSFActive | kSFAutoAnim | kSFMarkDirty | kSFBlitDirectly; + + if (_spriteTable[spriteId].image != origResId || _spriteTable[spriteId].imageStateCount != origResWizStates) + _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; + } else { + if (_spriteTable[spriteId].flags & kSFImageless) + _spriteTable[spriteId].flags = 0; + else + _spriteTable[spriteId].flags = kSFChanged | kSFBlitDirectly; + _spriteTable[spriteId].curImage = 0; + _spriteTable[spriteId].curImageState = 0; + _spriteTable[spriteId].imageStateCount = 0; + } +} + +// +// spriteGroupSet functions +// +void Sprite::redrawSpriteGroup(int spriteGroupId) { + for (int i = 0; i < _numSpritesToProcess; ++i) { + SpriteInfo *spi = _activeSpritesTable[i]; + if (spi->group == spriteGroupId) { + spi->flags |= kSFChanged | kSFNeedRedraw; + } + } +} + +void Sprite::moveGroupMembers(int spriteGroupId, int value1, int value2) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + for (int i = 1; i < _varNumSprites; i++) { + if (_spriteTable[i].group == spriteGroupId) { + _spriteTable[i].tx += value1; + _spriteTable[i].ty += value2; + + if (value1 || value2) + _spriteTable[i].flags |= kSFChanged | kSFNeedRedraw; + } + } +} + +void Sprite::setGroupMembersPriority(int spriteGroupId, int value) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + for (int i = 1; i < _varNumSprites; i++) { + if (_spriteTable[i].group == spriteGroupId) + _spriteTable[i].priority = value; + } +} + +void Sprite::setGroupMembersGroup(int spriteGroupId, int value) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + for (int i = 1; i < _varNumSprites; i++) { + if (_spriteTable[i].group == spriteGroupId) { + _spriteTable[i].group = value; + _spriteTable[i].flags |= kSFChanged | kSFNeedRedraw; + } + } +} + +void Sprite::setGroupMembersUpdateType(int spriteGroupId, int value) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + for (int i = 1; i < _varNumSprites; i++) { + if (_spriteTable[i].group == spriteGroupId) + setSpriteFlagUpdateType(i, value); + } +} + +void Sprite::setGroupMembersResetSprite(int spriteGroupId) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + for (int i = 1; i < _varNumSprites; i++) { + if (_spriteTable[i].group == spriteGroupId) + resetSprite(i); + } +} + +void Sprite::setGroupMembersAnimationSpeed(int spriteGroupId, int value) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + for (int i = 1; i < _varNumSprites; i++) { + if (_spriteTable[i].group == spriteGroupId) { + _spriteTable[i].animSpeed = value; + _spriteTable[i].animProgress = value; + } + } +} + +void Sprite::setGroupMembersAutoAnimFlag(int spriteGroupId, int value) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + for (int i = 1; i < _varNumSprites; i++) { + if (_spriteTable[i].group == spriteGroupId) { + if (value) + _spriteTable[i].flags |= kSFAutoAnim; + else + _spriteTable[i].flags &= ~kSFAutoAnim; + } + } +} + +void Sprite::setGroupMembersShadow(int spriteGroupId, int value) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + for (int i = 1; i < _varNumSprites; i++) { + if (_spriteTable[i].group == spriteGroupId) { + _spriteTable[i].shadow = value; + if (_spriteTable[i].image) + _spriteTable[i].flags |= kSFChanged | kSFNeedRedraw; + } + } +} + +void Sprite::setGroupBounds(int spriteGroupId, int x1, int y1, int x2, int y2) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + _spriteGroups[spriteGroupId].flags |= kSGFClipBox; + _spriteGroups[spriteGroupId].bbox.left = x1; + _spriteGroups[spriteGroupId].bbox.top = y1; + _spriteGroups[spriteGroupId].bbox.right = x2; + _spriteGroups[spriteGroupId].bbox.bottom = y2; + + redrawSpriteGroup(spriteGroupId); +} + +void Sprite::setGroupPriority(int spriteGroupId, int value) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + if (_spriteGroups[spriteGroupId].priority != value) { + _spriteGroups[spriteGroupId].priority = value; + redrawSpriteGroup(spriteGroupId); + } +} + +void Sprite::setGroupPosition(int spriteGroupId, int value1, int value2) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + if (_spriteGroups[spriteGroupId].tx != value1 || _spriteGroups[spriteGroupId].ty != value2) { + _spriteGroups[spriteGroupId].tx = value1; + _spriteGroups[spriteGroupId].ty = value2; + redrawSpriteGroup(spriteGroupId); + } +} + +void Sprite::moveGroup(int spriteGroupId, int value1, int value2) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + if (value1 || value2) { + _spriteGroups[spriteGroupId].tx += value1; + _spriteGroups[spriteGroupId].ty += value2; + redrawSpriteGroup(spriteGroupId); + } +} + +void Sprite::setGroupImage(int spriteGroupId, int value) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + if (_spriteGroups[spriteGroupId].image != value) { + _spriteGroups[spriteGroupId].image = value; + redrawSpriteGroup(spriteGroupId); + } +} + +void Sprite::setGroupScaling(int spriteGroupId) { + if ((_spriteGroups[spriteGroupId].scale_x_ratio_mul != _spriteGroups[spriteGroupId].scale_x_ratio_div) || (_spriteGroups[spriteGroupId].scale_y_ratio_mul != _spriteGroups[spriteGroupId].scale_y_ratio_div)) + _spriteGroups[spriteGroupId].scaling = 1; + else + _spriteGroups[spriteGroupId].scaling = 0; + +} + +void Sprite::setGroupXMul(int spriteGroupId, int value) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + if (_spriteGroups[spriteGroupId].scale_x_ratio_mul != value) { + _spriteGroups[spriteGroupId].scale_x_ratio_mul = value; + setGroupScaling(spriteGroupId); + redrawSpriteGroup(spriteGroupId); + } +} + +void Sprite::setGroupXDiv(int spriteGroupId, int value) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + if (value == 0) + error("setGroupXDiv: Divisor must not be 0"); + + if (_spriteGroups[spriteGroupId].scale_x_ratio_div != value) { + _spriteGroups[spriteGroupId].scale_x_ratio_div = value; + setGroupScaling(spriteGroupId); + redrawSpriteGroup(spriteGroupId); + } +} + +void Sprite::setGroupYMul(int spriteGroupId, int value) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + if (_spriteGroups[spriteGroupId].scale_y_ratio_mul != value) { + _spriteGroups[spriteGroupId].scale_y_ratio_mul = value; + setGroupScaling(spriteGroupId); + redrawSpriteGroup(spriteGroupId); + } +} + +void Sprite::setGroupYDiv(int spriteGroupId, int value) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + if (value == 0) + error("setGroupYDiv: Divisor must not be 0"); + + if (_spriteGroups[spriteGroupId].scale_y_ratio_div != value) { + _spriteGroups[spriteGroupId].scale_y_ratio_div = value; + setGroupScaling(spriteGroupId); + redrawSpriteGroup(spriteGroupId); + } +} + +void Sprite::resetGroupBounds(int spriteGroupId) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + + _spriteGroups[spriteGroupId].flags &= ~(kSGFClipBox); + redrawSpriteGroup(spriteGroupId); +} + +void Sprite::allocTables(int numSprites, int numGroups, int numMaxSprites) { + _varNumSpriteGroups = numGroups; + _numSpritesToProcess = 0; + _varNumSprites = numSprites; + _varMaxSprites = numMaxSprites; + _spriteGroups = (SpriteGroup *)malloc((_varNumSpriteGroups + 1) * sizeof(SpriteGroup)); + _spriteTable = (SpriteInfo *)malloc((_varNumSprites + 1) * sizeof(SpriteInfo)); + _activeSpritesTable = (SpriteInfo **)malloc((_varNumSprites + 1) * sizeof(SpriteInfo *)); +} + +void Sprite::resetGroup(int spriteGroupId) { + checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); + SpriteGroup *spg = &_spriteGroups[spriteGroupId]; + + spg->priority = 0; + spg->tx = spg->ty = 0; + + spg->flags &= ~kSGFClipBox; + redrawSpriteGroup(spriteGroupId); + + spg->image = 0; + spg->scaling = 0; + spg->scale_x_ratio_mul = 1; + spg->scale_x_ratio_div = 1; + spg->scale_y_ratio_mul = 1; + spg->scale_y_ratio_div = 1; +} + +void Sprite::resetTables(bool refreshScreen) { + memset(_spriteTable, 0, (_varNumSprites + 1) * sizeof(SpriteInfo)); + memset(_spriteGroups, 0, (_varNumSpriteGroups + 1) * sizeof(SpriteGroup)); + for (int curGrp = 1; curGrp < _varNumSpriteGroups; ++curGrp) + resetGroup(curGrp); + + if (refreshScreen) { + _vm->gdi.copyVirtScreenBuffers(Common::Rect(_vm->_screenWidth, _vm->_screenHeight)); + } + _numSpritesToProcess = 0; +} + +void Sprite::resetBackground() { + int xmin, xmax, ymin, ymax; + xmin = ymin = 1234; + xmax = ymax = -1234; + bool firstLoop = true; + bool refreshScreen = false; + + for (int i = 0; i < _numSpritesToProcess; ++i) { + SpriteInfo *spi = _activeSpritesTable[i]; + if (!(spi->flags & kSFImageless) && (spi->flags & kSFChanged)) { + spi->flags &= ~kSFChanged; + if (spi->bbox.left <= spi->bbox.right && spi->bbox.top <= spi->bbox.bottom) { + if (spi->flags & kSFBlitDirectly) { + _vm->gdi.copyVirtScreenBuffers(spi->bbox, USAGE_BIT_RESTORED); + } else if (firstLoop) { + xmin = spi->bbox.left; + ymin = spi->bbox.top; + xmax = spi->bbox.right; + ymax = spi->bbox.bottom; + firstLoop = false; + refreshScreen = true; + } else { + if (xmin > spi->bbox.left) { + xmin = spi->bbox.left; + } + if (ymin > spi->bbox.top) { + ymin = spi->bbox.top; + } + if (xmax < spi->bbox.right) { + xmax = spi->bbox.right; + } + if (ymax < spi->bbox.bottom) { + ymax = spi->bbox.bottom; + } + refreshScreen = true; + } + if (!(spi->flags & kSFNeedRedraw) && spi->image) + spi->flags |= kSFNeedRedraw; + } + } + } + if (refreshScreen) { + _vm->gdi.copyVirtScreenBuffers(Common::Rect(xmin, ymin, xmax, ymax), USAGE_BIT_RESTORED); + } +} + +void Sprite::setRedrawFlags(bool checkZOrder) { + VirtScreen *vs = &_vm->virtscr[kMainVirtScreen]; + for (int i = 0; i < _numSpritesToProcess; ++i) { + SpriteInfo *spi = _activeSpritesTable[i]; + if (!(spi->flags & kSFNeedRedraw)) { + if ((!checkZOrder || spi->priority >= 0) && (spi->flags & kSFMarkDirty)) { + int lp = spi->bbox.left / 8; + lp = MAX(0, lp); + lp = MIN(lp, 79); + int rp = (spi->bbox.right + 7) / 8; + rp = MAX(0, rp); + rp = MIN(rp, 79); + for (; lp <= rp; ++lp) { + if (vs->tdirty[lp] < vs->h && spi->bbox.bottom >= vs->tdirty[lp] && spi->bbox.top <= vs->bdirty[lp]) { + spi->flags |= kSFNeedRedraw; + break; + } + } + } + } + } +} + +void Sprite::updateImages() { + for (int i = 0; i < _numSpritesToProcess; ++i) { + SpriteInfo *spi = _activeSpritesTable[i]; + if (spi->dx || spi->dy) { + int tx = spi->tx; + int ty = spi->ty; + spi->tx += spi->dx; + spi->ty += spi->dy; + if (tx != spi->tx || ty != spi->ty) { + spi->flags |= kSFChanged | kSFNeedRedraw; + } + } + if (spi->flags & kSFAutoAnim) { + if (spi->animSpeed) { + --spi->animProgress; + if (spi->animProgress) + continue; + + spi->animProgress = spi->animSpeed; + } + int imageState = spi->imageState; + ++spi->imageState; + if (spi->imageState >= spi->imageStateCount) { + spi->imageState = 0; + if (imageState == 0) + continue; + } + spi->flags |= kSFChanged | kSFNeedRedraw; + } + } +} + +static int compareSprTable(const void *a, const void *b) { + const SpriteInfo *spr1 = *(const SpriteInfo *const*)a; + const SpriteInfo *spr2 = *(const SpriteInfo *const*)b; + + if (spr1->zorder > spr2->zorder) + return 1; + + if (spr1->zorder < spr2->zorder) + return -1; + + return 0; +} + +void Sprite::sortActiveSprites() { + int groupZorder; + + _numSpritesToProcess = 0; + + if (_varNumSprites <= 1) + return; + + for (int i = 1; i < _varNumSprites; i++) { + SpriteInfo *spi = &_spriteTable[i]; + + if (spi->flags & kSFActive) { + if (!(spi->flags & kSFMarkDirty)) { + spi->flags |= kSFNeedRedraw; + if (!(spi->flags & kSFImageless)) + spi->flags |= kSFChanged; + } + if (spi->group) + groupZorder = _spriteGroups[spi->group].priority; + else + groupZorder = 0; + + spi->id = i; + spi->zorder = spi->priority + groupZorder; + + _activeSpritesTable[_numSpritesToProcess++] = spi; + } + } + + if (_numSpritesToProcess < 2) + return; + + qsort(_activeSpritesTable, _numSpritesToProcess, sizeof(SpriteInfo *), compareSprTable); +} + +void Sprite::processImages(bool arg) { + int spr_flags; + int32 spr_wiz_x, spr_wiz_y; + int image, imageState; + Common::Rect *bboxPtr; + int angle, scale; + int32 w, h; + WizParameters wiz; + + for (int i = 0; i < _numSpritesToProcess; i++) { + SpriteInfo *spi = _activeSpritesTable[i]; + + if (!(spi->flags & kSFNeedRedraw)) + continue; + + spr_flags = spi->flags; + + if (arg) { + if (spi->zorder >= 0) + return; + } else { + if (spi->zorder < 0) + continue; + } + + spi->flags &= ~kSFNeedRedraw; + image = spi->image; + imageState = spi->imageState; + _vm->_wiz->getWizImageSpot(spi->image, spi->imageState, spr_wiz_x, spr_wiz_y); + + if (spi->group) { + SpriteGroup *spg = &_spriteGroups[spi->group]; + + if (spg->scaling) { + wiz.img.x1 = spi->tx * spg->scale_x_ratio_mul / spg->scale_x_ratio_div - spr_wiz_x + spg->tx; + wiz.img.y1 = spi->ty * spg->scale_y_ratio_mul / spg->scale_y_ratio_div - spr_wiz_y + spg->ty; + } else { + wiz.img.x1 = spi->tx - spr_wiz_x + spg->tx; + wiz.img.y1 = spi->ty - spr_wiz_y + spg->ty; + } + } else { + wiz.img.x1 = spi->tx - spr_wiz_x; + wiz.img.y1 = spi->ty - spr_wiz_y; + } + + wiz.spriteId = spi->id; + wiz.spriteGroup = spi->group; + wiz.field_23EA = spi->field_90; + spi->curImageState = wiz.img.state = imageState; + spi->curImage = wiz.img.resNum = image; + wiz.processFlags = kWPFNewState | kWPFSetPos; + spi->curAngle = spi->angle; + spi->curScale = spi->scale; + spi->pos.x = wiz.img.x1; + spi->pos.y = wiz.img.y1; + bboxPtr = &spi->bbox; + if (image) { + angle = spi->angle; + scale = spi->scale; + _vm->_wiz->getWizImageDim(image, imageState, w, h); + if (spi->flags & (kSFScaled | kSFRotated)) { + Common::Point pts[4]; + _vm->_wiz->polygonTransform(image, imageState, wiz.img.x1, wiz.img.y1, angle, scale, pts); + _vm->_wiz->polygonCalcBoundBox(pts, 4, spi->bbox); + } else { + bboxPtr->left = wiz.img.x1; + bboxPtr->top = wiz.img.y1; + bboxPtr->right = wiz.img.x1 + w; + bboxPtr->bottom = wiz.img.y1 + h; + } + } else { + bboxPtr->left = 1234; + bboxPtr->top = 1234; + bboxPtr->right = -1234; + bboxPtr->bottom = -1234; + } + + wiz.img.flags = kWIFMarkBufferDirty; + wiz.img.zorder = 0; + if (spr_flags & kSFXFlipped) + wiz.img.flags |= kWIFFlipX; + if (spr_flags & kSFYFlipped) + wiz.img.flags |= kWIFFlipY; + if (spr_flags & kSFDoubleBuffered) { + wiz.img.flags &= ~kWIFMarkBufferDirty; + wiz.img.flags |= kWIFBlitToFrontVideoBuffer; + } + if (spi->shadow) { + wiz.img.flags |= 0x200; + wiz.processFlags |= kWPFShadow; + wiz.img.shadow = spi->shadow; + } + if (spr_flags & kSFRemapPalette) + wiz.img.flags |= kWIFRemapPalette; + if (spi->field_84) { + wiz.processFlags |= 0x200000; + wiz.img.field_390 = spi->field_84; + wiz.img.zorder = spi->priority; + } + if (spi->sourceImage) { + wiz.processFlags |= kWPFMaskImg; + wiz.sourceImage = spi->sourceImage; + } + wiz.processFlags |= kWPFNewFlags; + wiz.img.flags |= spi->imgFlags; + + if (spr_flags & kSFRotated) { + wiz.processFlags |= kWPFRotate; + wiz.angle = spi->angle; + } + if (spr_flags & kSFScaled) { + wiz.processFlags |= kWPFScaled; + wiz.scale = spi->scale; + } + spi->curImgFlags = wiz.img.flags; + + if (spi->group && (_spriteGroups[spi->group].flags & kSGFClipBox)) { + Common::Rect &spgBbox = _spriteGroups[spi->group].bbox; + if (spgBbox.isValidRect() && spi->bbox.intersects(spgBbox)) { + spi->bbox.clip(spgBbox); + wiz.processFlags |= kWPFClipBox; + wiz.box = spi->bbox; + } else { + bboxPtr->left = 1234; + bboxPtr->top = 1234; + bboxPtr->right = -1234; + bboxPtr->bottom = -1234; + continue; + } + } + if (spi->palette) { + wiz.processFlags |= kWPFPaletteNum; + wiz.img.palette = spi->palette; + } + if (spi->image && spi->group && _spriteGroups[spi->group].image) { + wiz.processFlags |= kWPFDstResNum; + wiz.dstResNum = _spriteGroups[spi->group].image; + } + _vm->_wiz->displayWizComplexImage(&wiz); + } +} + +void Sprite::saveOrLoadSpriteData(Serializer *s) { + static const SaveLoadEntry spriteEntries[] = { + MKLINE(SpriteInfo, id, sleInt32, VER(48)), + MKLINE(SpriteInfo, zorder, sleInt32, VER(48)), + MKLINE(SpriteInfo, flags, sleInt32, VER(48)), + MKLINE(SpriteInfo, image, sleInt32, VER(48)), + MKLINE(SpriteInfo, imageState, sleInt32, VER(48)), + MKLINE(SpriteInfo, group, sleInt32, VER(48)), + MKLINE(SpriteInfo, palette, sleInt32, VER(48)), + MKLINE(SpriteInfo, priority, sleInt32, VER(48)), + MKLINE(SpriteInfo, bbox.left, sleInt32, VER(48)), + MKLINE(SpriteInfo, bbox.top, sleInt32, VER(48)), + MKLINE(SpriteInfo, bbox.right, sleInt32, VER(48)), + MKLINE(SpriteInfo, bbox.bottom, sleInt32, VER(48)), + MKLINE(SpriteInfo, dx, sleInt32, VER(48)), + MKLINE(SpriteInfo, dy, sleInt32, VER(48)), + MKLINE(SpriteInfo, pos.x, sleInt32, VER(48)), + MKLINE(SpriteInfo, pos.y, sleInt32, VER(48)), + MKLINE(SpriteInfo, tx, sleInt32, VER(48)), + MKLINE(SpriteInfo, ty, sleInt32, VER(48)), + MKLINE(SpriteInfo, userValue, sleInt32, VER(48)), + MKLINE(SpriteInfo, curImageState, sleInt32, VER(48)), + MKLINE(SpriteInfo, curImage, sleInt32, VER(48)), + MKLINE(SpriteInfo, imglistNum, sleInt32, VER(48)), + MKLINE(SpriteInfo, shadow, sleInt32, VER(48)), + MKLINE(SpriteInfo, imageStateCount, sleInt32, VER(48)), + MKLINE(SpriteInfo, angle, sleInt32, VER(48)), + MKLINE(SpriteInfo, scale, sleInt32, VER(48)), + MKLINE(SpriteInfo, animProgress, sleInt32, VER(48)), + MKLINE(SpriteInfo, curAngle, sleInt32, VER(48)), + MKLINE(SpriteInfo, curScale, sleInt32, VER(48)), + MKLINE(SpriteInfo, curImgFlags, sleInt32, VER(48)), + MKLINE(SpriteInfo, field_74, sleInt32, VER(48)), + MKLINE(SpriteInfo, animSpeed, sleInt32, VER(48)), + MKLINE(SpriteInfo, sourceImage, sleInt32, VER(48)), + MKLINE(SpriteInfo, maskImage, sleInt32, VER(48)), + MKLINE(SpriteInfo, field_84, sleInt32, VER(48)), + MKLINE(SpriteInfo, classFlags, sleInt32, VER(48)), + MKLINE(SpriteInfo, imgFlags, sleInt32, VER(48)), + MKLINE(SpriteInfo, field_90, sleInt32, VER(48)), + MKEND() + }; + + static const SaveLoadEntry spriteGroupEntries[] = { + MKLINE(SpriteGroup, bbox.left, sleInt32, VER(48)), + MKLINE(SpriteGroup, bbox.top, sleInt32, VER(48)), + MKLINE(SpriteGroup, bbox.right, sleInt32, VER(48)), + MKLINE(SpriteGroup, bbox.bottom, sleInt32, VER(48)), + MKLINE(SpriteGroup, priority, sleInt32, VER(48)), + MKLINE(SpriteGroup, flags, sleInt32, VER(48)), + MKLINE(SpriteGroup, tx, sleInt32, VER(48)), + MKLINE(SpriteGroup, ty, sleInt32, VER(48)), + MKLINE(SpriteGroup, image, sleInt32, VER(48)), + MKLINE(SpriteGroup, scaling, sleInt32, VER(48)), + MKLINE(SpriteGroup, scale_x_ratio_mul, sleInt32, VER(48)), + MKLINE(SpriteGroup, scale_x_ratio_div, sleInt32, VER(48)), + MKLINE(SpriteGroup, scale_y_ratio_mul, sleInt32, VER(48)), + MKLINE(SpriteGroup, scale_y_ratio_div, sleInt32, VER(48)), + MKEND() + }; + + if (s->getVersion() >= VER(64)) { + s->saveLoadArrayOf(_spriteTable, _varNumSprites + 1, sizeof(_spriteTable[0]), spriteEntries); + s->saveLoadArrayOf(_spriteGroups, _varNumSpriteGroups + 1, sizeof(_spriteGroups[0]), spriteGroupEntries); + } else { + s->saveLoadArrayOf(_activeSpritesTable, _varNumSprites, sizeof(_activeSpritesTable[0]), spriteEntries); + s->saveLoadArrayOf(_spriteTable, _varNumSprites, sizeof(_spriteTable[0]), spriteEntries); + s->saveLoadArrayOf(_spriteGroups, _varNumSpriteGroups, sizeof(_spriteGroups[0]), spriteGroupEntries); + } + + // Reset active sprite table + if (s->isLoading()) + _numSpritesToProcess = 0; + +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/sprite_he.h b/engines/scumm/he/sprite_he.h new file mode 100644 index 0000000000..5396c1fed4 --- /dev/null +++ b/engines/scumm/he/sprite_he.h @@ -0,0 +1,222 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#if !defined(SPRITE_HE_H) && !defined(DISABLE_HE) +#define SPRITE_HE_H + +namespace Scumm { + +enum SpriteFlags { + kSFChanged = 0x1, + kSFNeedRedraw = 0x2, + kSFScaled = 0x10, + kSFRotated = 0x20, + kSFDoubleBuffered = 0x1000, + kSFYFlipped = 0x2000, + kSFXFlipped = 0x4000, + kSFActive = 0x8000, + kSFRemapPalette = 0x80000, + kSFAutoAnim = 0x200000, + kSFMarkDirty = 0x400000, + kSFBlitDirectly = 0x2000000, + kSFImageless = 0x40000000 +}; + +enum SpriteGroupFlags { + kSGFClipBox = (1 << 0) +}; + +struct SpriteInfo { + int32 id; + int32 zorder; + int32 flags; + int32 image; + int32 imageState; + int32 group; + int32 palette; + int32 priority; + Common::Rect bbox; + int32 dx; + int32 dy; + Common::Point pos; + int32 tx; + int32 ty; + int32 userValue; + int32 curImageState; + int32 curImage; + int32 imglistNum; + int32 shadow; + int32 imageStateCount; + int32 angle; + int32 scale; + int32 animProgress; + int32 curAngle; + int32 curScale; + int32 curImgFlags; + int32 field_74; + int32 animSpeed; + int32 sourceImage; + int32 maskImage; + int32 field_84; + int32 classFlags; + int32 imgFlags; + int32 field_90; +}; + +struct SpriteGroup { + Common::Rect bbox; + int32 priority; + int32 flags; + int32 tx; + int32 ty; + int32 image; + int32 scaling; + int32 scale_x_ratio_mul; + int32 scale_x_ratio_div; + int32 scale_y_ratio_mul; + int32 scale_y_ratio_div; +}; + +class ScummEngine_v90he; + +class Sprite { +public: + Sprite(ScummEngine_v90he *vm); + virtual ~Sprite(); + + SpriteInfo *_spriteTable; + SpriteGroup *_spriteGroups; + SpriteInfo **_activeSpritesTable; + + int32 _numSpritesToProcess; + int32 _varNumSpriteGroups; + int32 _varNumSprites; + int32 _varMaxSprites; + + void saveOrLoadSpriteData(Serializer *s); + void resetBackground(); + void setRedrawFlags(bool checkZOrder); + void sortActiveSprites(); + void processImages(bool arg); + void updateImages(); + + int findSpriteWithClassOf(int x, int y, int spriteGroupId, int d, int num, int *args); + int getSpriteClass(int spriteId, int num, int *args); + int getSpriteFlagDoubleBuffered(int spriteId); + int getSpriteFlagYFlipped(int spriteId); + int getSpriteFlagXFlipped(int spriteId); + int getSpriteFlagActive(int spriteId); + int getSpriteFlagRemapPalette(int spriteId); + int getSpriteFlagAutoAnim(int spriteId); + int getSpriteFlagUpdateType(int spriteId); + int getSpriteFlagEraseType(int spriteId); + int getSpriteImage(int spriteId); + int getSpriteImageState(int spriteId); + int getSpriteGroup(int spriteId); + int getSpritePalette(int spriteId); + int getSpritePriority(int spriteId); + int getSpriteDisplayX(int spriteId); + int getSpriteDisplayY(int spriteId); + int getSpriteUserValue(int spriteId); + int getSpriteShadow(int spriteId); + int getSpriteImageStateCount(int spriteId); + int getSpriteScale(int spriteId); + int getSpriteAnimSpeed(int spriteId); + int getSpriteSourceImage(int spriteId); + int getSpriteMaskImage(int spriteId); + int getSpriteGeneralProperty(int spriteId, int type); + void getSpriteBounds(int spriteId, bool checkGroup, Common::Rect &bound); + void getSpriteImageDim(int spriteId, int32 &w, int32 &h); + void getSpritePosition(int spriteId, int32 &tx, int32 &ty); + void getSpriteDist(int spriteId, int32 &dx, int32 &dy); + + int getGroupPriority(int spriteGroupId); + int getGroupDstResNum(int spriteGroupId); + int getGroupXMul(int spriteGroupId); + int getGroupXDiv(int spriteGroupId); + int getGroupYMul(int spriteGroupId); + int getGroupYDiv(int spriteGroupId); + void getGroupPosition(int spriteGroupId, int32 &tx, int32 &ty); + + void setSpritePalette(int spriteId, int value); + void setSpriteSourceImage(int spriteId, int value); + void setSpriteMaskImage(int spriteId, int value); + void resetSprite(int spriteId); + void setSpriteImageState(int spriteId, int value); + void setSpritePosition(int spriteId, int value1, int value2); + void setSpriteGroup(int spriteId, int value); + void setSpriteDist(int spriteId, int value1, int value2); + void setSpriteShadow(int spriteId, int value); + void setSpriteUserValue(int spriteId, int value1, int value2); + void setSpritePriority(int spriteId, int value); + void moveSprite(int spriteId, int value1, int value2); + void setSpriteScale(int spriteId, int value); + void setSpriteAngle(int spriteId, int value); + void setSpriteFlagDoubleBuffered(int spriteId, int value); + void setSpriteFlagYFlipped(int spriteId, int value); + void setSpriteFlagXFlipped(int spriteId, int value); + void setSpriteFlagActive(int spriteId, int value); + void setSpriteFlagRemapPalette(int spriteId, int value); + void setSpriteFlagAutoAnim(int spriteId, int value); + void setSpriteFlagUpdateType(int spriteId, int value); + void setSpriteFlagEraseType(int spriteId, int value); + void setSpriteAnimSpeed(int spriteId, int value); + void setSpriteSetClass(int spriteId, int classId, int toggle); + void setSpriteResetClass(int spriteId); + void setSpriteField84(int spriteId, int value); + void setSpriteGeneralProperty(int spriteId, int type, int value); + + void moveGroupMembers(int spriteGroupId, int value1, int value2); + void redrawSpriteGroup(int spriteGroupId); + void setGroupMembersPriority(int spriteGroupId, int value); + void setGroupMembersGroup(int spriteGroupId, int value); + void setGroupMembersUpdateType(int spriteGroupId, int value); + void setGroupMembersResetSprite(int spriteGroupId); + void setGroupMembersAnimationSpeed(int spriteGroupId, int value); + void setGroupMembersAutoAnimFlag(int spriteGroupId, int value); + void setGroupMembersShadow(int spriteGroupId, int value); + + void moveGroup(int spriteGroupId, int value1, int value2); + void setGroupBounds(int spriteGroupId, int x1, int y1, int x2, int y2); + void setGroupPriority(int spriteGroupId, int value); + void setGroupPosition(int spriteGroupId, int value1, int value2); + void setGroupImage(int spriteGroupId, int value); + void setGroupScaling(int spriteGroupId); + void setGroupXMul(int spriteGroupId, int value); + void setGroupXDiv(int spriteGroupId, int value); + void setGroupYMul(int spriteGroupId, int value); + void setGroupYDiv(int spriteGroupId, int value); + void resetGroupBounds(int spriteGroupId); + + void allocTables(int numSprites, int numGroups, int numMaxSprites); + void resetGroup(int spriteGroupId); + void resetTables(bool refreshScreen); + void setSpriteImage(int spriteId, int imageNum); +private: + ScummEngine_v90he *_vm; +}; + +} // End of namespace Scumm + +#endif + diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp new file mode 100644 index 0000000000..1d3baa74d2 --- /dev/null +++ b/engines/scumm/he/wiz_he.cpp @@ -0,0 +1,2088 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" + +#include "scumm/he/intern_he.h" +#include "scumm/resource.h" +#include "scumm/scumm.h" +#include "scumm/he/wiz_he.h" + +namespace Scumm { + +Wiz::Wiz(ScummEngine_v70he *vm) : _vm(vm) { + _imagesNum = 0; + memset(&_images, 0, sizeof(_images)); + memset(&_polygons, 0, sizeof(_polygons)); + _rectOverrideEnabled = false; +} + +void Wiz::clearWizBuffer() { + _imagesNum = 0; +} + +void Wiz::polygonClear() { + for (int i = 0; i < ARRAYSIZE(_polygons); i++) { + if (_polygons[i].flag == 1) + memset(&_polygons[i], 0, sizeof(WizPolygon)); + } +} + +void Wiz::polygonLoad(const uint8 *polData) { + int slots = READ_LE_UINT32(polData); + polData += 4; + + bool flag = 1; + int id, points, vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y; + while (slots--) { + id = READ_LE_UINT32(polData); + points = READ_LE_UINT32(polData + 4); + if (points != 4) + error("Illegal polygon with %d points", points); + vert1x = READ_LE_UINT32(polData + 8); + vert1y = READ_LE_UINT32(polData + 12); + vert2x = READ_LE_UINT32(polData + 16); + vert2y = READ_LE_UINT32(polData + 20); + vert3x = READ_LE_UINT32(polData + 24); + vert3y = READ_LE_UINT32(polData + 28); + vert4x = READ_LE_UINT32(polData + 32); + vert4y = READ_LE_UINT32(polData + 36); + + polData += 40; + polygonStore(id, flag, vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y); + } +} + +void Wiz::polygonStore(int id, bool flag, int vert1x, int vert1y, int vert2x, int vert2y, int vert3x, int vert3y, int vert4x, int vert4y) { + WizPolygon *wp = NULL; + for (int i = 0; i < ARRAYSIZE(_polygons); ++i) { + if (_polygons[i].id == 0) { + wp = &_polygons[i]; + break; + } + } + if (!wp) { + error("Wiz::polygonStore: out of polygon slot, max = %d", ARRAYSIZE(_polygons)); + } + + wp->vert[0].x = vert1x; + wp->vert[0].y = vert1y; + wp->vert[1].x = vert2x; + wp->vert[1].y = vert2y; + wp->vert[2].x = vert3x; + wp->vert[2].y = vert3y; + wp->vert[3].x = vert4x; + wp->vert[3].y = vert4y; + wp->vert[4].x = vert1x; + wp->vert[4].y = vert1y; + wp->id = id; + wp->numVerts = 5; + wp->flag = flag; + + polygonCalcBoundBox(wp->vert, wp->numVerts, wp->bound); +} + +void Wiz::polygonRotatePoints(Common::Point *pts, int num, int angle) { + double alpha = angle * PI / 180.; + double cos_alpha = cos(alpha); + double sin_alpha = sin(alpha); + + for (int i = 0; i < num; ++i) { + int16 x = pts[i].x; + int16 y = pts[i].y; + pts[i].x = (int16)(x * cos_alpha - y * sin_alpha); + pts[i].y = (int16)(y * cos_alpha + x * sin_alpha); + } +} + +void Wiz::polygonTransform(int resNum, int state, int po_x, int po_y, int angle, int scale, Common::Point *pts) { + int32 w, h; + + getWizImageDim(resNum, state, w, h); + + // set the transformation origin to the center of the image + if (_vm->_heversion >= 99) { + pts[0].x = pts[3].x = -(w / 2); + pts[1].x = pts[2].x = w / 2 - 1; + pts[0].y = pts[1].y = -(h / 2); + pts[2].y = pts[3].y = h / 2 - 1; + } else { + pts[1].x = pts[2].x = w / 2 - 1; + pts[0].x = pts[0].y = pts[1].y = pts[3].x = -(w / 2); + pts[2].y = pts[3].y = h / 2 - 1; + } + + // scale + if (scale != 0 && scale != 256) { + for (int i = 0; i < 4; ++i) { + pts[i].x = pts[i].x * scale / 256; + pts[i].y = pts[i].y * scale / 256; + } + } + + // rotate + if (angle != 0) + polygonRotatePoints(pts, 4, angle); + + // translate + for (int i = 0; i < 4; ++i) { + pts[i].x += po_x; + pts[i].y += po_y; + } +} + +void Wiz::polygonCalcBoundBox(Common::Point *vert, int numVerts, Common::Rect &bound) { + bound.left = 10000; + bound.top = 10000; + bound.right = -10000; + bound.bottom = -10000; + + // compute bounding box + for (int j = 0; j < numVerts; j++) { + Common::Rect r(vert[j].x, vert[j].y, vert[j].x + 1, vert[j].y + 1); + bound.extend(r); + } +} + +void Wiz::polygonErase(int fromId, int toId) { + for (int i = 0; i < ARRAYSIZE(_polygons); i++) { + if (_polygons[i].id >= fromId && _polygons[i].id <= toId) + memset(&_polygons[i], 0, sizeof(WizPolygon)); + } +} + +int Wiz::polygonHit(int id, int x, int y) { + for (int i = 0; i < ARRAYSIZE(_polygons); i++) { + if ((id == 0 || _polygons[i].id == id) && _polygons[i].bound.contains(x, y)) { + if (polygonContains(_polygons[i], x, y)) { + return _polygons[i].id; + } + } + } + return 0; +} + +bool Wiz::polygonDefined(int id) { + for (int i = 0; i < ARRAYSIZE(_polygons); i++) + if (_polygons[i].id == id) + return true; + return false; +} + +bool Wiz::polygonContains(const WizPolygon &pol, int x, int y) { + int pi = pol.numVerts - 1; + bool diry = (y < pol.vert[pi].y); + bool curdir; + bool r = false; + + for (int i = 0; i < pol.numVerts; i++) { + curdir = (y < pol.vert[i].y); + + if (curdir != diry) { + if (((pol.vert[pi].y - pol.vert[i].y) * (pol.vert[i].x - x) < + (pol.vert[pi].x - pol.vert[i].x) * (pol.vert[i].y - y)) == diry) + r = !r; + } + + pi = i; + diry = curdir; + } + + // HE80+ + int a, b; + pi = pol.numVerts - 1; + if (r == 0) { + for (int i = 0; i < pol.numVerts; i++) { + if (pol.vert[i].y == y && pol.vert[i].y == pol.vert[pi].y) { + + a = pol.vert[i].x; + b = pol.vert[pi].x; + + if (pol.vert[i].x >= pol.vert[pi].x) + a = pol.vert[pi].x; + + if (pol.vert[i].x > pol.vert[pi].x) + b = pol.vert[i].x; + + if (x >= a && x <= b) + return 1; + + } else if (pol.vert[i].x == x && pol.vert[i].x == pol.vert[pi].x) { + + a = pol.vert[i].y; + b = pol.vert[i].y; + + if (pol.vert[i].y >= pol.vert[pi].y) + a = pol.vert[pi].y; + + if (pol.vert[i].y <= pol.vert[pi].y) + b = pol.vert[pi].y; + + if (y >= a && y <= b) + return 1; + } + pi = i; + } + } + + return r; +} + +void Wiz::copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch) { + Common::Rect dstRect(srcx, srcy, srcx + srcw, srcy + srch); + dstRect.clip(dstw, dsth); + + int rw = dstRect.width(); + int rh = dstRect.height(); + if (rh <= 0 || rw <= 0) + return; + + uint8 *dst1Ptr = dst1 + dstRect.left + dstRect.top * dstw; + uint8 *dst2Ptr = dst2 + dstRect.left + dstRect.top * dstw; + const uint8 *dataPtr = src; + + while (rh--) { + uint16 off = READ_LE_UINT16(dataPtr); dataPtr += 2; + const uint8 *dataPtrNext = off + dataPtr; + uint8 *dst1PtrNext = dst1Ptr + dstw; + uint8 *dst2PtrNext = dst2Ptr + dstw; + if (off != 0) { + int w = rw; + while (w > 0) { + uint8 code = *dataPtr++; + if (code & 1) { + code >>= 1; + dst1Ptr += code; + dst2Ptr += code; + w -= code; + } else if (code & 2) { + code = (code >> 2) + 1; + w -= code; + if (w >= 0) { + memset(dst1Ptr, *dataPtr++, code); + dst1Ptr += code; + dst2Ptr += code; + } else { + code += w; + memset(dst1Ptr, *dataPtr, code); + } + } else { + code = (code >> 2) + 1; + w -= code; + if (w >= 0) { + memcpy(dst1Ptr, dst2Ptr, code); + dst1Ptr += code; + dst2Ptr += code; + } else { + code += w; + memcpy(dst1Ptr, dst2Ptr, code); + } + } + } + } + dataPtr = dataPtrNext; + dst1Ptr = dst1PtrNext; + dst2Ptr = dst2PtrNext; + } +} + +static bool calcClipRects(int dst_w, int dst_h, int src_x, int src_y, int src_w, int src_h, const Common::Rect *rect, Common::Rect &srcRect, Common::Rect &dstRect) { + srcRect = Common::Rect(src_w, src_h); + dstRect = Common::Rect(src_x, src_y, src_x + src_w, src_y + src_h); + Common::Rect r3; + int diff; + + if (rect) { + r3 = *rect; + Common::Rect r4(dst_w, dst_h); + if (r3.intersects(r4)) { + r3.clip(r4); + } else { + return false; + } + } else { + r3 = Common::Rect(dst_w, dst_h); + } + diff = dstRect.left - r3.left; + if (diff < 0) { + srcRect.left -= diff; + dstRect.left -= diff; + } + diff = dstRect.right - r3.right; + if (diff > 0) { + srcRect.right -= diff; + dstRect.right -= diff; + } + diff = dstRect.top - r3.top; + if (diff < 0) { + srcRect.top -= diff; + dstRect.top -= diff; + } + diff = dstRect.bottom - r3.bottom; + if (diff > 0) { + srcRect.bottom -= diff; + dstRect.bottom -= diff; + } + + return srcRect.isValidRect() && dstRect.isValidRect(); +} + +void Wiz::copyWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, const uint8 *xmapPtr) { + Common::Rect r1, r2; + if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { + dst += r2.left + r2.top * dstw; + decompressWizImage(dst, dstw, r2, src, r1, flags, palPtr, xmapPtr); + } +} + +void Wiz::copyRaw16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor) { + // RAW 16 bits in 555 format + + // HACK: Skip every second bit for now + Common::Rect r1, r2; + if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { + if (flags & kWIFFlipX) { + int l = r1.left; + int r = r1.right; + r1.left = srcw - r; + r1.right = srcw - l; + } + if (flags & kWIFFlipY) { + int t = r1.top; + int b = r1.bottom; + r1.top = srch - b; + r1.bottom = srch - t; + } + byte imagePal[256]; + if (!palPtr) { + for (int i = 0; i < 256; i++) { + imagePal[i] = i; + } + palPtr = imagePal; + } + + int h = r1.height(); + int w = r1.width(); + src += r1.left + r1.top * srcw * 2; + dst += r2.left + r2.top * dstw; + + while (h--) { + const uint8 *p = src; + for (int i = 0; i < w; ++i) { + uint8 col = *p; + if (transColor == -1 || transColor != col) { + dst[i] = palPtr[col]; + } + p += 2; + } + src += srcw * 2; + dst += dstw; + } + + } +} + +void Wiz::copyRawWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor) { + Common::Rect r1, r2; + if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { + if (flags & kWIFFlipX) { + int l = r1.left; + int r = r1.right; + r1.left = srcw - r; + r1.right = srcw - l; + } + if (flags & kWIFFlipY) { + int t = r1.top; + int b = r1.bottom; + r1.top = srch - b; + r1.bottom = srch - t; + } + byte imagePal[256]; + if (!palPtr) { + for (int i = 0; i < 256; i++) { + imagePal[i] = i; + } + palPtr = imagePal; + } + int h = r1.height(); + int w = r1.width(); + src += r1.left + r1.top * srcw; + dst += r2.left + r2.top * dstw; + while (h--) { + const uint8 *p = src; + for (int i = 0; i < w; ++i) { + uint8 col = *p++; + if (transColor == -1 || transColor != col) { + dst[i] = palPtr[col]; + } + } + src += srcw; + dst += dstw; + } + } +} + +void Wiz::decompressWizImage(uint8 *dst, int dstPitch, const Common::Rect &dstRect, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr, const uint8 *xmapPtr) { + if (flags & kWIFFlipX) { + debug(1, "decompressWizImage: Unhandled flag kWIFFlipX"); + } + if (flags & kWIFFlipY) { + debug(1, "decompressWizImage: Unhandled flag kWIFFlipY"); + } + + const uint8 *dataPtr, *dataPtrNext; + uint8 *dstPtr, *dstPtrNext; + uint32 code; + uint8 databit; + int h, w, xoff; + uint16 off; + + byte imagePal[256]; + if (!palPtr) { + for (int i = 0; i < 256; i++) { + imagePal[i] = i; + } + palPtr = imagePal; + } + + dstPtr = dst; + dataPtr = src; + + // Skip over the first 'srcRect->top' lines in the data + h = srcRect.top; + while (h--) { + dataPtr += READ_LE_UINT16(dataPtr) + 2; + } + h = srcRect.height(); + w = srcRect.width(); + if (h <= 0 || w <= 0) + return; + + while (h--) { + xoff = srcRect.left; + off = READ_LE_UINT16(dataPtr); + w = srcRect.right - srcRect.left; + dstPtrNext = dstPitch + dstPtr; + dataPtrNext = off + 2 + dataPtr; + dataPtr += 2; + if (off == 0) + goto dec_next; + + // Skip over the leftmost 'srcRect->left' pixels. + // TODO: This code could be merged (at a loss of efficency) with the + // loop below which does the actual drawing. + while (xoff > 0) { + code = *dataPtr++; + databit = code & 1; + code >>= 1; + if (databit) { + xoff -= code; + if (xoff < 0) { + code = -xoff; + goto dec_sub1; + } + } else { + databit = code & 1; + code = (code >> 1) + 1; + if (databit) { + ++dataPtr; + xoff -= code; + if (xoff < 0) { + code = -xoff; + --dataPtr; + goto dec_sub2; + } + } else { + dataPtr += code; + xoff -= code; + if (xoff < 0) { + dataPtr += xoff; + code = -xoff; + goto dec_sub3; + } + } + } + } + + while (w > 0) { + code = *dataPtr++; + databit = code & 1; + code >>= 1; + if (databit) { +dec_sub1: dstPtr += code; + w -= code; + } else { + databit = code & 1; + code = (code >> 1) + 1; + if (databit) { +dec_sub2: w -= code; + if (w < 0) { + code += w; + } + while (code--) { + if (xmapPtr) { + *dstPtr = xmapPtr[palPtr[*dataPtr] * 256 + *dstPtr]; + dstPtr++; + } else { + *dstPtr++ = palPtr[*dataPtr]; + } + } + dataPtr++; + } else { +dec_sub3: w -= code; + if (w < 0) { + code += w; + } + while (code--) { + if (xmapPtr) { + *dstPtr = xmapPtr[palPtr[*dataPtr++] * 256 + *dstPtr]; + dstPtr++; + } else { + *dstPtr++ = palPtr[*dataPtr++]; + } + } + } + } + } +dec_next: + dataPtr = dataPtrNext; + dstPtr = dstPtrNext; + } +} + +int Wiz::isWizPixelNonTransparent(const uint8 *data, int x, int y, int w, int h) { + if (x < 0 || x >= w || y < 0 || y >= h) { + return 0; + } + while (y != 0) { + data += READ_LE_UINT16(data) + 2; + --y; + } + uint16 off = READ_LE_UINT16(data); data += 2; + if (off == 0) { + return 0; + } + while (x > 0) { + uint8 code = *data++; + if (code & 1) { + code >>= 1; + if (code > x) { + return 0; + } + x -= code; + } else if (code & 2) { + code = (code >> 2) + 1; + if (code > x) { + return 1; + } + x -= code; + ++data; + } else { + code = (code >> 2) + 1; + if (code > x) { + return 1; + } + x -= code; + data += code; + } + } + return (~data[0]) & 1; +} + +uint8 Wiz::getWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color) { + if (x < 0 || x >= w || y < 0 || y >= h) { + return color; + } + while (y != 0) { + data += READ_LE_UINT16(data) + 2; + --y; + } + uint16 off = READ_LE_UINT16(data); data += 2; + if (off == 0) { + return color; + } + while (x > 0) { + uint8 code = *data++; + if (code & 1) { + code >>= 1; + if (code > x) { + return color; + } + x -= code; + } else if (code & 2) { + code = (code >> 2) + 1; + if (code > x) { + return data[0]; + } + x -= code; + ++data; + } else { + code = (code >> 2) + 1; + if (code > x) { + return data[x]; + } + x -= code; + data += code; + } + } + return (data[0] & 1) ? color : data[1]; +} + +uint8 Wiz::getRawWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color) { + if (x < 0 || x >= w || y < 0 || y >= h) { + return color; + } + return data[y * w + x]; +} + +void Wiz::computeWizHistogram(uint32 *histogram, const uint8 *data, const Common::Rect &rCapt) { + int y = rCapt.top; + while (y != 0) { + data += READ_LE_UINT16(data) + 2; + --y; + } + int ih = rCapt.height(); + while (ih--) { + uint16 off = READ_LE_UINT16(data); data += 2; + if (off != 0) { + const uint8 *p = data; + int x1 = rCapt.left; + int x2 = rCapt.right; + uint8 code; + while (x1 > 0) { + code = *p++; + if (code & 1) { + code >>= 1; + if (code > x1) { + code -= x1; + x2 -= code; + break; + } + x1 -= code; + } else if (code & 2) { + code = (code >> 2) + 1; + if (code > x1) { + code -= x1; + goto dec_sub2; + } + x1 -= code; + ++p; + } else { + code = (code >> 2) + 1; + if (code > x1) { + code -= x1; + p += x1; + goto dec_sub3; + } + x1 -= code; + p += code; + } + } + while (x2 > 0) { + code = *p++; + if (code & 1) { + code >>= 1; + x2 -= code; + } else if (code & 2) { + code = (code >> 2) + 1; +dec_sub2: x2 -= code; + if (x2 < 0) { + code += x2; + } + histogram[*p++] += code; + } else { + code = (code >> 2) + 1; +dec_sub3: x2 -= code; + if (x2 < 0) { + code += x2; + } + int n = code; + while (n--) { + ++histogram[*p++]; + } + } + } + data += off; + } + } +} + +void Wiz::computeRawWizHistogram(uint32 *histogram, const uint8 *data, int srcPitch, const Common::Rect &rCapt) { + data += rCapt.top * srcPitch + rCapt.left; + int iw = rCapt.width(); + int ih = rCapt.height(); + while (ih--) { + for (int i = 0; i < iw; ++i) { + ++histogram[data[i]]; + } + data += srcPitch; + } +} + +static int wizPackType1(uint8 *dst, const uint8 *src, int srcPitch, const Common::Rect& rCapt, uint8 transColor) { + debug(9, "wizPackType1(%d, [%d,%d,%d,%d])", transColor, rCapt.left, rCapt.top, rCapt.right, rCapt.bottom); + src += rCapt.top * srcPitch + rCapt.left; + int w = rCapt.width(); + int h = rCapt.height(); + int dataSize = 0; + while (h--) { + uint8 *dstLine = dst; + if (dst) { + dst += 2; + } + uint8 diffBuffer[0x40]; + int runCountSame = 0; + int runCountDiff = 0; + uint8 prevColor = src[0]; + for (int i = 1; i < w; ) { + uint8 color = src[i++]; + if (i == 2) { + if (prevColor == color) { + runCountSame = 1; + } else { + diffBuffer[0] = prevColor; + runCountDiff = 1; + } + } + if (prevColor == color) { + if (runCountDiff != 0) { + runCountSame = 1; + if (runCountDiff > 1) { + --runCountDiff; + if (dst) { + *dst++ = ((runCountDiff - 1) << 2) | 0; + memcpy(dst, diffBuffer, runCountDiff); + dst += runCountDiff; + } + dataSize += runCountDiff + 1; + } + runCountDiff = 0; + } + ++runCountSame; + if (prevColor == transColor) { + if (runCountSame == 0x7F) { + if (dst) { + *dst++ = (runCountSame << 1) | 1; + } + ++dataSize; + runCountSame = 0; + } + } else { + if (runCountSame == 0x40) { + if (dst) { + *dst++ = ((runCountSame - 1) << 2) | 2; + *dst++ = prevColor; + } + dataSize += 2; + runCountSame = 0; + } + } + } else { + if (runCountSame != 0) { + if (prevColor == transColor) { + if (dst) { + *dst++ = (runCountSame << 1) | 1; + } + ++dataSize; + } else { + if (dst) { + *dst++ = ((runCountSame - 1) << 2) | 2; + *dst++ = prevColor; + } + dataSize += 2; + } + runCountSame = 0; + } + assert(runCountDiff < ARRAYSIZE(diffBuffer)); + diffBuffer[runCountDiff++] = color; + if (runCountDiff == 0x40) { + if (dst) { + *dst++ = ((runCountDiff - 1) << 2) | 0; + memcpy(dst, diffBuffer, runCountDiff); + dst += runCountDiff + 1; + } + dataSize += runCountDiff + 1; + runCountDiff = 0; + } + } + prevColor = color; + } + if (runCountSame != 0) { + if (prevColor == transColor) { + if (dst) { + *dst++ = (runCountSame << 1) | 1; + } + ++dataSize; + } else { + if (dst) { + *dst++ = ((runCountSame - 1) << 2) | 2; + *dst++ = prevColor; + } + dataSize += 2; + } + } + if (runCountDiff != 0) { + if (dst) { + *dst++ = ((runCountDiff - 1) << 2) | 0; + memcpy(dst, diffBuffer, runCountDiff); + dst += runCountDiff; + } + dataSize += runCountDiff + 1; + } + if (dst) { + WRITE_LE_UINT16(dstLine, dst - dstLine - 2); + } + dataSize += 2; + src += srcPitch; + } + return dataSize; +} + +static int wizPackType0(uint8 *dst, const uint8 *src, int srcPitch, const Common::Rect& rCapt) { + debug(9, "wizPackType0([%d,%d,%d,%d])", rCapt.left, rCapt.top, rCapt.right, rCapt.bottom); + int w = rCapt.width(); + int h = rCapt.height(); + int size = w * h; + if (dst) { + src += rCapt.top * srcPitch + rCapt.left; + while (h--) { + memcpy(dst, src, w); + dst += w; + src += srcPitch; + } + } + return size; +} + +void Wiz::captureWizImage(int resNum, const Common::Rect& r, bool backBuffer, int compType) { + debug(5, "ScummEngine_v72he::captureWizImage(%d, %d, [%d,%d,%d,%d])", resNum, compType, r.left, r.top, r.right, r.bottom); + uint8 *src = NULL; + VirtScreen *pvs = &_vm->virtscr[kMainVirtScreen]; + if (backBuffer) { + src = pvs->getBackPixels(0, 0); + } else { + src = pvs->getPixels(0, 0); + } + Common::Rect rCapt(pvs->w, pvs->h); + if (rCapt.intersects(r)) { + rCapt.clip(r); + const uint8 *palPtr; + if (_vm->_heversion >= 99) { + palPtr = _vm->_hePalettes + 1024; + } else { + palPtr = _vm->_currentPalette; + } + + int w = rCapt.width(); + int h = rCapt.height(); + int transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : 5; + + // compute compressed size + int dataSize = 0; + int headerSize = palPtr ? 1080 : 36; + switch (compType) { + case 0: + dataSize = wizPackType0(0, src, pvs->pitch, rCapt); + break; + case 1: + dataSize = wizPackType1(0, src, pvs->pitch, rCapt, transColor); + break; + default: + error("unhandled compression type %d", compType); + break; + } + + // alignment + dataSize = (dataSize + 1) & ~1; + int wizSize = headerSize + dataSize; + // write header + uint8 *wizImg = _vm->res.createResource(rtImage, resNum, dataSize + headerSize); + WRITE_BE_UINT32(wizImg + 0x00, 'AWIZ'); + WRITE_BE_UINT32(wizImg + 0x04, wizSize); + WRITE_BE_UINT32(wizImg + 0x08, 'WIZH'); + WRITE_BE_UINT32(wizImg + 0x0C, 0x14); + WRITE_LE_UINT32(wizImg + 0x10, compType); + WRITE_LE_UINT32(wizImg + 0x14, w); + WRITE_LE_UINT32(wizImg + 0x18, h); + int curSize = 0x1C; + if (palPtr) { + WRITE_BE_UINT32(wizImg + 0x1C, 'RGBS'); + WRITE_BE_UINT32(wizImg + 0x20, 0x308); + memcpy(wizImg + 0x24, palPtr, 0x300); + WRITE_BE_UINT32(wizImg + 0x324, 'RMAP'); + WRITE_BE_UINT32(wizImg + 0x328, 0x10C); + WRITE_BE_UINT32(wizImg + 0x32C, 0); + curSize = 0x330; + for (int i = 0; i < 256; ++i) { + wizImg[curSize] = i; + ++curSize; + } + } + WRITE_BE_UINT32(wizImg + curSize + 0x0, 'WIZD'); + WRITE_BE_UINT32(wizImg + curSize + 0x4, dataSize + 8); + curSize += 8; + + // write compressed data + switch (compType) { + case 0: + wizPackType0(wizImg + headerSize, src, pvs->pitch, rCapt); + break; + case 1: + wizPackType1(wizImg + headerSize, src, pvs->pitch, rCapt, transColor); + break; + default: + break; + } + } + _vm->res.setModified(rtImage, resNum); +} + +void Wiz::displayWizImage(WizImage *pwi) { + if (_vm->_fullRedraw) { + assert(_imagesNum < ARRAYSIZE(_images)); + WizImage *wi = &_images[_imagesNum]; + wi->resNum = pwi->resNum; + wi->x1 = pwi->x1; + wi->y1 = pwi->y1; + wi->zorder = 0; + wi->state = pwi->state; + wi->flags = pwi->flags; + wi->shadow = 0; + wi->field_390 = 0; + wi->palette = 0; + ++_imagesNum; + } else if (pwi->flags & kWIFIsPolygon) { + drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags, 0, 0, 0); + } else { + const Common::Rect *r = NULL; + drawWizImage(pwi->resNum, pwi->state, pwi->x1, pwi->y1, 0, 0, 0, r, pwi->flags, 0, 0); + } +} + +uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, int palette) { + debug(2, "drawWizImage(resNum %d, x1 %d y1 %d flags 0x%X zorder %d shadow %d field_390 %d dstResNum %d palette %d)", resNum, x1, y1, flags, zorder, shadow, field_390, dstResNum, palette); + uint8 *dataPtr; + uint8 *dst = NULL; + + const uint8 *palPtr = NULL; + if (_vm->_heversion >= 99) { + if (palette) { + palPtr = _vm->_hePalettes + palette * 1024 + 768; + } else { + palPtr = _vm->_hePalettes + 1792; + } + } + + const uint8 *xmapPtr = NULL; + if (shadow) { + dataPtr = _vm->getResourceAddress(rtImage, shadow); + assert(dataPtr); + xmapPtr = _vm->findResourceData(MKID('XMAP'), dataPtr); + assert(xmapPtr); + } + + dataPtr = _vm->getResourceAddress(rtImage, resNum); + assert(dataPtr); + + uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); + assert(wizh); + uint32 comp = READ_LE_UINT32(wizh + 0x0); + uint32 width = READ_LE_UINT32(wizh + 0x4); + uint32 height = READ_LE_UINT32(wizh + 0x8); + debug(2, "wiz_header.comp = %d wiz_header.w = %d wiz_header.h = %d", comp, width, height); + + uint8 *wizd = _vm->findWrappedBlock(MKID('WIZD'), dataPtr, state, 0); + assert(wizd); + + if (flags & kWIFHasPalette) { + uint8 *pal = _vm->findWrappedBlock(MKID('RGBS'), dataPtr, state, 0); + assert(pal); + _vm->setPaletteFromPtr(pal, 256); + } + + uint8 *rmap = NULL; + if (flags & kWIFRemapPalette) { + rmap = _vm->findWrappedBlock(MKID('RMAP'), dataPtr, state, 0); + assert(rmap); + if (_vm->_heversion <= 80 || READ_BE_UINT32(rmap) != 0x01234567) { + uint8 *rgbs = _vm->findWrappedBlock(MKID('RGBS'), dataPtr, state, 0); + assert(rgbs); + _vm->remapHEPalette(rgbs, rmap + 4); + } + } + + if (flags & kWIFPrint) { + error("WizImage printing is unimplemented"); + } + + int32 cw, ch; + if (flags & kWIFBlitToMemBuffer) { + dst = (uint8 *)malloc(width * height); + int transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? (_vm->VAR(_vm->VAR_WIZ_TCOLOR)) : 5; + memset(dst, transColor, width * height); + cw = width; + ch = height; + } else { + if (dstResNum) { + uint8 *dstPtr = _vm->getResourceAddress(rtImage, dstResNum); + assert(dstPtr); + dst = _vm->findWrappedBlock(MKID('WIZD'), dstPtr, 0, 0); + assert(dst); + getWizImageDim(dstResNum, 0, cw, ch); + } else { + VirtScreen *pvs = &_vm->virtscr[kMainVirtScreen]; + if (flags & kWIFMarkBufferDirty) { + dst = pvs->getPixels(0, pvs->topline); + } else { + dst = pvs->getBackPixels(0, pvs->topline); + } + cw = pvs->w; + ch = pvs->h; + } + } + + Common::Rect rScreen(cw, ch); + if (clipBox) { + Common::Rect clip(clipBox->left, clipBox->top, clipBox->right, clipBox->bottom); + if (rScreen.intersects(clip)) { + rScreen.clip(clip); + } else { + return 0; + } + } else if (_rectOverrideEnabled) { + if (rScreen.intersects(_rectOverride)) { + rScreen.clip(_rectOverride); + } else { + return 0; + } + } + + if (flags & kWIFRemapPalette) { + palPtr = rmap + 4; + } + + int transColor = -1; + if (_vm->VAR_WIZ_TCOLOR != 0xFF) { + uint8 *trns = _vm->findWrappedBlock(MKID('TRNS'), dataPtr, state, 0); + transColor = (trns == NULL) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : -1; + } + + switch (comp) { + case 0: + copyRawWizImage(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, transColor); + break; + case 1: + // TODO Adding masking for flags 0x80 and 0x100 + if (flags & 0x80) + // Used in maze + debug(0, "drawWizImage: Unhandled flag 0x80"); + if (flags & 0x100) { + // Used in readdemo + debug(0, "drawWizImage: Unhandled flag 0x100"); + } + copyWizImage(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, xmapPtr); + break; + case 2: + copyRaw16BitWizImage(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, transColor); + break; + default: + error("drawWizImage: Unhandled wiz compression type %d", comp); + } + + if (!(flags & kWIFBlitToMemBuffer) && dstResNum == 0) { + Common::Rect rImage(x1, y1, x1 + width, y1 + height); + if (rImage.intersects(rScreen)) { + rImage.clip(rScreen); + if (!(flags & kWIFBlitToFrontVideoBuffer) && (flags & (kWIFBlitToFrontVideoBuffer | kWIFMarkBufferDirty))) { + ++rImage.bottom; + _vm->markRectAsDirty(kMainVirtScreen, rImage); + } else { + _vm->gdi.copyVirtScreenBuffers(rImage); + } + } + } + + return dst; +} + +struct PolygonDrawData { + struct PolygonArea { + int32 xmin; + int32 xmax; + int32 x1; + int32 y1; + int32 x2; + int32 y2; + }; + struct ResultArea { + int32 dst_offs; + int32 x_step; + int32 y_step; + int32 x_s; + int32 y_s; + int32 w; + }; + Common::Point mat[4]; + PolygonArea *pa; + ResultArea *ra; + int rAreasNum; + int pAreasNum; + + PolygonDrawData(int n) { + memset(mat, 0, sizeof(mat)); + pa = new PolygonArea[n]; + for (int i = 0; i < n; ++i) { + pa[i].xmin = 0x7FFFFFFF; + pa[i].xmax = 0x80000000; + } + ra = new ResultArea[n]; + rAreasNum = 0; + pAreasNum = n; + } + + ~PolygonDrawData() { + delete[] pa; + delete[] ra; + } + + void transform(const Common::Point *tp1, const Common::Point *tp2, const Common::Point *sp1, const Common::Point *sp2) { + int32 tx_acc = tp1->x << 16; + int32 sx_acc = sp1->x << 16; + int32 sy_acc = sp1->y << 16; + uint16 dy = ABS(tp2->y - tp1->y) + 1; + int32 tx_step = ((tp2->x - tp1->x) << 16) / dy; + int32 sx_step = ((sp2->x - sp1->x) << 16) / dy; + int32 sy_step = ((sp2->y - sp1->y) << 16) / dy; + + int y = tp1->y - mat[0].y; + while (dy--) { + assert(y >= 0 && y < pAreasNum); + PolygonArea *ppa = &pa[y]; + int32 ttx = tx_acc >> 16; + int32 tsx = sx_acc >> 16; + int32 tsy = sy_acc >> 16; + + if (ppa->xmin > ttx) { + ppa->xmin = ttx; + ppa->x1 = tsx; + ppa->y1 = tsy; + } + if (ppa->xmax < ttx) { + ppa->xmax = ttx; + ppa->x2 = tsx; + ppa->y2 = tsy; + } + + tx_acc += tx_step; + sx_acc += sx_step; + sy_acc += sy_step; + + if (tp2->y <= tp1->y) { + --y; + } else { + ++y; + } + } + } +}; + +void Wiz::drawWizComplexPolygon(int resNum, int state, int po_x, int po_y, int shadow, int angle, int scale, const Common::Rect *r, int flags, int dstResNum, int palette) { + Common::Point pts[4]; + + polygonTransform(resNum, state, po_x, po_y, angle, scale, pts); + drawWizPolygonTransform(resNum, state, pts, flags, shadow, dstResNum, palette); +} + +void Wiz::drawWizPolygon(int resNum, int state, int id, int flags, int shadow, int dstResNum, int palette) { + int i; + WizPolygon *wp = NULL; + for (i = 0; i < ARRAYSIZE(_polygons); ++i) { + if (_polygons[i].id == id) { + wp = &_polygons[i]; + break; + } + } + if (!wp) { + error("Polygon %d is not defined", id); + } + if (wp->numVerts != 5) { + error("Invalid point count %d for Polygon %d", wp->numVerts, id); + } + + drawWizPolygonTransform(resNum, state, wp->vert, flags, shadow, dstResNum, palette); +} + +void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int flags, int shadow, int dstResNum, int palette) { + debug(2, "drawWizPolygonTransform(resNum %d, flags 0x%X, shadow %d dstResNum %d palette %d)", resNum, flags, shadow, dstResNum, palette); + int i; + + if (flags & 0x800000) { + warning("0x800000 flags not supported"); + return; + } + + const Common::Rect *r = NULL; + uint8 *srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, shadow, 0, r, kWIFBlitToMemBuffer, 0, palette); + if (srcWizBuf) { + uint8 *dst; + int32 dstw, dsth, dstpitch, wizW, wizH; + VirtScreen *pvs = &_vm->virtscr[kMainVirtScreen]; + int transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : 5; + + if (dstResNum) { + uint8 *dstPtr = _vm->getResourceAddress(rtImage, dstResNum); + assert(dstPtr); + dst = _vm->findWrappedBlock(MKID('WIZD'), dstPtr, 0, 0); + assert(dst); + getWizImageDim(dstResNum, 0, dstw, dsth); + dstpitch = dstw; + } else { + if (flags & kWIFMarkBufferDirty) { + dst = pvs->getPixels(0, 0); + } else { + dst = pvs->getBackPixels(0, 0); + } + dstw = pvs->w; + dsth = pvs->h; + dstpitch = pvs->pitch; + } + + getWizImageDim(resNum, state, wizW, wizH); + + Common::Point bbox[4]; + bbox[0].x = 0; + bbox[0].y = 0; + bbox[1].x = wizW - 1; + bbox[1].y = 0; + bbox[2].x = wizW - 1; + bbox[2].y = wizH - 1; + bbox[3].x = 0; + bbox[3].y = wizH - 1; + + int16 xmin_p, xmax_p, ymin_p, ymax_p; + xmin_p = ymin_p = (int16)0x7FFF; + xmax_p = ymax_p = (int16)0x8000; + + for (i = 0; i < 4; ++i) { + xmin_p = MIN(wp[i].x, xmin_p); + xmax_p = MAX(wp[i].x, xmax_p); + ymin_p = MIN(wp[i].y, ymin_p); + ymax_p = MAX(wp[i].y, ymax_p); + } + + int16 xmin_b, xmax_b, ymin_b, ymax_b; + xmin_b = ymin_b = (int16)0x7FFF; + xmax_b = ymax_b = (int16)0x8000; + + for (i = 0; i < 4; ++i) { + xmin_b = MIN(bbox[i].x, xmin_b); + xmax_b = MAX(bbox[i].x, xmax_b); + ymin_b = MIN(bbox[i].y, ymin_b); + ymax_b = MAX(bbox[i].y, ymax_b); + } + + PolygonDrawData pdd(ymax_p - ymin_p + 1); + pdd.mat[0].x = xmin_p; + pdd.mat[0].y = ymin_p; + pdd.mat[1].x = xmax_p; + pdd.mat[1].y = ymax_p; + pdd.mat[2].x = xmin_b; + pdd.mat[2].y = ymin_b; + pdd.mat[3].x = xmax_b; + pdd.mat[3].y = ymax_b; + + // precompute the transformation which remaps 'bbox' pixels to 'wp' + for (i = 0; i < 3; ++i) { + pdd.transform(&wp[i], &wp[i + 1], &bbox[i], &bbox[i + 1]); + } + pdd.transform(&wp[3], &wp[0], &bbox[3], &bbox[0]); + + pdd.rAreasNum = 0; + PolygonDrawData::ResultArea *pra = &pdd.ra[0]; + int32 yoff = pdd.mat[0].y * dstpitch; + int16 y_start = pdd.mat[0].y; + for (i = 0; i < pdd.pAreasNum; ++i) { + PolygonDrawData::PolygonArea *ppa = &pdd.pa[i]; + if (y_start >= 0 && y_start < dsth) { + int16 x1 = ppa->xmin; + if (x1 < 0) { + x1 = 0; + } + int16 x2 = ppa->xmax; + if (x2 >= dstw) { + x2 = dstw - 1; + } + int16 w = x2 - x1 + 1; + if (w > 0) { + int16 width = ppa->xmax - ppa->xmin + 1; + pra->x_step = ((ppa->x2 - ppa->x1) << 16) / width; + pra->y_step = ((ppa->y2 - ppa->y1) << 16) / width; + pra->dst_offs = yoff + x1; + pra->w = w; + pra->x_s = ppa->x1 << 16; + pra->y_s = ppa->y1 << 16; + int16 tmp = x1 - ppa->xmin; + if (tmp != 0) { + pra->x_s += pra->x_step * tmp; + pra->y_s += pra->y_step * tmp; + } + ++pra; + ++pdd.rAreasNum; + } + } + ++ppa; + yoff += dstpitch; + ++y_start; + } + + pra = &pdd.ra[0]; + for (i = 0; i < pdd.rAreasNum; ++i, ++pra) { + uint8 *dstPtr = dst + pra->dst_offs; + int32 w = pra->w; + int32 x_acc = pra->x_s; + int32 y_acc = pra->y_s; + while (--w) { + int32 src_offs = (y_acc >> 16) * wizW + (x_acc >> 16); + assert(src_offs < wizW * wizH); + x_acc += pra->x_step; + y_acc += pra->y_step; + if (transColor == -1 || transColor != srcWizBuf[src_offs]) { + *dstPtr = srcWizBuf[src_offs]; + } + dstPtr++; + } + } + + Common::Rect bound(xmin_p, ymin_p, xmax_p + 1, ymax_p + 1); + if (flags & kWIFMarkBufferDirty) { + _vm->markRectAsDirty(kMainVirtScreen, bound); + } else { + _vm->gdi.copyVirtScreenBuffers(bound); + } + + free(srcWizBuf); + } +} + +void Wiz::flushWizBuffer() { + for (int i = 0; i < _imagesNum; ++i) { + WizImage *pwi = &_images[i]; + if (pwi->flags & kWIFIsPolygon) { + drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags, pwi->shadow, 0, pwi->palette); + } else { + const Common::Rect *r = NULL; + drawWizImage(pwi->resNum, pwi->state, pwi->x1, pwi->y1, pwi->zorder, pwi->shadow, pwi->field_390, r, pwi->flags, 0, pwi->palette); + } + } + _imagesNum = 0; +} + +void Wiz::loadWizCursor(int resId) { + int32 x, y; + getWizImageSpot(resId, 0, x, y); + if (x < 0) { + x = 0; + } else if (x > 32) { + x = 32; + } + if (y < 0) { + y = 0; + } else if (y > 32) { + y = 32; + } + + const Common::Rect *r = NULL; + uint8 *cursor = drawWizImage(resId, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, 0); + int32 cw, ch; + getWizImageDim(resId, 0, cw, ch); + _vm->setCursorFromBuffer(cursor, cw, ch, cw); + _vm->setCursorHotspot(x, y); + free(cursor); +} + +void Wiz::displayWizComplexImage(const WizParameters *params) { + int sourceImage = 0; + if (params->processFlags & kWPFMaskImg) { + sourceImage = params->sourceImage; + debug(0, "displayWizComplexImage() unhandled flag 0x80000"); + } + int palette = 0; + if (params->processFlags & kWPFPaletteNum) { + palette = params->img.palette; + } + int scale = 256; + if (params->processFlags & kWPFScaled) { + scale = params->scale; + } + int rotationAngle = 0; + if (params->processFlags & kWPFRotate) { + rotationAngle = params->angle; + } + int state = 0; + if (params->processFlags & kWPFNewState) { + state = params->img.state; + } + int flags = 0; + if (params->processFlags & kWPFNewFlags) { + flags = params->img.flags; + } + int po_x = 0; + int po_y = 0; + if (params->processFlags & kWPFSetPos) { + po_x = params->img.x1; + po_y = params->img.y1; + } + int shadow = 0; + if (params->processFlags & kWPFShadow) { + shadow = params->img.shadow; + } + int field_390 = 0; + if (params->processFlags & 0x200000) { + field_390 = params->img.field_390; + debug(0, "displayWizComplexImage() unhandled flag 0x200000"); + } + const Common::Rect *r = NULL; + if (params->processFlags & kWPFClipBox) { + r = ¶ms->box; + } + int dstResNum = 0; + if (params->processFlags & kWPFDstResNum) { + dstResNum = params->dstResNum; + } + if (params->processFlags & kWPFRemapPalette) { + remapWizImagePal(params); + flags |= kWIFRemapPalette; + } + + if (_vm->_fullRedraw && dstResNum == 0) { + if (sourceImage != 0 || (params->processFlags & (kWPFScaled | kWPFRotate))) + error("Can't do this command in the enter script."); + + assert(_imagesNum < ARRAYSIZE(_images)); + WizImage *pwi = &_images[_imagesNum]; + pwi->resNum = params->img.resNum; + pwi->x1 = po_x; + pwi->y1 = po_y; + pwi->zorder = params->img.zorder; + pwi->state = state; + pwi->flags = flags; + pwi->shadow = shadow; + pwi->field_390 = field_390; + pwi->palette = palette; + ++_imagesNum; + } else { + if (sourceImage != 0) { + // TODO + } else if (params->processFlags & (kWPFScaled | kWPFRotate)) { + drawWizComplexPolygon(params->img.resNum, state, po_x, po_y, shadow, rotationAngle, scale, r, flags, dstResNum, palette); + } else { + if (flags & kWIFIsPolygon) { + drawWizPolygon(params->img.resNum, state, po_x, flags, shadow, dstResNum, palette); // XXX , VAR(VAR_WIZ_TCOLOR)); + } else { + drawWizImage(params->img.resNum, state, po_x, po_y, params->img.zorder, shadow, field_390, r, flags, dstResNum, palette); + } + } + } +} + +void Wiz::createWizEmptyImage(const WizParameters *params) { + int img_w = 640; + if (params->processFlags & kWPFUseDefImgWidth) { + img_w = params->resDefImgW; + } + int img_h = 480; + if (params->processFlags & kWPFUseDefImgHeight) { + img_h = params->resDefImgH; + } + int img_x = 0; + int img_y = 0; + if (params->processFlags & 1) { + img_x = params->img.x1; + img_y = params->img.y1; + } + const uint16 flags = 0xB; + int res_size = 0x1C; + if (flags & 1) { + res_size += 0x308; + } + if (flags & 2) { + res_size += 0x10; + } + if (flags & 8) { + res_size += 0x10C; + } + res_size += 8 + img_w * img_h; + + const uint8 *palPtr; + if (_vm->_heversion >= 99) { + palPtr = _vm->_hePalettes + 1024; + } else { + palPtr = _vm->_currentPalette; + } + uint8 *res_data = _vm->res.createResource(rtImage, params->img.resNum, res_size); + if (!res_data) { + _vm->VAR(119) = -1; + } else { + _vm->VAR(119) = 0; + WRITE_BE_UINT32(res_data, 'AWIZ'); res_data += 4; + WRITE_BE_UINT32(res_data, res_size); res_data += 4; + WRITE_BE_UINT32(res_data, 'WIZH'); res_data += 4; + WRITE_BE_UINT32(res_data, 0x14); res_data += 4; + WRITE_LE_UINT32(res_data, 0); res_data += 4; + WRITE_LE_UINT32(res_data, img_w); res_data += 4; + WRITE_LE_UINT32(res_data, img_h); res_data += 4; + if (flags & 1) { + WRITE_BE_UINT32(res_data, 'RGBS'); res_data += 4; + WRITE_BE_UINT32(res_data, 0x308); res_data += 4; + memcpy(res_data, palPtr, 0x300); res_data += 0x300; + } + if (flags & 2) { + WRITE_BE_UINT32(res_data, 'SPOT'); res_data += 4; + WRITE_BE_UINT32(res_data, 0x10); res_data += 4; + WRITE_BE_UINT32(res_data, img_x); res_data += 4; + WRITE_BE_UINT32(res_data, img_y); res_data += 4; + } + if (flags & 8) { + WRITE_BE_UINT32(res_data, 'RMAP'); res_data += 4; + WRITE_BE_UINT32(res_data, 0x10C); res_data += 4; + WRITE_BE_UINT32(res_data, 0); res_data += 4; + for (int i = 0; i < 256; ++i) { + *res_data++ = i; + } + } + WRITE_BE_UINT32(res_data, 'WIZD'); res_data += 4; + WRITE_BE_UINT32(res_data, 8 + img_w * img_h); res_data += 4; + } + _vm->res.setModified(rtImage, params->img.resNum); +} + +void Wiz::fillWizRect(const WizParameters *params) { + int state = 0; + if (params->processFlags & kWPFNewState) { + state = params->img.state; + } + uint8 *dataPtr = _vm->getResourceAddress(rtImage, params->img.resNum); + if (dataPtr) { + uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); + assert(wizh); + int c = READ_LE_UINT32(wizh + 0x0); + int w = READ_LE_UINT32(wizh + 0x4); + int h = READ_LE_UINT32(wizh + 0x8); + assert(c == 0); + Common::Rect areaRect, imageRect(w, h); + if (params->processFlags & kWPFClipBox) { + if (!imageRect.intersects(params->box)) { + return; + } + imageRect.clip(params->box); + } + if (params->processFlags & kWPFClipBox2) { + areaRect = params->box2; + } else { + areaRect = imageRect; + } + uint8 color = _vm->VAR(93); + if (params->processFlags & kWPFFillColor) { + color = params->fillColor; + } + if (areaRect.intersects(imageRect)) { + areaRect.clip(imageRect); + uint8 *wizd = _vm->findWrappedBlock(MKID('WIZD'), dataPtr, state, 0); + assert(wizd); + int dx = areaRect.width(); + int dy = areaRect.height(); + wizd += areaRect.top * w + areaRect.left; + while (dy--) { + memset(wizd, color, dx); + wizd += w; + } + } + } + _vm->res.setModified(rtImage, params->img.resNum); +} + +void Wiz::fillWizLine(const WizParameters *params) { + if (params->processFlags & kWPFClipBox2) { + int state = 0; + if (params->processFlags & kWPFNewState) { + state = params->img.state; + } + uint8 *dataPtr = _vm->getResourceAddress(rtImage, params->img.resNum); + if (dataPtr) { + uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); + assert(wizh); + int c = READ_LE_UINT32(wizh + 0x0); + int w = READ_LE_UINT32(wizh + 0x4); + int h = READ_LE_UINT32(wizh + 0x8); + assert(c == 0); + Common::Rect imageRect(w, h); + if (params->processFlags & kWPFClipBox) { + if (!imageRect.intersects(params->box)) { + return; + } + imageRect.clip(params->box); + } + uint8 color = _vm->VAR(93); + if (params->processFlags & kWPFFillColor) { + color = params->fillColor; + } + uint8 *wizd = _vm->findWrappedBlock(MKID('WIZD'), dataPtr, state, 0); + assert(wizd); + int x1 = params->box2.left; + int y1 = params->box2.top; + int x2 = params->box2.right; + int y2 = params->box2.bottom; + + int dx = x2 - x1; + int incx = 0; + if (dx > 0) { + incx = 1; + } else if (dx < 0) { + incx = -1; + } + int dy = y2 - y1; + int incy = 0; + if (dy > 0) { + incy = 1; + } else if (dy < 0) { + incy = -1; + } + + dx = ABS(x2 - x1); + dy = ABS(y2 - y1); + + if (imageRect.contains(x1, y1)) { + *(wizd + y1 * w + x1) = color; + } + + if (dx >= dy) { + int step1_y = (dy - dx) * 2; + int step2_y = dy * 2; + int accum_y = dy * 2 - dx; + while (x1 != x2) { + if (accum_y <= 0) { + accum_y += step2_y; + } else { + accum_y += step1_y; + y1 += incy; + } + x1 += incx; + if (imageRect.contains(x1, y1)) { + *(wizd + y1 * w + x1) = color; + } + } + } else { + int step1_x = (dx - dy) * 2; + int step2_x = dx * 2; + int accum_x = dx * 2 - dy; + while (y1 != y2) { + if (accum_x <= 0) { + accum_x += step2_x; + } else { + accum_x += step1_x; + x1 += incx; + } + y1 += incy; + if (imageRect.contains(x1, y1)) { + *(wizd + y1 * w + x1) = color; + } + } + } + } + } + _vm->res.setModified(rtImage, params->img.resNum); +} + +void Wiz::fillWizPixel(const WizParameters *params) { + if (params->processFlags & kWPFClipBox2) { + int px = params->box2.left; + int py = params->box2.top; + uint8 *dataPtr = _vm->getResourceAddress(rtImage, params->img.resNum); + if (dataPtr) { + int state = 0; + if (params->processFlags & kWPFNewState) { + state = params->img.state; + } + uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); + assert(wizh); + int c = READ_LE_UINT32(wizh + 0x0); + int w = READ_LE_UINT32(wizh + 0x4); + int h = READ_LE_UINT32(wizh + 0x8); + assert(c == 0); + Common::Rect imageRect(w, h); + if (params->processFlags & kWPFClipBox) { + if (!imageRect.intersects(params->box)) { + return; + } + imageRect.clip(params->box); + } + uint8 color = _vm->VAR(93); + if (params->processFlags & kWPFFillColor) { + color = params->fillColor; + } + if (imageRect.contains(px, py)) { + uint8 *wizd = _vm->findWrappedBlock(MKID('WIZD'), dataPtr, state, 0); + assert(wizd); + *(wizd + py * w + px) = color; + } + } + } + _vm->res.setModified(rtImage, params->img.resNum); +} + +void Wiz::remapWizImagePal(const WizParameters *params) { + int st = (params->processFlags & kWPFNewState) ? params->img.state : 0; + int num = params->remapNum; + const uint8 *index = params->remapIndex; + uint8 *iwiz = _vm->getResourceAddress(rtImage, params->img.resNum); + assert(iwiz); + uint8 *rmap = _vm->findWrappedBlock(MKID('RMAP'), iwiz, st, 0) ; + assert(rmap); + WRITE_BE_UINT32(rmap, 0x01234567); + while (num--) { + uint8 idx = *index++; + rmap[4 + idx] = params->remapColor[idx]; + } + _vm->res.setModified(rtImage, params->img.resNum); +} + +void Wiz::processWizImage(const WizParameters *params) { + char buf[512]; + unsigned int i; + + debug(2, "processWizImage: processMode %d", params->processMode); + switch (params->processMode) { + case 0: + // Used in racedemo + break; + case 1: + displayWizComplexImage(params); + break; + case 2: + captureWizImage(params->img.resNum, params->box, (params->img.flags & kWIFBlitToFrontVideoBuffer) != 0, params->compType); + break; + case 3: + if (params->processFlags & kWPFUseFile) { + Common::File f; + + // Convert Windows path separators to something more portable + strncpy(buf, (const char *)params->filename, 512); + for (i = 0; i < strlen(buf); i++) { + if (buf[i] == '\\') + buf[i] = '/'; + } + + if (f.open((const char *)buf, Common::File::kFileReadMode)) { + uint32 id = f.readUint32LE(); + if (id == TO_LE_32(MKID('AWIZ')) || id == TO_LE_32(MKID('MULT'))) { + uint32 size = f.readUint32BE(); + f.seek(0, SEEK_SET); + byte *p = _vm->res.createResource(rtImage, params->img.resNum, size); + if (f.read(p, size) != size) { + _vm->res.nukeResource(rtImage, params->img.resNum); + error("i/o error when reading '%s'", buf); + _vm->VAR(_vm->VAR_GAME_LOADED) = -2; + _vm->VAR(119) = -2; + } else { + _vm->res.setModified(rtImage, params->img.resNum); + _vm->VAR(_vm->VAR_GAME_LOADED) = 0; + _vm->VAR(119) = 0; + } + } else { + _vm->VAR(_vm->VAR_GAME_LOADED) = -1; + _vm->VAR(119) = -1; + } + f.close(); + } else { + _vm->VAR(_vm->VAR_GAME_LOADED) = -3; + _vm->VAR(119) = -3; + debug(0, "Unable to open for read '%s'", buf); + } + } + break; + case 4: + if (params->processFlags & kWPFUseFile) { + Common::File f; + + switch(params->fileWriteMode) { + case 2: + _vm->VAR(119) = -1; + break; + case 1: + // TODO Write image to file + break; + case 0: + // Convert Windows path separators to something more portable + strncpy(buf, (const char *)params->filename, 512); + for (i = 0; i < strlen(buf); i++) { + if (buf[i] == '\\') + buf[i] = '/'; + } + + if (!f.open((const char *)buf, Common::File::kFileWriteMode)) { + debug(0, "Unable to open for write '%s'", buf); + _vm->VAR(119) = -3; + } else { + byte *p = _vm->getResourceAddress(rtImage, params->img.resNum); + uint32 size = READ_BE_UINT32(p + 4); + if (f.write(p, size) != size) { + error("i/o error when writing '%s'", params->filename); + _vm->VAR(119) = -2; + } else { + _vm->VAR(119) = 0; + } + f.close(); + } + break; + default: + error("processWizImage: processMode 4 unhandled fileWriteMode %d", params->fileWriteMode); + } + } + break; + case 6: + if (params->processFlags & kWPFRemapPalette) { + remapWizImagePal(params); + } + break; + // HE 99+ + case 7: + // Used in PuttsFunShop/SamsFunShop/soccer2004 + // TODO: Capture polygon + _vm->res.setModified(rtImage, params->img.resNum); + break; + case 8: + createWizEmptyImage(params); + break; + case 9: + fillWizRect(params); + break; + case 10: + fillWizLine(params); + break; + case 11: + fillWizPixel(params); + break; + case 12: + fillWizFlood(params); + break; + case 13: + // Used for text in FreddisFunShop/PuttsFunShop/SamsFunShop + // TODO: Start Font + break; + case 14: + // Used for text in FreddisFunShop/PuttsFunShop/SamsFunShop + // TODO: End Font + break; + case 15: + // Used for text in FreddisFunShop/PuttsFunShop/SamsFunShop + // TODO: Create Font + break; + case 16: + // TODO: Render Font String + error("Render Font String"); + break; + case 17: + // Used in to draw circles in FreddisFunShop/PuttsFunShop/SamsFunShop + // TODO: Ellipse + _vm->res.setModified(rtImage, params->img.resNum); + break; + default: + error("Unhandled processWizImage mode %d", params->processMode); + } +} + +void Wiz::getWizImageDim(int resNum, int state, int32 &w, int32 &h) { + uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum); + assert(dataPtr); + uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); + assert(wizh); + w = READ_LE_UINT32(wizh + 0x4); + h = READ_LE_UINT32(wizh + 0x8); +} + +void Wiz::getWizImageSpot(int resId, int state, int32 &x, int32 &y) { + uint8 *dataPtr = _vm->getResourceAddress(rtImage, resId); + assert(dataPtr); + uint8 *spotPtr = _vm->findWrappedBlock(MKID('SPOT'), dataPtr, state, 0); + if (spotPtr) { + x = READ_LE_UINT32(spotPtr + 0); + y = READ_LE_UINT32(spotPtr + 4); + } else { + x = 0; + y = 0; + } +} + +int Wiz::getWizImageData(int resNum, int state, int type) { + uint8 *dataPtr, *wizh; + + dataPtr = _vm->getResourceAddress(rtImage, resNum); + assert(dataPtr); + + switch (type) { + case 0: + wizh = _vm->findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); + assert(wizh); + return READ_LE_UINT32(wizh + 0x0); + case 1: + return (_vm->findWrappedBlock(MKID('RGBS'), dataPtr, state, 0) != NULL) ? 1 : 0; + case 2: + return (_vm->findWrappedBlock(MKID('RMAP'), dataPtr, state, 0) != NULL) ? 1 : 0; + case 3: + return (_vm->findWrappedBlock(MKID('TRNS'), dataPtr, state, 0) != NULL) ? 1 : 0; + case 4: + return (_vm->findWrappedBlock(MKID('XMAP'), dataPtr, state, 0) != NULL) ? 1 : 0; + default: + error("getWizImageData: Unknown type %d", type); + } +} + +int Wiz::getWizImageStates(int resNum) { + const uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum); + assert(dataPtr); + if (READ_UINT32(dataPtr) == MKID('MULT')) { + const byte *offs, *wrap; + + wrap = _vm->findResource(MKID('WRAP'), dataPtr); + if (wrap == NULL) + return 1; + + offs = _vm->findResourceData(MKID('OFFS'), wrap); + if (offs == NULL) + return 1; + + return _vm->getResourceDataSize(offs) / 4; + } else { + return 1; + } +} + +int Wiz::isWizPixelNonTransparent(int resNum, int state, int x, int y, int flags) { + int ret = 0; + uint8 *data = _vm->getResourceAddress(rtImage, resNum); + assert(data); + uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), data, state, 0); + assert(wizh); + int c = READ_LE_UINT32(wizh + 0x0); + int w = READ_LE_UINT32(wizh + 0x4); + int h = READ_LE_UINT32(wizh + 0x8); + uint8 *wizd = _vm->findWrappedBlock(MKID('WIZD'), data, state, 0); + assert(wizd); + if (x >= 0 && x < w && y >= 0 && y < h) { + if (flags & kWIFFlipX) { + x = w - x - 1; + } + if (flags & kWIFFlipY) { + y = h - y - 1; + } + switch (c) { + case 0: + if (_vm->_heversion >= 99) { + ret = getRawWizPixelColor(wizd, x, y, w, h, _vm->VAR(_vm->VAR_WIZ_TCOLOR)) != _vm->VAR(_vm->VAR_WIZ_TCOLOR) ? 1 : 0; + } else { + ret = 0; + } + break; + case 1: + ret = isWizPixelNonTransparent(wizd, x, y, w, h); + break; + case 2: + // Used baseball2003 + debug(0, "isWizPixelNonTransparent: Unhandled wiz compression type %d", c); + break; + default: + error("isWizPixelNonTransparent: Unhandled wiz compression type %d", c); + break; + } + } + return ret; +} + +uint8 Wiz::getWizPixelColor(int resNum, int state, int x, int y, int flags) { + uint8 color; + uint8 *data = _vm->getResourceAddress(rtImage, resNum); + assert(data); + uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), data, state, 0); + assert(wizh); + int c = READ_LE_UINT32(wizh + 0x0); + int w = READ_LE_UINT32(wizh + 0x4); + int h = READ_LE_UINT32(wizh + 0x8); + uint8 *wizd = _vm->findWrappedBlock(MKID('WIZD'), data, state, 0); + assert(wizd); + switch (c) { + case 0: + if (_vm->_heversion >= 99) { + color = getRawWizPixelColor(wizd, x, y, w, h, _vm->VAR(_vm->VAR_WIZ_TCOLOR)); + } else { + color = _vm->VAR(_vm->VAR_WIZ_TCOLOR); + } + break; + case 1: + color = getWizPixelColor(wizd, x, y, w, h, _vm->VAR(_vm->VAR_WIZ_TCOLOR)); + break; + default: + error("getWizPixelColor: Unhandled wiz compression type %d", c); + break; + } + return color; +} + +int ScummEngine_v90he::computeWizHistogram(int resNum, int state, int x, int y, int w, int h) { + writeVar(0, 0); + defineArray(0, kDwordArray, 0, 0, 0, 255); + if (readVar(0) != 0) { + Common::Rect rCapt(x, y, w + 1, h + 1); + uint8 *data = getResourceAddress(rtImage, resNum); + assert(data); + uint8 *wizh = findWrappedBlock(MKID('WIZH'), data, state, 0); + assert(wizh); + int c = READ_LE_UINT32(wizh + 0x0); + w = READ_LE_UINT32(wizh + 0x4); + h = READ_LE_UINT32(wizh + 0x8); + Common::Rect rWiz(w, h); + uint8 *wizd = findWrappedBlock(MKID('WIZD'), data, state, 0); + assert(wizd); + if (rCapt.intersects(rWiz)) { + rCapt.clip(rWiz); + uint32 histogram[256]; + memset(histogram, 0, sizeof(histogram)); + switch (c) { + case 0: + _wiz->computeRawWizHistogram(histogram, wizd, w, rCapt); + break; + case 1: + _wiz->computeWizHistogram(histogram, wizd, rCapt); + break; + default: + error("computeWizHistogram: Unhandled wiz compression type %d", c); + break; + } + for (int i = 0; i < 256; ++i) { + writeArray(0, 0, i, histogram[i]); + } + } + } + return readVar(0); +} + +} // End of namespace Scumm diff --git a/engines/scumm/he/wiz_he.h b/engines/scumm/he/wiz_he.h new file mode 100644 index 0000000000..86d3e97721 --- /dev/null +++ b/engines/scumm/he/wiz_he.h @@ -0,0 +1,211 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#if !defined(WIZ_HE_H) && !defined(DISABLE_HE) +#define WIZ_HE_H + +#include "common/rect.h" + +namespace Scumm { + +struct WizPolygon { + Common::Point vert[5]; + Common::Rect bound; + int id; + int numVerts; + bool flag; +}; + +struct WizImage { + int resNum; + int x1; + int y1; + int zorder; + int state; + int flags; + int shadow; + int field_390; + int palette; +}; + +struct WizParameters { + int field_0; + byte filename[260]; + Common::Rect box; + int processFlags; + int processMode; + int field_11C; + int field_120; + int field_124; + int field_128; + int field_12C; + int field_130; + int field_134; + int field_138; + int compType; + int fileWriteMode; + int angle; + int scale; + int field_164; + int field_168; + int resDefImgW; + int resDefImgH; + int sourceImage; + int field_180; + int field_184; + uint8 remapColor[256]; + uint8 remapIndex[256]; + int remapNum; + int dstResNum; + byte fillColor; + byte string1[4096]; + byte string2[4096]; + int field_2399; + int field_239D; + int field_23A1; + int field_23A5; + int field_23A9; + int field_23AD; + int field_23B1; + int field_23B5; + int field_23B9; + int field_23BD; + int field_23C1; + int field_23C5; + int field_23C9; + int field_23CD; + Common::Rect box2; + int field_23DE; + int spriteId; + int spriteGroup; + int field_23EA; + WizImage img; +}; + +enum WizImageFlags { + kWIFHasPalette = 0x1, + kWIFRemapPalette = 0x2, + kWIFPrint = 0x4, + kWIFBlitToFrontVideoBuffer = 0x8, + kWIFMarkBufferDirty = 0x10, + kWIFBlitToMemBuffer = 0x20, + kWIFIsPolygon = 0x40, + kWIFFlipX = 0x400, + kWIFFlipY = 0x800 +}; + +enum WizProcessFlags { + kWPFSetPos = 0x1, + kWPFShadow = 0x4, + kWPFScaled = 0x8, + kWPFRotate = 0x10, + kWPFNewFlags = 0x20, + kWPFRemapPalette = 0x40, + kWPFClipBox = 0x200, + kWPFNewState = 0x400, + kWPFUseFile = 0x800, + kWPFUseDefImgWidth = 0x2000, + kWPFUseDefImgHeight = 0x4000, + kWPFPaletteNum = 0x8000, + kWPFDstResNum = 0x10000, + kWPFFillColor = 0x20000, + kWPFClipBox2 = 0x40000, + kWPFMaskImg = 0x80000 +}; + +class ScummEngine_v70he; + +class Wiz { +public: + enum { + NUM_POLYGONS = 200, + NUM_IMAGES = 255 + }; + + WizImage _images[NUM_IMAGES]; + uint16 _imagesNum; + WizPolygon _polygons[NUM_POLYGONS]; + + Wiz(ScummEngine_v70he *vm); + + void clearWizBuffer(); + Common::Rect _rectOverride; + bool _rectOverrideEnabled; + + void polygonClear(); + void polygonLoad(const uint8 *polData); + void polygonStore(int id, bool flag, int vert1x, int vert1y, int vert2x, int vert2y, int vert3x, int vert3y, int vert4x, int vert4y); + void polygonCalcBoundBox(Common::Point *vert, int numVerts, Common::Rect & bound); + void polygonErase(int fromId, int toId); + int polygonHit(int id, int x, int y); + bool polygonDefined(int id); + bool polygonContains(const WizPolygon &pol, int x, int y); + void polygonRotatePoints(Common::Point *pts, int num, int alpha); + void polygonTransform(int resNum, int state, int po_x, int po_y, int angle, int zoom, Common::Point *vert); + + void createWizEmptyImage(const WizParameters *params); + void fillWizRect(const WizParameters *params); + void fillWizLine(const WizParameters *params); + void fillWizPixel(const WizParameters *params); + void fillWizFlood(const WizParameters *params); + void remapWizImagePal(const WizParameters *params); + + void getWizImageDim(int resNum, int state, int32 &w, int32 &h); + int getWizImageStates(int resnum); + int isWizPixelNonTransparent(int resnum, int state, int x, int y, int flags); + uint8 getWizPixelColor(int resnum, int state, int x, int y, int flags); + int getWizImageData(int resNum, int state, int type); + + void flushWizBuffer(); + + void getWizImageSpot(int resId, int state, int32 &x, int32 &y); + void loadWizCursor(int resId); + + void captureWizImage(int resNum, const Common::Rect& r, bool frontBuffer, int compType); + void displayWizComplexImage(const WizParameters *params); + void displayWizImage(WizImage *pwi); + void processWizImage(const WizParameters *params); + + uint8 *drawWizImage(int resNum, int state, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, int palette); + void drawWizPolygon(int resNum, int state, int id, int flags, int shadow, int dstResNum, int palette); + void drawWizComplexPolygon(int resNum, int state, int po_x, int po_y, int shadow, int angle, int zoom, const Common::Rect *r, int flags, int dstResNum, int palette); + void drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int flags, int shadow, int dstResNum, int palette); + + static void copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch); + static void copyWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags = 0, const uint8 *palPtr = NULL, const uint8 *xmapPtr = NULL); + static void copyRawWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor); + static void copyRaw16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor); + static void decompressWizImage(uint8 *dst, int dstPitch, const Common::Rect &dstRect, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr = NULL, const uint8 *xmapPtr = NULL); + int isWizPixelNonTransparent(const uint8 *data, int x, int y, int w, int h); + uint8 getWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color); + uint8 getRawWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color); + void computeWizHistogram(uint32 *histogram, const uint8 *data, const Common::Rect& rCapt); + void computeRawWizHistogram(uint32 *histogram, const uint8 *data, int srcPitch, const Common::Rect& rCapt); + +private: + ScummEngine_v70he *_vm; +}; + +} // End of namespace Scumm + +#endif diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp index ad890604c4..7073bd596f 100644 --- a/engines/scumm/input.cpp +++ b/engines/scumm/input.cpp @@ -34,9 +34,9 @@ #include "scumm/insane/insane.h" #include "scumm/imuse.h" #ifndef DISABLE_HE -#include "scumm/intern_he.h" +#include "scumm/he/intern_he.h" +#include "scumm/he/logic_he.h" #endif -#include "scumm/logic_he.h" #include "scumm/scumm.h" #include "scumm/sound.h" diff --git a/engines/scumm/intern_he.h b/engines/scumm/intern_he.h deleted file mode 100644 index 7a4917b8c9..0000000000 --- a/engines/scumm/intern_he.h +++ /dev/null @@ -1,606 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#ifndef SCUMM_INTERN_HE_H -#define SCUMM_INTERN_HE_H - -#include "scumm/intern.h" -#ifndef DISABLE_HE -#include "scumm/floodfill_he.h" -#include "scumm/wiz_he.h" -#endif - -namespace Scumm { - -#ifndef DISABLE_HE -class ResExtractor; -class LogicHE; -class Sprite; -#endif - -class ScummEngine_v60he : public ScummEngine_v6 { -protected: - typedef void (ScummEngine_v60he::*OpcodeProcv60he)(); - struct OpcodeEntryv60he { - OpcodeProcv60he proc; - const char *desc; - }; - - const OpcodeEntryv60he *_opcodesv60he; - - Common::File _hFileTable[17]; - -public: - ScummEngine_v60he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex) : ScummEngine_v6(detector, syst, gs, md5sum, substResFileNameIndex) {} - - virtual void scummInit(); - -protected: - virtual void setupOpcodes(); - virtual void executeOpcode(byte i); - virtual const char *getOpcodeDesc(byte i); - - virtual void saveOrLoad(Serializer *s); - - void localizeArray(int slot, byte scriptSlot); - void redimArray(int arrayId, int newX, int newY, int d); - int readFileToArray(int slot, int32 size); - void writeFileFromArray(int slot, int resID); - int virtScreenSave(byte *dst, int x1, int y1, int x2, int y2); - void virtScreenLoad(int resIdx, int x1, int y1, int x2, int y2); - virtual void decodeParseString(int a, int b); - void swapObjects(int object1, int object2); - - /* HE version 60 script opcodes */ - void o60_setState(); - void o60_roomOps(); - void o60_actorOps(); - void o60_kernelSetFunctions(); - void o60_kernelGetFunctions(); - void o60_openFile(); - void o60_closeFile(); - void o60_deleteFile(); - void o60_readFile(); - void o60_rename(); - void o60_writeFile(); - void o60_soundOps(); - void o60_seekFilePos(); - void o60_localizeArrayToScript(); - void o60_redimArray(); - void o60_readFilePos(); -}; - -#ifndef DISABLE_HE -class ScummEngine_v70he : public ScummEngine_v60he { - friend class ResExtractor; - friend class Wiz; - -protected: - typedef void (ScummEngine_v70he::*OpcodeProcv70he)(); - struct OpcodeEntryv70he { - OpcodeProcv70he proc; - const char *desc; - }; - - const OpcodeEntryv70he *_opcodesv70he; - - ResExtractor *_resExtractor; - - byte *_heV7RoomOffsets; - - int32 _heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags, _heSndSoundFreq; - - bool _skipProcessActors; - -public: - ScummEngine_v70he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex); - ~ScummEngine_v70he(); - - Wiz *_wiz; - - byte *heFindResourceData(uint32 tag, byte *ptr); - byte *heFindResource(uint32 tag, byte *ptr); - byte *findWrappedBlock(uint32 tag, byte *ptr, int state, bool flagError); - -protected: - virtual void setupOpcodes(); - virtual void executeOpcode(byte i); - virtual const char *getOpcodeDesc(byte i); - - virtual void setupScummVars(); - virtual void initScummVars(); - - virtual void saveOrLoad(Serializer *s); - - virtual void readRoomsOffsets(); - virtual void readGlobalObjects(); - virtual void readIndexBlock(uint32 blocktype, uint32 itemsize); - - virtual int getActorFromPos(int x, int y); - - int getStringCharWidth(byte chr); - virtual int setupStringArray(int size); - void appendSubstring(int dst, int src, int len2, int len); - - virtual void setCursorFromImg(uint img, uint room, uint imgindex); - - virtual void clearDrawQueues(); - - void remapHEPalette(const uint8 *src, uint8 *dst); - - /* HE version 70 script opcodes */ - void o70_startSound(); - void o70_pickupObject(); - void o70_getActorRoom(); - void o70_resourceRoutines(); - void o70_systemOps(); - void o70_kernelSetFunctions(); - void o70_seekFilePos(); - void o70_copyString(); - void o70_getStringWidth(); - void o70_getStringLen(); - void o70_appendString(); - void o70_concatString(); - void o70_compareString(); - void o70_isResourceLoaded(); - void o70_readINI(); - void o70_writeINI(); - void o70_getStringLenForWidth(); - void o70_getCharIndexInString(); - void o70_setFilePath(); - void o70_setSystemMessage(); - void o70_polygonOps(); - void o70_polygonHit(); - - byte VAR_NUM_SOUND_CHANNELS; - byte VAR_WIZ_TCOLOR; -}; - -class ScummEngine_v71he : public ScummEngine_v70he { -public: - ScummEngine_v71he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex); - -protected: - virtual void saveOrLoad(Serializer *s); - - virtual void redrawBGAreas(); - - virtual void processActors(); - void preProcessAuxQueue(); - void postProcessAuxQueue(); - -public: - /* Actor AuxQueue stuff (HE) */ - AuxBlock _auxBlocks[16]; - uint16 _auxBlocksNum; - AuxEntry _auxEntries[16]; - uint16 _auxEntriesNum; - - void queueAuxBlock(Actor *a); - void queueAuxEntry(int actorNum, int subIndex); -}; - -class ScummEngine_v72he : public ScummEngine_v71he { -protected: - typedef void (ScummEngine_v72he::*OpcodeProcV72he)(); - struct OpcodeEntryV72he { - OpcodeProcV72he proc; - const char *desc; - }; - -#if !defined(__GNUC__) - #pragma START_PACK_STRUCTS -#endif - - struct ArrayHeader { - int32 type; //0 - int32 dim1start; //4 - int32 dim1end; //8 - int32 dim2start; //0C - int32 dim2end; //10 - byte data[1]; //14 - } GCC_PACK; - -#if !defined(__GNUC__) - #pragma END_PACK_STRUCTS -#endif - - const OpcodeEntryV72he *_opcodesV72he; - - int _stringLength; - byte _stringBuffer[4096]; - - WizParameters _wizParams; - -public: - ScummEngine_v72he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex); - - virtual void scummInit(); - -protected: - virtual void setupOpcodes(); - virtual void executeOpcode(byte i); - virtual const char *getOpcodeDesc(byte i); - - virtual void setupScummVars(); - virtual void initScummVars(); - virtual void readArrayFromIndexFile(); - - virtual byte *getStringAddress(int i); - virtual void readMAXS(int blockSize); - - virtual void redrawBGAreas(); - - ArrayHeader *defineArray(int array, int type, int dim2start, int dim2end, int dim1start, int dim1end); - virtual int readArray(int array, int idx2, int idx1); - virtual void writeArray(int array, int idx2, int idx1, int value); - void redimArray(int arrayId, int newDim2start, int newDim2end, - int newDim1start, int newDim1end, int type); - void checkArrayLimits(int array, int dim2start, int dim2end, int dim1start, int dim1end); - void copyArray(int array1, int a1_dim2start, int a1_dim2end, int a1_dim1start, int a1_dim1end, - int array2, int a2_dim2start, int a2_dim2end, int a2_dim1start, int a2_dim1end); - void copyArrayHelper(ArrayHeader *ah, int idx2, int idx1, int len1, byte **data, int *size, int *num); - virtual int setupStringArray(int size); - int readFileToArray(int slot, int32 size); - void writeFileFromArray(int slot, int32 resID); - - virtual void decodeParseString(int a, int b); - void decodeScriptString(byte *dst, bool scriptString = false); - void copyScriptString(byte *dst, int dstSize); - int convertFilePath(byte *dst, bool setFilePath = false); - - int findObject(int x, int y, int num, int *args); - int getSoundResourceSize(int id); - - virtual bool handleNextCharsetCode(Actor *a, int *c); - - /* HE version 72 script opcodes */ - void o72_pushDWord(); - void o72_getScriptString(); - void o72_isAnyOf(); - void o72_resetCutscene(); - void o72_findObjectWithClassOf(); - void o72_getObjectImageX(); - void o72_getObjectImageY(); - void o72_captureWizImage(); - void o72_getTimer(); - void o72_setTimer(); - void o72_getSoundPosition(); - void o72_startScript(); - void o72_startObject(); - void o72_drawObject(); - void o72_printWizImage(); - void o72_getArrayDimSize(); - void o72_getNumFreeArrays(); - void o72_roomOps(); - void o72_actorOps(); - void o72_verbOps(); - void o72_findObject(); - void o72_arrayOps(); - void o72_systemOps(); - void o72_talkActor(); - void o72_talkEgo(); - void o72_dimArray(); - void o72_dim2dimArray(); - void o72_traceStatus(); - void o72_debugInput(); - void o72_drawWizImage(); - void o72_kernelGetFunctions(); - void o72_jumpToScript(); - void o72_openFile(); - void o72_readFile(); - void o72_writeFile(); - void o72_findAllObjects(); - void o72_deleteFile(); - void o72_rename(); - void o72_getPixel(); - void o72_pickVarRandom(); - void o72_redimArray(); - void o72_readINI(); - void o72_writeINI(); - void o72_getResourceSize(); - void o72_setFilePath(); - void o72_setSystemMessage(); - - byte VAR_NUM_ROOMS; - byte VAR_NUM_SCRIPTS; - byte VAR_NUM_SOUNDS; - byte VAR_NUM_COSTUMES; - byte VAR_NUM_IMAGES; - byte VAR_NUM_CHARSETS; - - byte VAR_POLYGONS_ONLY; -}; - -class ScummEngine_v80he : public ScummEngine_v72he { -protected: - typedef void (ScummEngine_v80he::*OpcodeProcV80he)(); - struct OpcodeEntryV80he { - OpcodeProcV80he proc; - const char *desc; - }; - - const OpcodeEntryV80he *_opcodesV80he; - - int32 _heSndResId, _curSndId, _sndPtrOffs, _sndTmrOffs; - -public: - ScummEngine_v80he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex); - -protected: - virtual void setupOpcodes(); - virtual void executeOpcode(byte i); - virtual const char *getOpcodeDesc(byte i); - - virtual void setupScummVars(); - virtual void initScummVars(); - - virtual void initCharset(int charset); - - virtual void clearDrawQueues(); - - void createSound(int snd1id, int snd2id); - - void drawLine(int x1, int y1, int x, int unk1, int unk2, int type, int id); - void drawPixel(int x, int y, int flags); - - /* HE version 80 script opcodes */ - void o80_createSound(); - void o80_getFileSize(); - void o80_stringToInt(); - void o80_getSoundVar(); - void o80_localizeArrayToRoom(); - void o80_sourceDebug(); - void o80_readConfigFile(); - void o80_writeConfigFile(); - void o80_cursorCommand(); - void o80_setState(); - void o80_drawWizPolygon(); - void o80_drawLine(); - void o80_pickVarRandom(); - - byte VAR_PLATFORM; - byte VAR_WINDOWS_VERSION; - byte VAR_CURRENT_CHARSET; - byte VAR_COLOR_DEPTH; -}; - -class ScummEngine_v90he : public ScummEngine_v80he { - friend class LogicHE; - friend class Sprite; - -protected: - typedef void (ScummEngine_v90he::*OpcodeProcV90he)(); - struct OpcodeEntryV90he { - OpcodeProcV90he proc; - const char *desc; - }; - - const OpcodeEntryV90he *_opcodesV90he; - - FloodFillParameters _floodFillParams; - - struct VideoParameters { - byte filename[260]; - int32 status; - int32 flags; - int32 unk2; - int32 wizResNum; - }; - - VideoParameters _videoParams; - - int32 _heObject, _heObjectNum; - int32 _hePaletteNum; - - int32 _curMaxSpriteId; - int32 _curSpriteId; - int32 _curSpriteGroupId; - -public: - ScummEngine_v90he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex); - ~ScummEngine_v90he(); - - virtual void scummInit(); - - LogicHE *_logicHE; - Sprite *_sprite; - -protected: - virtual void allocateArrays(); - virtual void setupOpcodes(); - virtual void executeOpcode(byte i); - virtual const char *getOpcodeDesc(byte i); - - virtual void setupScummVars(); - virtual void initScummVars(); - - virtual void saveOrLoad(Serializer *s); - - virtual void readMAXS(int blockSize); - - virtual void processActors(); - - int computeWizHistogram(int resnum, int state, int x, int y, int w, int h); - void getArrayDim(int array, int *dim2start, int *dim2end, int *dim1start, int *dim1end); - void sortArray(int array, int dim2start, int dim2end, int dim1start, int dim1end, int sortOrder); - -public: - int getGroupSpriteArray(int spriteGroupId); - -protected: - uint8 *getHEPaletteIndex(int palSlot); - int getHEPaletteColor(int palSlot, int color); - int getHEPaletteSimilarColor(int palSlot, int red, int green, int start, int end); - int getHEPaletteColorComponent(int palSlot, int color, int component); - void setHEPaletteColor(int palSlot, uint8 color, uint8 r, uint8 g, uint8 b); - void setHEPaletteFromPtr(int palSlot, const uint8 *palData); - void setHEPaletteFromCostume(int palSlot, int resId); - void setHEPaletteFromImage(int palSlot, int resId, int state); - void setHEPaletteFromRoom(int palSlot, int resId, int state); - void restoreHEPalette(int palSlot); - void copyHEPalette(int dstPalSlot, int srcPalSlot); - void copyHEPaletteColor(int palSlot, uint8 dstColor, uint8 srcColor); - - - void setDefaultCursor(); - -protected: - /* HE version 90 script opcodes */ - void o90_dup_n(); - void o90_min(); - void o90_max(); - void o90_sin(); - void o90_cos(); - void o90_sqrt(); - void o90_atan2(); - void o90_getSegmentAngle(); - void o90_getActorData(); - void o90_startScriptUnk(); - void o90_jumpToScriptUnk(); - void o90_videoOps(); - void o90_getVideoData(); - void o90_wizImageOps(); - void o90_getDistanceBetweenPoints(); - void o90_getSpriteInfo(); - void o90_setSpriteInfo(); - void o90_getSpriteGroupInfo(); - void o90_setSpriteGroupInfo(); - void o90_getWizData(); - void o90_floodFill(); - void o90_mod(); - void o90_shl(); - void o90_shr(); - void o90_xor(); - void o90_findAllObjectsWithClassOf(); - void o90_getPolygonOverlap(); - void o90_cond(); - void o90_dim2dim2Array(); - void o90_redim2dimArray(); - void o90_getLinesIntersectionPoint(); - void o90_sortArray(); - void o90_getObjectData(); - void o90_getPaletteData(); - void o90_paletteOps(); - void o90_fontUnk(); - void o90_getActorAnimProgress(); - void o90_kernelGetFunctions(); - void o90_kernelSetFunctions(); - - byte VAR_NUM_SPRITE_GROUPS; - byte VAR_NUM_SPRITES; - byte VAR_NUM_PALETTES; - byte VAR_NUM_UNK; - - byte VAR_U32_VERSION; - byte VAR_U32_ARRAY_UNK; -}; - -class ScummEngine_v99he : public ScummEngine_v90he { -public: - ScummEngine_v99he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex) : ScummEngine_v90he(detector, syst, gs, md5sum, substResFileNameIndex) {} - - virtual void scummInit(); - -protected: - virtual void initScummVars(); - - virtual void readMAXS(int blockSize); - - virtual void saveOrLoad(Serializer *s); - - virtual void copyPalColor(int dst, int src); - virtual void darkenPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor); - virtual void setPaletteFromPtr(const byte *ptr, int numcolor = -1); - virtual void setPalColor(int index, int r, int g, int b); - virtual void updatePalette(); -}; - -class ScummEngine_v100he : public ScummEngine_v99he { -protected: - typedef void (ScummEngine_v100he::*OpcodeProcV100he)(); - struct OpcodeEntryV100he { - OpcodeProcV100he proc; - const char *desc; - }; - - int32 _heResId, _heResType; - - const OpcodeEntryV100he *_opcodesV100he; - -public: - ScummEngine_v100he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex) : ScummEngine_v99he(detector, syst, gs, md5sum, substResFileNameIndex) {} - -protected: - virtual void setupOpcodes(); - virtual void executeOpcode(byte i); - virtual const char *getOpcodeDesc(byte i); - - virtual void saveOrLoad(Serializer *s); - - virtual void decodeParseString(int a, int b); - - /* HE version 100 script opcodes */ - void o100_actorOps(); - void o100_arrayOps(); - void o100_dim2dimArray(); - void o100_redim2dimArray(); - void o100_dimArray(); - void o100_drawLine(); - void o100_drawObject(); - void o100_floodFill(); - void o100_setSpriteGroupInfo(); - void o100_resourceRoutines(); - void o100_wizImageOps(); - void o100_jumpToScript(); - void o100_createSound(); - void o100_dim2dim2Array(); - void o100_paletteOps(); - void o100_jumpToScriptUnk(); - void o100_startScriptUnk(); - void o100_redimArray(); - void o100_roomOps(); - void o100_setSystemMessage(); - void o100_startSound(); - void o100_setSpriteInfo(); - void o100_startScript(); - void o100_systemOps(); - void o100_cursorCommand(); - void o100_videoOps(); - void o100_wait(); - void o100_writeFile(); - void o100_isResourceLoaded(); - void o100_getResourceSize(); - void o100_getSpriteGroupInfo(); - void o100_getPaletteData(); - void o100_readFile(); - void o100_getSpriteInfo(); - void o100_getWizData(); - void o100_getVideoData(); -}; -#endif - - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/logic_he.cpp b/engines/scumm/logic_he.cpp deleted file mode 100644 index 401a41def5..0000000000 --- a/engines/scumm/logic_he.cpp +++ /dev/null @@ -1,836 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2005-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" - -#include "scumm/intern_he.h" -#include "scumm/logic_he.h" - -namespace Scumm { - -LogicHE::LogicHE(ScummEngine_v90he *vm) : _vm(vm) { - // Originally it used 0x930 and stored both floats and doubles inside - _userData = (float *)calloc(550, sizeof(float)); - _userDataD = (double *)calloc(30, sizeof(double)); -} - -LogicHE::~LogicHE() { - free(_userData); - free(_userDataD); -} - -void LogicHE::writeScummVar(int var, int32 value) { - _vm->writeVar(var, value); -} - -static int32 scumm_round(double arg) { - return (int32)(arg + 0.5); -} - -int LogicHE::versionID() { - return 1; -} - -int LogicHE::getFromArray(int arg0, int idx2, int idx1) { - _vm->VAR(_vm->VAR_U32_ARRAY_UNK) = arg0; - return _vm->readArray(116, idx2, idx1); -} - -void LogicHE::putInArray(int arg0, int idx2, int idx1, int val) { - _vm->VAR(_vm->VAR_U32_ARRAY_UNK) = arg0; - _vm->writeArray(116, idx2, idx1, val); -} - -int32 LogicHE::dispatch(int op, int numArgs, int32 *args) { -#if 1 - char tmp[32], str[256]; - - if (numArgs > 0) - snprintf(tmp, 32, "%d", args[0]); - else - *tmp = 0; - - snprintf(str, 256, "LogicHE::dispatch(%d, %d, [%s", op, numArgs, tmp); - - for (int i = 1; i < numArgs; i++) { - snprintf(tmp, 32, ", %d", args[i]); - strncat(str, tmp, 256); - } - strncat(str, "])", 256); - - debug(0, str); -#else - // Used for parallel trace utility - for (int i = 0; i < numArgs; i++) - debug(0, "args[%d] = %d;", i, args[i]); - - debug(0, "dispatch(%d, %d, args);", op, numArgs); - -#endif - - return 1; -} - -/*********************** - * Putt-Putt Joins the Race - * - */ - -int LogicHErace::versionID() { - return 1; -} - -int32 LogicHErace::dispatch(int op, int numArgs, int32 *args) { - int32 res; - - switch (op) { - case 1003: - res = op_1003(args); - break; - - case 1004: - res = op_1004(args); - break; - - case 1100: - res = op_1100(args); - break; - - case 1101: - res = op_1101(args); - break; - - case 1102: - res = op_1102(args); - break; - - case 1103: - res = op_1103(args); - break; - - case 1110: - res = op_1110(); - break; - - case 1120: - res = op_1120(args); - break; - - case 1130: - res = op_1130(args); - break; - - case 1140: - res = op_1140(args); - break; - - default: - res = 0; - break; - - } - - return res; -} - -#define RAD2DEG (180 / PI) -#define DEG2RAD (PI / 180) - -int32 LogicHErace::op_1003(int32 *args) { - int value = args[2] ? args[2] : 1; - - writeScummVar(108, (int32)(atan2((double)args[0], (double)args[1]) * RAD2DEG * value)); - - return 1; -} - -int32 LogicHErace::op_1004(int32 *args) { - int value = args[1] ? args[1] : 1; - - writeScummVar(108, (int32)(sqrt((float)args[0]) * value)); - - return 1; -} - -int32 LogicHErace::op_1100(int32 *args) { - _userData[516] = (float)args[0] / args[10]; - _userData[517] = (float)args[1] / args[10]; - _userData[518] = (float)args[2] / args[10]; - _userData[519] = (float)args[3] / args[10]; - _userData[520] = (float)args[4] / args[10]; - - op_sub1(_userData[520]); - - _userData[521] = (float)args[5] / args[10]; - - op_sub2(_userData[521]); - - _userData[532] = (float)args[10]; - - _userData[524] = (float)args[8]; - _userData[525] = (float)args[9]; - _userData[522] = (float)args[6] / args[10]; - _userData[523] = (float)args[7] / args[10]; - _userData[526] = (float)args[6] / args[8] / args[10]; - _userData[527] = (float)args[7] / args[9] / args[10]; - - writeScummVar(108, (int32)((float)args[6] / args[8] * args[10])); - - writeScummVar(109, (int32)((float)args[7] / args[9] * args[10])); - - _userData[528] = (float)(_userData[519] - _userData[523] * 0.5); - _userData[529] = (float)(_userData[519] + _userData[523] * 0.5); - - writeScummVar(110, (int32)(_userData[528] * args[10])); - writeScummVar(111, (int32)(_userData[529] * args[10])); - - _userData[530] = (float)(_userData[517] / tan(_userData[529] * DEG2RAD)); - _userData[531] = (float)(_userData[517] / tan(_userData[528] * DEG2RAD)); - - writeScummVar(112, (int32)(_userData[530] * args[10])); - writeScummVar(113, (int32)(_userData[531] * args[10])); - - return 1; -} - -int32 LogicHErace::op_1101(int32 *args) { - int32 retval; - float temp; - - temp = args[0] / _userData[532]; - - if (_userData[519] == temp) { - retval = (int32)temp; - } else { - _userData[519] = temp; - op_sub3(temp); - retval = 1; - } - - temp = args[1] / _userData[532]; - - if (_userData[520] != temp) { - _userData[520] = temp; - op_sub1(temp); - retval = 1; - } - - temp = args[2] / _userData[532]; - - if (_userData[521] != temp) { - _userData[521] = temp; - op_sub2(temp); - retval = 1; - } - - return retval; -} - -int32 LogicHErace::op_1102(int32 *args) { - int32 retval; - float temp; - - temp = args[0] / _userData[532]; - if (_userData[516] != temp) { - _userData[516] = temp; - retval = 1; - } else { - retval = (int32)_userData[532]; - } - - temp = args[1] / _userData[532]; - if (_userData[517] != temp) { - _userData[517] = temp; - retval = 1; - } - - temp = args[2] / _userData[532]; - if (_userData[518] != temp) { - _userData[518] = temp; - retval = 1; - } - - return retval; -} - -int32 LogicHErace::op_1103(int32 *args) { - double angle = args[0] / args[1] * DEG2RAD; - - writeScummVar(108, (int32)(sin(angle) * args[2])); - writeScummVar(109, (int32)(cos(angle) * args[2])); - - return 1; -} - -int32 LogicHErace::op_1110() { - writeScummVar(108, (int32)(_userData[526] * _userData[532] * _userData[532])); - writeScummVar(109, (int32)(_userData[527] * _userData[532] * _userData[532])); - writeScummVar(110, (int32)(_userData[532])); - - return 1; -} - -int32 LogicHErace::op_1120(int32 *args) { - double a0, a1, a2, expr; - double res1, res2; - - a0 = args[0] / _userData[532] - _userData[516]; - a1 = args[1] / _userData[532] - _userData[517]; - a2 = args[2] / _userData[532] - _userData[518]; - - expr = a2 * _userDataD[17] + a1 * _userDataD[14] + a0 * _userDataD[11]; - - res1 = (atan2(a2 * _userDataD[15] + a1 * _userDataD[12] + a0 * _userDataD[9], expr) * RAD2DEG) - / _userData[526]; - res2 = (atan2(a2 * _userDataD[16] + a1 * _userDataD[13] + a0 * _userDataD[10], expr) * RAD2DEG - - _userData[528]) / _userData[527]; - - writeScummVar(108, (int32)res1); - writeScummVar(109, (int32)res2); - - return 1; -} - -int32 LogicHErace::op_1130(int32 *args) { - double cs = cos(args[0] / _userData[532] * DEG2RAD); - double sn = sin(args[0] / _userData[532] * DEG2RAD); - - writeScummVar(108, (int32)(cs * args[1] + sn * args[2])); - - writeScummVar(109, (int32)(cs * args[2] - sn * args[1])); - - return 1; -} - -int32 LogicHErace::op_1140(int32 *args) { - double arg2 = -args[2] * args[2]; - double arg3 = -args[3] * args[3]; - double sq = sqrt(arg2 + arg3); - double res; - - arg2 = arg2 / sq; - arg3 = arg3 / sq; - - res = (args[0] - 2 * (arg2 * args[0] + arg3 * args[1]) * arg2) * 0.86956525; - - writeScummVar(108, (int32)res); - - res = args[1] - 2 * (arg2 * args[0] + arg3 * args[1]) * arg3; - - if (-args[3] * args[3] >= 0) - res *= 0.83333331f; - - writeScummVar(109, (int32)res); - - return 1; -} - -void LogicHErace::op_sub1(float arg) { - _userDataD[10] = _userDataD[12] = _userDataD[14] = _userDataD[16] = 0; - _userDataD[13] = 1; - - _userDataD[9] = cos(arg * DEG2RAD); - _userDataD[15] = sin(arg * DEG2RAD); - _userDataD[11] = -_userDataD[15]; - _userDataD[17] = _userDataD[9]; -} - -void LogicHErace::op_sub2(float arg) { - _userDataD[20] = _userDataD[21] = _userDataD[24] = _userDataD[25] = 0; - _userDataD[26] = 1; - - _userDataD[19] = sin(arg * DEG2RAD); - _userDataD[18] = cos(arg * DEG2RAD); - _userDataD[21] = -_userDataD[19]; - _userDataD[22] = _userDataD[18]; -} - -void LogicHErace::op_sub3(float arg) { - _userDataD[1] = _userDataD[2] = _userDataD[3] = _userDataD[6] = 0; - _userDataD[0] = 1; - - _userDataD[4] = cos(arg * DEG2RAD); - _userDataD[5] = sin(arg * DEG2RAD); - _userDataD[7] = -_userDataD[5]; - _userDataD[8] = _userDataD[4]; -} - -/*********************** - * Freddi Fish's One-Stop Fun Shop - * Pajama Sam's One-Stop Fun Shop - * Putt-Putt's One-Stop Fun Shop - * - */ - -int LogicHEfunshop::versionID() { - return 1; -} - -int32 LogicHEfunshop::dispatch(int op, int numArgs, int32 *args) { - switch (op) { - case 1004: - op_1004(args); - break; - - case 1005: - op_1005(args); - break; - - default: - break; - - } - - return 0; -} - -void LogicHEfunshop::op_1004(int32 *args) { - double data[8], at, sq; - int32 x, y; - int i=0; - - for (i = 0; i <= 6; i += 2) { - data[i] = getFromArray(args[0], 0, 519 + i); - data[i + 1] = getFromArray(args[0], 0, 519 + i + 1); - } - int s = checkShape((int32)data[0], (int32)data[1], (int32)data[4], (int32)data[5], - (int32)data[2], (int32)data[3], (int32)data[6], (int32)data[7], &x, &y); - - if (s != 1) { - error("LogicHEfunshop::op_1004: Your shape has defied the laws of physics\n"); - return; - } - - for (i = 0; i <= 6; i += 2) { - data[i] -= (double)x; - data[i + 1] -= (double)y; - } - - double a1 = (double)args[1] * DEG2RAD; - - for (i = 0; i <= 6; i += 2) { - at = atan2(data[i + 1], data[i]); - sq = sqrt(data[i + 1] * data[i + 1] + data[i] * data[i]); - - if (at <= 0) - at += 2 * PI; - - data[i] = cos(at + a1) * sq; - data[i + 1] = sin(at + a1) * sq; - } - - int minx = 2; - int miny = 3; - - for (i = 0; i <= 6; i += 2) { - if (data[i] < data[minx]) - minx = i; - if (data[i + 1] < data[miny]) - miny = i + 1; - } - - for (i = 0; i <= 6; i += 2) { - data[i] -= data[minx]; - data[i + 1] -= data[miny]; - - putInArray(args[0], 0, 519 + i, scumm_round(data[i])); - putInArray(args[0], 0, 519 + i + 1, scumm_round(data[i + 1])); - } -} - -void LogicHEfunshop::op_1005(int32 *args) { - double data[8]; - double args1, args2; - int i=0; - for (i = 520; i <= 526; i += 2) { - data[i - 520] = getFromArray(args[0], 0, i - 1); - data[i - 520 + 1] = getFromArray(args[0], 0, i); - } - - args1 = args[1] * 0.01 + 1; - args2 = args[2] * 0.01 + 1; - - for (i = 0; i < 4; i++) { - data[2 * i] *= args1; - data[2 * i + 1] *= args2; - } - - for (i = 520; i <= 526; i += 2) { - putInArray(args[0], 0, i - 1, scumm_round(data[i - 520])); - putInArray(args[0], 0, i, scumm_round(data[i - 520 + 1])); - } -} - -int LogicHEfunshop::checkShape(int32 data0, int32 data1, int32 data4, int32 data5, int32 data2, int32 data3, int32 data6, int32 data7, int32 *x, int32 *y) { - int32 diff5_1, diff0_4, diff7_3, diff2_6; - int32 diff1, diff2; - int32 delta, delta2; - int32 sum1, sum2; - - diff0_4 = data0 - data4; - diff5_1 = data5 - data1; - diff1 = data1 * data4 - data0 * data5; - sum1 = diff0_4 * data3 + diff1 + diff5_1 * data2; - sum2 = diff0_4 * data7 + diff1 + diff5_1 * data6; - - if (sum1 != 0 && sum2 != 0) { - sum2 ^= sum1; - - if (sum2 >= 0) - return 0; - } - - diff2_6 = data2 - data6; - diff7_3 = data7 - data3; - diff2 = data3 * data6 - data2 * data7; - sum1 = diff2_6 * data1 + diff2 + diff7_3 * data0; - sum2 = diff2_6 * data5 + diff2 + diff7_3 * data4;; - - if (sum1 != 0 && sum2 != 0) { - sum2 ^= sum1; - - if (sum2 >= 0) - return 0; - } - - delta = diff2_6 * diff5_1 - diff0_4 * diff7_3; - - if (delta == 0) { - return 2; - } - - if (delta < 0) { - data7 = -((delta + 1) >> 1); - } else { - data7 = delta >> 1; - } - - delta2 = diff2 * diff0_4 - diff1 * diff2_6; - - if (delta2 < 0) { - delta2 -= data7; - } else { - delta2 += data7; - } - - *x = delta2 / delta; - - delta2 = diff1 * diff7_3 - diff2 * diff5_1; - - if (delta2 < 0) { - delta2 -= data7; - } else { - delta2 += data7; - } - - *y = delta2 / delta; - - return 1; -} - -/*********************** - * Backyard Football - * Backyard Football Demo - * - */ - -int LogicHEfootball::versionID() { - return 1; -} - -int32 LogicHEfootball::dispatch(int op, int numArgs, int32 *args) { - int res = 0; - - switch (op) { - case 1004: - res = op_1004(args); - break; - - case 1006: - res = op_1006(args); - break; - - case 1007: - res = op_1007(args); - break; - - case 1010: - res = op_1010(args); - break; - - case 1022: - res = op_1022(args); - break; - - case 1023: - res = op_1023(args); - break; - - case 1024: - res = op_1024(args); - break; - - case 8221968: - // Someone had a fun and used his birthday as opcode number - res = getFromArray(args[0], args[1], args[2]); - break; - - case 1492: case 1493: case 1494: case 1495: case 1496: - case 1497: case 1498: case 1499: case 1500: case 1501: - case 1502: case 1503: case 1504: case 1505: case 1506: - case 1507: case 1508: case 1509: case 1510: case 1511: - case 1512: case 1513: case 1514: case 1555: - // DirectPlay-related - // 1513: initialize - // 1555: set fake lag - break; - - case 2200: case 2201: case 2202: case 2203: case 2204: - case 2205: case 2206: case 2207: case 2208: case 2209: - case 2210: case 2211: case 2212: case 2213: case 2214: - case 2215: case 2216: case 2217: case 2218: case 2219: - case 2220: case 2221: case 2222: case 2223: case 2224: - case 2225: case 2226: case 2227: case 2228: - // Boneyards-related - break; - - case 3000: case 3001: case 3002: case 3003: case 3004: - // Internet-related - // 3000: check for updates - // 3001: check network status - // 3002: autoupdate - // 3003: close connection - break; - - default: - LogicHE::dispatch(op, numArgs, args); - error("Tell sev how to reproduce it"); - } - - return res; -} - -int LogicHEfootball::op_1004(int32 *args) { - double res, a2, a4, a5; - - a5 = ((double)args[4] - (double)args[1]) / ((double)args[5] - (double)args[2]); - a4 = ((double)args[3] - (double)args[0]) / ((double)args[5] - (double)args[2]); - a2 = (double)args[2] - (double)args[0] * a4 - args[1] * a5; - - res = (double)args[6] * a4 + (double)args[7] * a5 + a2; - writeScummVar(108, (int32)res); - - writeScummVar(109, (int32)a2); - writeScummVar(110, (int32)a5); - writeScummVar(111, (int32)a4); - - return 1; -} - -int LogicHEfootball::op_1006(int32 *args) { - double res; - - res = (1.0 - args[1] * 2.9411764e-4 * 5.3050399e-2) * args[0] * 1.2360656e-1 + - args[1] * 1.1764706e-2 + 46; - writeScummVar(108, (int32)res); - - res = 640.0 - args[2] * 1.2360656e-1 - args[1] * 1.1588235e-1 - 26; - writeScummVar(109, (int32)res); - - return 1; -} - -int LogicHEfootball::op_1007(int32 *args) { - double res, temp; - - temp = (double)args[1] * 0.32; - - if (temp > 304.0) - res = -args[2] * 0.142; - else - res = args[2] * 0.142; - - res += temp; - - writeScummVar(108, (int32)res); - - res = (1000.0 - args[2]) * 0.48; - - writeScummVar(109, (int32)res); - - return 1; -} - -int LogicHEfootball::op_1010(int32 *args) { - double a1 = (640.0 - (double)args[1] - 26.0) * 8.6294413; - double res; - - res = ((double)args[0] - 46 - a1 * 1.1764706e-2) / - ((1.0 - a1 * 2.9411764e-4 * 5.3050399e-2) * 1.2360656e-1); - writeScummVar(108, (int32)res); - - writeScummVar(109, (int32)a1); - - return 1; -} - -int LogicHEfootball::op_1022(int32 *args) { - double res; - double var10 = args[4] - args[1]; - double var8 = args[5] - args[2]; - double var6 = args[3] - args[0]; - - res = sqrt(var8 * var8 + var6 * var6 + var10 * var10); - - if (res >= (double)args[6]) { - var8 = (double)args[6] * var8 / res; - var10 = (double)args[6] * var10 / res; - res = (double)args[6] * var6 / res; - } - - writeScummVar(108, (int32)res); - writeScummVar(109, (int32)var10); - writeScummVar(110, (int32)var8); - - return 1; -} - -int LogicHEfootball::op_1023(int32 *args) { - double var10, var18, var20, var28, var30, var30_; - double argf[7]; - - for (int i = 0; i < 7; i++) - argf[i] = args[i]; - - var10 = (argf[3] - argf[1]) / (argf[2] - argf[0]); - var28 = var10 * var10 + 1; - var20 = argf[0] * var10; - var18 = (argf[5] + argf[1] + var20) * argf[4] * var10 * 2 + - argf[6] * argf[6] * var28 + argf[4] * argf[4] - - argf[0] * argf[0] * var10 * var10 - - argf[5] * argf[0] * var10 * 2 - - argf[5] * argf[1] * 2 - - argf[1] * argf[1] - argf[5] * argf[5]; - - if (var18 >= 0) { - var18 = sqrt(var18); - - var30_ = argf[4] + argf[5] * var10 + argf[1] * var10 + argf[0] * var10 * var10; - var30 = (var30_ - var18) / var28; - var18 = (var30_ + var18) / var28; - - if ((argf[0] - var30 < 0) && (argf[0] - var18 < 0)) { - var30_ = var30; - var30 = var18; - var18 = var30_; - } - var28 = var18 * var10 - var20 - argf[1]; - var20 = var30 * var10 - var20 - argf[1]; - } else { - var18 = 0; - var20 = 0; - var28 = 0; - var30 = 0; - } - - writeScummVar(108, (int32)var18); - writeScummVar(109, (int32)var28); - writeScummVar(110, (int32)var30); - writeScummVar(111, (int32)var20); - - return 1; -} -int LogicHEfootball::op_1024(int32 *args) { - writeScummVar(108, 0); - writeScummVar(109, 0); - writeScummVar(110, 0); - writeScummVar(111, 0); - - return 1; -} - - -/*********************** - * Backyard Soccer - * - */ - -int LogicHEsoccer::versionID() { - return 1; -} - -int32 LogicHEsoccer::dispatch(int op, int numArgs, int32 *args) { - int res = 0; - - switch (op) { - case 1001: - res = op_1001(args); - break; - - case 1002: - res = op_1002(args); - break; - - case 1004: - res = op_1004(args); - break; - - case 8221968: - // Someone had a fun and used his birthday as opcode number - res = getFromArray(args[0], args[1], args[2]); - break; - - default: - // original range is 1001 - 1021 - LogicHE::dispatch(op, numArgs, args); - warning("Tell sev how to reproduce it"); - } - - return res; -} - -int LogicHEsoccer::op_1001(int32 *args) { - return args[0] * sin(args[1]); -} - -int LogicHEsoccer::op_1002(int32 *args) { - return _vm->VAR(2) * args[0]; -} - -int LogicHEsoccer::op_1004(int32 *args) { - double res, a2, a4, a5; - - a5 = ((double)args[4] - (double)args[1]) / ((double)args[5] - (double)args[2]); - a4 = ((double)args[3] - (double)args[0]) / ((double)args[5] - (double)args[2]); - a2 = (double)args[2] - (double)args[0] * a4 - args[1] * a5; - - res = (double)args[6] * a4 + (double)args[7] * a5 + a2; - writeScummVar(108, (int32)res); - - writeScummVar(109, (int32)a2); - writeScummVar(110, (int32)a5); - writeScummVar(111, (int32)a4); - - return 1; -} - -} // End of namespace Scumm diff --git a/engines/scumm/logic_he.h b/engines/scumm/logic_he.h deleted file mode 100644 index 59476f2e3b..0000000000 --- a/engines/scumm/logic_he.h +++ /dev/null @@ -1,124 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2005-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#if !defined(LOGIC_HE_H) && !defined(DISABLE_HE) -#define LOGIC_HE_H - -#include "common/stdafx.h" - -namespace Scumm { - -class ScummEngine_v90he; - -class LogicHE { -public: - float *_userData; - double *_userDataD; - ScummEngine_v90he *_vm; - - LogicHE(ScummEngine_v90he *vm); - virtual ~LogicHE(); - - void writeScummVar(int var, int32 value); - int getFromArray(int arg0, int idx2, int idx1); - void putInArray(int arg0, int idx2, int idx1, int val); - - void beforeBootScript(void) {}; - void initOnce() {}; - void startOfFrame() {}; - void endOfFrame() {}; - void processKeyStroke(int keyPressed) {}; - - virtual int versionID(); - virtual int32 dispatch(int op, int numArgs, int32 *args); -}; - -class LogicHErace : public LogicHE { -public: - LogicHErace(ScummEngine_v90he *vm) : LogicHE(vm) {} - - int versionID(); - int32 dispatch(int op, int numArgs, int32 *args); - -private: - int32 op_1003(int32 *args); - int32 op_1004(int32 *args); - int32 op_1100(int32 *args); - int32 op_1101(int32 *args); - int32 op_1102(int32 *args); - int32 op_1103(int32 *args); - int32 op_1110(); - int32 op_1120(int32 *args); - int32 op_1130(int32 *args); - int32 op_1140(int32 *args); - - void op_sub1(float arg); - void op_sub2(float arg); - void op_sub3(float arg); -}; - -class LogicHEfunshop : public LogicHE { -public: - LogicHEfunshop(ScummEngine_v90he *vm) : LogicHE(vm) {} - - int versionID(); - int32 dispatch(int op, int numArgs, int32 *args); - -private: - void op_1004(int32 *args); - void op_1005(int32 *args); - int checkShape(int32 data0, int32 data1, int32 data4, int32 data5, int32 data2, int32 data3, int32 data6, int32 data7, int32 *x, int32 *y); -}; - -class LogicHEfootball : public LogicHE { -public: - LogicHEfootball(ScummEngine_v90he *vm) : LogicHE(vm) {} - - int versionID(); - int32 dispatch(int op, int numArgs, int32 *args); - -private: - int op_1004(int32 *args); - int op_1006(int32 *args); - int op_1007(int32 *args); - int op_1010(int32 *args); - int op_1022(int32 *args); - int op_1023(int32 *args); - int op_1024(int32 *args); -}; - -class LogicHEsoccer : public LogicHE { -public: - LogicHEsoccer(ScummEngine_v90he *vm) : LogicHE(vm) {} - - int versionID(); - int32 dispatch(int op, int numArgs, int32 *args); - -private: - int op_1001(int32 *args); - int op_1002(int32 *args); - int op_1004(int32 *args); -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk index fa56739dde..0e90736329 100644 --- a/engines/scumm/module.mk +++ b/engines/scumm/module.mk @@ -39,10 +39,10 @@ MODULE_OBJS := \ script_v2.o \ script_v5.o \ script_v6.o \ - script_v6he.o \ + he/script_v6he.o \ scumm.o \ sound.o \ - sound_he.o \ + he/sound_he.o \ string.o \ usage_bits.o \ util.o \ @@ -80,17 +80,17 @@ endif ifndef DISABLE_HE MODULE_OBJS += \ - floodfill_he.o \ - logic_he.o \ - palette_he.o \ - resource_v7he.o \ - script_v7he.o \ - script_v72he.o \ - script_v80he.o \ - script_v90he.o \ - script_v100he.o \ - sprite_he.o \ - wiz_he.o + he/floodfill_he.o \ + he/logic_he.o \ + he/palette_he.o \ + he/resource_v7he.o \ + he/script_v7he.o \ + he/script_v72he.o \ + he/script_v80he.o \ + he/script_v90he.o \ + he/script_v100he.o \ + he/sprite_he.o \ + he/wiz_he.o endif MODULE_DIRS += \ diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp index 0472edcc15..7f09a69b72 100644 --- a/engines/scumm/object.cpp +++ b/engines/scumm/object.cpp @@ -27,7 +27,7 @@ #include "scumm/bomp.h" #include "scumm/intern.h" #ifndef DISABLE_HE -#include "scumm/intern_he.h" +#include "scumm/he/intern_he.h" #endif #include "scumm/object.h" #include "scumm/resource.h" diff --git a/engines/scumm/palette_he.cpp b/engines/scumm/palette_he.cpp deleted file mode 100644 index 2d6a471d79..0000000000 --- a/engines/scumm/palette_he.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" -#include "common/system.h" -#include "scumm/scumm.h" -#include "scumm/intern_he.h" -#include "scumm/resource.h" -#include "scumm/util.h" - -namespace Scumm { - -void ScummEngine_v70he::remapHEPalette(const uint8 *src, uint8 *dst) { - int r, g, b, sum, bestitem, bestsum; - int ar, ag, ab; - uint8 *palPtr; - src += 30; - - if (_heversion >= 99) { - palPtr = _hePalettes + 1024 + 30; - } else { - palPtr = _currentPalette + 30; - } - - for (int j = 10; j < 246; j++) { - bestitem = 0xFFFF; - bestsum = 0xFFFF; - - r = *src++; - g = *src++; - b = *src++; - - uint8 *curPal = palPtr; - - for (int k = 10; k < 246; k++) { - ar = r - *curPal++; - ag = g - *curPal++; - ab = b - *curPal++; - - sum = (ar * ar) + (ag * ag) + (ab * ab); - - if (bestitem == 0xFFFF || sum <= bestsum) { - bestitem = k; - bestsum = sum; - } - } - - dst[j] = bestitem; - } -} - -uint8 *ScummEngine_v90he::getHEPaletteIndex(int palSlot) { - if (palSlot) { - assert(palSlot >= 1 && palSlot <= _numPalettes); - return _hePalettes + palSlot * 1024; - } else { - return _hePalettes + 1024; - } -} - -int ScummEngine_v90he::getHEPaletteSimilarColor(int palSlot, int red, int green, int start, int end) { - checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); - checkRange(255, 0, start, "Invalid palette slot %d"); - checkRange(255, 0, end, "Invalid palette slot %d"); - - uint8 *pal = _hePalettes + palSlot * 1024 + start * 3; - - int bestsum = 0xFFFFFFFF; - int bestitem = start; - - for (int i = start; i <= end; i++) { - int dr = red - pal[0]; - int dg = green - pal[1]; - int sum = dr * dr + dg * dg * 2; - if (sum == 0) { - return i; - } - if (sum < bestsum) { - bestsum = sum; - bestitem = i; - } - pal += 3; - } - return bestitem; -} - -int ScummEngine_v90he::getHEPaletteColorComponent(int palSlot, int color, int component) { - checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); - checkRange(255, 0, color, "Invalid palette slot %d"); - - return _hePalettes[palSlot * 1024 + color * 3 + component % 3]; -} - -int ScummEngine_v90he::getHEPaletteColor(int palSlot, int color) { - checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); - checkRange(255, 0, color, "Invalid palette slot %d"); - - return _hePalettes[palSlot * 1024 + 768 + color]; -} - -void ScummEngine_v90he::setHEPaletteColor(int palSlot, uint8 color, uint8 r, uint8 g, uint8 b) { - debug(7, "setHEPaletteColor(%d, %d, %d, %d, %d)", palSlot, color, r, g, b); - checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); - uint8 *p = _hePalettes + palSlot * 1024 + color * 3; - *(p + 0) = r; - *(p + 1) = g; - *(p + 2) = b; - _hePalettes[palSlot * 1024 + 768 + color] = color; -} - -void ScummEngine_v90he::setHEPaletteFromPtr(int palSlot, const uint8 *palData) { - checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); - uint8 *pc = _hePalettes + palSlot * 1024; - uint8 *pi = pc + 768; - for (int i = 0; i < 256; ++i) { - *pc++ = *palData++; - *pc++ = *palData++; - *pc++ = *palData++; - *pi++ = i; - } -} - -void ScummEngine_v90he::setHEPaletteFromCostume(int palSlot, int resId) { - debug(7, "setHEPaletteFromCostume(%d, %d)", palSlot, resId); - checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); - const uint8 *data = getResourceAddress(rtCostume, resId); - assert(data); - const uint8 *rgbs = findResourceData(MKID('RGBS'), data); - assert(rgbs); - setHEPaletteFromPtr(palSlot, rgbs); -} - -void ScummEngine_v90he::setHEPaletteFromImage(int palSlot, int resId, int state) { - debug(7, "setHEPaletteFromImage(%d, %d, %d)", palSlot, resId, state); - checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); - uint8 *data = getResourceAddress(rtImage, resId); - assert(data); - const uint8 *rgbs = findWrappedBlock(MKID('RGBS'), data, state, 0); - assert(rgbs); - setHEPaletteFromPtr(palSlot, rgbs); -} - -void ScummEngine_v90he::setHEPaletteFromRoom(int palSlot, int resId, int state) { - debug(7, "setHEPaletteFromRoom(%d, %d, %d)", palSlot, resId, state); - checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); - const uint8 *data = getResourceAddress(rtRoom, resId); - assert(data); - const uint8 *pals = findResourceData(MKID('PALS'), data); - assert(pals); - const uint8 *rgbs = findPalInPals(pals, state); - assert(rgbs); - setHEPaletteFromPtr(palSlot, rgbs); -} - -void ScummEngine_v90he::restoreHEPalette(int palSlot) { - debug(7, "restoreHEPalette(%d)", palSlot); - checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); - if (palSlot != 1) { - memcpy(_hePalettes + palSlot * 1024, _hePalettes + 1024, 1024); - } -} - -void ScummEngine_v90he::copyHEPalette(int dstPalSlot, int srcPalSlot) { - debug(7, "copyHEPalette(%d, %d)", dstPalSlot, srcPalSlot); - assert(dstPalSlot >= 1 && dstPalSlot <= _numPalettes); - assert(srcPalSlot >= 1 && srcPalSlot <= _numPalettes); - if (dstPalSlot != srcPalSlot) { - memcpy(_hePalettes + dstPalSlot * 1024, _hePalettes + srcPalSlot * 1024, 1024); - } -} - -void ScummEngine_v90he::copyHEPaletteColor(int palSlot, uint8 dstColor, uint8 srcColor) { - debug(7, "copyHEPaletteColor(%d, %d, %d)", palSlot, dstColor, srcColor); - checkRange(_numPalettes, 1, palSlot, "Invalid palette %d"); - uint8 *dstPal = _hePalettes + palSlot * 1024 + dstColor * 3; - uint8 *srcPal = _hePalettes + 1024 + srcColor * 3; - memcpy(dstPal, srcPal, 3); - _hePalettes[palSlot * 1024 + 768 + dstColor] = srcColor; -} - -void ScummEngine_v99he::setPaletteFromPtr(const byte *ptr, int numcolor) { - int i; - byte *dest, r, g, b; - - if (numcolor < 0) { - numcolor = getResourceDataSize(ptr) / 3; - } - - checkRange(256, 0, numcolor, "Too many colors (%d) in Palette"); - - dest = _hePalettes + 1024; - - for (i = 0; i < numcolor; i++) { - r = *ptr++; - g = *ptr++; - b = *ptr++; - - if (i == 15 || r < 252 || g < 252 || b < 252) { - *dest++ = r; - *dest++ = g; - *dest++ = b; - _hePalettes[1792 + i] = i; - } else { - dest += 3; - } - } - - memcpy(_hePalettes, _hePalettes + 1024, 768); - - for (i = 0; i < 10; ++i) - _hePalettes[1792 + i] = i; - for (i = 246; i < 256; ++i) - _hePalettes[1792 + i] = i; - - setDirtyColors(0, numcolor - 1); -} - -void ScummEngine_v99he::darkenPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor) { - uint8 *src, *dst; - int color, j; - - src = _hePalettes + startColor * 3; - dst = _hePalettes + 1024 + startColor * 3; - for (j = startColor; j <= endColor; j++) { - color = *src++; - color = color * redScale / 0xFF; - if (color > 255) - color = 255; - *dst++ = color; - - color = *src++; - color = color * greenScale / 0xFF; - if (color > 255) - color = 255; - *dst++ = color; - - color = *src++; - color = color * blueScale / 0xFF; - if (color > 255) - color = 255; - *dst++ = color; - - _hePalettes[1792 + j] = j; - setDirtyColors(j, endColor); - } -} - -void ScummEngine_v99he::copyPalColor(int dst, int src) { - byte *dp, *sp; - - if ((uint) dst >= 256 || (uint) src >= 256) - error("copyPalColor: invalid values, %d, %d", dst, src); - - dp = &_hePalettes[1024 + dst * 3]; - sp = &_hePalettes[1024 + src * 3]; - - dp[0] = sp[0]; - dp[1] = sp[1]; - dp[2] = sp[2]; - _hePalettes[1792 + dst] = dst; - - setDirtyColors(dst, dst); -} - -void ScummEngine_v99he::setPalColor(int idx, int r, int g, int b) { - _hePalettes[1024 + idx * 3 + 0] = r; - _hePalettes[1024 + idx * 3 + 1] = g; - _hePalettes[1024 + idx * 3 + 2] = b; - _hePalettes[1792 + idx] = idx; - setDirtyColors(idx, idx); -} - -void ScummEngine_v99he::updatePalette() { - if (_palDirtyMax == -1) - return; - - int num = _palDirtyMax - _palDirtyMin + 1; - int i; - - byte palette_colors[1024]; - byte *p = palette_colors; - - for (i = _palDirtyMin; i <= _palDirtyMax; i++) { - byte *data = _hePalettes + 1024 + i * 3; - - *p++ = data[0]; - *p++ = data[1]; - *p++ = data[2]; - *p++ = 0; - } - - _system->setPalette(palette_colors, _palDirtyMin, num); - - _palDirtyMax = -1; - _palDirtyMin = 256; -} - -} // End of namespace Scumm diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp index e1601ca991..c916183b9e 100644 --- a/engines/scumm/resource.cpp +++ b/engines/scumm/resource.cpp @@ -30,7 +30,7 @@ #include "scumm/imuse_digi/dimuse.h" #include "scumm/intern.h" #ifndef DISABLE_HE -#include "scumm/intern_he.h" +#include "scumm/he/intern_he.h" #endif #include "scumm/object.h" #include "scumm/resource.h" diff --git a/engines/scumm/resource_v7he.cpp b/engines/scumm/resource_v7he.cpp deleted file mode 100644 index 6ce8446a9a..0000000000 --- a/engines/scumm/resource_v7he.cpp +++ /dev/null @@ -1,1912 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2004-2006 The ScummVM project - * - * Parts of code heavily based on: - * icoutils - A set of programs dealing with MS Windows icons and cursors. - * Copyright (C) 1998-2001 Oskar Liljeblad - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" -#include "scumm/scumm.h" -#include "scumm/intern_he.h" -#include "scumm/resource.h" -#include "scumm/resource_v7he.h" -#include "scumm/sound.h" -#include "scumm/util.h" -#include "sound/wave.h" - -#include "common/stream.h" -#include "common/system.h" - -namespace Scumm { - -ResExtractor::ResExtractor(ScummEngine_v70he *scumm) - : _vm(scumm) { - - _fileName[0] = 0; - memset(_cursorCache, 0, sizeof(_cursorCache)); -} - -ResExtractor::~ResExtractor() { - for (int i = 0; i < MAX_CACHED_CURSORS; ++i) { - CachedCursor *cc = &_cursorCache[i]; - if (cc->valid) { - free(cc->bitmap); - free(cc->palette); - } - } - memset(_cursorCache, 0, sizeof(_cursorCache)); -} - -ResExtractor::CachedCursor *ResExtractor::findCachedCursor(int id) { - for (int i = 0; i < MAX_CACHED_CURSORS; ++i) { - CachedCursor *cc = &_cursorCache[i]; - if (cc->valid && cc->id == id) { - return cc; - } - } - return NULL; -} - -ResExtractor::CachedCursor *ResExtractor::getCachedCursorSlot() { - uint32 min_last_used = 0; - CachedCursor *r = NULL; - for (int i = 0; i < MAX_CACHED_CURSORS; ++i) { - CachedCursor *cc = &_cursorCache[i]; - if (!cc->valid) { - return cc; - } else { - if (min_last_used == 0 || cc->last_used < min_last_used) { - min_last_used = cc->last_used; - r = cc; - } - } - } - assert(r); - free(r->bitmap); - free(r->palette); - memset(r, 0, sizeof(CachedCursor)); - return r; -} - -void ResExtractor::setCursor(int id) { - byte *cursorRes = 0; - int cursorsize; - int keycolor = 0; - CachedCursor *cc = findCachedCursor(id); - if (cc != NULL) { - debug(7, "Found cursor %d in cache slot %d", id, cc - _cursorCache); - } else { - cc = getCachedCursorSlot(); - assert(cc && !cc->valid); - cursorsize = extractResource(id, &cursorRes); - convertIcons(cursorRes, cursorsize, &cc->bitmap, &cc->w, &cc->h, &cc->hotspot_x, &cc->hotspot_y, &keycolor, &cc->palette, &cc->palSize); - debug(7, "Adding cursor %d to cache slot %d", id, cc - _cursorCache); - free(cursorRes); - cc->valid = true; - cc->id = id; - cc->last_used = g_system->getMillis(); - } - - if (_vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette) && cc->palette) - _vm->_system->setCursorPalette(cc->palette, 0, cc->palSize); - - _vm->setCursorHotspot(cc->hotspot_x, cc->hotspot_y); - _vm->setCursorFromBuffer(cc->bitmap, cc->w, cc->h, cc->w); -} - - -/* - * Static variables - */ -const char *res_types[] = { - /* 0x01: */ - "cursor", "bitmap", "icon", "menu", "dialog", "string", - "fontdir", "font", "accelerator", "rcdata", "messagelist", - "group_cursor", NULL, "group_icon", NULL, - /* the following are not defined in winbase.h, but found in wrc. */ - /* 0x10: */ - "version", "dlginclude", NULL, "plugplay", "vxd", - "anicursor", "aniicon" -}; -#define RES_TYPE_COUNT (sizeof(res_types)/sizeof(char *)) - -Win32ResExtractor::Win32ResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) { -} - -int Win32ResExtractor::extractResource(int resId, byte **data) { - char buf[20]; - - snprintf(buf, sizeof(buf), "%d", resId); - - return extractResource_("group_cursor", buf, data); -} - -int Win32ResExtractor::extractResource_(const char *resType, char *resName, byte **data) { - char *arg_language = NULL; - const char *arg_type = resType; - char *arg_name = resName; - int arg_action = ACTION_LIST; - int ressize = 0; - - _arg_raw = false; - - /* translate --type option from resource type string to integer */ - arg_type = res_type_string_to_id(arg_type); - - WinLibrary fi; - - /* initiate stuff */ - fi.memory = NULL; - fi.file = new Common::File; - - if (!_fileName[0]) { // We are running for the first time - snprintf(_fileName, 256, "%s.he3", _vm->getBaseName()); - - if (_vm->_substResFileNameIndex > 0) { - char buf1[128]; - - _vm->generateSubstResFileName(_fileName, buf1, sizeof(buf1)); - strcpy(_fileName, buf1); - } - } - - - /* get file size */ - fi.file->open(_fileName); - if (!fi.file->isOpen()) { - error("Cannot open file %s", _fileName); - } - - fi.total_size = fi.file->size(); - if (fi.total_size == -1) { - error("Cannot get size of file %s", fi.file->name()); - goto cleanup; - } - if (fi.total_size == 0) { - error("%s: file has a size of 0", fi.file->name()); - goto cleanup; - } - - /* read all of file */ - fi.memory = (byte *)malloc(fi.total_size); - if (fi.file->read(fi.memory, fi.total_size) == 0) { - error("Cannot read from file %s", fi.file->name()); - goto cleanup; - } - - /* identify file and find resource table */ - if (!read_library(&fi)) { - /* error reported by read_library */ - goto cleanup; - } - - // verbose_printf("file is a %s\n", - // fi.is_PE_binary ? "Windows NT `PE' binary" : "Windows 3.1 `NE' binary"); - - /* errors will be printed by the callback */ - ressize = do_resources(&fi, arg_type, arg_name, arg_language, arg_action, data); - - /* free stuff and close file */ - cleanup: - if (fi.file != NULL) - fi.file->close(); - if (fi.memory != NULL) - free(fi.memory); - - return ressize; -} - - -/* res_type_id_to_string: - * Translate a numeric resource type to it's corresponding string type. - * (For informative-ness.) - */ -const char *Win32ResExtractor::res_type_id_to_string(int id) { - if (id == 241) - return "toolbar"; - if (id > 0 && id <= (int)RES_TYPE_COUNT) - return res_types[id-1]; - return NULL; -} - -/* res_type_string_to_id: - * Translate a resource type string to integer. - * (Used to convert the --type option.) - */ -const char *Win32ResExtractor::res_type_string_to_id(const char *type) { - static const char *res_type_ids[] = { - "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9", "-10", - "-11", "-12", NULL, "-14", NULL, "-16", "-17", NULL, "-19", - "-20", "-21", "-22" - }; - int c; - - if (type == NULL) - return NULL; - - for (c = 0 ; c < (int)RES_TYPE_COUNT ; c++) { - if (res_types[c] != NULL && !scumm_stricmp(type, res_types[c])) - return res_type_ids[c]; - } - - return type; -} - -int Win32ResExtractor::extract_resources(WinLibrary *fi, WinResource *wr, - WinResource *type_wr, WinResource *name_wr, - WinResource *lang_wr, byte **data) { - int size; - bool free_it; - const char *type; - int32 id; - - if (*data) { - error("Win32ResExtractor::extract_resources() more than one cursor"); - return 0; - } - - *data = extract_resource(fi, wr, &size, &free_it, type_wr->id, (lang_wr == NULL ? NULL : lang_wr->id), _arg_raw); - - if (data == NULL) { - error("Win32ResExtractor::extract_resources() problem with resource extraction"); - return 0; - } - - /* get named resource type if possible */ - type = NULL; - if ((id = strtol(type_wr->id, 0, 10)) != 0) - type = res_type_id_to_string(id); - - debugC(DEBUG_RESOURCE, "extractCursor(). Found cursor name: %s%s%s [size=%d]", - get_resource_id_quoted(name_wr), - (lang_wr->id[0] != '\0' ? " language: " : ""), - get_resource_id_quoted(lang_wr), size); - - return size; -} - -/* extract_resource: - * Extract a resource, returning pointer to data. - */ -byte *Win32ResExtractor::extract_resource(WinLibrary *fi, WinResource *wr, int *size, - bool *free_it, char *type, char *lang, bool raw) { - char *str; - int32 intval; - - /* just return pointer to data if raw */ - if (raw) { - *free_it = false; - /* get_resource_entry will print possible error */ - return get_resource_entry(fi, wr, size); - } - - /* find out how to extract */ - str = type; - if (str != NULL && (intval = strtol(STRIP_RES_ID_FORMAT(str), 0, 10))) { - if (intval == (int)RT_GROUP_ICON) { - *free_it = true; - return extract_group_icon_cursor_resource(fi, wr, lang, size, true); - } - if (intval == (int)RT_GROUP_CURSOR) { - *free_it = true; - return extract_group_icon_cursor_resource(fi, wr, lang, size, false); - } - } - - return NULL; -} - -/* extract_group_icon_resource: - * Create a complete RT_GROUP_ICON resource, that can be written to - * an `.ico' file without modifications. Returns an allocated - * memory block that should be freed with free() once used. - * - * `root' is the offset in file that specifies the resource. - * `base' is the offset that string pointers are calculated from. - * `ressize' should point to an integer variable where the size of - * the returned memory block will be placed. - * `is_icon' indicates whether resource to be extracted is icon - * or cursor group. - */ -byte *Win32ResExtractor::extract_group_icon_cursor_resource(WinLibrary *fi, WinResource *wr, char *lang, - int *ressize, bool is_icon) { - Win32CursorIconDir *icondir; - Win32CursorIconFileDir *fileicondir; - byte *memory; - int c, offset, skipped; - int size; - - /* get resource data and size */ - icondir = (Win32CursorIconDir *)get_resource_entry(fi, wr, &size); - if (icondir == NULL) { - /* get_resource_entry will print error */ - return NULL; - } - - /* calculate total size of output file */ - RETURN_IF_BAD_POINTER(NULL, icondir->count); - skipped = 0; - for (c = 0 ; c < icondir->count ; c++) { - int level; - int iconsize; - char name[14]; - WinResource *fwr; - - RETURN_IF_BAD_POINTER(NULL, icondir->entries[c]); - /*printf("%d. bytes_in_res=%d width=%d height=%d planes=%d bit_count=%d\n", c, - icondir->entries[c].bytes_in_res, - (is_icon ? icondir->entries[c].res_info.icon.width : icondir->entries[c].res_info.cursor.width), - (is_icon ? icondir->entries[c].res_info.icon.height : icondir->entries[c].res_info.cursor.height), - icondir->entries[c].plane_count, - icondir->entries[c].bit_count);*/ - - /* find the corresponding icon resource */ - snprintf(name, sizeof(name)/sizeof(char), "-%d", icondir->entries[c].res_id); - fwr = find_resource(fi, (is_icon ? "-3" : "-1"), name, lang, &level); - if (fwr == NULL) { - error("%s: could not find `%s' in `%s' resource.", - fi->file->name(), &name[1], (is_icon ? "group_icon" : "group_cursor")); - return NULL; - } - - if (get_resource_entry(fi, fwr, &iconsize) != NULL) { - if (iconsize == 0) { - debugC(DEBUG_RESOURCE, "%s: icon resource `%s' is empty, skipping", fi->file->name(), name); - skipped++; - continue; - } - if ((uint32)iconsize != icondir->entries[c].bytes_in_res) { - debugC(DEBUG_RESOURCE, "%s: mismatch of size in icon resource `%s' and group (%d != %d)", - fi->file->name(), name, iconsize, icondir->entries[c].bytes_in_res); - } - size += iconsize; /* size += icondir->entries[c].bytes_in_res; */ - - /* cursor resources have two additional WORDs that contain - * hotspot info */ - if (!is_icon) - size -= sizeof(uint16)*2; - } - } - offset = sizeof(Win32CursorIconFileDir) + (icondir->count-skipped) * sizeof(Win32CursorIconFileDirEntry); - size += offset; - *ressize = size; - - /* allocate that much memory */ - memory = (byte *)malloc(size); - fileicondir = (Win32CursorIconFileDir *)memory; - - /* transfer Win32CursorIconDir structure members */ - fileicondir->reserved = icondir->reserved; - fileicondir->type = icondir->type; - fileicondir->count = icondir->count - skipped; - - /* transfer each cursor/icon: Win32CursorIconDirEntry and data */ - skipped = 0; - for (c = 0 ; c < icondir->count ; c++) { - int level; - char name[14]; - WinResource *fwr; - byte *data; - - /* find the corresponding icon resource */ - snprintf(name, sizeof(name)/sizeof(char), "-%d", icondir->entries[c].res_id); - fwr = find_resource(fi, (is_icon ? "-3" : "-1"), name, lang, &level); - if (fwr == NULL) { - error("%s: could not find `%s' in `%s' resource.", - fi->file->name(), &name[1], (is_icon ? "group_icon" : "group_cursor")); - return NULL; - } - - /* get data and size of that resource */ - data = (byte *)get_resource_entry(fi, fwr, &size); - if (data == NULL) { - /* get_resource_entry has printed error */ - return NULL; - } - if (size == 0) { - skipped++; - continue; - } - - /* copy ICONDIRENTRY (not including last dwImageOffset) */ - memcpy(&fileicondir->entries[c-skipped], &icondir->entries[c], - sizeof(Win32CursorIconFileDirEntry)-sizeof(uint32)); - - /* special treatment for cursors */ - if (!is_icon) { - fileicondir->entries[c-skipped].width = icondir->entries[c].res_info.cursor.width; - fileicondir->entries[c-skipped].height = icondir->entries[c].res_info.cursor.height / 2; - fileicondir->entries[c-skipped].color_count = 0; - fileicondir->entries[c-skipped].reserved = 0; - } - - /* set image offset and increase it */ - fileicondir->entries[c-skipped].dib_offset = offset; - - /* transfer resource into file memory */ - if (is_icon) { - memcpy(&memory[offset], data, icondir->entries[c].bytes_in_res); - } else { - fileicondir->entries[c-skipped].hotspot_x = ((uint16 *) data)[0]; - fileicondir->entries[c-skipped].hotspot_y = ((uint16 *) data)[1]; - memcpy(&memory[offset], data+sizeof(uint16)*2, - icondir->entries[c].bytes_in_res-sizeof(uint16)*2); - offset -= sizeof(uint16)*2; - } - - /* increase the offset pointer */ - offset += icondir->entries[c].bytes_in_res; - } - - return memory; -} - -/* check_offset: - * Check if a chunk of data (determined by offset and size) - * is within the bounds of the WinLibrary file. - * Usually not called directly. - */ -bool Win32ResExtractor::check_offset(byte *memory, int total_size, const char *name, void *offset, int size) { - int need_size = (int)((byte *)offset - memory + size); - - debugC(DEBUG_RESOURCE, "check_offset: size=%x vs %x offset=%x size=%x", - need_size, total_size, (byte *)offset - memory, size); - - if (need_size < 0 || need_size > total_size) { - error("%s: premature end", name); - return false; - } - - return true; -} - - -/* do_resources: - * Do something for each resource matching type, name and lang. - */ -int Win32ResExtractor::do_resources(WinLibrary *fi, const char *type, char *name, char *lang, int action, byte **data) { - WinResource *type_wr; - WinResource *name_wr; - WinResource *lang_wr; - int size; - - type_wr = (WinResource *)calloc(sizeof(WinResource)*3, 1); - name_wr = type_wr + 1; - lang_wr = type_wr + 2; - - size = do_resources_recurs(fi, NULL, type_wr, name_wr, lang_wr, type, name, lang, action, data); - - free(type_wr); - - return size; -} - -/* what is each entry in this directory level for? type, name or language? */ -#define WINRESOURCE_BY_LEVEL(x) ((x)==0 ? type_wr : ((x)==1 ? name_wr : lang_wr)) - -/* does the id of this entry match the specified id? */ -#define LEVEL_MATCHES(x) (x == NULL || x ## _wr->id[0] == '\0' || compare_resource_id(x ## _wr, x)) - -int Win32ResExtractor::do_resources_recurs(WinLibrary *fi, WinResource *base, - WinResource *type_wr, WinResource *name_wr, WinResource *lang_wr, - const char *type, char *name, char *lang, int action, byte **data) { - int c, rescnt; - WinResource *wr; - uint32 size = 0; - - /* get a list of all resources at this level */ - wr = list_resources(fi, base, &rescnt); - if (wr == NULL) - if (size != 0) - return size; - else - return 0; - - /* process each resource listed */ - for (c = 0 ; c < rescnt ; c++) { - /* (over)write the corresponding WinResource holder with the current */ - memcpy(WINRESOURCE_BY_LEVEL(wr[c].level), wr+c, sizeof(WinResource)); - - /* go deeper unless there is something that does NOT match */ - if (LEVEL_MATCHES(type) && LEVEL_MATCHES(name) && LEVEL_MATCHES(lang)) { - if (wr->is_directory) - size = do_resources_recurs(fi, wr+c, type_wr, name_wr, lang_wr, type, name, lang, action, data); - else - size = extract_resources(fi, wr+c, type_wr, name_wr, lang_wr, data); - } - } - - /* since we're moving back one level after this, unset the - * WinResource holder used on this level */ - memset(WINRESOURCE_BY_LEVEL(wr[0].level), 0, sizeof(WinResource)); - - return size; -} - -/* return the resource id quoted if it's a string, otherwise just return it */ -char *Win32ResExtractor::get_resource_id_quoted(WinResource *wr) { - static char tmp[WINRES_ID_MAXLEN+2]; - - if (wr->numeric_id || wr->id[0] == '\0') - return wr->id; - - sprintf(tmp, "'%s'", wr->id); - return tmp; -} - -bool Win32ResExtractor::compare_resource_id(WinResource *wr, const char *id) { - if (wr->numeric_id) { - int32 cmp1, cmp2; - if (id[0] == '+') - return false; - if (id[0] == '-') - id++; - if (!(cmp1 = strtol(wr->id, 0, 10)) || !(cmp2 = strtol(id, 0, 10)) || cmp1 != cmp2) - return false; - } else { - if (id[0] == '-') - return false; - if (id[0] == '+') - id++; - if (strcmp(wr->id, id)) - return false; - } - - return true; -} - -bool Win32ResExtractor::decode_pe_resource_id(WinLibrary *fi, WinResource *wr, uint32 value) { - if (value & IMAGE_RESOURCE_NAME_IS_STRING) { /* numeric id */ - int c, len; - uint16 *mem = (uint16 *) - (fi->first_resource + (value & ~IMAGE_RESOURCE_NAME_IS_STRING)); - - /* copy each char of the string, and terminate it */ - RETURN_IF_BAD_POINTER(false, *mem); - len = mem[0]; - RETURN_IF_BAD_OFFSET(false, &mem[1], sizeof(uint16) * len); - - len = MIN(mem[0], (uint16)WINRES_ID_MAXLEN); - for (c = 0 ; c < len ; c++) - wr->id[c] = mem[c+1] & 0x00FF; - wr->id[len] = '\0'; - } else { /* Unicode string id */ - /* translate id into a string */ - snprintf(wr->id, WINRES_ID_MAXLEN, "%d", value); - } - - wr->numeric_id = (value & IMAGE_RESOURCE_NAME_IS_STRING ? false:true); - return true; -} - -byte *Win32ResExtractor::get_resource_entry(WinLibrary *fi, WinResource *wr, int *size) { - if (fi->is_PE_binary) { - Win32ImageResourceDataEntry *dataent; - - dataent = (Win32ImageResourceDataEntry *) wr->children; - RETURN_IF_BAD_POINTER(NULL, *dataent); - *size = dataent->size; - RETURN_IF_BAD_OFFSET(NULL, fi->memory + dataent->offset_to_data, *size); - - return fi->memory + dataent->offset_to_data; - } else { - Win16NENameInfo *nameinfo; - int sizeshift; - - nameinfo = (Win16NENameInfo *) wr->children; - sizeshift = *((uint16 *) fi->first_resource - 1); - *size = nameinfo->length << sizeshift; - RETURN_IF_BAD_OFFSET(NULL, fi->memory + (nameinfo->offset << sizeshift), *size); - - return fi->memory + (nameinfo->offset << sizeshift); - } -} - -bool Win32ResExtractor::decode_ne_resource_id(WinLibrary *fi, WinResource *wr, uint16 value) { - if (value & NE_RESOURCE_NAME_IS_NUMERIC) { /* numeric id */ - /* translate id into a string */ - snprintf(wr->id, WINRES_ID_MAXLEN, "%d", value & ~NE_RESOURCE_NAME_IS_NUMERIC); - } else { /* ASCII string id */ - int len; - char *mem = (char *)NE_HEADER(fi->memory) - + NE_HEADER(fi->memory)->rsrctab - + value; - - /* copy each char of the string, and terminate it */ - RETURN_IF_BAD_POINTER(false, *mem); - len = mem[0]; - RETURN_IF_BAD_OFFSET(false, &mem[1], sizeof(char) * len); - memcpy(wr->id, &mem[1], len); - wr->id[len] = '\0'; - } - - wr->numeric_id = (value & NE_RESOURCE_NAME_IS_NUMERIC ? true:false); - return true; -} - -Win32ResExtractor::WinResource *Win32ResExtractor::list_pe_resources(WinLibrary *fi, Win32ImageResourceDirectory *pe_res, int level, int *count) { - WinResource *wr; - int c, rescnt; - Win32ImageResourceDirectoryEntry *dirent - = (Win32ImageResourceDirectoryEntry *)(pe_res + 1); - - /* count number of `type' resources */ - RETURN_IF_BAD_POINTER(NULL, *dirent); - rescnt = pe_res->number_of_named_entries + pe_res->number_of_id_entries; - *count = rescnt; - - /* allocate WinResource's */ - wr = (WinResource *)malloc(sizeof(WinResource) * rescnt); - - /* fill in the WinResource's */ - for (c = 0 ; c < rescnt ; c++) { - RETURN_IF_BAD_POINTER(NULL, dirent[c]); - wr[c].this_ = pe_res; - wr[c].level = level; - wr[c].is_directory = (dirent[c].u2.s.data_is_directory); - wr[c].children = fi->first_resource + dirent[c].u2.s.offset_to_directory; - - /* fill in wr->id, wr->numeric_id */ - if (!decode_pe_resource_id (fi, wr + c, dirent[c].u1.name)) - return NULL; - } - - return wr; -} - -Win32ResExtractor::WinResource *Win32ResExtractor::list_ne_name_resources(WinLibrary *fi, WinResource *typeres, int *count) { - int c, rescnt; - WinResource *wr; - Win16NETypeInfo *typeinfo = (Win16NETypeInfo *) typeres->this_; - Win16NENameInfo *nameinfo = (Win16NENameInfo *) typeres->children; - - /* count number of `type' resources */ - RETURN_IF_BAD_POINTER(NULL, typeinfo->count); - *count = rescnt = typeinfo->count; - - /* allocate WinResource's */ - wr = (WinResource *)malloc(sizeof(WinResource) * rescnt); - - /* fill in the WinResource's */ - for (c = 0 ; c < rescnt ; c++) { - RETURN_IF_BAD_POINTER(NULL, nameinfo[c]); - wr[c].this_ = nameinfo+c; - wr[c].is_directory = false; - wr[c].children = nameinfo+c; - wr[c].level = 1; - - /* fill in wr->id, wr->numeric_id */ - if (!decode_ne_resource_id(fi, wr + c, (nameinfo+c)->id)) - return NULL; - } - - return wr; -} - -Win32ResExtractor::WinResource *Win32ResExtractor::list_ne_type_resources(WinLibrary *fi, int *count) { - int c, rescnt; - WinResource *wr; - Win16NETypeInfo *typeinfo; - - /* count number of `type' resources */ - typeinfo = (Win16NETypeInfo *) fi->first_resource; - RETURN_IF_BAD_POINTER(NULL, *typeinfo); - for (rescnt = 0 ; typeinfo->type_id != 0 ; rescnt++) { - typeinfo = NE_TYPEINFO_NEXT(typeinfo); - RETURN_IF_BAD_POINTER(NULL, *typeinfo); - } - *count = rescnt; - - /* allocate WinResource's */ - wr = (WinResource *)malloc(sizeof(WinResource) * rescnt); - - /* fill in the WinResource's */ - typeinfo = (Win16NETypeInfo *) fi->first_resource; - for (c = 0 ; c < rescnt ; c++) { - wr[c].this_ = typeinfo; - wr[c].is_directory = (typeinfo->count != 0); - wr[c].children = typeinfo+1; - wr[c].level = 0; - - /* fill in wr->id, wr->numeric_id */ - if (!decode_ne_resource_id(fi, wr + c, typeinfo->type_id)) - return NULL; - - typeinfo = NE_TYPEINFO_NEXT(typeinfo); - } - - return wr; -} - -/* list_resources: - * Return an array of WinResource's in the current - * resource level specified by res. - */ -Win32ResExtractor::WinResource *Win32ResExtractor::list_resources(WinLibrary *fi, WinResource *res, int *count) { - if (res != NULL && !res->is_directory) - return NULL; - - if (fi->is_PE_binary) { - return list_pe_resources(fi, (Win32ImageResourceDirectory *) - (res == NULL ? fi->first_resource : res->children), - (res == NULL ? 0 : res->level+1), - count); - } else { - return (res == NULL - ? list_ne_type_resources(fi, count) - : list_ne_name_resources(fi, res, count)); - } -} - -/* read_library: - * Read header and get resource directory offset in a Windows library - * (AKA module). - * - */ -bool Win32ResExtractor::read_library(WinLibrary *fi) { - /* check for DOS header signature `MZ' */ - RETURN_IF_BAD_POINTER(false, MZ_HEADER(fi->memory)->magic); - if (MZ_HEADER(fi->memory)->magic == IMAGE_DOS_SIGNATURE) { - DOSImageHeader *mz_header = MZ_HEADER(fi->memory); - - RETURN_IF_BAD_POINTER(false, mz_header->lfanew); - if (mz_header->lfanew < sizeof(DOSImageHeader)) { - error("%s: not a Windows library", fi->file->name()); - return false; - } - } - - /* check for OS2 (Win16) header signature `NE' */ - RETURN_IF_BAD_POINTER(false, NE_HEADER(fi->memory)->magic); - if (NE_HEADER(fi->memory)->magic == IMAGE_OS2_SIGNATURE) { - OS2ImageHeader *header = NE_HEADER(fi->memory); - - RETURN_IF_BAD_POINTER(false, header->rsrctab); - RETURN_IF_BAD_POINTER(false, header->restab); - if (header->rsrctab >= header->restab) { - error("%s: no resource directory found", fi->file->name()); - return false; - } - - fi->is_PE_binary = false; - fi->first_resource = (byte *) NE_HEADER(fi->memory) - + header->rsrctab + sizeof(uint16); - RETURN_IF_BAD_POINTER(false, *(Win16NETypeInfo *) fi->first_resource); - - return true; - } - - /* check for NT header signature `PE' */ - RETURN_IF_BAD_POINTER(false, PE_HEADER(fi->memory)->signature); - if (PE_HEADER(fi->memory)->signature == IMAGE_NT_SIGNATURE) { - Win32ImageSectionHeader *pe_sec; - Win32ImageDataDirectory *dir; - Win32ImageNTHeaders *pe_header; - int d; - - /* allocate new memory */ - fi->total_size = calc_vma_size(fi); - if (fi->total_size == 0) { - /* calc_vma_size has reported error */ - return false; - } - fi->memory = (byte *)realloc(fi->memory, fi->total_size); - - /* relocate memory, start from last section */ - pe_header = PE_HEADER(fi->memory); - RETURN_IF_BAD_POINTER(false, pe_header->file_header.number_of_sections); - - /* we don't need to do OFFSET checking for the sections. - * calc_vma_size has already done that */ - for (d = pe_header->file_header.number_of_sections - 1; d >= 0 ; d--) { - pe_sec = PE_SECTIONS(fi->memory) + d; - - if (pe_sec->characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) - continue; - - //if (pe_sec->virtual_address + pe_sec->size_of_raw_data > fi->total_size) - - RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->virtual_address, pe_sec->size_of_raw_data); - RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->pointer_to_raw_data, pe_sec->size_of_raw_data); - if (pe_sec->virtual_address != pe_sec->pointer_to_raw_data) { - memmove(fi->memory + pe_sec->virtual_address, - fi->memory + pe_sec->pointer_to_raw_data, - pe_sec->size_of_raw_data); - } - } - - /* find resource directory */ - RETURN_IF_BAD_POINTER(false, pe_header->optional_header.data_directory[IMAGE_DIRECTORY_ENTRY_RESOURCE]); - dir = pe_header->optional_header.data_directory + IMAGE_DIRECTORY_ENTRY_RESOURCE; - if (dir->size == 0) { - error("%s: file contains no resources", fi->file->name()); - return false; - } - - fi->first_resource = fi->memory + dir->virtual_address; - fi->is_PE_binary = true; - return true; - } - - /* other (unknown) header signature was found */ - error("%s: not a Windows library", fi->file->name()); - return false; -} - -/* calc_vma_size: - * Calculate the total amount of memory needed for a 32-bit Windows - * module. Returns -1 if file was too small. - */ -int Win32ResExtractor::calc_vma_size(WinLibrary *fi) { - Win32ImageSectionHeader *seg; - int c, segcount, size; - - size = 0; - RETURN_IF_BAD_POINTER(-1, PE_HEADER(fi->memory)->file_header.number_of_sections); - segcount = PE_HEADER(fi->memory)->file_header.number_of_sections; - - /* If there are no segments, just process file like it is. - * This is (probably) not the right thing to do, but problems - * will be delt with later anyway. - */ - if (segcount == 0) - return fi->total_size; - - seg = PE_SECTIONS(fi->memory); - RETURN_IF_BAD_POINTER(-1, *seg); - for (c = 0 ; c < segcount ; c++) { - RETURN_IF_BAD_POINTER(0, *seg); - - size = MAX((uint32)size, seg->virtual_address + seg->size_of_raw_data); - /* I have no idea what misc.virtual_size is for... */ - size = MAX((uint32)size, seg->virtual_address + seg->misc.virtual_size); - seg++; - } - - return size; -} - -Win32ResExtractor::WinResource *Win32ResExtractor::find_with_resource_array(WinLibrary *fi, WinResource *wr, const char *id) { - int c, rescnt; - WinResource *return_wr; - - wr = list_resources(fi, wr, &rescnt); - if (wr == NULL) - return NULL; - - for (c = 0 ; c < rescnt ; c++) { - if (compare_resource_id(&wr[c], id)) { - /* duplicate WinResource and return it */ - return_wr = (WinResource *)malloc(sizeof(WinResource)); - memcpy(return_wr, &wr[c], sizeof(WinResource)); - - /* free old WinResource */ - free(wr); - return return_wr; - } - } - - return NULL; -} - -Win32ResExtractor::WinResource *Win32ResExtractor::find_resource(WinLibrary *fi, const char *type, const char *name, const char *language, int *level) { - WinResource *wr; - - *level = 0; - if (type == NULL) - return NULL; - wr = find_with_resource_array(fi, NULL, type); - if (wr == NULL || !wr->is_directory) - return wr; - - *level = 1; - if (name == NULL) - return wr; - wr = find_with_resource_array(fi, wr, name); - if (wr == NULL || !wr->is_directory) - return wr; - - *level = 2; - if (language == NULL) - return wr; - wr = find_with_resource_array(fi, wr, language); - return wr; -} - -#define ROW_BYTES(bits) ((((bits) + 31) >> 5) << 2) - - -int Win32ResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, - int *hotspot_x, int *hotspot_y, int *keycolor, byte **pal, int *palSize) { - Win32CursorIconFileDir dir; - Win32CursorIconFileDirEntry *entries = NULL; - uint32 offset; - uint32 c, d; - int completed; - int matched = 0; - MemoryReadStream *in = new MemoryReadStream(data, datasize); - - if (!in->read(&dir, sizeof(Win32CursorIconFileDir)- sizeof(Win32CursorIconFileDirEntry))) - goto cleanup; - fix_win32_cursor_icon_file_dir_endian(&dir); - - if (dir.reserved != 0) { - error("not an icon or cursor file (reserved non-zero)"); - goto cleanup; - } - if (dir.type != 1 && dir.type != 2) { - error("not an icon or cursor file (wrong type)"); - goto cleanup; - } - - entries = (Win32CursorIconFileDirEntry *)malloc(dir.count * sizeof(Win32CursorIconFileDirEntry)); - for (c = 0; c < dir.count; c++) { - if (!in->read(&entries[c], sizeof(Win32CursorIconFileDirEntry))) - goto cleanup; - fix_win32_cursor_icon_file_dir_entry_endian(&entries[c]); - if (entries[c].reserved != 0) - error("reserved is not zero"); - } - - offset = sizeof(Win32CursorIconFileDir) + (dir.count - 1) * (sizeof(Win32CursorIconFileDirEntry)); - - for (completed = 0; completed < dir.count; ) { - uint32 min_offset = 0x7fffffff; - int previous = completed; - - for (c = 0; c < dir.count; c++) { - if (entries[c].dib_offset == offset) { - Win32BitmapInfoHeader bitmap; - Win32RGBQuad *palette = NULL; - uint32 palette_count = 0; - uint32 image_size, mask_size; - uint32 width, height; - byte *image_data = NULL, *mask_data = NULL; - byte *row = NULL; - - if (!in->read(&bitmap, sizeof(Win32BitmapInfoHeader))) - goto local_cleanup; - - fix_win32_bitmap_info_header_endian(&bitmap); - if (bitmap.size < sizeof(Win32BitmapInfoHeader)) { - error("bitmap header is too short"); - goto local_cleanup; - } - if (bitmap.compression != 0) { - error("compressed image data not supported"); - goto local_cleanup; - } - if (bitmap.x_pels_per_meter != 0) - error("x_pels_per_meter field in bitmap should be zero"); - if (bitmap.y_pels_per_meter != 0) - error("y_pels_per_meter field in bitmap should be zero"); - if (bitmap.clr_important != 0) - error("clr_important field in bitmap should be zero"); - if (bitmap.planes != 1) - error("planes field in bitmap should be one"); - if (bitmap.size != sizeof(Win32BitmapInfoHeader)) { - uint32 skip = bitmap.size - sizeof(Win32BitmapInfoHeader); - error("skipping %d bytes of extended bitmap header", skip); - in->seek(skip, SEEK_CUR); - } - offset += bitmap.size; - - if (bitmap.clr_used != 0 || bitmap.bit_count < 24) { - palette_count = (bitmap.clr_used != 0 ? bitmap.clr_used : 1 << bitmap.bit_count); - palette = (Win32RGBQuad *)malloc(sizeof(Win32RGBQuad) * palette_count); - if (!in->read(palette, sizeof(Win32RGBQuad) * palette_count)) - goto local_cleanup; - offset += sizeof(Win32RGBQuad) * palette_count; - } - - width = bitmap.width; - height = ABS(bitmap.height)/2; - - image_size = height * ROW_BYTES(width * bitmap.bit_count); - mask_size = height * ROW_BYTES(width); - - if (entries[c].dib_size != bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad)) - debugC(DEBUG_RESOURCE, "incorrect total size of bitmap (%d specified; %d real)", - entries[c].dib_size, - bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad) - ); - - image_data = (byte *)malloc(image_size); - if (!in->read(image_data, image_size)) - goto local_cleanup; - - mask_data = (byte *)malloc(mask_size); - if (!in->read(mask_data, mask_size)) - goto local_cleanup; - - offset += image_size; - offset += mask_size; - completed++; - matched++; - - *hotspot_x = entries[c].hotspot_x; - *hotspot_y = entries[c].hotspot_y; - *w = width; - *h = height; - *keycolor = 0; - *cursor = (byte *)malloc(width * height); - - row = (byte *)malloc(width * 4); - - for (d = 0; d < height; d++) { - uint32 x; - uint32 y = (bitmap.height < 0 ? d : height - d - 1); - uint32 imod = y * (image_size / height) * 8 / bitmap.bit_count; - //uint32 mmod = y * (mask_size / height) * 8; - - for (x = 0; x < width; x++) { - - uint32 color = simple_vec(image_data, x + imod, bitmap.bit_count); - - // FIXME?: This works only with b/w cursors and white index may be - // different. But now it's enough. - if (color) { - cursor[0][width * d + x] = 15; // white in SCUMM - } else { - cursor[0][width * d + x] = 255; // transparent - } - /* - - if (bitmap.bit_count <= 16) { - if (color >= palette_count) { - error("color out of range in image data"); - goto local_cleanup; - } - row[4*x+0] = palette[color].red; - row[4*x+1] = palette[color].green; - row[4*x+2] = palette[color].blue; - - } else { - row[4*x+0] = (color >> 16) & 0xFF; - row[4*x+1] = (color >> 8) & 0xFF; - row[4*x+2] = (color >> 0) & 0xFF; - } - if (bitmap.bit_count == 32) - row[4*x+3] = (color >> 24) & 0xFF; - else - row[4*x+3] = simple_vec(mask_data, x + mmod, 1) ? 0 : 0xFF; - */ - } - - } - - if (row != NULL) - free(row); - if (palette != NULL) - free(palette); - if (image_data != NULL) { - free(image_data); - free(mask_data); - } - continue; - - local_cleanup: - - if (row != NULL) - free(row); - if (palette != NULL) - free(palette); - if (image_data != NULL) { - free(image_data); - free(mask_data); - } - goto cleanup; - } else { - if (entries[c].dib_offset > offset) - min_offset = MIN(min_offset, entries[c].dib_offset); - } - } - - if (previous == completed) { - if (min_offset < offset) { - error("offset of bitmap header incorrect (too low)"); - goto cleanup; - } - debugC(DEBUG_RESOURCE, "skipping %d bytes of garbage at %d", min_offset-offset, offset); - in->seek(min_offset - offset, SEEK_CUR); - offset = min_offset; - } - } - - free(entries); - return matched; - -cleanup: - - free(entries); - return -1; -} - -uint32 Win32ResExtractor::simple_vec(byte *data, uint32 ofs, byte size) { - switch (size) { - case 1: - return (data[ofs/8] >> (7 - ofs%8)) & 1; - case 2: - return (data[ofs/4] >> ((3 - ofs%4) << 1)) & 3; - case 4: - return (data[ofs/2] >> ((1 - ofs%2) << 2)) & 15; - case 8: - return data[ofs]; - case 16: - return data[2*ofs] | data[2*ofs+1] << 8; - case 24: - return data[3*ofs] | data[3*ofs+1] << 8 | data[3*ofs+2] << 16; - case 32: - return data[4*ofs] | data[4*ofs+1] << 8 | data[4*ofs+2] << 16 | data[4*ofs+3] << 24; - } - - return 0; -} - -#define LE16(x) ((x) = TO_LE_16(x)) -#define LE32(x) ((x) = TO_LE_32(x)) - -void Win32ResExtractor::fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj) { - LE16(obj->reserved); - LE16(obj->type); - LE16(obj->count); -} - -void Win32ResExtractor::fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj) { - LE32(obj->size); - LE32(obj->width); - LE32(obj->height); - LE16(obj->planes); - LE16(obj->bit_count); - LE32(obj->compression); - LE32(obj->size_image); - LE32(obj->x_pels_per_meter); - LE32(obj->y_pels_per_meter); - LE32(obj->clr_used); - LE32(obj->clr_important); -} - -void Win32ResExtractor::fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj) { - LE16(obj->hotspot_x); - LE16(obj->hotspot_y); - LE32(obj->dib_size); - LE32(obj->dib_offset); -} - -void Win32ResExtractor::fix_win32_image_section_header(Win32ImageSectionHeader *obj) { - LE32(obj->misc.physical_address); - LE32(obj->virtual_address); - LE32(obj->size_of_raw_data); - LE32(obj->pointer_to_raw_data); - LE32(obj->pointer_to_relocations); - LE32(obj->pointer_to_linenumbers); - LE16(obj->number_of_relocations); - LE16(obj->number_of_linenumbers); - LE32(obj->characteristics); -} - -void Win32ResExtractor::fix_os2_image_header_endian(OS2ImageHeader *obj) { - LE16(obj->magic); - LE16(obj->enttab); - LE16(obj->cbenttab); - LE32(obj->crc); - LE16(obj->flags); - LE16(obj->autodata); - LE16(obj->heap); - LE16(obj->stack); - LE32(obj->csip); - LE32(obj->sssp); - LE16(obj->cseg); - LE16(obj->cmod); - LE16(obj->cbnrestab); - LE16(obj->segtab); - LE16(obj->rsrctab); - LE16(obj->restab); - LE16(obj->modtab); - LE16(obj->imptab); - LE32(obj->nrestab); - LE16(obj->cmovent); - LE16(obj->align); - LE16(obj->cres); - LE16(obj->fastload_offset); - LE16(obj->fastload_length); - LE16(obj->swaparea); - LE16(obj->expver); -} - -/* fix_win32_image_header_endian: - * NOTE: This assumes that the optional header is always available. - */ -void Win32ResExtractor::fix_win32_image_header_endian(Win32ImageNTHeaders *obj) { - LE32(obj->signature); - LE16(obj->file_header.machine); - LE16(obj->file_header.number_of_sections); - LE32(obj->file_header.time_date_stamp); - LE32(obj->file_header.pointer_to_symbol_table); - LE32(obj->file_header.number_of_symbols); - LE16(obj->file_header.size_of_optional_header); - LE16(obj->file_header.characteristics); - LE16(obj->optional_header.magic); - LE32(obj->optional_header.size_of_code); - LE32(obj->optional_header.size_of_initialized_data); - LE32(obj->optional_header.size_of_uninitialized_data); - LE32(obj->optional_header.address_of_entry_point); - LE32(obj->optional_header.base_of_code); - LE32(obj->optional_header.base_of_data); - LE32(obj->optional_header.image_base); - LE32(obj->optional_header.section_alignment); - LE32(obj->optional_header.file_alignment); - LE16(obj->optional_header.major_operating_system_version); - LE16(obj->optional_header.minor_operating_system_version); - LE16(obj->optional_header.major_image_version); - LE16(obj->optional_header.minor_image_version); - LE16(obj->optional_header.major_subsystem_version); - LE16(obj->optional_header.minor_subsystem_version); - LE32(obj->optional_header.win32_version_value); - LE32(obj->optional_header.size_of_image); - LE32(obj->optional_header.size_of_headers); - LE32(obj->optional_header.checksum); - LE16(obj->optional_header.subsystem); - LE16(obj->optional_header.dll_characteristics); - LE32(obj->optional_header.size_of_stack_reserve); - LE32(obj->optional_header.size_of_stack_commit); - LE32(obj->optional_header.size_of_heap_reserve); - LE32(obj->optional_header.size_of_heap_commit); - LE32(obj->optional_header.loader_flags); - LE32(obj->optional_header.number_of_rva_and_sizes); -} - -void Win32ResExtractor::fix_win32_image_data_directory(Win32ImageDataDirectory *obj) { - LE32(obj->virtual_address); - LE32(obj->size); -} - - -MacResExtractor::MacResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) { - _resOffset = -1; -} - -int MacResExtractor::extractResource(int id, byte **buf) { - Common::File in; - int size; - - if (!_fileName[0]) // We are running for the first time - if (_vm->_substResFileNameIndex > 0) { - char buf1[128]; - - snprintf(buf1, 128, "%s.he3", _vm->getBaseName()); - _vm->generateSubstResFileName(buf1, _fileName, sizeof(buf1)); - - // Some programs write it as .bin. Try that too - if (!in.exists(_fileName)) { - strcpy(buf1, _fileName); - snprintf(_fileName, 128, "%s.bin", buf1); - - if (!in.exists(_fileName)) { - // And finally check if we have dumped resource fork - snprintf(_fileName, 128, "%s.rsrc", buf1); - if (!in.exists(_fileName)) { - error("Cannot open file any of files '%s', '%s.bin', '%s.rsrc", - buf1, buf1, buf1); - } - } - } - } - - in.open(_fileName); - if (!in.isOpen()) { - error("Cannot open file %s", _fileName); - } - - // we haven't calculated it - if (_resOffset == -1) { - if (!init(in)) - error("Resource fork is missing in file '%s'", _fileName); - in.close(); - in.open(_fileName); - } - - *buf = getResource(in, "crsr", 1000 + id, &size); - - in.close(); - - if (*buf == NULL) - error("There is no cursor ID #%d", 1000 + id); - - return size; -} - -#define MBI_INFOHDR 128 -#define MBI_ZERO1 0 -#define MBI_NAMELEN 1 -#define MBI_ZERO2 74 -#define MBI_ZERO3 82 -#define MBI_DFLEN 83 -#define MBI_RFLEN 87 -#define MAXNAMELEN 63 - -bool MacResExtractor::init(Common::File in) { - byte infoHeader[MBI_INFOHDR]; - int32 data_size, rsrc_size; - int32 data_size_pad, rsrc_size_pad; - int filelen; - - filelen = in.size(); - in.read(infoHeader, MBI_INFOHDR); - - // Maybe we have MacBinary? - if (infoHeader[MBI_ZERO1] == 0 && infoHeader[MBI_ZERO2] == 0 && - infoHeader[MBI_ZERO3] == 0 && infoHeader[MBI_NAMELEN] <= MAXNAMELEN) { - - // Pull out fork lengths - data_size = READ_BE_UINT32(infoHeader + MBI_DFLEN); - rsrc_size = READ_BE_UINT32(infoHeader + MBI_RFLEN); - - data_size_pad = (((data_size + 127) >> 7) << 7); - rsrc_size_pad = (((rsrc_size + 127) >> 7) << 7); - - // Length check - int sumlen = MBI_INFOHDR + data_size_pad + rsrc_size_pad; - - if (sumlen == filelen) - _resOffset = MBI_INFOHDR + data_size_pad; - } - - if (_resOffset == -1) // MacBinary check is failed - _resOffset = 0; // Maybe we have dumped fork? - - in.seek(_resOffset); - - _dataOffset = in.readUint32BE() + _resOffset; - _mapOffset = in.readUint32BE() + _resOffset; - _dataLength = in.readUint32BE(); - _mapLength = in.readUint32BE(); - - // do sanity check - if (_dataOffset >= filelen || _mapOffset >= filelen || - _dataLength + _mapLength > filelen) { - _resOffset = -1; - return false; - } - - debug(7, "got header: data %d [%d] map %d [%d]", - _dataOffset, _dataLength, _mapOffset, _mapLength); - - readMap(in); - - return true; -} - -byte *MacResExtractor::getResource(Common::File in, const char *typeID, int16 resID, int *size) { - int i; - int typeNum = -1; - int resNum = -1; - byte *buf; - int len; - - for (i = 0; i < _resMap.numTypes; i++) - if (strcmp(_resTypes[i].id, typeID) == 0) { - typeNum = i; - break; - } - - if (typeNum == -1) - return NULL; - - for (i = 0; i < _resTypes[typeNum].items; i++) - if (_resLists[typeNum][i].id == resID) { - resNum = i; - break; - } - - if (resNum == -1) - return NULL; - - in.seek(_dataOffset + _resLists[typeNum][resNum].dataOffset); - - len = in.readUint32BE(); - buf = (byte *)malloc(len); - - in.read(buf, len); - - *size = len; - - return buf; -} - -void MacResExtractor::readMap(Common::File in) { - int i, j, len; - - in.seek(_mapOffset + 22); - - _resMap.resAttr = in.readUint16BE(); - _resMap.typeOffset = in.readUint16BE(); - _resMap.nameOffset = in.readUint16BE(); - _resMap.numTypes = in.readUint16BE(); - _resMap.numTypes++; - - in.seek(_mapOffset + _resMap.typeOffset + 2); - _resTypes = new ResType[_resMap.numTypes]; - - for (i = 0; i < _resMap.numTypes; i++) { - in.read(_resTypes[i].id, 4); - _resTypes[i].id[4] = 0; - _resTypes[i].items = in.readUint16BE(); - _resTypes[i].offset = in.readUint16BE(); - _resTypes[i].items++; - } - - _resLists = new ResPtr[_resMap.numTypes]; - - for (i = 0; i < _resMap.numTypes; i++) { - _resLists[i] = new Resource[_resTypes[i].items]; - in.seek(_resTypes[i].offset + _mapOffset + _resMap.typeOffset); - - for (j = 0; j < _resTypes[i].items; j++) { - ResPtr resPtr = _resLists[i] + j; - - resPtr->id = in.readUint16BE(); - resPtr->nameOffset = in.readUint16BE(); - resPtr->dataOffset = in.readUint32BE(); - in.readUint32BE(); - resPtr->name = 0; - - resPtr->attr = resPtr->dataOffset >> 24; - resPtr->dataOffset &= 0xFFFFFF; - } - - for (j = 0; j < _resTypes[i].items; j++) { - if (_resLists[i][j].nameOffset != -1) { - in.seek(_resLists[i][j].nameOffset + _mapOffset + _resMap.nameOffset); - - len = in.readByte(); - _resLists[i][j].name = new byte[len + 1]; - _resLists[i][j].name[len] = 0; - in.read(_resLists[i][j].name, len); - } - } - } -} - -int MacResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, - int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize) { - Common::MemoryReadStream dis(data, datasize); - int i, b; - byte imageByte; - byte *iconData; - int numBytes; - int pixelsPerByte, bpp; - int ctSize; - byte bitmask; - int iconRowBytes, iconBounds[4]; - int ignored; - int iconDataSize; - - dis.readUint16BE(); // type - dis.readUint32BE(); // offset to pixel map - dis.readUint32BE(); // offset to pixel data - dis.readUint32BE(); // expanded cursor data - dis.readUint16BE(); // expanded data depth - dis.readUint32BE(); // reserved - - // Grab B/W icon data - *cursor = (byte *)malloc(16 * 16); - for (i = 0; i < 32; i++) { - imageByte = dis.readByte(); - for (b = 0; b < 8; b++) - cursor[0][i*8+b] = (byte)((imageByte & - (0x80 >> b)) > 0? 0x0F: 0x00); - } - - // Apply mask data - for (i = 0; i < 32; i++) { - imageByte = dis.readByte(); - for (b = 0; b < 8; b++) - if ((imageByte & (0x80 >> b)) == 0) - cursor[0][i*8+b] = 0xff; - } - - *hotspot_y = dis.readUint16BE(); - *hotspot_x = dis.readUint16BE(); - *w = *h = 16; - - // Use b/w cursor on backends which don't support cursor palettes - if (!_vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette)) - return 1; - - dis.readUint32BE(); // reserved - dis.readUint32BE(); // cursorID - - // Color version of cursor - dis.readUint32BE(); // baseAddr - - // Keep only lowbyte for now - dis.readByte(); - iconRowBytes = dis.readByte(); - - if (!iconRowBytes) - return 1; - - iconBounds[0] = dis.readUint16BE(); - iconBounds[1] = dis.readUint16BE(); - iconBounds[2] = dis.readUint16BE(); - iconBounds[3] = dis.readUint16BE(); - - dis.readUint16BE(); // pmVersion - dis.readUint16BE(); // packType - dis.readUint32BE(); // packSize - - dis.readUint32BE(); // hRes - dis.readUint32BE(); // vRes - - dis.readUint16BE(); // pixelType - dis.readUint16BE(); // pixelSize - dis.readUint16BE(); // cmpCount - dis.readUint16BE(); // cmpSize - - dis.readUint32BE(); // planeByte - dis.readUint32BE(); // pmTable - dis.readUint32BE(); // reserved - - // Pixel data for cursor - iconDataSize = iconRowBytes * (iconBounds[3] - iconBounds[1]); - iconData = (byte *)malloc(iconDataSize); - dis.read(iconData, iconDataSize); - - // Color table - dis.readUint32BE(); // ctSeed - dis.readUint16BE(); // ctFlag - ctSize = dis.readUint16BE() + 1; - - *palette = (byte *)malloc(ctSize * 4); - - // Read just high byte of 16-bit color - for (int c = 0; c < ctSize; c++) { - // We just use indices 0..ctSize, so ignore color ID - dis.readUint16BE(); // colorID[c] - - palette[0][c * 4 + 0] = dis.readByte(); - ignored = dis.readByte(); - - palette[0][c * 4 + 1] = dis.readByte(); - ignored = dis.readByte(); - - palette[0][c * 4 + 2] = dis.readByte(); - ignored = dis.readByte(); - - palette[0][c * 4 + 3] = 0; - } - - *palSize = ctSize; - - numBytes = - (iconBounds[2] - iconBounds[0]) * - (iconBounds[3] - iconBounds[1]); - - pixelsPerByte = (iconBounds[2] - iconBounds[0]) / iconRowBytes; - bpp = 8 / pixelsPerByte; - - // build a mask to make sure the pixels are properly shifted out - bitmask = 0; - for (int m = 0; m < bpp; m++) { - bitmask <<= 1; - bitmask |= 1; - } - - // Extract pixels from bytes - for (int j = 0; j < iconDataSize; j++) - for (b = 0; b < pixelsPerByte; b++) { - int idx = j * pixelsPerByte + (pixelsPerByte - 1 - b); - - if (cursor[0][idx] != 0xff) // if mask is not there - cursor[0][idx] = (byte)((iconData[j] >> (b * bpp)) & bitmask); - } - - free(iconData); - - assert(datasize - dis.pos() == 0); - - return 1; -} - - - -void ScummEngine_v70he::readRoomsOffsets() { - int num, i; - byte *ptr; - - debug(9, "readRoomOffsets()"); - - num = READ_LE_UINT16(_heV7RoomOffsets); - ptr = _heV7RoomOffsets + 2; - for (i = 0; i < num; i++) { - res.roomoffs[rtRoom][i] = READ_LE_UINT32(ptr); - ptr += 4; - } -} - -void ScummEngine_v70he::readGlobalObjects() { - int num = _fileHandle->readUint16LE(); - assert(num == _numGlobalObjects); - - _fileHandle->read(_objectStateTable, num); - _fileHandle->read(_objectOwnerTable, num); - _fileHandle->read(_objectRoomTable, num); - - _fileHandle->read(_classData, num * sizeof(uint32)); - -#if defined(SCUMM_BIG_ENDIAN) - // Correct the endianess if necessary - for (int i = 0; i != num; i++) - _classData[i] = FROM_LE_32(_classData[i]); -#endif -} - -void ScummEngine_v99he::readMAXS(int blockSize) { - debug(0, "ScummEngine_v99he readMAXS: MAXS has blocksize %d", blockSize); - - _numVariables = _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _numRoomVariables = _fileHandle->readUint16LE(); - _numLocalObjects = _fileHandle->readUint16LE(); - _numArray = _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _numFlObject = _fileHandle->readUint16LE(); - _numInventory = _fileHandle->readUint16LE(); - _numRooms = _fileHandle->readUint16LE(); - _numScripts = _fileHandle->readUint16LE(); - _numSounds = _fileHandle->readUint16LE(); - _numCharsets = _fileHandle->readUint16LE(); - _numCostumes = _fileHandle->readUint16LE(); - _numGlobalObjects = _fileHandle->readUint16LE(); - _numImages = _fileHandle->readUint16LE(); - _numSprites = _fileHandle->readUint16LE(); - _numLocalScripts = _fileHandle->readUint16LE(); - _HEHeapSize = _fileHandle->readUint16LE(); - _numPalettes = _fileHandle->readUint16LE(); - _numUnk = _fileHandle->readUint16LE(); - _numTalkies = _fileHandle->readUint16LE(); - _numNewNames = 10; - - _objectRoomTable = (byte *)calloc(_numGlobalObjects, 1); - _numGlobalScripts = 2048; -} - -void ScummEngine_v90he::readMAXS(int blockSize) { - debug(0, "ScummEngine_v90he readMAXS: MAXS has blocksize %d", blockSize); - - _numVariables = _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _numRoomVariables = _fileHandle->readUint16LE(); - _numLocalObjects = _fileHandle->readUint16LE(); - _numArray = _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _numFlObject = _fileHandle->readUint16LE(); - _numInventory = _fileHandle->readUint16LE(); - _numRooms = _fileHandle->readUint16LE(); - _numScripts = _fileHandle->readUint16LE(); - _numSounds = _fileHandle->readUint16LE(); - _numCharsets = _fileHandle->readUint16LE(); - _numCostumes = _fileHandle->readUint16LE(); - _numGlobalObjects = _fileHandle->readUint16LE(); - _numImages = _fileHandle->readUint16LE(); - _numSprites = _fileHandle->readUint16LE(); - _numLocalScripts = _fileHandle->readUint16LE(); - _HEHeapSize = _fileHandle->readUint16LE(); - _numNewNames = 10; - - _objectRoomTable = (byte *)calloc(_numGlobalObjects, 1); - if (_features & GF_HE_985) - _numGlobalScripts = 2048; - else - _numGlobalScripts = 200; -} - -void ScummEngine_v72he::readMAXS(int blockSize) { - debug(0, "ScummEngine_v72he readMAXS: MAXS has blocksize %d", blockSize); - - _numVariables = _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _numBitVariables = _numRoomVariables = _fileHandle->readUint16LE(); - _numLocalObjects = _fileHandle->readUint16LE(); - _numArray = _fileHandle->readUint16LE(); - _fileHandle->readUint16LE(); - _numVerbs = _fileHandle->readUint16LE(); - _numFlObject = _fileHandle->readUint16LE(); - _numInventory = _fileHandle->readUint16LE(); - _numRooms = _fileHandle->readUint16LE(); - _numScripts = _fileHandle->readUint16LE(); - _numSounds = _fileHandle->readUint16LE(); - _numCharsets = _fileHandle->readUint16LE(); - _numCostumes = _fileHandle->readUint16LE(); - _numGlobalObjects = _fileHandle->readUint16LE(); - _numImages = _fileHandle->readUint16LE(); - _numNewNames = 10; - - _objectRoomTable = (byte *)calloc(_numGlobalObjects, 1); - _numGlobalScripts = 200; -} - -byte *ScummEngine_v72he::getStringAddress(int i) { - byte *addr = getResourceAddress(rtString, i); - if (addr == NULL) - return NULL; - return ((ScummEngine_v72he::ArrayHeader *)addr)->data; -} - -int ScummEngine_v72he::getSoundResourceSize(int id) { - const byte *ptr; - int offs, size; - - if (id > _numSounds) { - if (!_sound->getHEMusicDetails(id, offs, size)) { - debug(0, "getSoundResourceSize: musicID %d not found", id); - return 0; - } - } else { - ptr = getResourceAddress(rtSound, id); - if (!ptr) - return 0; - - if (READ_UINT32(ptr) == MKID('RIFF')) { - byte flags; - int rate; - - size = READ_BE_UINT32(ptr + 4); - Common::MemoryReadStream stream(ptr, size); - - if (!loadWAVFromStream(stream, size, rate, flags)) { - error("getSoundResourceSize: Not a valid WAV file"); - } - } else { - ptr += 8 + READ_BE_UINT32(ptr + 12); - if (READ_UINT32(ptr) == MKID('SBNG')) { - ptr += READ_BE_UINT32(ptr + 4); - } - - assert(READ_UINT32(ptr) == MKID('SDAT')); - size = READ_BE_UINT32(ptr + 4) - 8; - } - } - - return size; -} - -void ScummEngine_v80he::createSound(int snd1id, int snd2id) { - debug(0, "createSound: snd1id %d snd2id %d", snd1id, snd2id); - - byte *snd1Ptr, *snd2Ptr; - byte *sbng1Ptr, *sbng2Ptr; - byte *sdat1Ptr, *sdat2Ptr; - byte *src, *dst, *tmp; - int len, offs, size; - int sdat1size, sdat2size; - - if (snd2id == -1) { - _sndPtrOffs = 0; - _sndTmrOffs = 0; - return; - } - - if (snd1id != _curSndId) { - _curSndId = snd1id; - _sndPtrOffs = 0; - _sndTmrOffs = 0; - } - - snd1Ptr = getResourceAddress(rtSound, snd1id); - assert(snd1Ptr); - snd2Ptr = getResourceAddress(rtSound, snd2id); - assert(snd2Ptr); - - int i; - int chan = -1; - for (i = 0; i < ARRAYSIZE(_sound->_heChannel); i++) { - if (_sound->_heChannel[i].sound == snd1id) - chan = i; - } - - sbng1Ptr = heFindResource(MKID('SBNG'), snd1Ptr); - sbng2Ptr = heFindResource(MKID('SBNG'), snd2Ptr); - - if (sbng1Ptr != NULL && sbng2Ptr != NULL) { - if (chan != -1 && _sound->_heChannel[chan].codeOffs > 0) { - int curOffs = _sound->_heChannel[chan].codeOffs; - - src = snd1Ptr + curOffs; - dst = sbng1Ptr + 8; - size = READ_BE_UINT32(sbng1Ptr + 4); - len = sbng1Ptr - snd1Ptr + size - curOffs; - - byte *data = (byte *)malloc(len); - memcpy(data, src, len); - memcpy(dst, data, len); - free(data); - - dst = sbng1Ptr + 8; - while ((size = READ_LE_UINT16(dst)) != 0) - dst += size; - } else { - dst = sbng1Ptr + 8; - } - - _sound->_heChannel[chan].codeOffs = sbng1Ptr - snd1Ptr + 8; - - tmp = sbng2Ptr + 8; - while ((offs = READ_LE_UINT16(tmp)) != 0) { - tmp += offs; - } - - src = sbng2Ptr + 8; - len = tmp - sbng2Ptr - 6; - memcpy(dst, src, len); - - int32 time; - while ((size = READ_LE_UINT16(dst)) != 0) { - time = READ_LE_UINT32(dst + 2); - time += _sndTmrOffs; - WRITE_LE_UINT32(dst + 2, time); - dst += size; - } - } - - sdat1Ptr = heFindResource(MKID('SDAT'), snd1Ptr); - assert(sdat1Ptr); - sdat2Ptr = heFindResource(MKID('SDAT'), snd2Ptr); - assert(sdat2Ptr); - - sdat1size = READ_BE_UINT32(sdat1Ptr + 4) - 8 - _sndPtrOffs; - sdat2size = READ_BE_UINT32(sdat2Ptr + 4) - 8; - - debug(0, "SDAT size1 %d size2 %d", sdat1size, sdat2size); - if (sdat2size < sdat1size) { - src = sdat2Ptr + 8; - dst = sdat1Ptr + 8 + _sndPtrOffs; - len = sdat2size; - - memcpy(dst, src, len); - - _sndPtrOffs += sdat2size; - _sndTmrOffs += sdat2size; - } else { - src = sdat2Ptr + 8; - dst = sdat1Ptr + 8 + _sndPtrOffs; - len = sdat1size; - - memcpy(dst, src, len); - - if (sdat2size != sdat1size) { - src = sdat2Ptr + 8 + sdat1size; - dst = sdat1Ptr + 8; - len = sdat2size - sdat1size; - - memcpy(dst, src, len); - } - - _sndPtrOffs = sdat2size - sdat1size; - _sndTmrOffs += sdat2size; - } -} - -} // End of namespace Scumm diff --git a/engines/scumm/resource_v7he.h b/engines/scumm/resource_v7he.h deleted file mode 100644 index 1496aa3d7f..0000000000 --- a/engines/scumm/resource_v7he.h +++ /dev/null @@ -1,556 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2004-2006 The ScummVM project - * - * Parts of code heavily based on: - * icoutils - A set of programs dealing with MS Windows icons and cursors. - * Copyright (C) 1998-2001 Oskar Liljeblad - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#if !defined(RESOURCE_V7HE_H) && !defined(DISABLE_HE) -#define RESOURCE_V7HE_H - -namespace Scumm { - -#define WINRES_ID_MAXLEN (256) - -/* - * Definitions - */ - -#define ACTION_LIST 1 /* command: list resources */ -#define ACTION_EXTRACT 2 /* command: extract resources */ -#define CALLBACK_STOP 0 /* results of ResourceCallback */ -#define CALLBACK_CONTINUE 1 -#define CALLBACK_CONTINUE_RECURS 2 - -#define MZ_HEADER(x) ((DOSImageHeader *)(x)) -#define NE_HEADER(x) ((OS2ImageHeader *)PE_HEADER(x)) -#define NE_TYPEINFO_NEXT(x) ((Win16NETypeInfo *)((byte *)(x) + sizeof(Win16NETypeInfo) + \ - ((Win16NETypeInfo *)x)->count * sizeof(Win16NENameInfo))) -#define NE_RESOURCE_NAME_IS_NUMERIC (0x8000) - -#define STRIP_RES_ID_FORMAT(x) (x != NULL && (x[0] == '-' || x[0] == '+') ? ++x : x) - -#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 -#define IMAGE_SIZEOF_SHORT_NAME 8 - -#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 -#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 - -#define PE_HEADER(module) \ - ((Win32ImageNTHeaders*)((byte *)(module) + \ - (((DOSImageHeader*)(module))->lfanew))) - -#define PE_SECTIONS(module) \ - ((Win32ImageSectionHeader *)((byte *) &PE_HEADER(module)->optional_header + \ - PE_HEADER(module)->file_header.size_of_optional_header)) - -#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ -#define IMAGE_OS2_SIGNATURE 0x454E /* NE */ -#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */ -#define IMAGE_OS2_SIGNATURE_LX 0x584C /* LX */ -#define IMAGE_VXD_SIGNATURE 0x454C /* LE */ -#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ - -#if !defined (WIN32) -#define IMAGE_SCN_CNT_CODE 0x00000020 -#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 -#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 -#endif - -#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 -#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 -#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 -#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 -#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 -#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 -#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 -#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 -#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* (MIPS GP) */ -#define IMAGE_DIRECTORY_ENTRY_TLS 9 -#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 -#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 -#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ -#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 -#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 - -#if !defined (WIN32) -#define RT_CURSOR 1 -#define RT_BITMAP 2 -#define RT_ICON 3 -#define RT_MENU 4 -#define RT_DIALOG 5 -#define RT_STRING 6 -#define RT_FONTDIR 7 -#define RT_FONT 8 -#define RT_ACCELERATOR 9 -#define RT_RCDATA 10 -#define RT_MESSAGELIST 11 -#define RT_GROUP_CURSOR 12 -#define RT_GROUP_ICON 14 -#endif - -#define RETURN_IF_BAD_POINTER(r, x) \ - if (!check_offset(fi->memory, fi->total_size, fi->file->name(), &(x), sizeof(x))) \ - return (r); -#define RETURN_IF_BAD_OFFSET(r, x, s) \ - if (!check_offset(fi->memory, fi->total_size, fi->file->name(), x, s)) \ - return (r); - -class ScummEngine_v70he; - -class ResExtractor { -public: - ResExtractor(ScummEngine_v70he *scumm); - virtual ~ResExtractor(); - - void setCursor(int id); - - virtual int extractResource(int id, byte **buf) { return 0; }; - virtual int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, - int *hotspot_x, int *hotspot_y, int *keycolor, - byte **palette, int *palSize) { return 0; }; - - enum { - MAX_CACHED_CURSORS = 10 - }; - - struct CachedCursor { - bool valid; - int id; - byte *bitmap; - int w, h; - int hotspot_x, hotspot_y; - uint32 last_used; - byte *palette; - int palSize; - }; - - ScummEngine_v70he *_vm; - - ResExtractor::CachedCursor *findCachedCursor(int id); - ResExtractor::CachedCursor *getCachedCursorSlot(); - - bool _arg_raw; - char _fileName[256]; - CachedCursor _cursorCache[MAX_CACHED_CURSORS]; - - typedef Common::MemoryReadStream MemoryReadStream; - -}; - -class Win32ResExtractor : public ResExtractor { - public: - Win32ResExtractor(ScummEngine_v70he *scumm); - ~Win32ResExtractor() {}; - int extractResource(int id, byte **data); - void setCursor(int id); - int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, - int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize); - - private: - int extractResource_(const char *resType, char *resName, byte **data); -/* - * Structures - */ - -#if !defined(__GNUC__) - #pragma START_PACK_STRUCTS -#endif - - struct WinLibrary { - Common::File *file; - byte *memory; - byte *first_resource; - bool is_PE_binary; - int total_size; - }; - - struct WinResource { - char id[256]; - void *this_; - void *children; - int level; - bool numeric_id; - bool is_directory; - }; - - - struct Win32IconResDir { - byte width; - byte height; - byte color_count; - byte reserved; - }; - - struct Win32CursorDir { - uint16 width; - uint16 height; - }; - - struct Win32CursorIconDirEntry { - union { - Win32IconResDir icon; - Win32CursorDir cursor; - } res_info; - uint16 plane_count; - uint16 bit_count; - uint32 bytes_in_res; - uint16 res_id; - }; - - struct Win32CursorIconDir { - uint16 reserved; - uint16 type; - uint16 count; - Win32CursorIconDirEntry entries[1] GCC_PACK; - }; - - struct Win32CursorIconFileDirEntry { - byte width; - byte height; - byte color_count; - byte reserved; - uint16 hotspot_x; - uint16 hotspot_y; - uint32 dib_size; - uint32 dib_offset; - }; - - struct Win32CursorIconFileDir { - uint16 reserved; - uint16 type; - uint16 count; - Win32CursorIconFileDirEntry entries[1]; - }; - - struct Win32BitmapInfoHeader { - uint32 size; - int32 width; - int32 height; - uint16 planes; - uint16 bit_count; - uint32 compression; - uint32 size_image; - int32 x_pels_per_meter; - int32 y_pels_per_meter; - uint32 clr_used; - uint32 clr_important; - }; - - struct Win32RGBQuad { - byte blue; - byte green; - byte red; - byte reserved; - }; - - struct Win32ImageResourceDirectoryEntry { - union { - struct { - #ifdef SCUMM_BIGENDIAN - unsigned name_is_string:1; - unsigned name_offset:31; - #else - unsigned name_offset:31; - unsigned name_is_string:1; - #endif - } s1; - uint32 name; - struct { - #ifdef SCUMM_BIG_ENDIAN - uint16 __pad; - uint16 id; - #else - uint16 id; - uint16 __pad; - #endif - } s2; - } u1; - union { - uint32 offset_to_data; - struct { - #ifdef SCUMM_BIG_ENDIAN - unsigned data_is_directory:1; - unsigned offset_to_directory:31; - #else - unsigned offset_to_directory:31; - unsigned data_is_directory:1; - #endif - } s; - } u2; - }; - - struct Win16NETypeInfo { - uint16 type_id; - uint16 count; - uint32 resloader; // FARPROC16 - smaller? uint16? - }; - - struct Win16NENameInfo { - uint16 offset; - uint16 length; - uint16 flags; - uint16 id; - uint16 handle; - uint16 usage; - }; - - struct OS2ImageHeader { - uint16 magic; - byte ver; - byte rev; - uint16 enttab; - uint16 cbenttab; - int32 crc; - uint16 flags; - uint16 autodata; - uint16 heap; - uint16 stack; - uint32 csip; - uint32 sssp; - uint16 cseg; - uint16 cmod; - uint16 cbnrestab; - uint16 segtab; - uint16 rsrctab; - uint16 restab; - uint16 modtab; - uint16 imptab; - uint32 nrestab; - uint16 cmovent; - uint16 align; - uint16 cres; - byte exetyp; - byte flagsothers; - uint16 fastload_offset; - uint16 fastload_length; - uint16 swaparea; - uint16 expver; - }; - - struct DOSImageHeader { - uint16 magic; - uint16 cblp; - uint16 cp; - uint16 crlc; - uint16 cparhdr; - uint16 minalloc; - uint16 maxalloc; - uint16 ss; - uint16 sp; - uint16 csum; - uint16 ip; - uint16 cs; - uint16 lfarlc; - uint16 ovno; - uint16 res[4]; - uint16 oemid; - uint16 oeminfo; - uint16 res2[10]; - uint32 lfanew; - }; - - struct Win32ImageFileHeader { - uint16 machine; - uint16 number_of_sections; - uint32 time_date_stamp; - uint32 pointer_to_symbol_table; - uint32 number_of_symbols; - uint16 size_of_optional_header; - uint16 characteristics; - }; - - struct Win32ImageDataDirectory { - uint32 virtual_address; - uint32 size; - }; - - struct Win32ImageOptionalHeader { - uint16 magic; - byte major_linker_version; - byte minor_linker_version; - uint32 size_of_code; - uint32 size_of_initialized_data; - uint32 size_of_uninitialized_data; - uint32 address_of_entry_point; - uint32 base_of_code; - uint32 base_of_data; - uint32 image_base; - uint32 section_alignment; - uint32 file_alignment; - uint16 major_operating_system_version; - uint16 minor_operating_system_version; - uint16 major_image_version; - uint16 minor_image_version; - uint16 major_subsystem_version; - uint16 minor_subsystem_version; - uint32 win32_version_value; - uint32 size_of_image; - uint32 size_of_headers; - uint32 checksum; - uint16 subsystem; - uint16 dll_characteristics; - uint32 size_of_stack_reserve; - uint32 size_of_stack_commit; - uint32 size_of_heap_reserve; - uint32 size_of_heap_commit; - uint32 loader_flags; - uint32 number_of_rva_and_sizes; - Win32ImageDataDirectory data_directory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - }; - - struct Win32ImageNTHeaders { - uint32 signature; - Win32ImageFileHeader file_header; - Win32ImageOptionalHeader optional_header; - }; - - struct Win32ImageSectionHeader { - byte name[IMAGE_SIZEOF_SHORT_NAME]; - union { - uint32 physical_address; - uint32 virtual_size; - } misc; - uint32 virtual_address; - uint32 size_of_raw_data; - uint32 pointer_to_raw_data; - uint32 pointer_to_relocations; - uint32 pointer_to_linenumbers; - uint16 number_of_relocations; - uint16 number_of_linenumbers; - uint32 characteristics; - }; - - struct Win32ImageResourceDataEntry { - uint32 offset_to_data; - uint32 size; - uint32 code_page; - uint32 resource_handle; - }; - - struct Win32ImageResourceDirectory { - uint32 characteristics; - uint32 time_date_stamp; - uint16 major_version; - uint16 minor_version; - uint16 number_of_named_entries; - uint16 number_of_id_entries; - }; - -#if !defined(__GNUC__) - #pragma END_PACK_STRUCTS -#endif - -/* - * Function Prototypes - */ - - WinResource *list_resources(WinLibrary *, WinResource *, int *); - bool read_library(WinLibrary *); - WinResource *find_resource(WinLibrary *, const char *, const char *, const char *, int *); - byte *get_resource_entry(WinLibrary *, WinResource *, int *); - int do_resources(WinLibrary *, const char *, char *, char *, int, byte **); - bool compare_resource_id(WinResource *, const char *); - const char *res_type_string_to_id(const char *); - - const char *res_type_id_to_string(int); - char *get_destination_name(WinLibrary *, char *, char *, char *); - - byte *extract_resource(WinLibrary *, WinResource *, int *, bool *, char *, char *, bool); - int extract_resources(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *, byte **); - byte *extract_group_icon_cursor_resource(WinLibrary *, WinResource *, char *, int *, bool); - - bool decode_pe_resource_id(WinLibrary *, WinResource *, uint32); - bool decode_ne_resource_id(WinLibrary *, WinResource *, uint16); - WinResource *list_ne_type_resources(WinLibrary *, int *); - WinResource *list_ne_name_resources(WinLibrary *, WinResource *, int *); - WinResource *list_pe_resources(WinLibrary *, Win32ImageResourceDirectory *, int, int *); - int calc_vma_size(WinLibrary *); - int do_resources_recurs(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *, const char *, char *, char *, int, byte **); - char *get_resource_id_quoted(WinResource *); - WinResource *find_with_resource_array(WinLibrary *, WinResource *, const char *); - - bool check_offset(byte *, int, const char *, void *, int); - - uint32 simple_vec(byte *data, uint32 ofs, byte size); - - void fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj); - void fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj); - void fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj); - void fix_win32_image_section_header(Win32ImageSectionHeader *obj); - void fix_os2_image_header_endian(OS2ImageHeader *obj); - void fix_win32_image_header_endian(Win32ImageNTHeaders *obj); - void fix_win32_image_data_directory(Win32ImageDataDirectory *obj); -}; - -class MacResExtractor : public ResExtractor { - -public: - MacResExtractor(ScummEngine_v70he *scumm); - ~MacResExtractor() { } - void setCursor(int id) ; - -private: - int extractResource(int id, byte **buf); - bool init(Common::File in); - void readMap(Common::File in); - byte *getResource(Common::File in, const char *typeID, int16 resID, int *size); - int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, - int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize); - - struct ResMap { - int16 resAttr; - int16 typeOffset; - int16 nameOffset; - int16 numTypes; - }; - - struct ResType { - char id[5]; - int16 items; - int16 offset; - }; - - struct Resource { - int16 id; - int16 nameOffset; - byte attr; - int32 dataOffset; - byte *name; - }; - - typedef Resource *ResPtr; - -private: - int _resOffset; - int32 _dataOffset; - int32 _dataLength; - int32 _mapOffset; - int32 _mapLength; - ResMap _resMap; - ResType *_resTypes; - ResPtr *_resLists; -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/room.cpp b/engines/scumm/room.cpp index e53b13c663..d5734e6334 100644 --- a/engines/scumm/room.cpp +++ b/engines/scumm/room.cpp @@ -27,7 +27,7 @@ #include "scumm/boxes.h" #include "scumm/intern.h" #ifndef DISABLE_HE -#include "scumm/intern_he.h" +#include "scumm/he/intern_he.h" #endif #include "scumm/object.h" #include "scumm/resource.h" diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 9dca7abd40..57acfac3aa 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -32,13 +32,13 @@ #include "scumm/imuse_digi/dimuse.h" #include "scumm/imuse.h" #include "scumm/intern.h" -#include "scumm/intern_he.h" +#include "scumm/he/intern_he.h" #include "scumm/object.h" #include "scumm/resource.h" #include "scumm/saveload.h" #include "scumm/scumm.h" #include "scumm/sound.h" -#include "scumm/sprite_he.h" +#include "scumm/he/sprite_he.h" #include "scumm/verbs.h" #include "sound/audiocd.h" diff --git a/engines/scumm/script_v100he.cpp b/engines/scumm/script_v100he.cpp deleted file mode 100644 index 6be750b03e..0000000000 --- a/engines/scumm/script_v100he.cpp +++ /dev/null @@ -1,2978 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" - -#include "common/system.h" - -#include "scumm/actor.h" -#include "scumm/charset.h" -#include "scumm/intern_he.h" -#include "scumm/object.h" -#include "scumm/resource.h" -#include "scumm/resource_v7he.h" -#include "scumm/scumm.h" -#include "scumm/sound.h" -#include "scumm/sprite_he.h" -#include "scumm/util.h" - -namespace Scumm { - -#define OPCODE(x) _OPCODE(ScummEngine_v100he, x) - -void ScummEngine_v100he::setupOpcodes() { - static const OpcodeEntryV100he opcodes[256] = { - /* 00 */ - OPCODE(o100_actorOps), - OPCODE(o6_add), - OPCODE(o6_faceActor), - OPCODE(o90_sortArray), - /* 04 */ - OPCODE(o100_arrayOps), - OPCODE(o6_band), - OPCODE(o6_bor), - OPCODE(o6_breakHere), - /* 08 */ - OPCODE(o6_delayFrames), - OPCODE(o90_shl), - OPCODE(o90_shr), - OPCODE(o90_xor), - /* 0C */ - OPCODE(o6_setCameraAt), - OPCODE(o6_actorFollowCamera), - OPCODE(o6_loadRoom), - OPCODE(o6_panCameraTo), - /* 10 */ - OPCODE(o72_captureWizImage), - OPCODE(o100_jumpToScript), - OPCODE(o6_setClass), - OPCODE(o60_closeFile), - /* 14 */ - OPCODE(o6_loadRoomWithEgo), - OPCODE(o6_invalid), - OPCODE(o72_setFilePath), - OPCODE(o100_createSound), - /* 18 */ - OPCODE(o6_cutscene), - OPCODE(o6_pop), - OPCODE(o72_traceStatus), - OPCODE(o6_wordVarDec), - /* 1C */ - OPCODE(o6_wordArrayDec), - OPCODE(o72_deleteFile), - OPCODE(o100_dim2dimArray), - OPCODE(o100_dimArray), - /* 20 */ - OPCODE(o6_div), - OPCODE(o6_animateActor), - OPCODE(o6_doSentence), - OPCODE(o6_drawBox), - /* 24 */ - OPCODE(o72_drawWizImage), - OPCODE(o80_drawWizPolygon), - OPCODE(o100_drawLine), - OPCODE(o100_drawObject), - /* 28 */ - OPCODE(o6_dup), - OPCODE(o90_dup_n), - OPCODE(o6_endCutscene), - OPCODE(o6_stopObjectCode), - /* 2C */ - OPCODE(o6_stopObjectCode), - OPCODE(o6_eq), - OPCODE(o100_floodFill), - OPCODE(o6_freezeUnfreeze), - /* 30 */ - OPCODE(o6_ge), - OPCODE(o6_getDateTime), - OPCODE(o100_setSpriteGroupInfo), - OPCODE(o6_gt), - /* 34 */ - OPCODE(o100_resourceRoutines), - OPCODE(o6_if), - OPCODE(o6_ifNot), - OPCODE(o100_wizImageOps), - /* 38 */ - OPCODE(o72_isAnyOf), - OPCODE(o6_wordVarInc), - OPCODE(o6_wordArrayInc), - OPCODE(o6_jump), - /* 3C */ - OPCODE(o90_kernelSetFunctions), - OPCODE(o6_land), - OPCODE(o6_le), - OPCODE(o60_localizeArrayToScript), - /* 40 */ - OPCODE(o6_wordArrayRead), - OPCODE(o6_wordArrayIndexedRead), - OPCODE(o6_lor), - OPCODE(o6_lt), - /* 44 */ - OPCODE(o90_mod), - OPCODE(o6_mul), - OPCODE(o6_neq), - OPCODE(o100_dim2dim2Array), - /* 48 */ - OPCODE(o6_setObjectName), - OPCODE(o100_redim2dimArray), - OPCODE(o6_not), - OPCODE(o6_invalid), - /* 4C */ - OPCODE(o6_beginOverride), - OPCODE(o6_endOverride), - OPCODE(o72_resetCutscene), - OPCODE(o6_setOwner), - /* 50 */ - OPCODE(o100_paletteOps), - OPCODE(o70_pickupObject), - OPCODE(o70_polygonOps), - OPCODE(o6_pop), - /* 54 */ - OPCODE(o6_printDebug), - OPCODE(o72_printWizImage), - OPCODE(o6_printLine), - OPCODE(o6_printSystem), - /* 58 */ - OPCODE(o6_printText), - OPCODE(o100_jumpToScriptUnk), - OPCODE(o100_startScriptUnk), - OPCODE(o6_pseudoRoom), - /* 5C */ - OPCODE(o6_pushByte), - OPCODE(o72_pushDWord), - OPCODE(o72_getScriptString), - OPCODE(o6_pushWord), - /* 60 */ - OPCODE(o6_pushWordVar), - OPCODE(o6_putActorAtObject), - OPCODE(o6_putActorAtXY), - OPCODE(o6_invalid), - /* 64 */ - OPCODE(o100_redimArray), - OPCODE(o72_rename), - OPCODE(o6_stopObjectCode), - OPCODE(o80_localizeArrayToRoom), - /* 68 */ - OPCODE(o100_roomOps), - OPCODE(o6_printActor), - OPCODE(o6_printEgo), - OPCODE(o72_talkActor), - /* 6C */ - OPCODE(o72_talkEgo), - OPCODE(o6_invalid), - OPCODE(o70_seekFilePos), - OPCODE(o6_setBoxFlags), - /* 70 */ - OPCODE(o6_invalid), - OPCODE(o6_setBoxSet), - OPCODE(o100_setSystemMessage), - OPCODE(o6_shuffle), - /* 74 */ - OPCODE(o6_delay), - OPCODE(o6_delayMinutes), - OPCODE(o6_delaySeconds), - OPCODE(o100_startSound), - /* 78 */ - OPCODE(o80_sourceDebug), - OPCODE(o100_setSpriteInfo), - OPCODE(o6_stampObject), - OPCODE(o72_startObject), - /* 7C */ - OPCODE(o100_startScript), - OPCODE(o6_startScriptQuick), - OPCODE(o80_setState), - OPCODE(o6_stopObjectScript), - /* 80 */ - OPCODE(o6_stopScript), - OPCODE(o6_stopSentence), - OPCODE(o6_stopSound), - OPCODE(o6_stopTalking), - /* 84 */ - OPCODE(o6_writeWordVar), - OPCODE(o6_wordArrayWrite), - OPCODE(o6_wordArrayIndexedWrite), - OPCODE(o6_sub), - /* 88 */ - OPCODE(o100_systemOps), - OPCODE(o6_invalid), - OPCODE(o72_setTimer), - OPCODE(o100_cursorCommand), - /* 8C */ - OPCODE(o100_videoOps), - OPCODE(o100_wait), - OPCODE(o6_walkActorToObj), - OPCODE(o6_walkActorTo), - /* 90 */ - OPCODE(o100_writeFile), - OPCODE(o72_writeINI), - OPCODE(o80_writeConfigFile), - OPCODE(o6_abs), - /* 94 */ - OPCODE(o6_getActorWalkBox), - OPCODE(o6_getActorCostume), - OPCODE(o6_getActorElevation), - OPCODE(o6_getObjectOldDir), - /* 98 */ - OPCODE(o6_getActorMoving), - OPCODE(o90_getActorData), - OPCODE(o6_getActorRoom), - OPCODE(o6_getActorScaleX), - /* 9C */ - OPCODE(o6_getAnimateVariable), - OPCODE(o6_getActorWidth), - OPCODE(o6_getObjectX), - OPCODE(o6_getObjectY), - /* A0 */ - OPCODE(o90_atan2), - OPCODE(o90_getSegmentAngle), - OPCODE(o90_getActorAnimProgress), - OPCODE(o90_getDistanceBetweenPoints), - /* A4 */ - OPCODE(o6_ifClassOfIs), - OPCODE(o6_invalid), - OPCODE(o90_cond), - OPCODE(o90_cos), - /* A8 */ - OPCODE(o6_invalid), - OPCODE(o80_getFileSize), - OPCODE(o6_getActorFromXY), - OPCODE(o72_findAllObjects), - /* AC */ - OPCODE(o90_findAllObjectsWithClassOf), - OPCODE(o6_invalid), - OPCODE(o6_findInventory), - OPCODE(o72_findObject), - /* B0 */ - OPCODE(o72_findObjectWithClassOf), - OPCODE(o70_polygonHit), - OPCODE(o90_getLinesIntersectionPoint), - OPCODE(o90_fontUnk), - /* B4 */ - OPCODE(o72_getNumFreeArrays), - OPCODE(o72_getArrayDimSize), - OPCODE(o100_isResourceLoaded), - OPCODE(o100_getResourceSize), - /* B8 */ - OPCODE(o100_getSpriteGroupInfo), - OPCODE(o6_invalid), - OPCODE(o100_getWizData), - OPCODE(o6_isActorInBox), - /* BC */ - OPCODE(o6_isAnyOf), - OPCODE(o6_getInventoryCount), - OPCODE(o90_kernelGetFunctions), - OPCODE(o90_max), - /* C0 */ - OPCODE(o90_min), - OPCODE(o72_getObjectImageX), - OPCODE(o72_getObjectImageY), - OPCODE(o6_isRoomScriptRunning), - /* C4 */ - OPCODE(o90_getObjectData), - OPCODE(o72_openFile), - OPCODE(o90_getPolygonOverlap), - OPCODE(o6_getOwner), - /* C8 */ - OPCODE(o100_getPaletteData), - OPCODE(o6_pickOneOf), - OPCODE(o6_pickOneOfDefault), - OPCODE(o80_pickVarRandom), - /* CC */ - OPCODE(o72_getPixel), - OPCODE(o6_distObjectObject), - OPCODE(o6_distObjectPt), - OPCODE(o6_distPtPt), - /* D0 */ - OPCODE(o6_getRandomNumber), - OPCODE(o6_getRandomNumberRange), - OPCODE(o6_invalid), - OPCODE(o100_readFile), - /* D4 */ - OPCODE(o72_readINI), - OPCODE(o80_readConfigFile), - OPCODE(o6_isScriptRunning), - OPCODE(o90_sin), - /* D8 */ - OPCODE(o72_getSoundPosition), - OPCODE(o6_isSoundRunning), - OPCODE(o80_getSoundVar), - OPCODE(o100_getSpriteInfo), - /* DC */ - OPCODE(o90_sqrt), - OPCODE(o6_startObjectQuick), - OPCODE(o6_startScriptQuick2), - OPCODE(o6_getState), - /* E0 */ - OPCODE(o70_compareString), - OPCODE(o70_copyString), - OPCODE(o70_appendString), - OPCODE(o70_concatString), - /* E4 */ - OPCODE(o70_getStringLen), - OPCODE(o70_getStringLenForWidth), - OPCODE(o80_stringToInt), - OPCODE(o70_getCharIndexInString), - /* E8 */ - OPCODE(o70_getStringWidth), - OPCODE(o60_readFilePos), - OPCODE(o72_getTimer), - OPCODE(o6_getVerbEntrypoint), - /* EC */ - OPCODE(o100_getVideoData), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* F0 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* F4 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* F8 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* FC */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - }; - - _opcodesV100he = opcodes; -} - -void ScummEngine_v100he::executeOpcode(byte i) { - OpcodeProcV100he op = _opcodesV100he[i].proc; - (this->*op) (); -} - -const char *ScummEngine_v100he::getOpcodeDesc(byte i) { - return _opcodesV100he[i].desc; -} - -void ScummEngine_v100he::o100_actorOps() { - Actor *a; - int i, j, k; - int args[32]; - byte string[256]; - - byte subOp = fetchScriptByte(); - if (subOp == 129) { - _curActor = pop(); - return; - } - - a = derefActorSafe(_curActor, "o100_actorOps"); - if (!a) - return; - - switch (subOp) { - case 0: - // freddicove Ru Updated - // FIXME: check stack parameters - debug(0,"o100_actorOps: case 0 UNHANDLED"); - break; - case 3: - pop(); - pop(); - pop(); - break; - case 4: // SO_ANIMATION_SPEED - a->setAnimSpeed(pop()); - break; - case 6: - j = pop(); - i = pop(); - a->putActor(i, j, a->_room); - break; - case 8: - a->_drawToBackBuf = false; - a->_needRedraw = true; - a->_needBgReset = true; - break; - case 9: - a->drawActorToBackBuf(a->_pos.x, a->_pos.y); - break; - case 14: - a->_charset = pop(); - break; - case 18: - a->_clipOverride.bottom = pop(); - a->_clipOverride.right = pop(); - a->_clipOverride.top = pop(); - a->_clipOverride.left = pop(); - break; - case 22: - k = getStackList(args, ARRAYSIZE(args)); - for (i = 0; i < k; ++i) { - a->setUserCondition(args[i] & 0x7F, args[i] & 0x80); - } - break; - case 25: // SO_COSTUME - a->setActorCostume(pop()); - break; - case 27: // SO_DEFAULT - a->initActor(0); - break; - case 32: - i = pop(); - debug(0,"o100_actorOps: case 32 (%d)", i); - break; - case 52: // SO_ACTOR_NAME - copyScriptString(string, sizeof(string)); - loadPtrToResource(rtActorName, a->_number, string); - break; - case 53: // SO_ACTOR_NEW - a->initActor(2); - break; - case 57: // SO_PALETTE - j = pop(); - i = pop(); - checkRange(255, 0, i, "o100_actorOps: Illegal palette slot %d"); - a->remapActorPaletteColor(i, j); - a->_needRedraw = true; - break; - case 59: - // HE games use reverse order of layering, so we adjust - a->_layer = -pop(); - a->_needRedraw = true; - break; - case 63: - a->_hePaletteNum = pop(); - a->_needRedraw = true; - break; - case 65: // SO_SCALE - i = pop(); - a->setScale(i, i); - break; - case 70: // SO_SHADOW - a->_heXmapNum = pop(); - a->_needRedraw = true; - break; - case 74: // SO_STEP_DIST - j = pop(); - i = pop(); - a->setActorWalkSpeed(i, j); - break; - case 78: - { - copyScriptString(string, sizeof(string)); - int slot = pop(); - - int len = resStrLen(string) + 1; - memcpy(a->_heTalkQueue[slot].sentence, string, len); - - a->_heTalkQueue[slot].posX = a->_talkPosX; - a->_heTalkQueue[slot].posY = a->_talkPosY; - a->_heTalkQueue[slot].color = a->_talkColor; - } - break; - case 83: // SO_ACTOR_VARIABLE - i = pop(); - a->setAnimVar(pop(), i); - break; - case 87: // SO_ALWAYS_ZCLIP - a->_forceClip = pop(); - break; - case 89: // SO_NEVER_ZCLIP - a->_forceClip = 0; - break; - case 128: - _actorClipOverride.bottom = pop(); - _actorClipOverride.right = pop(); - _actorClipOverride.top = pop(); - _actorClipOverride.left = pop(); - break; - case 130: // SO_SOUND - k = getStackList(args, ARRAYSIZE(args)); - for (i = 0; i < k; i++) - a->_sound[i] = args[i]; - break; - case 131: // SO_ACTOR_WIDTH - a->_width = pop(); - break; - case 132: // SO_ANIMATION_DEFAULT - a->_initFrame = 1; - a->_walkFrame = 2; - a->_standFrame = 3; - a->_talkStartFrame = 4; - a->_talkStopFrame = 5; - break; - case 133: // SO_ELEVATION - a->setElevation(pop()); - break; - case 134: // SO_FOLLOW_BOXES - a->_ignoreBoxes = 0; - a->_forceClip = 0; - if (a->isInCurrentRoom()) - a->putActor(a->_pos.x, a->_pos.y, a->_room); - break; - case 135: // SO_IGNORE_BOXES - a->_ignoreBoxes = 1; - a->_forceClip = 0; - if (a->isInCurrentRoom()) - a->putActor(a->_pos.x, a->_pos.y, a->_room); - break; - case 136: // SO_ACTOR_IGNORE_TURNS_OFF - a->_ignoreTurns = false; - break; - case 137: // SO_ACTOR_IGNORE_TURNS_ON - a->_ignoreTurns = true; - break; - case 138: // SO_INIT_ANIMATION - a->_initFrame = pop(); - break; - case 139: // SO_STAND_ANIMATION - a->_standFrame = pop(); - break; - case 140: // SO_TALK_ANIMATION - a->_talkStopFrame = pop(); - a->_talkStartFrame = pop(); - break; - case 141: // SO_TALK_COLOR - a->_talkColor = pop(); - break; - case 142: - k = pop(); - if (k == 0) - k = _rnd.getRandomNumberRng(1, 10); - a->_heNoTalkAnimation = 1; - a->setTalkCondition(k); - break; - case 143: // SO_TEXT_OFFSET - a->_talkPosY = pop(); - a->_talkPosX = pop(); - break; - case 144: // SO_WALK_ANIMATION - a->_walkFrame = pop(); - break; - default: - error("o100_actorOps: default case %d", subOp); - } -} - -void ScummEngine_v100he::o100_arrayOps() { - ArrayHeader *ah; - byte string[1024]; - int dim1end, dim1start, dim2end, dim2start; - int id, len, b, c, list[128]; - int offs, tmp, tmp2; - uint tmp3; - - byte subOp = fetchScriptByte(); - int array = fetchScriptWord(); - debug(9,"o100_arrayOps: array %d case %d", array, subOp); - - switch (subOp) { - case 35: - decodeScriptString(string); - len = resStrLen(string); - ah = defineArray(array, kStringArray, 0, 0, 0, len); - memcpy(ah->data, string, len); - break; - case 77: // SO_ASSIGN_STRING - copyScriptString(string, sizeof(string)); - len = resStrLen(string); - ah = defineArray(array, kStringArray, 0, 0, 0, len); - memcpy(ah->data, string, len); - break; - - case 128: // SO_ASSIGN_2DIM_LIST - len = getStackList(list, ARRAYSIZE(list)); - id = readVar(array); - if (id == 0) - error("Must DIM a two dimensional array before assigning"); - c = pop(); - while (--len >= 0) { - writeArray(array, c, len, list[len]); - } - break; - case 129: // SO_ASSIGN_INT_LIST - b = pop(); - c = pop(); - id = readVar(array); - if (id == 0) { - defineArray(array, kDwordArray, 0, 0, 0, b + c - 1); - } - while (c--) { - writeArray(array, 0, b + c, pop()); - } - break; - case 130: - len = getStackList(list, ARRAYSIZE(list)); - dim1end = pop(); - dim1start = pop(); - dim2end = pop(); - dim2start = pop(); - id = readVar(array); - if (id == 0) { - defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end); - } - tmp2 = 0; - while (dim2start <= dim2end) { - tmp = dim1start; - while (tmp <= dim1end) { - writeArray(array, dim2start, tmp, list[tmp2++]); - if (tmp2 == len) - tmp2 = 0; - tmp++; - } - dim2start++; - } - break; - case 131: - { - int a2_dim1end = pop(); - int a2_dim1start = pop(); - int a2_dim2end = pop(); - int a2_dim2start = pop(); - int array2 = fetchScriptWord(); - int a1_dim1end = pop(); - int a1_dim1start = pop(); - int a1_dim2end = pop(); - int a1_dim2start = pop(); - if (a1_dim1end - a1_dim1start != a2_dim1end - a2_dim1start || a2_dim2end - a2_dim2start != a1_dim2end - a1_dim2start) { - error("Source and dest ranges size are mismatched"); - } - copyArray(array, a1_dim2start, a1_dim2end, a1_dim1start, a1_dim1end, array2, a2_dim2start, a2_dim2end, a2_dim1start, a2_dim1end); - } - break; - case 133: - b = pop(); - c = pop(); - dim1end = pop(); - dim1start = pop(); - dim2end = pop(); - dim2start = pop(); - id = readVar(array); - if (id == 0) { - defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end); - } - - offs = (b >= c) ? 1 : -1; - tmp2 = c; - tmp3 = c - b + 1; - while (dim2start <= dim2end) { - tmp = dim1start; - while (tmp <= dim1end) { - writeArray(array, dim2start, tmp, tmp2); - if (--tmp3 == 0) { - tmp2 = c; - tmp3 = c - b + 1; - } else { - tmp2 += offs; - } - tmp++; - } - dim2start++; - } - break; - default: - error("o100_arrayOps: default case %d (array %d)", subOp, array); - } -} - -void ScummEngine_v100he::o100_jumpToScript() { - int args[25]; - int script; - byte flags; - - getStackList(args, ARRAYSIZE(args)); - script = pop(); - flags = fetchScriptByte(); - stopObjectCode(); - runScript(script, (flags == 128 || flags == 129), (flags == 130 || flags == 129), args); -} - -void ScummEngine_v100he::o100_createSound() { - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 0: - _heSndResId = pop(); - break; - case 53: - createSound(_heSndResId, -1); - break; - case 92: - // dummy case - break; - case 128: - createSound(_heSndResId, pop()); - break; - default: - error("o100_createSound: default case %d", subOp); - } -} - -void ScummEngine_v100he::o100_dim2dimArray() { - int data, dim1end, dim2end; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 41: // SO_BIT_ARRAY - data = kBitArray; - break; - case 42: // SO_INT_ARRAY - data = kIntArray; - break; - case 43: - data = kDwordArray; - break; - case 44: // SO_NIBBLE_ARRAY - data = kNibbleArray; - break; - case 45: // SO_BYTE_ARRAY - data = kByteArray; - break; - case 77: // SO_STRING_ARRAY - data = kStringArray; - break; - default: - error("o100_dim2dimArray: default case %d", subOp); - } - - dim1end = pop(); - dim2end = pop(); - defineArray(fetchScriptWord(), data, 0, dim2end, 0, dim1end); -} - -void ScummEngine_v100he::o100_dimArray() { - int data; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 41: // SO_BIT_ARRAY - data = kBitArray; - break; - case 42: // SO_INT_ARRAY - data = kIntArray; - break; - case 43: - data = kDwordArray; - break; - case 44: // SO_NIBBLE_ARRAY - data = kNibbleArray; - break; - case 45: // SO_BYTE_ARRAY - data = kByteArray; - break; - case 77: // SO_STRING_ARRAY - data = kStringArray; - break; - case 135: // SO_UNDIM_ARRAY - nukeArray(fetchScriptWord()); - return; - default: - error("o100_dimArray: default case %d", subOp); - } - - defineArray(fetchScriptWord(), data, 0, 0, 0, pop()); -} - -void ScummEngine_v100he::o100_drawLine() { - int id, unk1, unk2, x, x1, y1; - - unk2 = pop(); - id = pop(); - unk1 = pop(); - x = pop(); - y1 = pop(); - x1 = pop(); - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 1: - drawLine(x1, y1, x, unk1, unk2, 2, id); - break; - case 20: - drawLine(x1, y1, x, unk1, unk2, 1, id); - break; - case 40: - drawLine(x1, y1, x, unk1, unk2, 3, id); - break; - default: - error("o100_drawLine: default case %d", subOp); - } -} - -void ScummEngine_v100he::o100_drawObject() { - int state, y, x; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 6: - state = 1; - y = pop(); - x = pop(); - break; - case 7: - state = pop(); - y = pop(); - x = pop(); - break; - case 40: - state = pop(); - if (state == 0) - state = 1; - y = x = -100; - break; - default: - error("o100_drawObject: default case %d", subOp); - } - - int object = pop(); - int objnum = getObjectIndex(object); - if (objnum == -1) - return; - - if (y != -100 && x != -100) { - _objs[objnum].x_pos = x * 8; - _objs[objnum].y_pos = y * 8; - } - - if (state != -1) { - addObjectToDrawQue(objnum); - putState(object, state); - } -} - -void ScummEngine_v100he::o100_floodFill() { - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 0: - memset(&_floodFillParams, 0, sizeof(_floodFillParams)); - _floodFillParams.box.left = 0; - _floodFillParams.box.top = 0; - _floodFillParams.box.right = 639; - _floodFillParams.box.bottom = 479; - break; - case 6: - _floodFillParams.y = pop(); - _floodFillParams.x = pop(); - break; - case 18: - _floodFillParams.box.bottom = pop(); - _floodFillParams.box.right = pop(); - _floodFillParams.box.top = pop(); - _floodFillParams.box.left = pop(); - break; - case 20: - _floodFillParams.flags = pop(); - break; - case 67: - pop(); - break; - case 92: - floodFill(&_floodFillParams, this); - break; - default: - error("o100_floodFill: Unknown case %d", subOp); - } -} - -void ScummEngine_v100he::o100_setSpriteGroupInfo() { - byte string[260]; - int type, value1, value2, value3, value4; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 0: - _curSpriteGroupId = pop(); - break; - case 6: - value2 = pop(); - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupPosition(_curSpriteGroupId, value1, value2); - break; - case 18: - value4 = pop(); - value3 = pop(); - value2 = pop(); - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupBounds(_curSpriteGroupId, value1, value2, value3, value4); - break; - case 38: - type = pop() - 1; - switch (type) { - case 0: - value2 = pop(); - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->moveGroupMembers(_curSpriteGroupId, value1, value2); - break; - case 1: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupMembersPriority(_curSpriteGroupId, value1); - break; - case 2: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupMembersGroup(_curSpriteGroupId, value1); - break; - case 3: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupMembersUpdateType(_curSpriteGroupId, value1); - break; - case 4: - if (!_curSpriteGroupId) - break; - - _sprite->setGroupMembersResetSprite(_curSpriteGroupId); - break; - case 5: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupMembersAnimationSpeed(_curSpriteGroupId, value1); - break; - case 6: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupMembersAutoAnimFlag(_curSpriteGroupId, value1); - break; - case 7: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupMembersShadow(_curSpriteGroupId, value1); - break; - default: - error("o100_setSpriteGroupInfo subOp 38: Unknown case %d", subOp); - } - break; - case 40: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupImage(_curSpriteGroupId, value1); - break; - case 49: - value2 = pop(); - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->moveGroup(_curSpriteGroupId, value1, value2); - break; - case 52: - copyScriptString(string, sizeof(string)); - break; - case 53: - if (!_curSpriteGroupId) - break; - - _sprite->resetGroup(_curSpriteGroupId); - break; - case 54: - // dummy case - pop(); - pop(); - break; - case 59: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupPriority(_curSpriteGroupId, value1); - break; - case 60: - type = pop(); - value1 = pop(); - if (!_curSpriteGroupId) - break; - - switch (type) { - case 0: - _sprite->setGroupXMul(_curSpriteGroupId, value1); - break; - case 1: - _sprite->setGroupXDiv(_curSpriteGroupId, value1); - break; - case 2: - _sprite->setGroupYMul(_curSpriteGroupId, value1); - break; - case 3: - _sprite->setGroupYDiv(_curSpriteGroupId, value1); - break; - default: - error("o100_setSpriteGroupInfo subOp 60: Unknown case %d", subOp); - } - break; - case 89: - if (!_curSpriteGroupId) - break; - - _sprite->resetGroupBounds(_curSpriteGroupId); - break; - default: - error("o100_setSpriteGroupInfo: Unknown case %d", subOp); - } -} - -void ScummEngine_v100he::o100_resourceRoutines() { - int objidx, room; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 14: - _heResType = rtCharset; - _heResId = pop(); - break; - case 25: - _heResType = rtCostume; - _heResId = pop(); - break; - case 34: - _heResType = rtFlObject; - _heResId = pop(); - break; - case 40: - _heResType = rtImage; - _heResId = pop(); - break; - case 47: - if (_heResType == rtFlObject) { - room = getObjectRoom(_heResId); - loadFlObject(_heResId, room); - } else if (_heResType == rtCharset) { - loadCharset(_heResId); - } else { - ensureResourceLoaded(_heResType, _heResId); - } - break; - case 62: - _heResType = rtRoom; - _heResId = pop(); - break; - case 66: - _heResType = rtScript; - _heResId = pop(); - break; - case 72: - _heResType = rtSound; - _heResId = pop(); - break; - case 128: - break; - case 132: - if (_heResType == rtScript && _heResId >= _numGlobalScripts) - break; - - if (_heResType == rtFlObject) { - objidx = getObjectIndex(_heResId); - if (objidx == -1) - break; - res.lock(rtFlObject, _objs[objidx].fl_object_index); - } else { - res.lock(_heResType, _heResId); - } - break; - case 133: - if (_heResType == rtCharset) - nukeCharset(_heResId); - else - res.nukeResource(_heResType, _heResId); - break; - case 134: - case 135: - // Heap related - break; - case 136: - if (_heResType == rtScript && _heResId >= _numGlobalScripts) - break; - - //queueLoadResource(_heResType, _heResId); - break; - case 137: - if (_heResType == rtScript && _heResId >= _numGlobalScripts) - break; - - if (_heResType == rtFlObject) { - objidx = getObjectIndex(_heResId); - if (objidx == -1) - break; - res.unlock(rtFlObject, _objs[objidx].fl_object_index); - } else { - res.unlock(_heResType, _heResId); - } - break; - default: - error("o100_resourceRoutines: default case %d", subOp); - } -} - -void ScummEngine_v100he::o100_wizImageOps() { - int a, b; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 0: - _wizParams.img.resNum = pop(); - _wizParams.processMode = 0; - _wizParams.processFlags = 0; - _wizParams.remapNum = 0; - _wizParams.img.flags = 0; - _wizParams.field_184 = 0; - _wizParams.field_180 = 0; - _wizParams.spriteId = 0; - _wizParams.spriteGroup = 0; - break; - case 2: - _wizParams.processFlags |= kWPFRotate; - _wizParams.angle = pop(); - break; - case 6: - case 132: - _wizParams.processFlags |= kWPFSetPos; - _wizParams.img.y1 = pop(); - _wizParams.img.x1 = pop(); - break; - case 7: - _wizParams.processFlags |= kWPFMaskImg; - _wizParams.sourceImage = pop(); - break; - case 11: - _wizParams.processFlags |= kWPFClipBox | 0x100; - _wizParams.processMode = 2; - _wizParams.box.bottom = pop(); - _wizParams.box.right = pop(); - _wizParams.box.top = pop(); - _wizParams.box.left = pop(); - _wizParams.compType = pop(); - break; - case 18: - _wizParams.processFlags |= kWPFClipBox; - _wizParams.box.bottom = pop(); - _wizParams.box.right = pop(); - _wizParams.box.top = pop(); - _wizParams.box.left = pop(); - break; - case 21: - b = pop(); - a = pop(); - _wizParams.processFlags |= kWPFRemapPalette; - _wizParams.processMode = 6; - if (_wizParams.remapNum == 0) { - memset(_wizParams.remapIndex, 0, sizeof(_wizParams.remapIndex)); - } else { - assert(_wizParams.remapNum < ARRAYSIZE(_wizParams.remapIndex)); - _wizParams.remapIndex[_wizParams.remapNum] = a; - _wizParams.remapColor[a] = b; - ++_wizParams.remapNum; - } - break; - case 29: - _wizParams.processMode = 1; - break; - case 36: - _wizParams.box.bottom = pop(); - _wizParams.box.right = pop(); - _wizParams.box.top = pop(); - _wizParams.box.left = pop(); - break; - case 37: - // Dummy case - pop(); - break; - case 39: - _wizParams.processFlags |= kWPFUseDefImgHeight; - _wizParams.resDefImgH = pop(); - break; - case 47: - _wizParams.processFlags |= kWPFUseFile; - _wizParams.processMode = 3; - copyScriptString(_wizParams.filename, sizeof(_wizParams.filename)); - break; - case 53: - _wizParams.processMode = 8; - break; - case 54: - _wizParams.processFlags |= 0x100000; - _wizParams.field_180 = pop(); - _wizParams.field_184 = pop(); - break; - case 55: - _wizParams.img.flags = pop(); - _wizParams.img.state = pop(); - _wizParams.img.y1 = pop(); - _wizParams.img.x1 = pop(); - _wizParams.spriteId = 0; - _wizParams.spriteGroup = 0; - _wizParams.img.resNum = pop(); - _wiz->displayWizImage(&_wizParams.img); - break; - case 57: - _wizParams.processFlags |= kWPFPaletteNum; - _wizParams.img.palette = pop(); - break; - case 58: - _wizParams.processFlags |= 0x1000 | 0x100 | 0x2; - _wizParams.processMode = 7; - _wizParams.field_168 = pop(); - _wizParams.field_164 = pop(); - _wizParams.compType = pop(); - break; - case 64: - _wizParams.processFlags |= kWPFUseFile; - _wizParams.processMode = 4; - copyScriptString(_wizParams.filename, sizeof(_wizParams.filename)); - _wizParams.fileWriteMode = pop(); - break; - case 65: - _wizParams.processFlags |= kWPFScaled; - _wizParams.scale = pop(); - break; - case 67: - _wizParams.processFlags |= kWPFNewFlags; - _wizParams.img.flags |= pop(); - break; - case 68: - _wizParams.processFlags |= kWPFNewFlags | kWPFSetPos | 2; - _wizParams.img.flags |= kWIFIsPolygon; - _wizParams.field_164 = _wizParams.img.y1 = _wizParams.img.x1 = pop(); - break; - case 70: - _wizParams.processFlags |= kWPFShadow; - _wizParams.img.shadow = pop(); - break; - case 73: - _wizParams.processFlags |= kWPFNewState; - _wizParams.img.state = pop(); - break; - case 84: - _wizParams.processFlags |= kWPFUseDefImgWidth; - _wizParams.resDefImgW = pop(); - break; - case 92: - if (_wizParams.img.resNum) - _wiz->processWizImage(&_wizParams); - break; - case 128: - _wizParams.field_239D = pop(); - _wizParams.field_2399 = pop(); - _wizParams.field_23A5 = pop(); - _wizParams.field_23A1 = pop(); - copyScriptString(_wizParams.string2, sizeof(_wizParams.string2)); - _wizParams.processMode = 15; - break; - case 129: - _wizParams.processMode = 14; - break; - case 130: - _wizParams.processMode = 16; - _wizParams.field_23AD = pop(); - _wizParams.field_23A9 = pop(); - copyScriptString(_wizParams.string1, sizeof(_wizParams.string1)); - break; - case 131: - _wizParams.processMode = 13; - break; - case 133: - _wizParams.processMode = 17; - _wizParams.field_23CD = pop(); - _wizParams.field_23C9 = pop(); - _wizParams.field_23C5 = pop(); - _wizParams.field_23C1 = pop(); - _wizParams.field_23BD = pop(); - _wizParams.field_23B9 = pop(); - _wizParams.field_23B5 = pop(); - _wizParams.field_23B1 = pop(); - break; - case 134: - _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; - _wizParams.processMode = 12; - _wizParams.fillColor = pop(); - _wizParams.box2.top = _wizParams.box2.bottom = pop(); - _wizParams.box2.left = _wizParams.box2.right = pop(); - break; - case 135: - _wizParams.processFlags |= kWPFDstResNum; - _wizParams.dstResNum = pop(); - break; - case 136: - _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; - _wizParams.processMode = 10; - _wizParams.fillColor = pop(); - _wizParams.box2.bottom = pop(); - _wizParams.box2.right = pop(); - _wizParams.box2.top = pop(); - _wizParams.box2.left = pop(); - break; - case 137: - _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; - _wizParams.processMode = 11; - _wizParams.fillColor = pop(); - _wizParams.box2.top = _wizParams.box2.bottom = pop(); - _wizParams.box2.left = _wizParams.box2.right = pop(); - break; - case 138: - _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; - _wizParams.processMode = 9; - _wizParams.fillColor = pop(); - _wizParams.box2.bottom = pop(); - _wizParams.box2.right = pop(); - _wizParams.box2.top = pop(); - _wizParams.box2.left = pop(); - break; - default: - error("o100_wizImageOps: Unknown case %d", subOp); - } -} - -void ScummEngine_v100he::o100_dim2dim2Array() { - int data, dim1start, dim1end, dim2start, dim2end; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 41: // SO_BIT_ARRAY - data = kBitArray; - break; - case 42: // SO_INT_ARRAY - data = kIntArray; - break; - case 43: - data = kDwordArray; - break; - case 44: // SO_NIBBLE_ARRAY - data = kNibbleArray; - break; - case 45: // SO_BYTE_ARRAY - data = kByteArray; - break; - case 77: // SO_STRING_ARRAY - data = kStringArray; - break; - default: - error("o100_dim2dim2Array: default case %d", subOp); - } - - if (pop() == 2) { - dim1end = pop(); - dim1start = pop(); - dim2end = pop(); - dim2start = pop(); - } else { - dim2end = pop(); - dim2start = pop(); - dim1end = pop(); - dim1start = pop(); - } - - defineArray(fetchScriptWord(), data, dim2start, dim2end, dim1start, dim1end); -} - -void ScummEngine_v100he::o100_redim2dimArray() { - int a, b, c, d; - d = pop(); - c = pop(); - b = pop(); - a = pop(); - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 42: - redimArray(fetchScriptWord(), a, b, c, d, kIntArray); - break; - case 43: - redimArray(fetchScriptWord(), a, b, c, d, kDwordArray); - break; - case 45: - redimArray(fetchScriptWord(), a, b, c, d, kByteArray); - break; - default: - error("o100_redim2dimArray: default type %d", subOp); - } -} - -void ScummEngine_v100he::o100_paletteOps() { - int a, b, c, d, e; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 0: - _hePaletteNum = pop(); - break; - case 20: - e = pop(); - d = pop(); - c = pop(); - b = pop(); - a = pop(); - if (_hePaletteNum != 0) { - for (; a <= b; ++a) { - setHEPaletteColor(_hePaletteNum, a, c, d, e); - } - } - break; - case 25: - a = pop(); - if (_hePaletteNum != 0) { - setHEPaletteFromCostume(_hePaletteNum, a); - } - break; - case 40: - b = pop(); - a = pop(); - if (_hePaletteNum != 0) { - setHEPaletteFromImage(_hePaletteNum, a, b); - } - break; - case 53: - if (_hePaletteNum != 0) { - restoreHEPalette(_hePaletteNum); - } - break; - case 57: - a = pop(); - if (_hePaletteNum != 0) { - copyHEPalette(_hePaletteNum, a); - } - break; - case 63: - b = pop(); - a = pop(); - if (_hePaletteNum != 0) { - setHEPaletteFromRoom(_hePaletteNum, a, b); - } - break; - case 81: - c = pop(); - b = pop(); - a = pop(); - if (_hePaletteNum) { - for (; a <= b; ++a) { - copyHEPaletteColor(_hePaletteNum, a, c); - } - } - break; - case 92: - _hePaletteNum = 0; - break; - default: - error("o100_paletteOps: Unknown case %d", subOp); - } -} - -void ScummEngine_v100he::o100_jumpToScriptUnk() { - int args[25]; - int script, cycle; - byte flags; - - getStackList(args, ARRAYSIZE(args)); - cycle = pop(); - script = pop(); - flags = fetchScriptByte(); - stopObjectCode(); - runScript(script, (flags == 128 || flags == 129), (flags == 130 || flags == 129), args, cycle); -} - -void ScummEngine_v100he::o100_startScriptUnk() { - int args[25]; - int script, cycle; - byte flags; - - getStackList(args, ARRAYSIZE(args)); - cycle = pop(); - script = pop(); - flags = fetchScriptByte(); - runScript(script, (flags == 128 || flags == 129), (flags == 130 || flags == 129), args, cycle); -} - -void ScummEngine_v100he::o100_redimArray() { - int newX, newY; - newY = pop(); - newX = pop(); - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 42: - redimArray(fetchScriptWord(), 0, newX, 0, newY, kIntArray); - break; - case 43: - redimArray(fetchScriptWord(), 0, newX, 0, newY, kDwordArray); - break; - case 45: - redimArray(fetchScriptWord(), 0, newX, 0, newY, kByteArray); - break; - default: - error("o100_redimArray: default type %d", subOp); - } -} - -void ScummEngine_v100he::o100_roomOps() { - int a, b, c, d, e; - byte filename[100]; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 63: // SO_ROOM_PALETTE - d = pop(); - c = pop(); - b = pop(); - a = pop(); - setPalColor(d, a, b, c); - break; - - case 129: - b = pop(); - a = pop(); - swapObjects(a, b); - break; - - case 130: - a = pop(); - b = pop(); - copyPalColor(a, b); - break; - - case 131: // SO_ROOM_FADE - // Defaults to 1 but doesn't use fade effects - a = pop(); - break; - - case 132: // SO_ROOM_INTENSITY - c = pop(); - b = pop(); - a = pop(); - darkenPalette(a, a, a, b, c); - break; - - case 133: // SO_RGB_ROOM_INTENSITY - e = pop(); - d = pop(); - c = pop(); - b = pop(); - a = pop(); - darkenPalette(a, b, c, d, e); - break; - - case 134: // SO_ROOM_NEW_PALETTE - a = pop(); - setPalette(a); - break; - - case 135: - b = pop(); - a = pop(); - setRoomPalette(a, b); - break; - - case 136: // SO_ROOM_SAVEGAME - _saveTemporaryState = true; - _saveLoadSlot = pop(); - _saveLoadFlag = pop(); - break; - - case 137: - copyScriptString(filename, sizeof(filename)); - _saveLoadFlag = pop(); - _saveLoadSlot = 1; - _saveTemporaryState = true; - break; - - case 138: // SO_ROOM_SCREEN - b = pop(); - a = pop(); - initScreens(a, _screenHeight); - break; - - case 139: // SO_ROOM_SCROLL - b = pop(); - a = pop(); - if (a < (_screenWidth / 2)) - a = (_screenWidth / 2); - if (b < (_screenWidth / 2)) - b = (_screenWidth / 2); - if (a > _roomWidth - (_screenWidth / 2)) - a = _roomWidth - (_screenWidth / 2); - if (b > _roomWidth - (_screenWidth / 2)) - b = _roomWidth - (_screenWidth / 2); - VAR(VAR_CAMERA_MIN_X) = a; - VAR(VAR_CAMERA_MAX_X) = b; - break; - - default: - error("o100_roomOps: default case %d", subOp); - } -} - -void ScummEngine_v100he::o100_setSystemMessage() { - byte name[1024]; - - copyScriptString(name, sizeof(name)); - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 80: // Set Window Caption - _system->setWindowCaption((const char *)name); - break; - case 131: // Set Version - debug(1,"o100_setSystemMessage: (%d) %s", subOp, name); - break; - default: - error("o100_setSystemMessage: default case %d", subOp); - } -} - -void ScummEngine_v100he::o100_startSound() { - byte filename[260]; - int var, value; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 6: - _heSndFlags |= 16; - _heSndOffset = pop(); - break; - case 47: - copyScriptString(filename, sizeof(filename)); - _heSndSoundId = pop(); - if (_heSndSoundId) - debug(0, "Load sound %d from file %s\n", _heSndSoundId, filename); - break; - case 55: - _heSndFlags |= 8; - break; - case 83: - value = pop(); - var = pop(); - _heSndSoundId = pop(); - _sound->setSoundVar(_heSndSoundId, var, value); - break; - case 92: - _sound->addSoundToQueue(_heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags); - break; - case 128: - _heSndFlags |= 2; - break; - case 129: - _heSndChannel = pop(); - break; - case 130: - _heSndFlags |= 64; - pop(); - break; - case 131: - _heSndFlags |= 1; - break; - case 132: // Music - case 134: // Sound - _heSndSoundId = pop(); - _heSndOffset = 0; - _heSndSoundFreq = 11025; - _heSndChannel = VAR(VAR_SOUND_CHANNEL); - _heSndFlags = 0; - break; - case 133: - _heSndFlags |= 128; - pop(); - break; - case 135: - _heSndFlags |= 4; - break; - case 136: - _heSndFlags |= 32; - pop(); - break; - default: - error("o100_startSound invalid case %d", subOp); - } -} - -void ScummEngine_v100he::o100_setSpriteInfo() { - int args[16]; - int spriteId, n; - int32 tmp[2]; - byte string[80]; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 0: - _curMaxSpriteId = pop(); - _curSpriteId = pop(); - - if (_curSpriteId > _curMaxSpriteId) - SWAP(_curSpriteId, _curMaxSpriteId); - break; - case 2: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteAngle(spriteId, args[0]); - break; - case 3: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteFlagAutoAnim(spriteId, args[0]); - break; - case 4: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteAnimSpeed(spriteId, args[0]); - break; - case 6: - args[1] = pop(); - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpritePosition(spriteId, args[0], args[1]); - break; - case 7: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteSourceImage(spriteId, args[0]); - break; - case 16: - n = getStackList(args, ARRAYSIZE(args)); - if (_curSpriteId != 0 && _curMaxSpriteId != 0 && n != 0) { - int *p = &args[n - 1]; - do { - int code = *p; - if (code == 0) { - for (int i = _curSpriteId; i <= _curMaxSpriteId; ++i) { - _sprite->setSpriteResetClass(i); - } - } else if (code & 0x80) { - for (int i = _curSpriteId; i <= _curMaxSpriteId; ++i) { - _sprite->setSpriteSetClass(i, code & 0x7F, 1); - } - } else { - for (int i = _curSpriteId; i <= _curMaxSpriteId; ++i) { - _sprite->setSpriteSetClass(i, code & 0x7F, 0); - } - } - --p; - } while (--n); - } - break; - case 32: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteFlagEraseType(spriteId, args[0]); - break; - case 38: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteGroup(spriteId, args[0]); - break; - case 40: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteImage(spriteId, args[0]); - break; - case 48: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteMaskImage(spriteId, args[0]); - break; - case 49: - args[1] = pop(); - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->moveSprite(spriteId, args[0], args[1]); - break; - case 52: - copyScriptString(string, sizeof(string)); - break; - case 53: - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->resetSprite(spriteId); - break; - case 54: - args[1] = pop(); - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteGeneralProperty(spriteId, args[0], args[1]); - break; - case 57: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpritePalette(spriteId, args[0]); - break; - case 59: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpritePriority(spriteId, args[0]); - break; - case 60: - args[1] = pop(); - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - switch(args[1]) { - case 0: - _sprite->setSpriteFlagXFlipped(spriteId, args[0]); - break; - case 1: - _sprite->setSpriteFlagYFlipped(spriteId, args[0]); - break; - case 2: - _sprite->setSpriteFlagActive(spriteId, args[0]); - break; - case 3: - _sprite->setSpriteFlagDoubleBuffered(spriteId, args[0]); - break; - case 4: - _sprite->setSpriteFlagRemapPalette(spriteId, args[0]); - break; - default: - break; - } - break; - case 61: - _sprite->resetTables(true); - break; - case 65: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteScale(spriteId, args[0]); - break; - case 70: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteShadow(spriteId, args[0]); - break; - case 73: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteImageState(spriteId, args[0]); - break; - case 74: - args[1] = pop(); - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteDist(spriteId, args[0], args[1]); - break; - case 75: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) { - _sprite->getSpriteDist(spriteId, tmp[0], tmp[1]); - _sprite->setSpriteDist(spriteId, args[0], tmp[1]); - } - break; - case 76: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) { - _sprite->getSpriteDist(spriteId, tmp[0], tmp[1]); - _sprite->setSpriteDist(spriteId, tmp[0], args[0]); - } - break; - case 82: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteFlagUpdateType(spriteId, args[0]); - break; - case 83: - args[1] = pop(); - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteUserValue(spriteId, args[0], args[1]); - break; - case 88: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteField84(spriteId, args[0]); - break; - case 89: - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteField84(spriteId, 0); - break; - default: - error("o100_setSpriteInfo: Unknown case %d", subOp); - } -} - -void ScummEngine_v100he::o100_startScript() { - int args[25]; - int script; - byte flags; - - getStackList(args, ARRAYSIZE(args)); - script = pop(); - flags = fetchScriptByte(); - runScript(script, (flags == 128 || flags == 129), (flags == 130 || flags == 129), args); -} - -void ScummEngine_v100he::o100_systemOps() { - byte string[1024]; - - byte subOp = fetchScriptByte(); - subOp -= 61; - - switch (subOp) { - case 0: - restart(); - break; - case 67: - clearDrawObjectQueue(); - break; - case 71: - // Confirm shutdown - shutDown(); - break; - case 72: - shutDown(); - break; - case 73: - copyScriptString(string, sizeof(string)); - debug(0, "Start game (%s)", string); - break; - case 74: - copyScriptString(string, sizeof(string)); - debug(0, "Start executable (%s)", string); - break; - case 75: - gdi.copyVirtScreenBuffers(Common::Rect(_screenWidth, _screenHeight)); - updatePalette(); - break; - default: - error("o100_systemOps invalid case %d", subOp); - } -} - -void ScummEngine_v100he::o100_cursorCommand() { - int a, i; - int args[16]; - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 0xE: // SO_CHARSET_SET - initCharset(pop()); - break; - case 0xF: // SO_CHARSET_COLOR - getStackList(args, ARRAYSIZE(args)); - for (i = 0; i < 16; i++) - _charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i]; - break; - case 0x80: - case 0x81: - a = pop(); - _wiz->loadWizCursor(a); - break; - case 0x82: - pop(); - a = pop(); - _wiz->loadWizCursor(a); - break; - case 0x86: // SO_CURSOR_ON Turn cursor on - _cursor.state = 1; - break; - case 0x87: // SO_CURSOR_OFF Turn cursor off - _cursor.state = 0; - break; - case 0x88: // SO_CURSOR_SOFT_ON Turn soft cursor on - _cursor.state++; - if (_cursor.state > 1) - error("o100_cursorCommand: Cursor state greater than 1 in script"); - break; - - case 0x89: // SO_CURSOR_SOFT_OFF Turn soft cursor off - _cursor.state--; - break; - case 0x8B: // SO_USERPUT_ON - _userPut = 1; - break; - case 0x8C: // SO_USERPUT_OFF - _userPut = 0; - break; - case 0x8D: // SO_USERPUT_SOFT_ON - _userPut++; - break; - case 0x8E: // SO_USERPUT_SOFT_OFF - _userPut--; - break; - default: - error("o100_cursorCommand: default case %x", subOp); - } - - VAR(VAR_CURSORSTATE) = _cursor.state; - VAR(VAR_USERPUT) = _userPut; -} - -void ScummEngine_v100he::o100_videoOps() { - // Uses Bink video - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 0: - memset(_videoParams.filename, 0, sizeof(_videoParams.filename)); - _videoParams.unk2 = pop(); - break; - case 19: - _videoParams.status = 19; - break; - case 40: - _videoParams.wizResNum = pop(); - if (_videoParams.wizResNum) - _videoParams.flags |= 2; - break; - case 47: - copyScriptString(_videoParams.filename, sizeof(_videoParams.filename)); - _videoParams.status = 47; - break; - case 67: - _videoParams.flags |= pop(); - break; - case 92: - if (_videoParams.status == 47) { - // Start video - if (_videoParams.flags == 0) - _videoParams.flags = 4; - - if (_videoParams.flags == 2) { - // result = startVideo(_videoParams.filename, _videoParams.flags, _videoParams.wizResNum); - // VAR(119) = result; - } else { - // result = startVideo(_videoParams.filename, _videoParams.flags); - // VAR(119) = result; - } - } else if (_videoParams.status == 19) { - // Stop video - } - break; - default: - error("o100_videoOps: unhandled case %d", subOp); - } - - debug(1,"o100_videoOps stub (%d)", subOp); -} - -void ScummEngine_v100he::o100_wait() { - int actnum; - int offs = -2; - Actor *a; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 128: // SO_WAIT_FOR_ACTOR Wait for actor - offs = fetchScriptWordSigned(); - actnum = pop(); - a = derefActor(actnum, "o100_wait:168"); - if (a->_moving) - break; - return; - case 129: // SO_WAIT_FOR_CAMERA Wait for camera - if (camera._cur.x / 8 != camera._dest.x / 8) - break; - return; - case 130: // SO_WAIT_FOR_MESSAGE Wait for message - if (VAR(VAR_HAVE_MSG)) - break; - return; - case 131: // SO_WAIT_FOR_SENTENCE - if (_sentenceNum) { - if (_sentence[_sentenceNum - 1].freezeCount && !isScriptInUse(VAR(VAR_SENTENCE_SCRIPT))) - return; - break; - } - if (!isScriptInUse(VAR(VAR_SENTENCE_SCRIPT))) - return; - break; - default: - error("o100_wait: default case 0x%x", subOp); - } - - _scriptPointer += offs; - o6_breakHere(); -} - -void ScummEngine_v100he::o100_writeFile() { - int32 resID = pop(); - int slot = pop(); - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 5: - fetchScriptByte(); - writeFileFromArray(slot, resID); - break; - case 42: - _hFileTable[slot].writeUint16LE(resID); - break; - case 43: - _hFileTable[slot].writeUint32LE(resID); - break; - case 45: - _hFileTable[slot].writeByte(resID); - break; - default: - error("o100_writeFile: default case %d", subOp); - } -} - -void ScummEngine_v100he::o100_isResourceLoaded() { - // Reports percentage of resource loaded by queue - int type; - - byte subOp = fetchScriptByte(); - /* int idx = */ pop(); - - switch (subOp) { - case 25: - type = rtCostume; - break; - case 40: - type = rtImage; - break; - case 62: - type = rtRoom; - break; - case 66: - type = rtScript; - break; - case 72: - type = rtSound; - break; - default: - error("o100_isResourceLoaded: default case %d", subOp); - } - - push(100); -} - -void ScummEngine_v100he::o100_getResourceSize() { - const byte *ptr; - int size, type; - - int resid = pop(); - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 25: - type = rtCostume; - break; - case 40: - type = rtImage; - break; - case 62: - type = rtRoomImage; - break; - case 66: - type = rtScript; - break; - case 72: - push (getSoundResourceSize(resid)); - return; - default: - error("o100_getResourceSize: default type %d", subOp); - } - - ptr = getResourceAddress(type, resid); - assert(ptr); - size = READ_BE_UINT32(ptr + 4) - 8; - push(size); -} - -void ScummEngine_v100he::o100_getSpriteGroupInfo() { - int32 tx, ty; - int spriteGroupId, type; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 5: - spriteGroupId = pop(); - if (spriteGroupId) - push(getGroupSpriteArray(spriteGroupId)); - else - push(0); - break; - case 40: - spriteGroupId = pop(); - if (spriteGroupId) - push(_sprite->getGroupDstResNum(spriteGroupId)); - else - push(0); - break; - case 54: - // TODO: U32 related - pop(); - pop(); - push(0); - break; - case 59: - spriteGroupId = pop(); - if (spriteGroupId) - push(_sprite->getGroupPriority(spriteGroupId)); - else - push(0); - break; - case 60: - type = pop(); - spriteGroupId = pop(); - if (spriteGroupId) { - switch(type) { - case 0: - push(_sprite->getGroupXMul(spriteGroupId)); - break; - case 1: - push(_sprite->getGroupXDiv(spriteGroupId)); - break; - case 2: - push(_sprite->getGroupYMul(spriteGroupId)); - break; - case 3: - push(_sprite->getGroupYDiv(spriteGroupId)); - break; - default: - push(0); - } - } else { - push(0); - } - break; - case 85: - spriteGroupId = pop(); - if (spriteGroupId) { - _sprite->getGroupPosition(spriteGroupId, tx, ty); - push(tx); - } else { - push(0); - } - break; - case 86: - spriteGroupId = pop(); - if (spriteGroupId) { - _sprite->getGroupPosition(spriteGroupId, tx, ty); - push(ty); - } else { - push(0); - } - break; - default: - error("o100_getSpriteGroupInfo: Unknown case %d", subOp); - } -} - -void ScummEngine_v100he::o100_getWizData() { - byte filename[4096]; - int resId, state, type; - int32 w, h; - int32 x, y; - - byte subOp = fetchScriptByte(); - subOp -= 20; - - switch (subOp) { - case 0: - y = pop(); - x = pop(); - state = pop(); - resId = pop(); - push(_wiz->getWizPixelColor(resId, state, x, y, 0)); - break; - case 6: - resId = pop(); - push(_wiz->getWizImageStates(resId)); - break; - case 13: - y = pop(); - x = pop(); - state = pop(); - resId = pop(); - push(_wiz->isWizPixelNonTransparent(resId, state, x, y, 0)); - break; - case 19: - state = pop(); - resId = pop(); - _wiz->getWizImageDim(resId, state, w, h); - push(h); - break; - case 34: - type = pop(); - state = pop(); - resId = pop(); - push(_wiz->getWizImageData(resId, state, type)); - break; - case 64: - state = pop(); - resId = pop(); - _wiz->getWizImageDim(resId, state, w, h); - push(w); - break; - case 65: - state = pop(); - resId = pop(); - _wiz->getWizImageSpot(resId, state, x, y); - push(x); - break; - case 66: - state = pop(); - resId = pop(); - _wiz->getWizImageSpot(resId, state, x, y); - push(y); - break; - case 111: - pop(); - copyScriptString(filename, sizeof(filename)); - pop(); - push(0); - debug(0, "o100_getWizData() case 111 unhandled"); - break; - case 112: - h = pop(); - w = pop(); - y = pop(); - x = pop(); - state = pop(); - resId = pop(); - if (x == -1 && y == -1 && w == -1 && h == -1) { - _wiz->getWizImageDim(resId, state, w, h); - x = 0; - y = 0; - } - push(computeWizHistogram(resId, state, x, y, w, h)); - break; - default: - error("o100_getWizData: Unknown case %d", subOp); - } -} - -void ScummEngine_v100he::o100_getPaletteData() { - int b, c, d, e; - int palSlot, color; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 13: - c = pop(); - b = pop(); - push(getHEPaletteColorComponent(1, b, c)); - break; - case 20: - color = pop(); - palSlot = pop(); - push(getHEPaletteColor(palSlot, color)); - break; - case 33: - e = pop(); - d = pop(); - palSlot = pop(); - pop(); - c = pop(); - b = pop(); - push(getHEPaletteSimilarColor(palSlot, b, c, d, e)); - break; - case 53: - pop(); - c = pop(); - c = MAX(0, c); - c = MIN(c, 255); - b = pop(); - b = MAX(0, b); - b = MIN(b, 255); - push(getHEPaletteSimilarColor(1, b, c, 10, 245)); - break; - case 73: - c = pop(); - b = pop(); - palSlot = pop(); - push(getHEPaletteColorComponent(palSlot, b, c)); - break; - default: - error("o100_getPaletteData: Unknown case %d", subOp); - } -} - -void ScummEngine_v100he::o100_readFile() { - int slot, val; - int32 size; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 5: - fetchScriptByte(); - size = pop(); - slot = pop(); - val = readFileToArray(slot, size); - push(val); - break; - case 42: - slot = pop(); - val = _hFileTable[slot].readUint16LE(); - push(val); - break; - case 43: - slot = pop(); - val = _hFileTable[slot].readUint32LE(); - push(val); - break; - case 45: - slot = pop(); - val = _hFileTable[slot].readByte(); - push(val); - break; - default: - error("o100_readFile: default case %d", subOp); - } -} - -void ScummEngine_v100he::o100_getSpriteInfo() { - int args[16]; - int spriteId, flags, groupId, type; - int32 x, y; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 3: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteFlagAutoAnim(spriteId)); - else - push(0); - break; - case 4: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteAnimSpeed(spriteId)); - else - push(1); - break; - case 7: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteSourceImage(spriteId)); - else - push(0); - break; - case 16: - flags = getStackList(args, ARRAYSIZE(args)); - spriteId = pop(); - if (spriteId) { - push(_sprite->getSpriteClass(spriteId, flags, args)); - } else { - push(0); - } - break; - case 26: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteImageStateCount(spriteId)); - else - push(0); - break; - case 30: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteDisplayX(spriteId)); - else - push(0); - break; - case 31: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteDisplayY(spriteId)); - else - push(0); - break; - case 32: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteFlagEraseType(spriteId)); - else - push(1); - break; - case 33: - flags = getStackList(args, ARRAYSIZE(args)); - type = pop(); - groupId = pop(); - y = pop(); - x = pop(); - push(_sprite->findSpriteWithClassOf(x, y, groupId, type, flags, args)); - break; - case 38: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteGroup(spriteId)); - else - push(0); - break; - case 39: - spriteId = pop(); - if (spriteId) { - _sprite->getSpriteImageDim(spriteId, x, y); - push(y); - } else { - push(0); - } - break; - case 40: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteImage(spriteId)); - else - push(0); - break; - case 48: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteMaskImage(spriteId)); - else - push(0); - break; - case 54: - flags = pop(); - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteGeneralProperty(spriteId, flags)); - else - push(0); - break; - case 57: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpritePalette(spriteId)); - else - push(0); - break; - case 59: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpritePriority(spriteId)); - else - push(0); - break; - case 60: - flags = pop(); - spriteId = pop(); - if (spriteId) { - switch(flags) { - case 0: - push(_sprite->getSpriteFlagXFlipped(spriteId)); - break; - case 1: - push(_sprite->getSpriteFlagYFlipped(spriteId)); - break; - case 2: - push(_sprite->getSpriteFlagActive(spriteId)); - break; - case 3: - push(_sprite->getSpriteFlagDoubleBuffered(spriteId)); - break; - case 4: - push(_sprite->getSpriteFlagRemapPalette(spriteId)); - break; - default: - push(0); - } - } else { - push(0); - } - break; - case 65: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteScale(spriteId)); - else - push(0); - break; - case 70: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteShadow(spriteId)); - else - push(0); - break; - case 73: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteImageState(spriteId)); - else - push(0); - break; - case 75: - spriteId = pop(); - if (spriteId) { - _sprite->getSpriteDist(spriteId, x, y); - push(x); - } else { - push(0); - } - break; - case 76: - spriteId = pop(); - if (spriteId) { - _sprite->getSpriteDist(spriteId, x, y); - push(y); - } else { - push(0); - } - break; - case 82: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteFlagUpdateType(spriteId)); - else - push(0); - break; - case 83: - pop(); - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteUserValue(spriteId)); - else - push(0); - break; - case 84: - spriteId = pop(); - if (spriteId) { - _sprite->getSpriteImageDim(spriteId, x, y); - push(x); - } else { - push(0); - } - break; - case 85: - spriteId = pop(); - if (spriteId) { - _sprite->getSpritePosition(spriteId, x, y); - push(x); - } else { - push(0); - } - break; - case 86: - spriteId = pop(); - if (spriteId) { - _sprite->getSpritePosition(spriteId, x, y); - push(y); - } else { - push(0); - } - break; - default: - error("o100_getSpriteInfo: Unknown case %d", subOp); - } -} - -void ScummEngine_v100he::o100_getVideoData() { - // Uses Bink video - byte subOp = fetchScriptByte(); - subOp -= 26; - - switch (subOp) { - case 0: - pop(); - break; - case 13: - pop(); - break; - case 14: - pop(); - break; - case 28: - pop(); - pop(); - break; - case 47: - pop(); - break; - case 58: - pop(); - break; - default: - error("o100_getVideoData: unhandled case %d", subOp); - } - - push(-1); - debug(1,"o100_getVideoData stub (%d)", subOp); -} - -void ScummEngine_v100he::decodeParseString(int m, int n) { - Actor *a; - int i, colors, size; - int args[31]; - byte name[1024]; - - byte b = fetchScriptByte(); - - switch (b) { - case 6: // SO_AT - _string[m].ypos = pop(); - _string[m].xpos = pop(); - _string[m].overhead = false; - break; - case 12: // SO_CENTER - _string[m].center = true; - _string[m].overhead = false; - break; - case 18: // SO_CLIPPED - _string[m].right = pop(); - break; - case 20: // SO_COLOR - _string[m].color = pop(); - break; - case 21: - colors = pop(); - if (colors == 1) { - _string[m].color = pop(); - } else { - push(colors); - getStackList(args, ARRAYSIZE(args)); - for (i = 0; i < 16; i++) - _charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i]; - _string[m].color = _charsetColorMap[0]; - } - break; - case 35: - decodeScriptString(name, true); - printString(m, name); - break; - case 46: // SO_LEFT - _string[m].center = false; - _string[m].overhead = false; - break; - case 51: // SO_MUMBLE - _string[m].no_talk_anim = true; - break; - case 56: // SO_OVERHEAD - _string[m].overhead = true; - _string[m].no_talk_anim = false; - break; - case 78: - { - byte *dataPtr = getResourceAddress(rtTalkie, pop()); - byte *text = findWrappedBlock(MKID('TEXT'), dataPtr, 0, 0); - size = getResourceDataSize(text); - memcpy(name, text, size); - printString(m, name); - } - break; - case 79: // SO_TEXTSTRING - printString(m, _scriptPointer); - _scriptPointer += resStrLen(_scriptPointer) + 1; - break; - case 91: - _string[m].loadDefault(); - if (n) { - _actorToPrintStrFor = pop(); - if (_actorToPrintStrFor != 0xFF) { - a = derefActor(_actorToPrintStrFor, "decodeParseString"); - _string[0].color = a->_talkColor; - } - } - break; - case 92: - _string[m].saveDefault(); - break; - default: - error("decodeParseString: default case %d", b); - } -} - -} // End of namespace Scumm diff --git a/engines/scumm/script_v6he.cpp b/engines/scumm/script_v6he.cpp deleted file mode 100644 index 5c08a7e336..0000000000 --- a/engines/scumm/script_v6he.cpp +++ /dev/null @@ -1,1276 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" -#include "common/savefile.h" - -#include "scumm/actor.h" -#include "scumm/charset.h" -#include "scumm/imuse.h" -#include "scumm/intern_he.h" -#include "scumm/object.h" -#include "scumm/resource.h" -#include "scumm/scumm.h" -#include "scumm/sound.h" -#include "scumm/usage_bits.h" -#include "scumm/util.h" -#include "scumm/verbs.h" - -namespace Scumm { - -struct vsUnpackCtx { - uint8 size; - uint8 type; - uint8 b; - uint8 *ptr; -}; - -struct vsPackCtx { - int size; - uint8 buf[256]; -}; - -static void virtScreenSavePackBuf(vsPackCtx *ctx, uint8 *&dst, int len); -static void virtScreenSavePackByte(vsPackCtx *ctx, uint8 *&dst, int len, uint8 b); -static uint8 virtScreenLoadUnpack(vsUnpackCtx *ctx, byte *data); -static int virtScreenSavePack(byte *dst, byte *src, int len, int unk); - -// Compatibility notes: -// -// FBEAR (fbear, fbeardemo) -// transparency in akos.cpp -// negative size in file read/write - -#define OPCODE(x) _OPCODE(ScummEngine_v60he, x) - -void ScummEngine_v60he::setupOpcodes() { - static const OpcodeEntryv60he opcodes[256] = { - /* 00 */ - OPCODE(o6_pushByte), - OPCODE(o6_pushWord), - OPCODE(o6_pushByteVar), - OPCODE(o6_pushWordVar), - /* 04 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayRead), - OPCODE(o6_wordArrayRead), - /* 08 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayIndexedRead), - OPCODE(o6_wordArrayIndexedRead), - /* 0C */ - OPCODE(o6_dup), - OPCODE(o6_not), - OPCODE(o6_eq), - OPCODE(o6_neq), - /* 10 */ - OPCODE(o6_gt), - OPCODE(o6_lt), - OPCODE(o6_le), - OPCODE(o6_ge), - /* 14 */ - OPCODE(o6_add), - OPCODE(o6_sub), - OPCODE(o6_mul), - OPCODE(o6_div), - /* 18 */ - OPCODE(o6_land), - OPCODE(o6_lor), - OPCODE(o6_pop), - OPCODE(o6_invalid), - /* 1C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 20 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 24 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 28 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 2C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 30 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 34 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 38 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 3C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 40 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_writeByteVar), - OPCODE(o6_writeWordVar), - /* 44 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayWrite), - OPCODE(o6_wordArrayWrite), - /* 48 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayIndexedWrite), - OPCODE(o6_wordArrayIndexedWrite), - /* 4C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteVarInc), - OPCODE(o6_wordVarInc), - /* 50 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayInc), - OPCODE(o6_wordArrayInc), - /* 54 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteVarDec), - OPCODE(o6_wordVarDec), - /* 58 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayDec), - OPCODE(o6_wordArrayDec), - /* 5C */ - OPCODE(o6_if), - OPCODE(o6_ifNot), - OPCODE(o6_startScript), - OPCODE(o6_startScriptQuick), - /* 60 */ - OPCODE(o6_startObject), - OPCODE(o6_drawObject), - OPCODE(o6_drawObjectAt), - OPCODE(o6_invalid), - /* 64 */ - OPCODE(o6_invalid), - OPCODE(o6_stopObjectCode), - OPCODE(o6_stopObjectCode), - OPCODE(o6_endCutscene), - /* 68 */ - OPCODE(o6_cutscene), - OPCODE(o6_stopMusic), - OPCODE(o6_freezeUnfreeze), - OPCODE(o6_cursorCommand), - /* 6C */ - OPCODE(o6_breakHere), - OPCODE(o6_ifClassOfIs), - OPCODE(o6_setClass), - OPCODE(o6_getState), - /* 70 */ - OPCODE(o60_setState), - OPCODE(o6_setOwner), - OPCODE(o6_getOwner), - OPCODE(o6_jump), - /* 74 */ - OPCODE(o6_startSound), - OPCODE(o6_stopSound), - OPCODE(o6_startMusic), - OPCODE(o6_stopObjectScript), - /* 78 */ - OPCODE(o6_panCameraTo), - OPCODE(o6_actorFollowCamera), - OPCODE(o6_setCameraAt), - OPCODE(o6_loadRoom), - /* 7C */ - OPCODE(o6_stopScript), - OPCODE(o6_walkActorToObj), - OPCODE(o6_walkActorTo), - OPCODE(o6_putActorAtXY), - /* 80 */ - OPCODE(o6_putActorAtObject), - OPCODE(o6_faceActor), - OPCODE(o6_animateActor), - OPCODE(o6_doSentence), - /* 84 */ - OPCODE(o6_pickupObject), - OPCODE(o6_loadRoomWithEgo), - OPCODE(o6_invalid), - OPCODE(o6_getRandomNumber), - /* 88 */ - OPCODE(o6_getRandomNumberRange), - OPCODE(o6_invalid), - OPCODE(o6_getActorMoving), - OPCODE(o6_isScriptRunning), - /* 8C */ - OPCODE(o6_getActorRoom), - OPCODE(o6_getObjectX), - OPCODE(o6_getObjectY), - OPCODE(o6_getObjectOldDir), - /* 90 */ - OPCODE(o6_getActorWalkBox), - OPCODE(o6_getActorCostume), - OPCODE(o6_findInventory), - OPCODE(o6_getInventoryCount), - /* 94 */ - OPCODE(o6_getVerbFromXY), - OPCODE(o6_beginOverride), - OPCODE(o6_endOverride), - OPCODE(o6_setObjectName), - /* 98 */ - OPCODE(o6_isSoundRunning), - OPCODE(o6_setBoxFlags), - OPCODE(o6_invalid), - OPCODE(o6_resourceRoutines), - /* 9C */ - OPCODE(o60_roomOps), - OPCODE(o60_actorOps), - OPCODE(o6_verbOps), - OPCODE(o6_getActorFromXY), - /* A0 */ - OPCODE(o6_findObject), - OPCODE(o6_pseudoRoom), - OPCODE(o6_getActorElevation), - OPCODE(o6_getVerbEntrypoint), - /* A4 */ - OPCODE(o6_arrayOps), - OPCODE(o6_saveRestoreVerbs), - OPCODE(o6_drawBox), - OPCODE(o6_pop), - /* A8 */ - OPCODE(o6_getActorWidth), - OPCODE(o6_wait), - OPCODE(o6_getActorScaleX), - OPCODE(o6_getActorAnimCounter1), - /* AC */ - OPCODE(o6_invalid), - OPCODE(o6_isAnyOf), - OPCODE(o6_systemOps), - OPCODE(o6_isActorInBox), - /* B0 */ - OPCODE(o6_delay), - OPCODE(o6_delaySeconds), - OPCODE(o6_delayMinutes), - OPCODE(o6_stopSentence), - /* B4 */ - OPCODE(o6_printLine), - OPCODE(o6_printText), - OPCODE(o6_printDebug), - OPCODE(o6_printSystem), - /* B8 */ - OPCODE(o6_printActor), - OPCODE(o6_printEgo), - OPCODE(o6_talkActor), - OPCODE(o6_talkEgo), - /* BC */ - OPCODE(o6_dimArray), - OPCODE(o6_stopObjectCode), - OPCODE(o6_startObjectQuick), - OPCODE(o6_startScriptQuick2), - /* C0 */ - OPCODE(o6_dim2dimArray), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* C4 */ - OPCODE(o6_abs), - OPCODE(o6_distObjectObject), - OPCODE(o6_distObjectPt), - OPCODE(o6_distPtPt), - /* C8 */ - OPCODE(o60_kernelGetFunctions), - OPCODE(o60_kernelSetFunctions), - OPCODE(o6_delayFrames), - OPCODE(o6_pickOneOf), - /* CC */ - OPCODE(o6_pickOneOfDefault), - OPCODE(o6_stampObject), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* D0 */ - OPCODE(o6_getDateTime), - OPCODE(o6_stopTalking), - OPCODE(o6_getAnimateVariable), - OPCODE(o6_invalid), - /* D4 */ - OPCODE(o6_shuffle), - OPCODE(o6_jumpToScript), - OPCODE(o6_band), - OPCODE(o6_bor), - /* D8 */ - OPCODE(o6_isRoomScriptRunning), - OPCODE(o60_closeFile), - OPCODE(o60_openFile), - OPCODE(o60_readFile), - /* DC */ - OPCODE(o60_writeFile), - OPCODE(o6_findAllObjects), - OPCODE(o60_deleteFile), - OPCODE(o60_rename), - /* E0 */ - OPCODE(o60_soundOps), - OPCODE(o6_getPixel), - OPCODE(o60_localizeArrayToScript), - OPCODE(o6_pickVarRandom), - /* E4 */ - OPCODE(o6_setBoxSet), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* E8 */ - OPCODE(o6_invalid), - OPCODE(o60_seekFilePos), - OPCODE(o60_redimArray), - OPCODE(o60_readFilePos), - /* EC */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* F0 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* F4 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* F8 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* FC */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - }; - - _opcodesv60he = opcodes; -} - -void ScummEngine_v60he::executeOpcode(byte i) { - OpcodeProcv60he op = _opcodesv60he[i].proc; - (this->*op) (); -} - -const char *ScummEngine_v60he::getOpcodeDesc(byte i) { - return _opcodesv60he[i].desc; -} - -void ScummEngine_v60he::o60_setState() { - int state = pop(); - int obj = pop(); - - if (state & 0x8000) { - state &= 0x7FFF; - putState(obj, state); - if (_heversion >= 72) - removeObjectFromDrawQue(obj); - } else { - putState(obj, state); - markObjectRectAsDirty(obj); - if (_bgNeedsRedraw) - clearDrawObjectQueue(); - } -} - -void ScummEngine_v60he::o60_roomOps() { - int a, b, c, d, e; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 172: // SO_ROOM_SCROLL - b = pop(); - a = pop(); - if (a < (_screenWidth / 2)) - a = (_screenWidth / 2); - if (b < (_screenWidth / 2)) - b = (_screenWidth / 2); - if (a > _roomWidth - (_screenWidth / 2)) - a = _roomWidth - (_screenWidth / 2); - if (b > _roomWidth - (_screenWidth / 2)) - b = _roomWidth - (_screenWidth / 2); - VAR(VAR_CAMERA_MIN_X) = a; - VAR(VAR_CAMERA_MAX_X) = b; - break; - - case 174: // SO_ROOM_SCREEN - b = pop(); - a = pop(); - if (_heversion >= 71) - initScreens(a, _screenHeight); - else - initScreens(a, b); - break; - - case 175: // SO_ROOM_PALETTE - d = pop(); - c = pop(); - b = pop(); - a = pop(); - setPalColor(d, a, b, c); - break; - - case 176: // SO_ROOM_SHAKE_ON - setShake(1); - break; - - case 177: // SO_ROOM_SHAKE_OFF - setShake(0); - break; - - case 179: // SO_ROOM_INTENSITY - c = pop(); - b = pop(); - a = pop(); - darkenPalette(a, a, a, b, c); - break; - - case 180: // SO_ROOM_SAVEGAME - _saveTemporaryState = true; - _saveLoadSlot = pop(); - _saveLoadFlag = pop(); - break; - - case 181: // SO_ROOM_FADE - a = pop(); - if (_heversion >= 70) { - // Defaults to 1 but doesn't use fade effects - } else if (a) { - _switchRoomEffect = (byte)(a & 0xFF); - _switchRoomEffect2 = (byte)(a >> 8); - } else { - fadeIn(_newEffect); - } - break; - - case 182: // SO_RGB_ROOM_INTENSITY - e = pop(); - d = pop(); - c = pop(); - b = pop(); - a = pop(); - darkenPalette(a, b, c, d, e); - break; - - case 183: // SO_ROOM_SHADOW - e = pop(); - d = pop(); - c = pop(); - b = pop(); - a = pop(); - if (_heversion == 60) - setupShadowPalette(a, b, c, d, e, 0, 256); - break; - - case 186: // SO_ROOM_TRANSFORM - d = pop(); - c = pop(); - b = pop(); - a = pop(); - palManipulateInit(a, b, c, d); - break; - - case 187: // SO_CYCLE_SPEED - b = pop(); - a = pop(); - checkRange(16, 1, a, "o60_roomOps: 187: color cycle out of range (%d)"); - _colorCycle[a - 1].delay = (b != 0) ? 0x4000 / (b * 0x4C) : 0; - break; - - case 213: // SO_ROOM_NEW_PALETTE - a = pop(); - setPalette(a); - break; - case 220: - a = pop(); - b = pop(); - copyPalColor(a, b); - break; - case 221: - int len; - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - _saveLoadFlag = pop(); - _saveLoadSlot = 1; - _saveTemporaryState = true; - break; - case 234: // HE 7.2 - b = pop(); - a = pop(); - swapObjects(a, b); - break; - case 236: // HE 7.2 - b = pop(); - a = pop(); - setRoomPalette(a, b); - break; - default: - error("o60_roomOps: default case %d", subOp); - } -} - -void ScummEngine_v60he::swapObjects(int object1, int object2) { - int idx1 = -1, idx2 = -1; - - for (int i = 0; i < _numLocalObjects; i++) { - if (_objs[i].obj_nr == object1) - idx1 = i; - - if (_objs[i].obj_nr == object2) - idx2 = i; - } - - if (idx1 == -1 || idx2 == -1 || idx1 <= idx2) - return; - - stopObjectScript(object1); - stopObjectScript(object2); - - ObjectData tmpOd; - - memcpy(&tmpOd, &_objs[idx1], sizeof(tmpOd)); - memcpy(&_objs[idx1], &_objs[idx2], sizeof(tmpOd)); - memcpy(&_objs[idx2], &tmpOd, sizeof(tmpOd)); -} - -void ScummEngine_v60he::o60_actorOps() { - Actor *a; - int i, j, k; - int args[8]; - - byte subOp = fetchScriptByte(); - if (subOp == 197) { - _curActor = pop(); - return; - } - - a = derefActorSafe(_curActor, "o60_actorOps"); - if (!a) - return; - - switch (subOp) { - case 30: - // _heversion >= 70 - _actorClipOverride.bottom = pop(); - _actorClipOverride.right = pop(); - _actorClipOverride.top = pop(); - _actorClipOverride.left = pop(); - break; - case 76: // SO_COSTUME - a->setActorCostume(pop()); - break; - case 77: // SO_STEP_DIST - j = pop(); - i = pop(); - a->setActorWalkSpeed(i, j); - break; - case 78: // SO_SOUND - k = getStackList(args, ARRAYSIZE(args)); - for (i = 0; i < k; i++) - a->_sound[i] = args[i]; - break; - case 79: // SO_WALK_ANIMATION - a->_walkFrame = pop(); - break; - case 80: // SO_TALK_ANIMATION - a->_talkStopFrame = pop(); - a->_talkStartFrame = pop(); - break; - case 81: // SO_STAND_ANIMATION - a->_standFrame = pop(); - break; - case 82: // SO_ANIMATION - // dummy case in scumm6 - pop(); - pop(); - pop(); - break; - case 83: // SO_DEFAULT - a->initActor(0); - break; - case 84: // SO_ELEVATION - a->setElevation(pop()); - break; - case 85: // SO_ANIMATION_DEFAULT - a->_initFrame = 1; - a->_walkFrame = 2; - a->_standFrame = 3; - a->_talkStartFrame = 4; - a->_talkStopFrame = 5; - break; - case 86: // SO_PALETTE - j = pop(); - i = pop(); - checkRange(255, 0, i, "Illegal palette slot %d"); - a->remapActorPaletteColor(i, j); - a->_needRedraw = true; - break; - case 87: // SO_TALK_COLOR - a->_talkColor = pop(); - break; - case 88: // SO_ACTOR_NAME - loadPtrToResource(rtActorName, a->_number, NULL); - break; - case 89: // SO_INIT_ANIMATION - a->_initFrame = pop(); - break; - case 91: // SO_ACTOR_WIDTH - a->_width = pop(); - break; - case 92: // SO_SCALE - i = pop(); - a->setScale(i, i); - break; - case 93: // SO_NEVER_ZCLIP - a->_forceClip = 0; - break; - case 94: // SO_ALWAYS_ZCLIP - a->_forceClip = pop(); - break; - case 95: // SO_IGNORE_BOXES - a->_ignoreBoxes = 1; - a->_forceClip = 0; - if (a->isInCurrentRoom()) - a->putActor(a->_pos.x, a->_pos.y, a->_room); - break; - case 96: // SO_FOLLOW_BOXES - a->_ignoreBoxes = 0; - a->_forceClip = 0; - if (a->isInCurrentRoom()) - a->putActor(a->_pos.x, a->_pos.y, a->_room); - break; - case 97: // SO_ANIMATION_SPEED - a->setAnimSpeed(pop()); - break; - case 98: // SO_SHADOW - a->_shadowMode = pop(); - a->_needRedraw = true; - break; - case 99: // SO_TEXT_OFFSET - a->_talkPosY = pop(); - a->_talkPosX = pop(); - break; - case 156: // HE 7.2 - a->_charset = pop(); - break; - case 198: // SO_ACTOR_VARIABLE - i = pop(); - a->setAnimVar(pop(), i); - break; - case 215: // SO_ACTOR_IGNORE_TURNS_ON - a->_ignoreTurns = true; - break; - case 216: // SO_ACTOR_IGNORE_TURNS_OFF - a->_ignoreTurns = false; - break; - case 217: // SO_ACTOR_NEW - a->initActor(2); - break; - case 218: - a->drawActorToBackBuf(a->_pos.x, a->_pos.y); - break; - case 219: - a->_drawToBackBuf = false; - a->_needRedraw = true; - a->_needBgReset = true; - break; - case 225: - { - byte string[128]; - copyScriptString(string); - int slot = pop(); - - int len = resStrLen(string) + 1; - convertMessageToString(string, a->_heTalkQueue[slot].sentence, len); - - a->_heTalkQueue[slot].posX = a->_talkPosX; - a->_heTalkQueue[slot].posY = a->_talkPosY; - a->_heTalkQueue[slot].color = a->_talkColor; - break; - } - default: - error("o60_actorOps: default case %d", subOp); - } -} - -void ScummEngine_v60he::o60_kernelSetFunctions() { - int args[29]; - int num; - - num = getStackList(args, ARRAYSIZE(args)); - - switch (args[0]) { - case 1: - // Used to restore images when decorating cake in - // Fatty Bear's Birthday Surprise - virtScreenLoad(args[1], args[2], args[3], args[4], args[5]); - break; - case 3: - case 4: - case 5: - case 6: - case 8: - //Used before mini games in 3DO versions, seems safe to ignore. - break; - default: - error("o60_kernelSetFunctions: default case %d (param count %d)", args[0], num); - } -} - -void ScummEngine_v60he::virtScreenLoad(int resIdx, int x1, int y1, int x2, int y2) { - vsUnpackCtx ctx; - memset(&ctx, 0, sizeof(ctx)); - VirtScreen &vs = virtscr[kMainVirtScreen]; - - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resIdx); - virtScreenLoadUnpack(&ctx, ah->data); - for (int j = y1; j <= y2; ++j) { - uint8 *p1 = vs.getPixels(x1, j - vs.topline); - uint8 *p2 = vs.getBackPixels(x1, j - vs.topline); - if (x2 >= x1) { - uint32 w = x2 - x1 + 1; - while (w--) { - uint8 decByte = virtScreenLoadUnpack(&ctx, 0); - *p1++ = decByte; - *p2++ = decByte; - } - } - } - markRectAsDirty(kMainVirtScreen, x1, x2, y1, y2 + 1, USAGE_BIT_RESTORED); -} - -uint8 virtScreenLoadUnpack(vsUnpackCtx *ctx, byte *data) { - uint8 decByte; - if (data != 0) { - ctx->type = 0; - ctx->ptr = data; - decByte = 0; - } else { - uint8 a; - if (ctx->type == 0) { - a = *(ctx->ptr)++; - if (a & 1) { - ctx->type = 1; - ctx->b = *(ctx->ptr)++; - } else { - ctx->type = 2; - } - ctx->size = a; - a = (a >> 1) + 1; - } else { - a = ctx->size; - } - if (ctx->type == 2) { - ctx->b = *(ctx->ptr)++; - } - ctx->size = a - 1; - if (ctx->size == 0) { - ctx->type = 0; - } - decByte = ctx->b; - } - return decByte; -} - - -void ScummEngine_v60he::o60_kernelGetFunctions() { - int args[29]; - ArrayHeader *ah; - getStackList(args, ARRAYSIZE(args)); - - switch (args[0]) { - case 1: - // Used to store images when decorating cake in - // Fatty Bear's Birthday Surprise - writeVar(0, 0); - ah = defineArray(0, kByteArray, 0, virtScreenSave(0, args[1], args[2], args[3], args[4])); - virtScreenSave(ah->data, args[1], args[2], args[3], args[4]); - push(readVar(0)); - break; - default: - error("o60_kernelGetFunctions: default case %d", args[0]); - } -} - -int ScummEngine_v60he::virtScreenSave(byte *dst, int x1, int y1, int x2, int y2) { - int packedSize = 0; - VirtScreen &vs = virtscr[kMainVirtScreen]; - - for (int j = y1; j <= y2; ++j) { - uint8 *p = vs.getBackPixels(x1, j - vs.topline); - - int size = virtScreenSavePack(dst, p, x2 - x1 + 1, 0); - if (dst != 0) { - dst += size; - } - packedSize += size; - } - return packedSize; -} - -int virtScreenSavePack(byte *dst, byte *src, int len, int unk) { - vsPackCtx ctx; - memset(&ctx, 0, sizeof(ctx)); - - uint8 prevByte, curByte; - - ctx.buf[0] = prevByte = *src++; - int flag = 0; - int iend = 1; - int ibeg = 0; - - for (--len; len != 0; --len, prevByte = curByte) { - bool pass = false; - - assert(iend < 0x100); - ctx.buf[iend] = curByte = *src++; - ++iend; - - if (flag == 0) { - if (iend > 0x80) { - virtScreenSavePackBuf(&ctx, dst, iend - 1); - ctx.buf[0] = curByte; - iend = 1; - ibeg = 0; - continue; - } - if (prevByte != curByte) { - ibeg = iend - 1; - continue; - } - if (iend - ibeg < 3) { - if (ibeg != 0) { - pass = true; - } else { - flag = 1; - } - } else { - if (ibeg > 0) { - virtScreenSavePackBuf(&ctx, dst, ibeg); - } - flag = 1; - } - } - if (flag == 1 || pass) { - if (prevByte != curByte || iend - ibeg > 0x80) { - virtScreenSavePackByte(&ctx, dst, iend - ibeg - 1, prevByte); - ctx.buf[0] = curByte; - iend = 1; - ibeg = 0; - flag = 0; - } - } - } - - if (flag == 0) { - virtScreenSavePackBuf(&ctx, dst, iend); - } else if (flag == 1) { - virtScreenSavePackByte(&ctx, dst, iend - ibeg, prevByte); - } - return ctx.size; -} - -void virtScreenSavePackBuf(vsPackCtx *ctx, uint8 *&dst, int len) { - if (dst) { - *dst++ = (len - 1) * 2; - } - ++ctx->size; - if (len > 0) { - ctx->size += len; - if (dst) { - memcpy(dst, ctx->buf, len); - dst += len; - } - } -} - -void virtScreenSavePackByte(vsPackCtx *ctx, uint8 *&dst, int len, uint8 b) { - if (dst) { - *dst++ = ((len - 1) * 2) | 1; - } - ++ctx->size; - if (dst) { - *dst++ = b; - } - ++ctx->size; -} - -void ScummEngine_v60he::o60_openFile() { - int mode, len, slot, l, r; - byte filename[100]; - - convertMessageToString(_scriptPointer, filename, sizeof(filename)); - - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - for (r = strlen((char*)filename); r != 0; r--) { - if (filename[r - 1] == '\\') - break; - } - - mode = pop(); - slot = -1; - for (l = 0; l < 17; l++) { - if (_hFileTable[l].isOpen() == false) { - slot = l; - break; - } - } - - if (slot != -1) { - switch(mode) { - case 1: - _hFileTable[slot].open((char*)filename + r, Common::File::kFileReadMode, _saveFileMan->getSavePath()); - if (_hFileTable[slot].isOpen() == false) - _hFileTable[slot].open((char*)filename + r, Common::File::kFileReadMode); - break; - case 2: - _hFileTable[slot].open((char*)filename + r, Common::File::kFileWriteMode, _saveFileMan->getSavePath()); - break; - default: - error("o60_openFile(): wrong open file mode %d", mode); - } - - if (_hFileTable[slot].isOpen() == false) - slot = -1; - - } - push(slot); -} - -void ScummEngine_v60he::o60_closeFile() { - int slot = pop(); - if (slot != -1) - _hFileTable[slot].close(); -} - -void ScummEngine_v60he::o60_deleteFile() { - int len, r; - byte filename[100]; - - convertMessageToString(_scriptPointer, filename, sizeof(filename)); - - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - for (r = strlen((char*)filename); r != 0; r--) { - if (filename[r - 1] == '\\') - break; - } - - debug(1, "stub o60_deleteFile(\"%s\")", filename + r); -} - -void ScummEngine_v60he::o60_rename() { - int len, r1, r2; - byte filename[100],filename2[100]; - - convertMessageToString(_scriptPointer, filename, sizeof(filename)); - - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - for (r1 = strlen((char*)filename); r1 != 0; r1--) { - if (filename[r1 - 1] == '\\') - break; - } - - convertMessageToString(_scriptPointer, filename2, sizeof(filename2)); - - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - for (r2 = strlen((char*)filename2); r2 != 0; r2--) { - if (filename2[r2 - 1] == '\\') - break; - } - - debug(1, "stub o60_rename(\"%s\" to \"%s\")", filename + r1, filename2 + r2); -} - -int ScummEngine_v60he::readFileToArray(int slot, int32 size) { - if (size == 0) - size = _hFileTable[slot].size() - _hFileTable[slot].pos(); - - writeVar(0, 0); - - ArrayHeader *ah = defineArray(0, kByteArray, 0, size); - _hFileTable[slot].read(ah->data, size); - - return readVar(0); -} - -void ScummEngine_v60he::o60_readFile() { - int32 size = pop(); - int slot = pop(); - int val; - - // Fatty Bear uses positive values - if ((_platform == Common::kPlatformPC) && (_gameId == GID_FBEAR)) - size = -size; - - if (size == -2) { - val = _hFileTable[slot].readUint16LE(); - push(val); - } else if (size == -1) { - val = _hFileTable[slot].readByte(); - push(val); - } else { - val = readFileToArray(slot, size); - push(val); - } -} - -void ScummEngine_v60he::writeFileFromArray(int slot, int resID) { - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resID); - int32 size = FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2); - - _hFileTable[slot].write(ah->data, size); -} - -void ScummEngine_v60he::o60_writeFile() { - int32 size = pop(); - int16 resID = pop(); - int slot = pop(); - - // Fatty Bear uses positive values - if ((_platform == Common::kPlatformPC) && (_gameId == GID_FBEAR)) - size = -size; - - if (size == -2) { - _hFileTable[slot].writeUint16LE(resID); - } else if (size == -1) { - _hFileTable[slot].writeByte(resID); - } else { - writeFileFromArray(slot, resID); - } -} - -void ScummEngine_v60he::o60_soundOps() { - byte subOp = fetchScriptByte(); - int arg = pop(); - - switch (subOp) { - case 0xde: - _imuse->setMusicVolume(arg); - break; - case 0xdf: - // Used in fbear introduction - break; - case 0xe0: - // Fatty Bear's Birthday surprise uses this when playing the - // piano, but only when using one of the digitized instruments. - // See also o6_startSound(). - _sound->setOverrideFreq(arg); - break; - default: - error("o60_soundOps: default case 0x%x", subOp); - } -} - -void ScummEngine_v60he::localizeArray(int slot, byte scriptSlot) { - if (_heversion >= 80) - slot &= ~0x33539000; - - if (slot >= _numArray) - error("o60_localizeArrayToScript(%d): array slot out of range", slot); - - _arraySlot[slot] = scriptSlot; -} - -void ScummEngine_v60he::o60_localizeArrayToScript() { - int slot = pop(); - localizeArray(slot, _currentScript); -} - -void ScummEngine_v60he::o60_seekFilePos() { - int mode, offset, slot; - - mode = pop(); - offset = pop(); - slot = pop(); - - if (slot == -1) - return; - - switch (mode) { - case 1: - _hFileTable[slot].seek(offset, SEEK_SET); - break; - case 2: - _hFileTable[slot].seek(offset, SEEK_CUR); - break; - case 3: - _hFileTable[slot].seek(offset, SEEK_END); - break; - default: - error("o60_seekFilePos: default case %d", mode); - } -} - -void ScummEngine_v60he::o60_readFilePos() { - int slot = pop(); - - if (slot == -1) { - push(0); - return; - } - - push(_hFileTable[slot].pos()); -} - -void ScummEngine_v60he::o60_redimArray() { - int newX, newY; - newY = pop(); - newX = pop(); - - if (newY == 0) - SWAP(newX, newY); - - byte subOp = fetchScriptByte(); - switch (subOp) { - case 199: - redimArray(fetchScriptWord(), newX, newY, kIntArray); - break; - case 202: - redimArray(fetchScriptWord(), newX, newY, kByteArray); - break; - default: - error("o60_redimArray: default type %d", subOp); - } -} - -void ScummEngine_v60he::redimArray(int arrayId, int newX, int newY, int type) { - // Used in mini game at Cosmic Dust Diner in puttmoon - int newSize, oldSize; - - if (readVar(arrayId) == 0) - error("redimArray: Reference to zeroed array pointer"); - - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(arrayId)); - - if (!ah) - error("redimArray: Invalid array (%d) reference", readVar(arrayId)); - - newSize = (type == kIntArray) ? 2 : 1; - oldSize = (ah->type == kIntArray) ? 2 : 1; - - newSize *= (newX + 1) * (newY + 1); - oldSize *= FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2); - - if (newSize != oldSize) - error("redimArray: array %d redim mismatch", readVar(arrayId)); - - ah->type = TO_LE_16(type); - ah->dim1 = TO_LE_16(newY + 1); - ah->dim2 = TO_LE_16(newX + 1); -} - -void ScummEngine_v60he::decodeParseString(int m, int n) { - int i, colors; - int args[31]; - - byte b = fetchScriptByte(); - - switch (b) { - case 65: // SO_AT - _string[m].ypos = pop(); - _string[m].xpos = pop(); - _string[m].overhead = false; - break; - case 66: // SO_COLOR - _string[m].color = pop(); - break; - case 67: // SO_CLIPPED - _string[m].right = pop(); - break; - case 69: // SO_CENTER - _string[m].center = true; - _string[m].overhead = false; - break; - case 71: // SO_LEFT - _string[m].center = false; - _string[m].overhead = false; - break; - case 72: // SO_OVERHEAD - _string[m].overhead = true; - _string[m].no_talk_anim = false; - break; - case 74: // SO_MUMBLE - _string[m].no_talk_anim = true; - break; - case 75: // SO_TEXTSTRING - printString(m, _scriptPointer); - _scriptPointer += resStrLen(_scriptPointer) + 1; - break; - case 0xF9: - colors = pop(); - if (colors == 1) { - _string[m].color = pop(); - } else { - push(colors); - getStackList(args, ARRAYSIZE(args)); - for (i = 0; i < 16; i++) - _charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i]; - _string[m].color = _charsetColorMap[0]; - } - break; - case 0xFE: - _string[m].loadDefault(); - if (n) - _actorToPrintStrFor = pop(); - break; - case 0xFF: - _string[m].saveDefault(); - break; - default: - error("decodeParseString: default case 0x%x", b); - } -} - -} // End of namespace Scumm diff --git a/engines/scumm/script_v72he.cpp b/engines/scumm/script_v72he.cpp deleted file mode 100644 index 3cd85042a3..0000000000 --- a/engines/scumm/script_v72he.cpp +++ /dev/null @@ -1,2368 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" - -#include "common/config-manager.h" -#include "common/savefile.h" -#include "common/system.h" - -#include "scumm/actor.h" -#include "scumm/charset.h" -#include "scumm/intern_he.h" -#include "scumm/object.h" -#include "scumm/resource.h" -#include "scumm/resource_v7he.h" -#include "scumm/scumm.h" -#include "scumm/sound.h" -#include "scumm/util.h" -#include "scumm/verbs.h" - -namespace Scumm { - -#define OPCODE(x) _OPCODE(ScummEngine_v72he, x) - -void ScummEngine_v72he::setupOpcodes() { - static const OpcodeEntryV72he opcodes[256] = { - /* 00 */ - OPCODE(o6_pushByte), - OPCODE(o6_pushWord), - OPCODE(o72_pushDWord), - OPCODE(o6_pushWordVar), - /* 04 */ - OPCODE(o72_getScriptString), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_wordArrayRead), - /* 08 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_wordArrayIndexedRead), - /* 0C */ - OPCODE(o6_dup), - OPCODE(o6_not), - OPCODE(o6_eq), - OPCODE(o6_neq), - /* 10 */ - OPCODE(o6_gt), - OPCODE(o6_lt), - OPCODE(o6_le), - OPCODE(o6_ge), - /* 14 */ - OPCODE(o6_add), - OPCODE(o6_sub), - OPCODE(o6_mul), - OPCODE(o6_div), - /* 18 */ - OPCODE(o6_land), - OPCODE(o6_lor), - OPCODE(o6_pop), - OPCODE(o72_isAnyOf), - /* 1C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 20 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 24 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 28 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 2C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 30 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 34 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 38 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 3C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 40 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_writeWordVar), - /* 44 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_wordArrayWrite), - /* 48 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_wordArrayIndexedWrite), - /* 4C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_wordVarInc), - /* 50 */ - OPCODE(o72_resetCutscene), - OPCODE(o6_invalid), - OPCODE(o72_findObjectWithClassOf), - OPCODE(o6_wordArrayInc), - /* 54 */ - OPCODE(o72_getObjectImageX), - OPCODE(o72_getObjectImageY), - OPCODE(o72_captureWizImage), - OPCODE(o6_wordVarDec), - /* 58 */ - OPCODE(o72_getTimer), - OPCODE(o72_setTimer), - OPCODE(o72_getSoundPosition), - OPCODE(o6_wordArrayDec), - /* 5C */ - OPCODE(o6_if), - OPCODE(o6_ifNot), - OPCODE(o72_startScript), - OPCODE(o6_startScriptQuick), - /* 60 */ - OPCODE(o72_startObject), - OPCODE(o72_drawObject), - OPCODE(o72_printWizImage), - OPCODE(o72_getArrayDimSize), - /* 64 */ - OPCODE(o72_getNumFreeArrays), - OPCODE(o6_stopObjectCode), - OPCODE(o6_stopObjectCode), - OPCODE(o6_endCutscene), - /* 68 */ - OPCODE(o6_cutscene), - OPCODE(o6_stopMusic), - OPCODE(o6_freezeUnfreeze), - OPCODE(o6_cursorCommand), - /* 6C */ - OPCODE(o6_breakHere), - OPCODE(o6_ifClassOfIs), - OPCODE(o6_setClass), - OPCODE(o6_getState), - /* 70 */ - OPCODE(o60_setState), - OPCODE(o6_setOwner), - OPCODE(o6_getOwner), - OPCODE(o6_jump), - /* 74 */ - OPCODE(o70_startSound), - OPCODE(o6_stopSound), - OPCODE(o6_startMusic), - OPCODE(o6_stopObjectScript), - /* 78 */ - OPCODE(o6_panCameraTo), - OPCODE(o6_actorFollowCamera), - OPCODE(o6_setCameraAt), - OPCODE(o6_loadRoom), - /* 7C */ - OPCODE(o6_stopScript), - OPCODE(o6_walkActorToObj), - OPCODE(o6_walkActorTo), - OPCODE(o6_putActorAtXY), - /* 80 */ - OPCODE(o6_putActorAtObject), - OPCODE(o6_faceActor), - OPCODE(o6_animateActor), - OPCODE(o6_doSentence), - /* 84 */ - OPCODE(o70_pickupObject), - OPCODE(o6_loadRoomWithEgo), - OPCODE(o6_invalid), - OPCODE(o6_getRandomNumber), - /* 88 */ - OPCODE(o6_getRandomNumberRange), - OPCODE(o6_invalid), - OPCODE(o6_getActorMoving), - OPCODE(o6_isScriptRunning), - /* 8C */ - OPCODE(o70_getActorRoom), - OPCODE(o6_getObjectX), - OPCODE(o6_getObjectY), - OPCODE(o6_getObjectOldDir), - /* 90 */ - OPCODE(o6_getActorWalkBox), - OPCODE(o6_getActorCostume), - OPCODE(o6_findInventory), - OPCODE(o6_getInventoryCount), - /* 94 */ - OPCODE(o6_getVerbFromXY), - OPCODE(o6_beginOverride), - OPCODE(o6_endOverride), - OPCODE(o6_setObjectName), - /* 98 */ - OPCODE(o6_isSoundRunning), - OPCODE(o6_setBoxFlags), - OPCODE(o6_invalid), - OPCODE(o70_resourceRoutines), - /* 9C */ - OPCODE(o72_roomOps), - OPCODE(o72_actorOps), - OPCODE(o72_verbOps), - OPCODE(o6_getActorFromXY), - /* A0 */ - OPCODE(o72_findObject), - OPCODE(o6_pseudoRoom), - OPCODE(o6_getActorElevation), - OPCODE(o6_getVerbEntrypoint), - /* A4 */ - OPCODE(o72_arrayOps), - OPCODE(o6_saveRestoreVerbs), - OPCODE(o6_drawBox), - OPCODE(o6_pop), - /* A8 */ - OPCODE(o6_getActorWidth), - OPCODE(o6_wait), - OPCODE(o6_getActorScaleX), - OPCODE(o6_getActorAnimCounter1), - /* AC */ - OPCODE(o6_invalid), - OPCODE(o6_isAnyOf), - OPCODE(o72_systemOps), - OPCODE(o6_isActorInBox), - /* B0 */ - OPCODE(o6_delay), - OPCODE(o6_delaySeconds), - OPCODE(o6_delayMinutes), - OPCODE(o6_stopSentence), - /* B4 */ - OPCODE(o6_printLine), - OPCODE(o6_printText), - OPCODE(o6_printDebug), - OPCODE(o6_printSystem), - /* B8 */ - OPCODE(o6_printActor), - OPCODE(o6_printEgo), - OPCODE(o72_talkActor), - OPCODE(o72_talkEgo), - /* BC */ - OPCODE(o72_dimArray), - OPCODE(o6_stopObjectCode), - OPCODE(o6_startObjectQuick), - OPCODE(o6_startScriptQuick2), - /* C0 */ - OPCODE(o72_dim2dimArray), - OPCODE(o72_traceStatus), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* C4 */ - OPCODE(o6_abs), - OPCODE(o6_distObjectObject), - OPCODE(o6_distObjectPt), - OPCODE(o6_distPtPt), - /* C8 */ - OPCODE(o72_kernelGetFunctions), - OPCODE(o70_kernelSetFunctions), - OPCODE(o6_delayFrames), - OPCODE(o6_pickOneOf), - /* CC */ - OPCODE(o6_pickOneOfDefault), - OPCODE(o6_stampObject), - OPCODE(o72_drawWizImage), - OPCODE(o72_debugInput), - /* D0 */ - OPCODE(o6_getDateTime), - OPCODE(o6_stopTalking), - OPCODE(o6_getAnimateVariable), - OPCODE(o6_invalid), - /* D4 */ - OPCODE(o6_shuffle), - OPCODE(o72_jumpToScript), - OPCODE(o6_band), - OPCODE(o6_bor), - /* D8 */ - OPCODE(o6_isRoomScriptRunning), - OPCODE(o60_closeFile), - OPCODE(o72_openFile), - OPCODE(o72_readFile), - /* DC */ - OPCODE(o72_writeFile), - OPCODE(o72_findAllObjects), - OPCODE(o72_deleteFile), - OPCODE(o72_rename), - /* E0 */ - OPCODE(o60_soundOps), - OPCODE(o72_getPixel), - OPCODE(o60_localizeArrayToScript), - OPCODE(o72_pickVarRandom), - /* E4 */ - OPCODE(o6_setBoxSet), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* E8 */ - OPCODE(o6_invalid), - OPCODE(o70_seekFilePos), - OPCODE(o72_redimArray), - OPCODE(o60_readFilePos), - /* EC */ - OPCODE(o70_copyString), - OPCODE(o70_getStringWidth), - OPCODE(o70_getStringLen), - OPCODE(o70_appendString), - /* F0 */ - OPCODE(o70_concatString), - OPCODE(o70_compareString), - OPCODE(o70_isResourceLoaded), - OPCODE(o72_readINI), - /* F4 */ - OPCODE(o72_writeINI), - OPCODE(o70_getStringLenForWidth), - OPCODE(o70_getCharIndexInString), - OPCODE(o6_invalid), - /* F8 */ - OPCODE(o72_getResourceSize), - OPCODE(o72_setFilePath), - OPCODE(o72_setSystemMessage), - OPCODE(o70_polygonOps), - /* FC */ - OPCODE(o70_polygonHit), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - }; - - _opcodesV72he = opcodes; -} - -void ScummEngine_v72he::executeOpcode(byte i) { - OpcodeProcV72he op = _opcodesV72he[i].proc; - (this->*op) (); -} - -const char *ScummEngine_v72he::getOpcodeDesc(byte i) { - return _opcodesV72he[i].desc; -} - -static const int arrayDataSizes[] = { 0, 1, 4, 8, 8, 16, 32 }; - -ScummEngine_v72he::ArrayHeader *ScummEngine_v72he::defineArray(int array, int type, int dim2start, int dim2end, - int dim1start, int dim1end) { - int id; - int size; - ArrayHeader *ah; - - assert(dim2start >= 0 && dim2start <= dim2end); - assert(dim1start >= 0 && dim1start <= dim1end); - assert(0 <= type && type <= 6); - - - if (type == kBitArray || type == kNibbleArray) - type = kByteArray; - - nukeArray(array); - - id = findFreeArrayId(); - - debug(9,"defineArray (array %d, dim2start %d, dim2end %d dim1start %d dim1end %d", id, dim2start, dim2end, dim1start, dim1end); - - if (array & 0x80000000) { - error("Can't define bit variable as array pointer"); - } - - size = arrayDataSizes[type]; - - if (_heversion >= 80) - id |= 0x33539000; - - writeVar(array, id); - - if (_heversion >= 80) - id &= ~0x33539000; - - size *= dim2end - dim2start + 1; - size *= dim1end - dim1start + 1; - size >>= 3; - - ah = (ArrayHeader *)res.createResource(rtString, id, size + sizeof(ArrayHeader)); - - ah->type = TO_LE_32(type); - ah->dim1start = TO_LE_32(dim1start); - ah->dim1end = TO_LE_32(dim1end); - ah->dim2start = TO_LE_32(dim2start); - ah->dim2end = TO_LE_32(dim2end); - - return ah; -} - -int ScummEngine_v72he::readArray(int array, int idx2, int idx1) { - debug(9, "readArray (array %d, idx2 %d, idx1 %d)", readVar(array), idx2, idx1); - - if (readVar(array) == 0) - error("readArray: Reference to zeroed array pointer"); - - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array)); - - if (ah == NULL || ah->data == NULL) - error("readArray: invalid array %d (%d)", array, readVar(array)); - - if (idx2 < (int)FROM_LE_32(ah->dim2start) || idx2 > (int)FROM_LE_32(ah->dim2end) || - idx1 < (int)FROM_LE_32(ah->dim1start) || idx1 > (int)FROM_LE_32(ah->dim1end)) { - error("readArray: array %d out of bounds: [%d, %d] exceeds [%d..%d, %d..%d]", - array, idx1, idx2, FROM_LE_32(ah->dim1start), FROM_LE_32(ah->dim1end), - FROM_LE_32(ah->dim2start), FROM_LE_32(ah->dim2end)); - } - - const int offset = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) * - (idx2 - FROM_LE_32(ah->dim2start)) - FROM_LE_32(ah->dim1start) + idx1; - - switch (FROM_LE_32(ah->type)) { - case kByteArray: - case kStringArray: - return ah->data[offset]; - - case kIntArray: - return (int16)READ_LE_UINT16(ah->data + offset * 2); - - case kDwordArray: - return (int32)READ_LE_UINT32(ah->data + offset * 4); - } - - return 0; -} - -void ScummEngine_v72he::writeArray(int array, int idx2, int idx1, int value) { - debug(9, "writeArray (array %d, idx2 %d, idx1 %d, value %d)", readVar(array), idx2, idx1, value); - - if (readVar(array) == 0) - error("writeArray: Reference to zeroed array pointer"); - - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array)); - - if (!ah) - error("writeArray: Invalid array (%d) reference", readVar(array)); - - if (idx2 < (int)FROM_LE_32(ah->dim2start) || idx2 > (int)FROM_LE_32(ah->dim2end) || - idx1 < (int)FROM_LE_32(ah->dim1start) || idx1 > (int)FROM_LE_32(ah->dim1end)) { - error("writeArray: array %d out of bounds: [%d, %d] exceeds [%d..%d, %d..%d]", - array, idx1, idx2, FROM_LE_32(ah->dim1start), FROM_LE_32(ah->dim1end), - FROM_LE_32(ah->dim2start), FROM_LE_32(ah->dim2end)); - } - - const int offset = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) * - (idx2 - FROM_LE_32(ah->dim2start)) - FROM_LE_32(ah->dim1start) + idx1; - - switch (FROM_LE_32(ah->type)) { - case kByteArray: - case kStringArray: - ah->data[offset] = value; - break; - - case kIntArray: - WRITE_LE_UINT16(ah->data + offset * 2, value); - break; - - case kDwordArray: - WRITE_LE_UINT32(ah->data + offset * 4, value); - break; - } -} - -int ScummEngine_v72he::setupStringArray(int size) { - writeVar(0, 0); - defineArray(0, kStringArray, 0, 0, 0, size + 1); - writeArray(0, 0, 0, 0); - return readVar(0); -} - -void ScummEngine_v72he::readArrayFromIndexFile() { - int num; - int a, b, c; - - while ((num = _fileHandle->readUint16LE()) != 0) { - a = _fileHandle->readUint16LE(); - b = _fileHandle->readUint16LE(); - c = _fileHandle->readUint16LE(); - - if (c == 1) - defineArray(num, kBitArray, 0, a, 0, b); - else - defineArray(num, kDwordArray, 0, a, 0, b); - } -} - -int ScummEngine_v72he::convertFilePath(byte *dst, bool setFilePath) { - debug(1, "convertFilePath: original filePath is %s", dst); - - // Switch all \ to / for portablity - int len = resStrLen(dst) + 1; - for (int i = 0; i < len; i++) { - if (dst[i] == '\\') - dst[i] = '/'; - } - - // Strip path - int r = 0; - if (dst[0] == '.' && dst[1] == '/') { - r = 2; - } else if (dst[0] == 'c' && dst[1] == ':') { - for (r = len; r != 0; r--) { - if (dst[r - 1] == '/') - break; - } - } - - if (setFilePath) { - char filePath[256]; - sprintf(filePath, "%s%s", _gameDataPath.c_str(), dst + r); - if (!Common::File::exists(filePath)) { - sprintf(filePath, "%s%s", _saveFileMan->getSavePath(), dst + r); - } - strcpy((char *)dst, filePath); - debug(1, "convertFilePath: filePath is %s", dst); - } - - return r; -} - -void ScummEngine_v72he::copyScriptString(byte *dst, int dstSize) { - byte string[1024]; - byte chr; - int pos = 0; - - int array = pop(); - if (array == -1) { - if (_stringLength == 1) - error("String stack underflow"); - - _stringLength -= 2; - while ((chr = _stringBuffer[_stringLength]) != 0) { - string[pos] = chr; - pos++; - - if (pos > dstSize) - error("String too long to pop"); - - _stringLength--; - } - - string[pos] = 0; - _stringLength++; - - // Reverse string - int len = resStrLen(string); - while (len--) - *dst++ = string[len]; - } else { - writeVar(0, array); - while ((chr = readArray(0, 0, pos)) != 0) { - *dst++ = chr; - pos++; - } - } - *dst = 0; -} - -void ScummEngine_v72he::decodeScriptString(byte *dst, bool scriptString) { - const byte *src; - int args[31]; - int num, len, val; - byte chr, string[1024]; - memset(args, 0, sizeof(args)); - memset(string, 0, sizeof(string)); - - // Get stack list, plus one - num = pop(); - for (int i = num; i >= 0; i--) - args[i] = pop(); - - // Get string - if (scriptString) { - len = resStrLen(_scriptPointer) + 1; - memcpy(string, _scriptPointer, len); - _scriptPointer += len; - } else { - copyScriptString(string, sizeof(string)); - len = resStrLen(string) + 1; - } - - // Decode string - num = 0; - val = 0; - while (len--) { - chr = string[num++]; - if (chr == '%') { - chr = string[num++]; - switch(chr) { - case 'b': - //dst += sprintf((char *)dst, "%b", args[val++]); - break; - case 'c': - *dst++ = args[val++]; - break; - case 'd': - dst += sprintf((char *)dst, "%d", args[val++]); - break; - case 's': - src = getStringAddress(args[val++]); - if (src) { - while (*src != 0) - *dst++ = *src++; - } - break; - case 'x': - dst += sprintf((char *)dst, "%x", args[val++]); - break; - default: - *dst++ = '%'; - num--; - break; - } - } else { - *dst++ = chr; - } - } - *dst = 0; -} - -byte *ScummEngine_v70he::heFindResourceData(uint32 tag, byte *ptr) { - ptr = heFindResource(tag, ptr); - - if (ptr == NULL) - return NULL; - return ptr + _resourceHeaderSize; -} - -byte *ScummEngine_v70he::heFindResource(uint32 tag, byte *searchin) { - uint32 curpos, totalsize, size; - - debugC(DEBUG_RESOURCE, "heFindResource(%s, %lx)", tag2str(tag), searchin); - - assert(searchin); - searchin += 4; - _resourceLastSearchSize = totalsize = READ_BE_UINT32(searchin); - curpos = 8; - searchin += 4; - - while (curpos < totalsize) { - if (READ_UINT32(searchin) == tag) { - return searchin; - } - - size = READ_BE_UINT32(searchin + 4); - if ((int32)size <= 0) { - error("(%s) Not found in %d... illegal block len %d", tag2str(tag), 0, size); - return NULL; - } - - curpos += size; - searchin += size; - } - - return NULL; -} - -byte *ScummEngine_v70he::findWrappedBlock(uint32 tag, byte *ptr, int state, bool errorFlag) { - if (READ_UINT32(ptr) == MKID('MULT')) { - byte *offs, *wrap; - uint32 size; - - wrap = heFindResource(MKID('WRAP'), ptr); - if (wrap == NULL) - return NULL; - - offs = heFindResourceData(MKID('OFFS'), wrap); - if (offs == NULL) - return NULL; - - size = getResourceDataSize(offs) / 4; - assert((uint32)state <= (uint32)size); - - - offs += READ_LE_UINT32(offs + state * sizeof(uint32)); - offs = heFindResourceData(tag, offs - 8); - if (offs) - return offs; - - offs = heFindResourceData(MKID('DEFA'), ptr); - if (offs == NULL) - return NULL; - - return heFindResourceData(tag, offs - 8); - } else { - return heFindResourceData(tag, ptr); - } -} - -int ScummEngine_v72he::findObject(int x, int y, int num, int *args) { - int b, cls, i, result; - - for (i = 1; i < _numLocalObjects; i++) { - result = 0; - if ((_objs[i].obj_nr < 1) || getClass(_objs[i].obj_nr, kObjectClassUntouchable)) - continue; - - // Check polygon bounds - if (_wiz->polygonDefined(_objs[i].obj_nr)) { - if (_wiz->polygonHit(_objs[i].obj_nr, x, y)) - result = _objs[i].obj_nr; - else if (VAR_POLYGONS_ONLY != 0xFF && VAR(VAR_POLYGONS_ONLY)) - continue; - } - - if (!result) { - // Check object bounds - if (_objs[i].x_pos <= x && _objs[i].width + _objs[i].x_pos > x && - _objs[i].y_pos <= y && _objs[i].height + _objs[i].y_pos > y) - result = _objs[i].obj_nr; - } - - if (result) { - if (!num) - return result; - - // Check object class - cls = args[0]; - b = getClass(_objs[i].obj_nr, cls); - if ((cls & 0x80 && b) || (!(cls & 0x80) && !b)) - return result; - } - } - - return 0; -} - -void ScummEngine_v72he::o72_pushDWord() { - push(fetchScriptDWordSigned()); -} - -void ScummEngine_v72he::o72_getScriptString() { - byte chr; - - while ((chr = fetchScriptByte()) != 0) { - _stringBuffer[_stringLength] = chr; - _stringLength++; - - if (_stringLength >= 4096) - error("String stack overflow"); - } - - _stringBuffer[_stringLength] = 0; - _stringLength++; -} - -void ScummEngine_v72he::o72_isAnyOf() { - int args[128]; - int num, value; - - num = getStackList(args, ARRAYSIZE(args)); - value = pop(); - - for (int i = 0; i < num; i++) { - if (args[i] == value) { - push(1); - return; - } - } - - push(0); -} - -void ScummEngine_v72he::o72_resetCutscene() { - int idx; - - idx = vm.cutSceneStackPointer; - vm.cutSceneStackPointer = 0; - vm.cutScenePtr[idx] = 0; - vm.cutSceneScript[idx] = 0; - - VAR(VAR_OVERRIDE) = 0; -} - -void ScummEngine_v72he::o72_findObjectWithClassOf() { - int args[16], num; - - num = getStackList(args, ARRAYSIZE(args)); - int y = pop(); - int x = pop(); - int r = findObject(x, y, num, args); - push(r); -} - -void ScummEngine_v72he::o72_getObjectImageX() { - int object = pop(); - int objnum = getObjectIndex(object); - - if (objnum == -1) { - push(0); - return; - } - - push(_objs[objnum].x_pos / 8); -} - -void ScummEngine_v72he::o72_getObjectImageY() { - int object = pop(); - int objnum = getObjectIndex(object); - - if (objnum == -1) { - push(0); - return; - } - - push(_objs[objnum].y_pos / 8); -} - -void ScummEngine_v72he::o72_captureWizImage() { - Common::Rect grab; - grab.bottom = pop() + 1; - grab.right = pop() + 1; - grab.top = pop(); - grab.left = pop(); - _wiz->captureWizImage(pop(), grab, false, true); -} - -void ScummEngine_v72he::o72_getTimer() { - int timer = pop(); - byte cmd = fetchScriptByte(); - - if (cmd == 10 || cmd == 50) { - push(getHETimer(timer)); - } else { - push(0); - } -} - -void ScummEngine_v72he::o72_setTimer() { - int timer = pop(); - byte cmd = fetchScriptByte(); - - if (cmd == 158 || cmd == 61) { - setHETimer(timer); - } else { - error("TIMER command %d?", cmd); - } -} - -void ScummEngine_v72he::o72_getSoundPosition() { - int snd = pop(); - push(_sound->getSoundPos(snd)); -} - -void ScummEngine_v72he::o72_startScript() { - int args[25]; - int script; - byte flags; - - getStackList(args, ARRAYSIZE(args)); - script = pop(); - flags = fetchScriptByte(); - runScript(script, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args); -} - -void ScummEngine_v72he::o72_startObject() { - int args[25]; - int script, entryp; - byte flags; - - getStackList(args, ARRAYSIZE(args)); - entryp = pop(); - script = pop(); - flags = fetchScriptByte(); - runObjectScript(script, entryp, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args); -} - -void ScummEngine_v72he::o72_drawObject() { - byte subOp = fetchScriptByte(); - int state, y, x; - - switch (subOp) { - case 62: - state = pop(); - y = pop(); - x = pop(); - break; - case 63: - state = pop(); - if (state == 0) - state = 1; - y = x = -100; - break; - case 65: - state = 1; - y = pop(); - x = pop(); - break; - default: - error("o72_drawObject: default case %d", subOp); - } - - int object = pop(); - int objnum = getObjectIndex(object); - if (objnum == -1) - return; - - if (y != -100 && x != -100) { - _objs[objnum].x_pos = x * 8; - _objs[objnum].y_pos = y * 8; - } - - if (state != -1) { - addObjectToDrawQue(objnum); - putState(object, state); - } -} - -void ScummEngine_v72he::o72_printWizImage() { - WizImage wi; - wi.resNum = pop(); - wi.x1 = wi.y1 = 0; - wi.state = 0; - wi.flags = kWIFPrint; - _wiz->displayWizImage(&wi); -} - -void ScummEngine_v72he::o72_getArrayDimSize() { - byte subOp = fetchScriptByte(); - int32 val1, val2; - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(fetchScriptWord())); - if (!ah) { - push(0); - return; - } - - switch (subOp) { - case 1: - case 3: - val1 = FROM_LE_32(ah->dim1end); - val2 = FROM_LE_32(ah->dim1start); - push(val1 - val2 + 1); - break; - case 2: - val1 = FROM_LE_32(ah->dim2end); - val2 = FROM_LE_32(ah->dim2start); - push(val1 - val2 + 1); - break; - case 4: - push(FROM_LE_32(ah->dim1start)); - break; - case 5: - push(FROM_LE_32(ah->dim1end)); - break; - case 6: - push(FROM_LE_32(ah->dim2start)); - break; - case 7: - push(FROM_LE_32(ah->dim2end)); - break; - default: - error("o72_getArrayDimSize: default case %d", subOp); - } -} - -void ScummEngine_v72he::o72_getNumFreeArrays() { - byte **addr = res.address[rtString]; - int i, num = 0; - - for (i = 1; i < _numArray; i++) { - if (!addr[i]) - num++; - } - - push (num); -} - -void ScummEngine_v72he::o72_roomOps() { - int a, b, c, d, e; - byte filename[100]; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 172: // SO_ROOM_SCROLL - b = pop(); - a = pop(); - if (a < (_screenWidth / 2)) - a = (_screenWidth / 2); - if (b < (_screenWidth / 2)) - b = (_screenWidth / 2); - if (a > _roomWidth - (_screenWidth / 2)) - a = _roomWidth - (_screenWidth / 2); - if (b > _roomWidth - (_screenWidth / 2)) - b = _roomWidth - (_screenWidth / 2); - VAR(VAR_CAMERA_MIN_X) = a; - VAR(VAR_CAMERA_MAX_X) = b; - break; - - case 174: // SO_ROOM_SCREEN - b = pop(); - a = pop(); - initScreens(a, _screenHeight); - break; - - case 175: // SO_ROOM_PALETTE - d = pop(); - c = pop(); - b = pop(); - a = pop(); - setPalColor(d, a, b, c); - break; - - case 179: // SO_ROOM_INTENSITY - c = pop(); - b = pop(); - a = pop(); - darkenPalette(a, a, a, b, c); - break; - - case 180: // SO_ROOM_SAVEGAME - _saveTemporaryState = true; - _saveLoadSlot = pop(); - _saveLoadFlag = pop(); - break; - - case 181: // SO_ROOM_FADE - // Defaults to 1 but doesn't use fade effects - a = pop(); - break; - - case 182: // SO_RGB_ROOM_INTENSITY - e = pop(); - d = pop(); - c = pop(); - b = pop(); - a = pop(); - darkenPalette(a, b, c, d, e); - break; - - case 213: // SO_ROOM_NEW_PALETTE - a = pop(); - setPalette(a); - break; - - case 220: - a = pop(); - b = pop(); - copyPalColor(a, b); - break; - - case 221: - copyScriptString(filename, sizeof(filename)); - _saveLoadFlag = pop(); - _saveLoadSlot = 1; - _saveTemporaryState = true; - break; - - case 234: - b = pop(); - a = pop(); - swapObjects(a, b); - break; - - case 236: - b = pop(); - a = pop(); - setRoomPalette(a, b); - break; - - default: - error("o72_roomOps: default case %d", subOp); - } -} - -void ScummEngine_v72he::o72_actorOps() { - Actor *a; - int i, j, k; - int args[32]; - byte string[256]; - - byte subOp = fetchScriptByte(); - if (subOp == 197) { - _curActor = pop(); - return; - } - - a = derefActorSafe(_curActor, "o72_actorOps"); - if (!a) - return; - - switch (subOp) { - case 21: // HE 80+ - k = getStackList(args, ARRAYSIZE(args)); - for (i = 0; i < k; ++i) { - a->setUserCondition(args[i] & 0x7F, args[i] & 0x80); - } - break; - case 24: // HE 80+ - k = pop(); - if (k == 0) - k = _rnd.getRandomNumberRng(1, 10); - a->_heNoTalkAnimation = 1; - a->setTalkCondition(k); - break; - case 43: // HE 90+ - // HE games use reverse order of layering, so we adjust - a->_layer = -pop(); - a->_needRedraw = true; - break; - case 64: - _actorClipOverride.bottom = pop(); - _actorClipOverride.right = pop(); - _actorClipOverride.top = pop(); - _actorClipOverride.left = pop(); - break; - case 67: // HE 99+ - a->_clipOverride.bottom = pop(); - a->_clipOverride.right = pop(); - a->_clipOverride.top = pop(); - a->_clipOverride.left = pop(); - break; - case 65: // HE 98+ - j = pop(); - i = pop(); - a->putActor(i, j, a->_room); - break; - case 68: // HE 90+ - k = pop(); - debug(0,"o72_actorOps: case 68 (%d)", k); - break; - case 76: // SO_COSTUME - a->setActorCostume(pop()); - break; - case 77: // SO_STEP_DIST - j = pop(); - i = pop(); - a->setActorWalkSpeed(i, j); - break; - case 78: // SO_SOUND - k = getStackList(args, ARRAYSIZE(args)); - for (i = 0; i < k; i++) - a->_sound[i] = args[i]; - break; - case 79: // SO_WALK_ANIMATION - a->_walkFrame = pop(); - break; - case 80: // SO_TALK_ANIMATION - a->_talkStopFrame = pop(); - a->_talkStartFrame = pop(); - break; - case 81: // SO_STAND_ANIMATION - a->_standFrame = pop(); - break; - case 82: // SO_ANIMATION - // dummy case in scumm6 - pop(); - pop(); - pop(); - break; - case 83: // SO_DEFAULT - a->initActor(0); - break; - case 84: // SO_ELEVATION - a->setElevation(pop()); - break; - case 85: // SO_ANIMATION_DEFAULT - a->_initFrame = 1; - a->_walkFrame = 2; - a->_standFrame = 3; - a->_talkStartFrame = 4; - a->_talkStopFrame = 5; - break; - case 86: // SO_PALETTE - j = pop(); - i = pop(); - checkRange(255, 0, i, "Illegal palette slot %d"); - a->remapActorPaletteColor(i, j); - a->_needRedraw = true; - break; - case 87: // SO_TALK_COLOR - a->_talkColor = pop(); - break; - case 88: // SO_ACTOR_NAME - copyScriptString(string, sizeof(string)); - loadPtrToResource(rtActorName, a->_number, string); - break; - case 89: // SO_INIT_ANIMATION - a->_initFrame = pop(); - break; - case 91: // SO_ACTOR_WIDTH - a->_width = pop(); - break; - case 92: // SO_SCALE - i = pop(); - a->setScale(i, i); - break; - case 93: // SO_NEVER_ZCLIP - a->_forceClip = 0; - break; - case 94: // SO_ALWAYS_ZCLIP - a->_forceClip = pop(); - break; - case 95: // SO_IGNORE_BOXES - a->_ignoreBoxes = 1; - a->_forceClip = 0; - if (a->isInCurrentRoom()) - a->putActor(a->_pos.x, a->_pos.y, a->_room); - break; - case 96: // SO_FOLLOW_BOXES - a->_ignoreBoxes = 0; - a->_forceClip = 0; - if (a->isInCurrentRoom()) - a->putActor(a->_pos.x, a->_pos.y, a->_room); - break; - case 97: // SO_ANIMATION_SPEED - a->setAnimSpeed(pop()); - break; - case 98: // SO_SHADOW - a->_heXmapNum = pop(); - a->_needRedraw = true; - break; - case 99: // SO_TEXT_OFFSET - a->_talkPosY = pop(); - a->_talkPosX = pop(); - break; - case 156: // HE 72+ - a->_charset = pop(); - break; - case 175: // HE 99+ - a->_hePaletteNum = pop(); - a->_needRedraw = true; - break; - case 198: // SO_ACTOR_VARIABLE - i = pop(); - a->setAnimVar(pop(), i); - break; - case 215: // SO_ACTOR_IGNORE_TURNS_ON - a->_ignoreTurns = true; - break; - case 216: // SO_ACTOR_IGNORE_TURNS_OFF - a->_ignoreTurns = false; - break; - case 217: // SO_ACTOR_NEW - a->initActor(2); - break; - case 218: - a->drawActorToBackBuf(a->_pos.x, a->_pos.y); - break; - case 219: - a->_drawToBackBuf = false; - a->_needRedraw = true; - a->_needBgReset = true; - break; - case 225: - { - copyScriptString(string, sizeof(string)); - int slot = pop(); - - int len = resStrLen(string) + 1; - memcpy(a->_heTalkQueue[slot].sentence, string, len); - - a->_heTalkQueue[slot].posX = a->_talkPosX; - a->_heTalkQueue[slot].posY = a->_talkPosY; - a->_heTalkQueue[slot].color = a->_talkColor; - break; - } - default: - error("o72_actorOps: default case %d", subOp); - } -} - -void ScummEngine_v72he::o72_verbOps() { - int slot, a, b; - VerbSlot *vs; - byte name[200]; - - byte subOp = fetchScriptByte(); - if (subOp == 196) { - _curVerb = pop(); - _curVerbSlot = getVerbSlot(_curVerb, 0); - checkRange(_numVerbs - 1, 0, _curVerbSlot, "Illegal new verb slot %d"); - return; - } - vs = &_verbs[_curVerbSlot]; - slot = _curVerbSlot; - switch (subOp) { - case 124: // SO_VERB_IMAGE - a = pop(); - if (_curVerbSlot) { - setVerbObject(_roomResource, a, slot); - vs->type = kImageVerbType; - vs->imgindex = a; - } - break; - case 125: // SO_VERB_NAME - copyScriptString(name, sizeof(name)); - loadPtrToResource(rtVerb, slot, name); - vs->type = kTextVerbType; - vs->imgindex = 0; - break; - case 126: // SO_VERB_COLOR - vs->color = pop(); - break; - case 127: // SO_VERB_HICOLOR - vs->hicolor = pop(); - break; - case 128: // SO_VERB_AT - vs->curRect.top = pop(); - vs->curRect.left = pop(); - break; - case 129: // SO_VERB_ON - vs->curmode = 1; - break; - case 130: // SO_VERB_OFF - vs->curmode = 0; - break; - case 131: // SO_VERB_DELETE - slot = getVerbSlot(pop(), 0); - killVerb(slot); - break; - case 132: // SO_VERB_NEW - slot = getVerbSlot(_curVerb, 0); - if (slot == 0) { - for (slot = 1; slot < _numVerbs; slot++) { - if (_verbs[slot].verbid == 0) - break; - } - if (slot == _numVerbs) - error("Too many verbs"); - _curVerbSlot = slot; - } - vs = &_verbs[slot]; - vs->verbid = _curVerb; - vs->color = 2; - vs->hicolor = 0; - vs->dimcolor = 8; - vs->type = kTextVerbType; - vs->charset_nr = _string[0]._default.charset; - vs->curmode = 0; - vs->saveid = 0; - vs->key = 0; - vs->center = 0; - vs->imgindex = 0; - break; - case 133: // SO_VERB_DIMCOLOR - vs->dimcolor = pop(); - break; - case 134: // SO_VERB_DIM - vs->curmode = 2; - break; - case 135: // SO_VERB_KEY - vs->key = pop(); - break; - case 136: // SO_VERB_CENTER - vs->center = 1; - break; - case 137: // SO_VERB_NAME_STR - a = pop(); - if (a == 0) { - loadPtrToResource(rtVerb, slot, (const byte *)""); - } else { - loadPtrToResource(rtVerb, slot, getStringAddress(a)); - } - vs->type = kTextVerbType; - vs->imgindex = 0; - break; - case 139: // SO_VERB_IMAGE_IN_ROOM - b = pop(); - a = pop(); - - if (slot && a != vs->imgindex) { - setVerbObject(b, a, slot); - vs->type = kImageVerbType; - vs->imgindex = a; - } - break; - case 140: // SO_VERB_BAKCOLOR - vs->bkcolor = pop(); - break; - case 255: - drawVerb(slot, 0); - verbMouseOver(0); - break; - default: - error("o72_verbops: default case %d", subOp); - } -} - -void ScummEngine_v72he::o72_findObject() { - int y = pop(); - int x = pop(); - int r = findObject(x, y, 0, 0); - push(r); -} - -void ScummEngine_v72he::o72_arrayOps() { - ArrayHeader *ah; - byte string[1024]; - int dim1end, dim1start, dim2end, dim2start; - int id, len, b, c, list[128]; - int offs, tmp, tmp2; - uint tmp3; - - byte subOp = fetchScriptByte(); - int array = fetchScriptWord(); - debug(9,"o72_arrayOps: array %d case %d", array, subOp); - - switch (subOp) { - case 7: // SO_ASSIGN_STRING - copyScriptString(string, sizeof(string)); - len = resStrLen(string); - ah = defineArray(array, kStringArray, 0, 0, 0, len); - memcpy(ah->data, string, len); - break; - - case 126: - len = getStackList(list, ARRAYSIZE(list)); - dim1end = pop(); - dim1start = pop(); - dim2end = pop(); - dim2start = pop(); - id = readVar(array); - if (id == 0) { - defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end); - } - tmp2 = 0; - while (dim2start <= dim2end) { - tmp = dim1start; - while (tmp <= dim1end) { - writeArray(array, dim2start, tmp, list[tmp2++]); - if (tmp2 == len) - tmp2 = 0; - tmp++; - } - dim2start++; - } - break; - case 127: - { - int a2_dim1end = pop(); - int a2_dim1start = pop(); - int a2_dim2end = pop(); - int a2_dim2start = pop(); - int array2 = fetchScriptWord(); - int a1_dim1end = pop(); - int a1_dim1start = pop(); - int a1_dim2end = pop(); - int a1_dim2start = pop(); - if (a1_dim1end - a1_dim1start != a2_dim1end - a2_dim1start || a2_dim2end - a2_dim2start != a1_dim2end - a1_dim2start) { - error("Source and dest ranges size are mismatched"); - } - copyArray(array, a1_dim2start, a1_dim2end, a1_dim1start, a1_dim1end, array2, a2_dim2start, a2_dim2end, a2_dim1start, a2_dim1end); - } - break; - case 128: - b = pop(); - c = pop(); - dim1end = pop(); - dim1start = pop(); - dim2end = pop(); - dim2start = pop(); - id = readVar(array); - if (id == 0) { - defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end); - } - - offs = (b >= c) ? 1 : -1; - tmp2 = c; - tmp3 = c - b + 1; - while (dim2start <= dim2end) { - tmp = dim1start; - while (tmp <= dim1end) { - writeArray(array, dim2start, tmp, tmp2); - if (--tmp3 == 0) { - tmp2 = c; - tmp3 = c - b + 1; - } else { - tmp2 += offs; - } - tmp++; - } - dim2start++; - } - break; - case 194: - decodeScriptString(string); - len = resStrLen(string); - ah = defineArray(array, kStringArray, 0, 0, 0, len); - memcpy(ah->data, string, len); - break; - case 208: // SO_ASSIGN_INT_LIST - b = pop(); - c = pop(); - id = readVar(array); - if (id == 0) { - defineArray(array, kDwordArray, 0, 0, 0, b + c - 1); - } - while (c--) { - writeArray(array, 0, b + c, pop()); - } - break; - case 212: // SO_ASSIGN_2DIM_LIST - len = getStackList(list, ARRAYSIZE(list)); - id = readVar(array); - if (id == 0) - error("Must DIM a two dimensional array before assigning"); - c = pop(); - while (--len >= 0) { - writeArray(array, c, len, list[len]); - } - break; - default: - error("o72_arrayOps: default case %d (array %d)", subOp, array); - } -} - -void ScummEngine_v72he::o72_systemOps() { - byte string[1024]; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 22: // HE80+ - clearDrawObjectQueue(); - break; - case 26: // HE80+ - gdi.copyVirtScreenBuffers(Common::Rect(_screenWidth, _screenHeight)); - updatePalette(); - break; - case 158: - restart(); - break; - case 160: - // Confirm shutdown - shutDown(); - break; - case 244: - shutDown(); - break; - case 251: - copyScriptString(string, sizeof(string)); - debug(0, "Start executable (%s)", string); - break; - case 252: - copyScriptString(string, sizeof(string)); - debug(0, "Start game (%s)", string); - break; - default: - error("o72_systemOps invalid case %d", subOp); - } -} - -void ScummEngine_v72he::o72_talkActor() { - Actor *a; - - int act = pop(); - - _string[0].loadDefault(); - - // A value of 225 can occur when examining the gold in the mine of pajama, after mining the gold. - // This is a script bug, the script should set the subtitle color, not actor number. - // This script bug was fixed in the updated version of pajama. - if (act == 225) { - _string[0].color = act; - } else { - _actorToPrintStrFor = act; - if (_actorToPrintStrFor != 0xFF) { - a = derefActor(_actorToPrintStrFor, "o72_talkActor"); - _string[0].color = a->_talkColor; - } - } - - actorTalk(_scriptPointer); - - _scriptPointer += resStrLen(_scriptPointer) + 1; -} - -void ScummEngine_v72he::o72_talkEgo() { - push(VAR(VAR_EGO)); - o72_talkActor(); -} - -void ScummEngine_v72he::o72_dimArray() { - int data; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 2: // SO_BIT_ARRAY - data = kBitArray; - break; - case 3: // SO_NIBBLE_ARRAY - data = kNibbleArray; - break; - case 4: // SO_BYTE_ARRAY - data = kByteArray; - break; - case 5: // SO_INT_ARRAY - data = kIntArray; - break; - case 6: - data = kDwordArray; - break; - case 7: // SO_STRING_ARRAY - data = kStringArray; - break; - case 204: // SO_UNDIM_ARRAY - nukeArray(fetchScriptWord()); - return; - default: - error("o72_dimArray: default case %d", subOp); - } - - defineArray(fetchScriptWord(), data, 0, 0, 0, pop()); -} - - -void ScummEngine_v72he::o72_dim2dimArray() { - int data, dim1end, dim2end; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 2: // SO_BIT_ARRAY - data = kBitArray; - break; - case 3: // SO_NIBBLE_ARRAY - data = kNibbleArray; - break; - case 4: // SO_BYTE_ARRAY - data = kByteArray; - break; - case 5: // SO_INT_ARRAY - data = kIntArray; - break; - case 6: - data = kDwordArray; - break; - case 7: // SO_STRING_ARRAY - data = kStringArray; - break; - default: - error("o72_dim2dimArray: default case %d", subOp); - } - - dim1end = pop(); - dim2end = pop(); - defineArray(fetchScriptWord(), data, 0, dim2end, 0, dim1end); -} - -void ScummEngine_v72he::o72_traceStatus() { - byte string[80]; - - copyScriptString(string, sizeof(string)); - pop(); -} - -void ScummEngine_v72he::o72_kernelGetFunctions() { - int args[29]; - ArrayHeader *ah; - getStackList(args, ARRAYSIZE(args)); - - switch (args[0]) { - case 1: - writeVar(0, 0); - ah = defineArray(0, kByteArray, 0, 0, 0, virtScreenSave(0, args[1], args[2], args[3], args[4])); - virtScreenSave(ah->data, args[1], args[2], args[3], args[4]); - push(readVar(0)); - break; - default: - error("o72_kernelGetFunctions: default case %d", args[0]); - } -} - -void ScummEngine_v72he::o72_drawWizImage() { - WizImage wi; - wi.flags = pop(); - wi.y1 = pop(); - wi.x1 = pop(); - wi.resNum = pop(); - wi.state = 0; - _wiz->displayWizImage(&wi); -} - -void ScummEngine_v72he::o72_debugInput() { - byte string[255]; - - copyScriptString(string, sizeof(string)); - int len = resStrLen(string) + 1; - - writeVar(0, 0); - ArrayHeader *ah = defineArray(0, kStringArray, 0, 0, 0, len); - memcpy(ah->data, string, len); - push(readVar(0)); - debug(1,"o72_debugInput: String %s", string); -} - -void ScummEngine_v72he::o72_jumpToScript() { - int args[25]; - int script; - byte flags; - - getStackList(args, ARRAYSIZE(args)); - script = pop(); - flags = fetchScriptByte(); - stopObjectCode(); - runScript(script, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args); -} - -void ScummEngine_v72he::o72_openFile() { - int mode, slot, i; - byte filename[256]; - - mode = pop(); - copyScriptString(filename, sizeof(filename)); - - debug(1,"Original filename %s", filename); - - // There are Macintosh specific versions of HE7.2 games. - if (_heversion >= 80 && _platform == Common::kPlatformMacintosh) { - // Work around for filename difference in HE7 file, needs to - // open 'Water (7)' instead of 'Water Worries (7)'. - if (_gameId == GID_WATER && _heversion == 99 && !strcmp((char *)filename, "Water.he7")) { - strcpy((char *)filename, "Water (7)"); - } else { - char buf1[128]; - buf1[0] = '\0'; - generateSubstResFileName((char *)filename, buf1, sizeof(buf1)); - if (buf1[0]) { - strcpy((char *)filename, buf1); - } - } - } - - int r = convertFilePath(filename); - debug(1,"Final filename to %s", filename + r); - - slot = -1; - for (i = 1; i < 17; i++) { - if (_hFileTable[i].isOpen() == false) { - slot = i; - break; - } - } - - if (slot != -1) { - switch(mode) { - case 1: - _hFileTable[slot].open((char*)filename + r, Common::File::kFileReadMode, _saveFileMan->getSavePath()); - if (_hFileTable[slot].isOpen() == false) - _hFileTable[slot].open((char*)filename + r, Common::File::kFileReadMode, _gameDataPath.c_str()); - break; - case 2: - _hFileTable[slot].open((char*)filename + r, Common::File::kFileWriteMode, _saveFileMan->getSavePath()); - break; - default: - error("o72_openFile(): wrong open file mode %d", mode); - } - - if (_hFileTable[slot].isOpen() == false) - slot = -1; - - } - debug(1, "o72_openFile: slot %d, mode %d", slot, mode); - push(slot); -} - -int ScummEngine_v72he::readFileToArray(int slot, int32 size) { - if (size == 0) - size = _hFileTable[slot].size() - _hFileTable[slot].pos(); - - writeVar(0, 0); - ArrayHeader *ah = defineArray(0, kByteArray, 0, 0, 0, size); - - if (_hFileTable[slot].isOpen()) - _hFileTable[slot].read(ah->data, size + 1); - - return readVar(0); -} - -void ScummEngine_v72he::o72_readFile() { - int slot, val; - int32 size; - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 4: - slot = pop(); - val = _hFileTable[slot].readByte(); - push(val); - break; - case 5: - slot = pop(); - val = _hFileTable[slot].readUint16LE(); - push(val); - break; - case 6: - slot = pop(); - val = _hFileTable[slot].readUint32LE(); - push(val); - break; - case 8: - fetchScriptByte(); - size = pop(); - slot = pop(); - val = readFileToArray(slot, size); - push(val); - break; - default: - error("o72_readFile: default case %d", subOp); - } -} - -void ScummEngine_v72he::writeFileFromArray(int slot, int32 resID) { - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resID); - int32 size = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) * - (FROM_LE_32(ah->dim2end) - FROM_LE_32(ah->dim2start) + 1); - - _hFileTable[slot].write(ah->data, size); -} - -void ScummEngine_v72he::o72_writeFile() { - int32 resID = pop(); - int slot = pop(); - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 4: - _hFileTable[slot].writeByte(resID); - break; - case 5: - _hFileTable[slot].writeUint16LE(resID); - break; - case 6: - _hFileTable[slot].writeUint32LE(resID); - break; - case 8: - fetchScriptByte(); - writeFileFromArray(slot, resID); - break; - default: - error("o72_writeFile: default case %d", subOp); - } -} - -void ScummEngine_v72he::o72_findAllObjects() { - int room = pop(); - int i; - - if (room != _currentRoom) - error("o72_findAllObjects: current room is not %d", room); - - writeVar(0, 0); - defineArray(0, kDwordArray, 0, 0, 0, _numLocalObjects); - writeArray(0, 0, 0, _numLocalObjects); - - for (i = 1; i < _numLocalObjects; i++) { - writeArray(0, 0, i, _objs[i].obj_nr); - } - - push(readVar(0)); -} - -void ScummEngine_v72he::o72_deleteFile() { - byte filename[256]; - - copyScriptString(filename, sizeof(filename)); - debug(1, "stub o72_deleteFile(%s)", filename); -} - -void ScummEngine_v72he::o72_rename() { - byte oldFilename[100],newFilename[100]; - - copyScriptString(newFilename, sizeof(newFilename)); - copyScriptString(oldFilename, sizeof(oldFilename)); - - debug(1, "stub o72_rename(%s to %s)", oldFilename, newFilename); -} - -void ScummEngine_v72he::o72_getPixel() { - byte area; - - int y = pop(); - int x = pop(); - byte subOp = fetchScriptByte(); - - VirtScreen *vs = findVirtScreen(y); - if (vs == NULL || x > _screenWidth - 1 || x < 0) { - push(-1); - return; - } - - switch (subOp) { - case 9: // HE 100 - case 218: - area = *vs->getBackPixels(x, y - vs->topline); - break; - case 8: // HE 100 - case 219: - area = *vs->getPixels(x, y - vs->topline); - break; - default: - error("o72_getPixel: default case %d", subOp); - } - push(area); -} - -void ScummEngine_v72he::o72_pickVarRandom() { - int num; - int args[100]; - int32 dim1end; - - num = getStackList(args, ARRAYSIZE(args)); - int value = fetchScriptWord(); - - if (readVar(value) == 0) { - defineArray(value, kDwordArray, 0, 0, 0, num); - if (num > 0) { - int16 counter = 0; - do { - writeArray(value, 0, counter + 1, args[counter]); - } while (++counter < num); - } - - shuffleArray(value, 1, num); - writeArray(value, 0, 0, 2); - push(readArray(value, 0, 1)); - return; - } - - num = readArray(value, 0, 0); - - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(value)); - dim1end = FROM_LE_32(ah->dim1end); - - if (dim1end < num) { - int32 var_2 = readArray(value, 0, num - 1); - shuffleArray(value, 1, dim1end); - if (readArray(value, 0, 1) == var_2) { - num = 2; - } else { - num = 1; - } - } - - writeArray(value, 0, 0, num + 1); - push(readArray(value, 0, num)); -} - -void ScummEngine_v72he::o72_redimArray() { - int newX, newY; - newY = pop(); - newX = pop(); - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 5: - redimArray(fetchScriptWord(), 0, newX, 0, newY, kIntArray); - break; - case 4: - redimArray(fetchScriptWord(), 0, newX, 0, newY, kByteArray); - break; - case 6: - redimArray(fetchScriptWord(), 0, newX, 0, newY, kDwordArray); - break; - default: - error("o72_redimArray: default type %d", subOp); - } -} - -void ScummEngine_v72he::redimArray(int arrayId, int newDim2start, int newDim2end, - int newDim1start, int newDim1end, int type) { - int newSize, oldSize; - - if (readVar(arrayId) == 0) - error("redimArray: Reference to zeroed array pointer"); - - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(arrayId)); - - if (!ah) - error("redimArray: Invalid array (%d) reference", readVar(arrayId)); - - newSize = arrayDataSizes[type]; - oldSize = arrayDataSizes[FROM_LE_32(ah->type)]; - - newSize *= (newDim1end - newDim1start + 1) * (newDim2end - newDim2start + 1); - oldSize *= (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) * - (FROM_LE_32(ah->dim2end) - FROM_LE_32(ah->dim2start) + 1); - - newSize >>= 3; - oldSize >>= 3; - - if (newSize != oldSize) - error("redimArray: array %d redim mismatch", readVar(arrayId)); - - ah->type = TO_LE_32(type); - ah->dim1start = TO_LE_32(newDim1start); - ah->dim1end = TO_LE_32(newDim1end); - ah->dim2start = TO_LE_32(newDim2start); - ah->dim2end = TO_LE_32(newDim2end); -} - -void ScummEngine_v72he::checkArrayLimits(int array, int dim2start, int dim2end, int dim1start, int dim1end) { - if (dim1end < dim1start) { - error("Across max %d smaller than min %d", dim1end, dim1start); - } - if (dim2end < dim2start) { - error("Down max %d smaller than min %d", dim2end, dim2start); - } - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array)); - assert(ah); - if (ah->dim2start > dim2start || ah->dim2end < dim2end || ah->dim1start > dim1start || ah->dim1end < dim1end) { - error("Invalid array access (%d,%d,%d,%d) limit (%d,%d,%d,%d)", dim2start, dim2end, dim1start, dim1end, ah->dim2start, ah->dim2end, ah->dim1start, ah->dim1end); - } -} - -void ScummEngine_v72he::copyArray(int array1, int a1_dim2start, int a1_dim2end, int a1_dim1start, int a1_dim1end, - int array2, int a2_dim2start, int a2_dim2end, int a2_dim1start, int a2_dim1end) -{ - byte *dst, *src; - int dstPitch, srcPitch; - int rowSize; - checkArrayLimits(array1, a1_dim2start, a1_dim2end, a1_dim1start, a1_dim1end); - checkArrayLimits(array2, a2_dim2start, a2_dim2end, a2_dim1start, a2_dim1end); - int a12_num = a1_dim2end - a1_dim2start + 1; - int a11_num = a1_dim1end - a1_dim1start + 1; - int a22_num = a2_dim2end - a2_dim2start + 1; - int a21_num = a2_dim1end - a2_dim1start + 1; - if (a22_num != a12_num || a21_num != a11_num) { - error("Operation size mismatch (%d vs %d)(%d vs %d)", a12_num, a22_num, a11_num, a21_num); - } - - if (array1 != array2) { - ArrayHeader *ah1 = (ArrayHeader *)getResourceAddress(rtString, readVar(array1)); - assert(ah1); - ArrayHeader *ah2 = (ArrayHeader *)getResourceAddress(rtString, readVar(array2)); - assert(ah2); - if (FROM_LE_32(ah1->type) == FROM_LE_32(ah2->type)) { - copyArrayHelper(ah1, a1_dim2start, a1_dim1start, a1_dim1end, &dst, &dstPitch, &rowSize); - copyArrayHelper(ah2, a2_dim2start, a2_dim1start, a2_dim1end, &src, &srcPitch, &rowSize); - for (; a1_dim2start <= a1_dim2end; ++a1_dim2start) { - memcpy(dst, src, rowSize); - dst += dstPitch; - src += srcPitch; - } - } else { - for (; a1_dim2start <= a1_dim2end; ++a1_dim2start, ++a2_dim2start) { - int a2dim1 = a2_dim1start; - int a1dim1 = a1_dim1start; - for (; a1dim1 <= a1_dim1end; ++a1dim1, ++a2dim1) { - int val = readArray(array2, a2_dim2start, a2dim1); - writeArray(array1, a1_dim2start, a1dim1, val); - } - } - } - } else { - if (a2_dim2start != a1_dim2start || a2_dim1start != a1_dim1start) { - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array1)); - assert(ah); - if (a2_dim2start > a1_dim2start) { - copyArrayHelper(ah, a1_dim2start, a1_dim1start, a1_dim1end, &dst, &dstPitch, &rowSize); - copyArrayHelper(ah, a2_dim2start, a2_dim1start, a2_dim1end, &src, &srcPitch, &rowSize); - } else { - copyArrayHelper(ah, a1_dim2end, a1_dim1start, a1_dim1end, &dst, &dstPitch, &rowSize); - copyArrayHelper(ah, a2_dim2end, a2_dim1start, a2_dim1end, &src, &srcPitch, &rowSize); - } - for (; a1_dim2start <= a1_dim2end; ++a1_dim2start) { - memcpy(dst, src, rowSize); - dst += dstPitch; - src += srcPitch; - } - } - } -} - -void ScummEngine_v72he::copyArrayHelper(ArrayHeader *ah, int idx2, int idx1, int len1, byte **data, int *size, int *num) { - const int pitch = FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1; - const int offset = pitch * (idx2 - FROM_LE_32(ah->dim2start)) + idx1 - FROM_LE_32(ah->dim1start); - - switch (FROM_LE_32(ah->type)) { - case kByteArray: - case kStringArray: - *num = len1 - idx1 + 1; - *size = pitch; - *data = ah->data + offset; - break; - case kIntArray: - *num = (len1 - idx1) * 2 + 2; - *size = pitch * 2; - *data = ah->data + offset * 2; - break; - case kDwordArray: - *num = (len1 - idx1) * 4 + 4; - *size = pitch * 4; - *data = ah->data + offset * 4; - break; - default: - error("Invalid array type", FROM_LE_32(ah->type)); - } -} - -void ScummEngine_v72he::o72_readINI() { - byte option[128]; - ArrayHeader *ah; - const char *entry; - int len; - - copyScriptString(option, sizeof(option)); - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 43: // HE 100 - case 6: // number - if (!strcmp((char *)option, "NoPrinting")) { - push(1); - } else if (!strcmp((char *)option, "TextOn")) { - push(ConfMan.getBool("subtitles")); - } else { - push(ConfMan.getInt((char *)option)); - } - break; - case 77: // HE 100 - case 7: // string - entry = (ConfMan.get((char *)option).c_str()); - - writeVar(0, 0); - len = resStrLen((const byte *)entry); - ah = defineArray(0, kStringArray, 0, 0, 0, len); - memcpy(ah->data, entry, len); - - push(readVar(0)); - break; - default: - error("o72_readINI: default type %d", subOp); - } - - debug(1, "o72_readINI: Option %s", option); -} - -void ScummEngine_v72he::o72_writeINI() { - int value; - byte option[256], string[1024]; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 43: // HE 100 - case 6: // number - value = pop(); - copyScriptString(option, sizeof(option)); - ConfMan.set((char *)option, value); - debug(1, "o72_writeINI: Option %s Value %d", option, value); - break; - case 77: // HE 100 - case 7: // string - copyScriptString(string, sizeof(string)); - copyScriptString(option, sizeof(option)); - - // Filter out useless setting - if (!strcmp((char *)option, "HETest")) - return; - - // Filter out confusing subtitle setting - if (!strcmp((char *)option, "TextOn")) - return; - - // Filter out confusing path settings - if (!strcmp((char *)option, "DownLoadPath") || !strcmp((char *)option, "GameResourcePath") || !strcmp((char *)option, "SaveGamePath")) - return; - - ConfMan.set((char *)option, (char *)string); - debug(1, "o72_writeINI: Option %s String %s", option, string); - break; - default: - error("o72_writeINI: default type %d", subOp); - } - - ConfMan.flushToDisk(); -} - -void ScummEngine_v72he::o72_getResourceSize() { - const byte *ptr; - int size, type; - - int resid = pop(); - if (_heversion == 72) { - push(getSoundResourceSize(resid)); - return; - } - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 13: - push (getSoundResourceSize(resid)); - return; - case 14: - type = rtRoomImage; - break; - case 15: - type = rtImage; - break; - case 16: - type = rtCostume; - break; - case 17: - type = rtScript; - break; - default: - error("o72_getResourceSize: default type %d", subOp); - } - - ptr = getResourceAddress(type, resid); - assert(ptr); - size = READ_BE_UINT32(ptr + 4) - 8; - push(size); -} - -void ScummEngine_v72he::o72_setFilePath() { - byte filename[255]; - - copyScriptString(filename, sizeof(filename)); - debug(1,"o72_setFilePath: %s", filename); -} - -void ScummEngine_v72he::o72_setSystemMessage() { - byte name[1024]; - - copyScriptString(name, sizeof(name)); - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 240: - debug(1,"o72_setSystemMessage: (%d) %s", subOp, name); - break; - case 241: // Set Version - debug(1,"o72_setSystemMessage: (%d) %s", subOp, name); - break; - case 242: - debug(1,"o72_setSystemMessage: (%d) %s", subOp, name); - break; - case 243: // Set Window Caption - _system->setWindowCaption((const char *)name); - break; - default: - error("o72_setSystemMessage: default case %d", subOp); - } -} - -void ScummEngine_v72he::decodeParseString(int m, int n) { - Actor *a; - int i, colors, size; - int args[31]; - byte name[1024]; - - byte b = fetchScriptByte(); - - switch (b) { - case 65: // SO_AT - _string[m].ypos = pop(); - _string[m].xpos = pop(); - _string[m].overhead = false; - break; - case 66: // SO_COLOR - _string[m].color = pop(); - break; - case 67: // SO_CLIPPED - _string[m].right = pop(); - break; - case 69: // SO_CENTER - _string[m].center = true; - _string[m].overhead = false; - break; - case 71: // SO_LEFT - _string[m].center = false; - _string[m].overhead = false; - break; - case 72: // SO_OVERHEAD - _string[m].overhead = true; - _string[m].no_talk_anim = false; - break; - case 73: // SO_SAY_VOICE - error("decodeParseString: case 73"); - break; - case 74: // SO_MUMBLE - _string[m].no_talk_anim = true; - break; - case 75: // SO_TEXTSTRING - printString(m, _scriptPointer); - _scriptPointer += resStrLen(_scriptPointer) + 1; - break; - case 194: - decodeScriptString(name, true); - printString(m, name); - break; - case 0xE1: - { - byte *dataPtr = getResourceAddress(rtTalkie, pop()); - byte *text = findWrappedBlock(MKID('TEXT'), dataPtr, 0, 0); - size = getResourceDataSize(text); - memcpy(name, text, size); - printString(m, name); - } - break; - case 0xF9: - colors = pop(); - if (colors == 1) { - _string[m].color = pop(); - } else { - push(colors); - getStackList(args, ARRAYSIZE(args)); - for (i = 0; i < 16; i++) - _charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i]; - _string[m].color = _charsetColorMap[0]; - } - break; - case 0xFE: - _string[m].loadDefault(); - if (n) { - _actorToPrintStrFor = pop(); - if (_actorToPrintStrFor != 0xFF) { - a = derefActor(_actorToPrintStrFor, "decodeParseString"); - _string[0].color = a->_talkColor; - } - } - break; - case 0xFF: - _string[m].saveDefault(); - break; - default: - error("decodeParseString: default case 0x%x", b); - } -} - -} // End of namespace Scumm diff --git a/engines/scumm/script_v7he.cpp b/engines/scumm/script_v7he.cpp deleted file mode 100644 index bae2654dae..0000000000 --- a/engines/scumm/script_v7he.cpp +++ /dev/null @@ -1,1153 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" - -#include "common/config-manager.h" -#include "common/system.h" - -#include "scumm/actor.h" -#include "scumm/charset.h" -#include "scumm/intern_he.h" -#include "scumm/object.h" -#include "scumm/resource.h" -#include "scumm/resource_v7he.h" -#include "scumm/scumm.h" -#include "scumm/sound.h" -#include "scumm/verbs.h" - -namespace Scumm { - -#define OPCODE(x) _OPCODE(ScummEngine_v70he, x) - -void ScummEngine_v70he::setupOpcodes() { - static const OpcodeEntryv70he opcodes[256] = { - /* 00 */ - OPCODE(o6_pushByte), - OPCODE(o6_pushWord), - OPCODE(o6_pushByteVar), - OPCODE(o6_pushWordVar), - /* 04 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayRead), - OPCODE(o6_wordArrayRead), - /* 08 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayIndexedRead), - OPCODE(o6_wordArrayIndexedRead), - /* 0C */ - OPCODE(o6_dup), - OPCODE(o6_not), - OPCODE(o6_eq), - OPCODE(o6_neq), - /* 10 */ - OPCODE(o6_gt), - OPCODE(o6_lt), - OPCODE(o6_le), - OPCODE(o6_ge), - /* 14 */ - OPCODE(o6_add), - OPCODE(o6_sub), - OPCODE(o6_mul), - OPCODE(o6_div), - /* 18 */ - OPCODE(o6_land), - OPCODE(o6_lor), - OPCODE(o6_pop), - OPCODE(o6_invalid), - /* 1C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 20 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 24 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 28 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 2C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 30 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 34 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 38 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 3C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 40 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_writeByteVar), - OPCODE(o6_writeWordVar), - /* 44 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayWrite), - OPCODE(o6_wordArrayWrite), - /* 48 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayIndexedWrite), - OPCODE(o6_wordArrayIndexedWrite), - /* 4C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteVarInc), - OPCODE(o6_wordVarInc), - /* 50 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayInc), - OPCODE(o6_wordArrayInc), - /* 54 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteVarDec), - OPCODE(o6_wordVarDec), - /* 58 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_byteArrayDec), - OPCODE(o6_wordArrayDec), - /* 5C */ - OPCODE(o6_if), - OPCODE(o6_ifNot), - OPCODE(o6_startScript), - OPCODE(o6_startScriptQuick), - /* 60 */ - OPCODE(o6_startObject), - OPCODE(o6_drawObject), - OPCODE(o6_drawObjectAt), - OPCODE(o6_invalid), - /* 64 */ - OPCODE(o6_invalid), - OPCODE(o6_stopObjectCode), - OPCODE(o6_stopObjectCode), - OPCODE(o6_endCutscene), - /* 68 */ - OPCODE(o6_cutscene), - OPCODE(o6_stopMusic), - OPCODE(o6_freezeUnfreeze), - OPCODE(o6_cursorCommand), - /* 6C */ - OPCODE(o6_breakHere), - OPCODE(o6_ifClassOfIs), - OPCODE(o6_setClass), - OPCODE(o6_getState), - /* 70 */ - OPCODE(o60_setState), - OPCODE(o6_setOwner), - OPCODE(o6_getOwner), - OPCODE(o6_jump), - /* 74 */ - OPCODE(o70_startSound), - OPCODE(o6_stopSound), - OPCODE(o6_startMusic), - OPCODE(o6_stopObjectScript), - /* 78 */ - OPCODE(o6_panCameraTo), - OPCODE(o6_actorFollowCamera), - OPCODE(o6_setCameraAt), - OPCODE(o6_loadRoom), - /* 7C */ - OPCODE(o6_stopScript), - OPCODE(o6_walkActorToObj), - OPCODE(o6_walkActorTo), - OPCODE(o6_putActorAtXY), - /* 80 */ - OPCODE(o6_putActorAtObject), - OPCODE(o6_faceActor), - OPCODE(o6_animateActor), - OPCODE(o6_doSentence), - /* 84 */ - OPCODE(o70_pickupObject), - OPCODE(o6_loadRoomWithEgo), - OPCODE(o6_invalid), - OPCODE(o6_getRandomNumber), - /* 88 */ - OPCODE(o6_getRandomNumberRange), - OPCODE(o6_invalid), - OPCODE(o6_getActorMoving), - OPCODE(o6_isScriptRunning), - /* 8C */ - OPCODE(o70_getActorRoom), - OPCODE(o6_getObjectX), - OPCODE(o6_getObjectY), - OPCODE(o6_getObjectOldDir), - /* 90 */ - OPCODE(o6_getActorWalkBox), - OPCODE(o6_getActorCostume), - OPCODE(o6_findInventory), - OPCODE(o6_getInventoryCount), - /* 94 */ - OPCODE(o6_getVerbFromXY), - OPCODE(o6_beginOverride), - OPCODE(o6_endOverride), - OPCODE(o6_setObjectName), - /* 98 */ - OPCODE(o6_isSoundRunning), - OPCODE(o6_setBoxFlags), - OPCODE(o6_invalid), - OPCODE(o70_resourceRoutines), - /* 9C */ - OPCODE(o60_roomOps), - OPCODE(o60_actorOps), - OPCODE(o6_verbOps), - OPCODE(o6_getActorFromXY), - /* A0 */ - OPCODE(o6_findObject), - OPCODE(o6_pseudoRoom), - OPCODE(o6_getActorElevation), - OPCODE(o6_getVerbEntrypoint), - /* A4 */ - OPCODE(o6_arrayOps), - OPCODE(o6_saveRestoreVerbs), - OPCODE(o6_drawBox), - OPCODE(o6_pop), - /* A8 */ - OPCODE(o6_getActorWidth), - OPCODE(o6_wait), - OPCODE(o6_getActorScaleX), - OPCODE(o6_getActorAnimCounter1), - /* AC */ - OPCODE(o6_invalid), - OPCODE(o6_isAnyOf), - OPCODE(o70_systemOps), - OPCODE(o6_isActorInBox), - /* B0 */ - OPCODE(o6_delay), - OPCODE(o6_delaySeconds), - OPCODE(o6_delayMinutes), - OPCODE(o6_stopSentence), - /* B4 */ - OPCODE(o6_printLine), - OPCODE(o6_printText), - OPCODE(o6_printDebug), - OPCODE(o6_printSystem), - /* B8 */ - OPCODE(o6_printActor), - OPCODE(o6_printEgo), - OPCODE(o6_talkActor), - OPCODE(o6_talkEgo), - /* BC */ - OPCODE(o6_dimArray), - OPCODE(o6_stopObjectCode), - OPCODE(o6_startObjectQuick), - OPCODE(o6_startScriptQuick2), - /* C0 */ - OPCODE(o6_dim2dimArray), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* C4 */ - OPCODE(o6_abs), - OPCODE(o6_distObjectObject), - OPCODE(o6_distObjectPt), - OPCODE(o6_distPtPt), - /* C8 */ - OPCODE(o60_kernelGetFunctions), - OPCODE(o70_kernelSetFunctions), - OPCODE(o6_delayFrames), - OPCODE(o6_pickOneOf), - /* CC */ - OPCODE(o6_pickOneOfDefault), - OPCODE(o6_stampObject), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* D0 */ - OPCODE(o6_getDateTime), - OPCODE(o6_stopTalking), - OPCODE(o6_getAnimateVariable), - OPCODE(o6_invalid), - /* D4 */ - OPCODE(o6_shuffle), - OPCODE(o6_jumpToScript), - OPCODE(o6_band), - OPCODE(o6_bor), - /* D8 */ - OPCODE(o6_isRoomScriptRunning), - OPCODE(o60_closeFile), - OPCODE(o60_openFile), - OPCODE(o60_readFile), - /* DC */ - OPCODE(o60_writeFile), - OPCODE(o6_findAllObjects), - OPCODE(o60_deleteFile), - OPCODE(o60_rename), - /* E0 */ - OPCODE(o60_soundOps), - OPCODE(o6_getPixel), - OPCODE(o60_localizeArrayToScript), - OPCODE(o6_pickVarRandom), - /* E4 */ - OPCODE(o6_setBoxSet), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* E8 */ - OPCODE(o6_invalid), - OPCODE(o70_seekFilePos), - OPCODE(o60_redimArray), - OPCODE(o60_readFilePos), - /* EC */ - OPCODE(o70_copyString), - OPCODE(o70_getStringWidth), - OPCODE(o70_getStringLen), - OPCODE(o70_appendString), - /* F0 */ - OPCODE(o70_concatString), - OPCODE(o70_compareString), - OPCODE(o70_isResourceLoaded), - OPCODE(o70_readINI), - /* F4 */ - OPCODE(o70_writeINI), - OPCODE(o70_getStringLenForWidth), - OPCODE(o70_getCharIndexInString), - OPCODE(o6_invalid), - /* F8 */ - OPCODE(o6_invalid), - OPCODE(o70_setFilePath), - OPCODE(o70_setSystemMessage), - OPCODE(o70_polygonOps), - /* FC */ - OPCODE(o70_polygonHit), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - }; - - _opcodesv70he = opcodes; -} - -void ScummEngine_v70he::executeOpcode(byte i) { - OpcodeProcv70he op = _opcodesv70he[i].proc; - (this->*op) (); -} - -const char *ScummEngine_v70he::getOpcodeDesc(byte i) { - return _opcodesv70he[i].desc; -} - -int ScummEngine_v70he::getStringCharWidth(byte chr) { - int charset = _string[0]._default.charset; - - byte *ptr = getResourceAddress(rtCharset, charset); - assert(ptr); - ptr += 29; - - int spacing = 0; - - int offs = READ_LE_UINT32(ptr + chr * 4 + 4); - if (offs) { - spacing = ptr[offs] + (signed char)ptr[offs + 2]; - } - - return spacing; -} - -int ScummEngine_v70he::setupStringArray(int size) { - writeVar(0, 0); - defineArray(0, kStringArray, 0, size + 1); - writeArray(0, 0, 0, 0); - return readVar(0); -} - -void ScummEngine_v70he::appendSubstring(int dst, int src, int srcOffs, int len) { - int dstOffs, value; - int i = 0; - - if (len == -1) { - len = resStrLen(getStringAddress(src)); - srcOffs = 0; - } - - dstOffs = resStrLen(getStringAddress(dst)); - - len -= srcOffs; - len++; - - while (i < len) { - writeVar(0, src); - value = readArray(0, 0, srcOffs + i); - writeVar(0, dst); - writeArray(0, 0, dstOffs + i, value); - i++; - } - - writeArray(0, 0, dstOffs + i, 0); -} - -void ScummEngine_v70he::o70_startSound() { - int var, value; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 9: - _heSndFlags |= 4; - break; - case 23: - value = pop(); - var = pop(); - _heSndSoundId = pop(); - _sound->setSoundVar(_heSndSoundId, var, value); - break; - case 25: - value = pop(); - _heSndSoundId = pop(); - _sound->addSoundToQueue(_heSndSoundId, 0, 0, 8); - case 56: - _heSndFlags |= 16; - break; - case 164: - _heSndFlags |= 2; - break; - case 224: - _heSndSoundFreq = pop(); - break; - case 230: - _heSndChannel = pop(); - break; - case 231: - _heSndOffset = pop(); - break; - case 232: - _heSndSoundId = pop(); - _heSndOffset = 0; - _heSndSoundFreq = 11025; - _heSndChannel = VAR(VAR_SOUND_CHANNEL); - break; - case 245: - _heSndFlags |= 1; - break; - case 255: - _sound->addSoundToQueue(_heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags); - _heSndFlags = 0; - break; - - default: - error("o70_startSound invalid case %d", subOp); - } -} - -void ScummEngine_v70he::o70_pickupObject() { - int obj, room; - - room = pop(); - obj = pop(); - if (room == 0) - room = getObjectRoom(obj); - - addObjectToInventory(obj, room); - putOwner(obj, VAR(VAR_EGO)); - if (_heversion <= 70) { - putClass(obj, kObjectClassUntouchable, 1); - putState(obj, 1); - markObjectRectAsDirty(obj); - clearDrawObjectQueue(); - } - runInventoryScript(obj); /* Difference */ -} - -void ScummEngine_v70he::o70_getActorRoom() { - int act = pop(); - - if (act < _numActors) { - Actor *a = derefActor(act, "o70_getActorRoom"); - push(a->_room); - } else - push(getObjectRoom(act)); -} - -void ScummEngine_v70he::o70_resourceRoutines() { - int objidx, resid; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 100: // SO_LOAD_SCRIPT - resid = pop(); - ensureResourceLoaded(rtScript, resid); - break; - case 101: // SO_LOAD_SOUND - resid = pop(); - ensureResourceLoaded(rtSound, resid); - break; - case 102: // SO_LOAD_COSTUME - resid = pop(); - ensureResourceLoaded(rtCostume, resid); - break; - case 103: // SO_LOAD_ROOM - resid = pop(); - ensureResourceLoaded(rtRoomImage, resid); - ensureResourceLoaded(rtRoom, resid); - break; - case 104: // SO_NUKE_SCRIPT - resid = pop(); - res.nukeResource(rtScript, resid); - break; - case 105: // SO_NUKE_SOUND - resid = pop(); - res.nukeResource(rtSound, resid); - break; - case 106: // SO_NUKE_COSTUME - resid = pop(); - res.nukeResource(rtCostume, resid); - break; - case 107: // SO_NUKE_ROOM - resid = pop(); - res.nukeResource(rtRoom, resid); - res.nukeResource(rtRoomImage, resid); - break; - case 108: // SO_LOCK_SCRIPT - resid = pop(); - if (resid >= _numGlobalScripts) - break; - res.lock(rtScript, resid); - break; - case 109: // SO_LOCK_SOUND - resid = pop(); - res.lock(rtSound, resid); - break; - case 110: // SO_LOCK_COSTUME - resid = pop(); - res.lock(rtCostume, resid); - break; - case 111: // SO_LOCK_ROOM - resid = pop(); - if (_heversion <= 71 && resid > 0x7F) - resid = _resourceMapper[resid & 0x7F]; - res.lock(rtRoom, resid); - res.lock(rtRoomImage, resid); - break; - case 112: // SO_UNLOCK_SCRIPT - resid = pop(); - if (resid >= _numGlobalScripts) - break; - res.unlock(rtScript, resid); - break; - case 113: // SO_UNLOCK_SOUND - resid = pop(); - res.unlock(rtSound, resid); - break; - case 114: // SO_UNLOCK_COSTUME - resid = pop(); - res.unlock(rtCostume, resid); - break; - case 115: // SO_UNLOCK_ROOM - resid = pop(); - if (_heversion <= 71 && resid > 0x7F) - resid = _resourceMapper[resid & 0x7F]; - res.unlock(rtRoom, resid); - res.unlock(rtRoomImage, resid); - break; - case 116: - break; - case 117: // SO_LOAD_CHARSET - resid = pop(); - loadCharset(resid); - break; - case 118: // SO_NUKE_CHARSET - resid = pop(); - nukeCharset(resid); - break; - case 119: // SO_LOAD_OBJECT - { - int obj = pop(); - int room = getObjectRoom(obj); - loadFlObject(obj, room); - break; - } - case 120: - resid = pop(); - if (resid >= _numGlobalScripts) - break; - //queueLoadResource(rtScript, resid); - break; - case 121: - resid = pop(); - //queueLoadResource(rtSound, resid); - break; - case 122: - resid = pop(); - //queueLoadResource(rtCostume, resid); - break; - case 123: - resid = pop(); - //queueLoadResource(rtRoomImage, resid); - break; - case 159: - resid = pop(); - res.unlock(rtImage, resid); - break; - case 192: - resid = pop(); - res.nukeResource(rtImage, resid); - break; - case 201: - resid = pop(); - ensureResourceLoaded(rtImage, resid); - break; - case 202: - resid = pop(); - res.lock(rtImage, resid); - break; - case 203: - resid = pop(); - //queueLoadResource(rtImage, resid); - break; - case 233: - resid = pop(); - objidx = getObjectIndex(resid); - if (objidx == -1) - break; - res.lock(rtFlObject, _objs[objidx].fl_object_index); - break; - case 235: - resid = pop(); - objidx = getObjectIndex(resid); - if (objidx == -1) - break; - res.unlock(rtFlObject, _objs[objidx].fl_object_index); - break; - case 239: - // Used in airport - break; - default: - error("o70_resourceRoutines: default case %d", subOp); - } -} - -void ScummEngine_v70he::o70_systemOps() { - byte *src, string[256]; - int id, len; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 158: - restart(); - break; - case 160: - // Confirm shutdown - shutDown(); - break; - case 244: - shutDown(); - break; - case 250: - id = pop(); - src = getStringAddress(id); - len = resStrLen(src) + 1; - memcpy(string, src, len); - debug(0, "Start executable (%s)", string); - break; - case 251: - convertMessageToString(_scriptPointer, string, sizeof(string)); - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - debug(0, "Start executable (%s)", string); - break; - case 252: - convertMessageToString(_scriptPointer, string, sizeof(string)); - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - debug(0, "Start game (%s)", string); - break; - case 253: - id = pop(); - src = getStringAddress(id); - len = resStrLen(src) + 1; - memcpy(string, src, len); - debug(0, "Start game (%s)", string); - break; - default: - error("o70_systemOps invalid case %d", subOp); - } -} - -void ScummEngine_v70he::o70_seekFilePos() { - int mode, offset, slot; - mode = pop(); - offset = pop(); - slot = pop(); - - if (slot == -1) - return; - - switch (mode) { - case 1: - _hFileTable[slot].seek(offset, SEEK_SET); - break; - case 2: - _hFileTable[slot].seek(offset, SEEK_CUR); - break; - case 3: - _hFileTable[slot].seek(offset, SEEK_END); - break; - default: - error("o70_seekFilePos: default case 0x%x", mode); - } -} - -void ScummEngine_v70he::o70_copyString() { - int dst, size; - int src = pop(); - - size = resStrLen(getStringAddress(src)) + 1; - dst = setupStringArray(size); - - appendSubstring(dst, src, -1, -1); - - push(dst); -} - -void ScummEngine_v70he::o70_getStringWidth() { - int array, pos, len; - int chr, width = 0; - - len = pop(); - pos = pop(); - array = pop(); - - if (len == -1) { - pos = 0; - len = resStrLen(getStringAddress(array)); - } - - writeVar(0, array); - while (pos <= len) { - chr = readArray(0, 0, pos); - if (chr == 0) - break; - width += getStringCharWidth(chr); - pos++; - } - - push(width); -} - -void ScummEngine_v70he::o70_kernelSetFunctions() { - int args[29]; - int num; - Actor *a; - - num = getStackList(args, ARRAYSIZE(args)); - - switch (args[0]) { - case 1: - // Used to restore images when decorating cake in - // Fatty Bear's Birthday Surprise - virtScreenLoad(args[1], args[2], args[3], args[4], args[5]); - break; - case 20: // HE72+ - a = derefActor(args[1], "o70_kernelSetFunctions: 20"); - ((ScummEngine_v71he *)this)->queueAuxBlock(a); - break; - case 21: - _skipDrawObject = 1; - break; - case 22: - _skipDrawObject = 0; - break; - case 23: - _charset->clearCharsetMask(); - _fullRedraw = true; - break; - case 24: - _skipProcessActors = 1; - redrawAllActors(); - break; - case 25: - _skipProcessActors = 0; - redrawAllActors(); - break; - case 26: - a = derefActor(args[1], "o70_kernelSetFunctions: 26"); - a->_auxBlock.r.left = 0; - a->_auxBlock.r.right = -1; - a->_auxBlock.r.top = 0; - a->_auxBlock.r.bottom = -2; - break; - case 30: - a = derefActor(args[1], "o70_kernelSetFunctions: 30"); - a->_clipOverride.bottom = args[2]; - break; - case 42: - _wiz->_rectOverrideEnabled = true; - _wiz->_rectOverride.left = args[1]; - _wiz->_rectOverride.top = args[2]; - _wiz->_rectOverride.right = args[3]; - _wiz->_rectOverride.bottom = args[4]; - break; - case 43: - _wiz->_rectOverrideEnabled = false; - break; - default: - error("o70_kernelSetFunctions: default case %d (param count %d)", args[0], num); - } -} - -void ScummEngine_v70he::o70_getStringLen() { - int id, len; - byte *addr; - - id = pop(); - - addr = getStringAddress(id); - if (!addr) - error("o70_getStringLen: Reference to zeroed array pointer (%d)", id); - - len = resStrLen(getStringAddress(id)); - push(len); -} - -void ScummEngine_v70he::o70_appendString() { - int dst, size; - - int len = pop(); - int srcOffs = pop(); - int src = pop(); - - size = len - srcOffs + 2; - dst = setupStringArray(size); - - appendSubstring(dst, src, srcOffs, len); - - push(dst); -} - -void ScummEngine_v70he::o70_concatString() { - int dst, size; - - int src2 = pop(); - int src1 = pop(); - - size = resStrLen(getStringAddress(src1)); - size += resStrLen(getStringAddress(src2)) + 1; - dst = setupStringArray(size); - - appendSubstring(dst, src1, 0, -1); - appendSubstring(dst, src2, 0, -1); - - push(dst); -} - -void ScummEngine_v70he::o70_compareString() { - int result; - - int array1 = pop(); - int array2 = pop(); - - byte *string1 = getStringAddress(array1); - if (!string1) - error("o70_compareString: Reference to zeroed array pointer (%d)", array1); - - byte *string2 = getStringAddress(array2); - if (!string2) - error("o70_compareString: Reference to zeroed array pointer (%d)", array2); - - while (*string1 == *string2) { - if (*string2 == 0) { - push(0); - return; - } - - string1++; - string2++; - } - - result = (*string1 > *string2) ? -1 : 1; - push(result); -} - -void ScummEngine_v70he::o70_isResourceLoaded() { - // Reports percentage of resource loaded by queue - int type; - - byte subOp = fetchScriptByte(); - /* int idx = */ pop(); - - switch (subOp) { - case 18: - type = rtImage; - break; - case 226: - type = rtRoom; - break; - case 227: - type = rtCostume; - break; - case 228: - type = rtSound; - break; - case 229: - type = rtScript; - break; - default: - error("o70_isResourceLoaded: default case %d", subOp); - } - - push(100); -} - -void ScummEngine_v70he::o70_readINI() { - byte option[256]; - ArrayHeader *ah; - const char *entry; - int len, type; - - convertMessageToString(_scriptPointer, option, sizeof(option)); - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - type = pop(); - switch (type) { - case 1: // number - if (!strcmp((char *)option, "NoPrinting")) { - push(1); - } else if (!strcmp((char *)option, "TextOn")) { - push(ConfMan.getBool("subtitles")); - } else { - push(ConfMan.getInt((char *)option)); - } - break; - case 2: // string - entry = (ConfMan.get((char *)option).c_str()); - - writeVar(0, 0); - len = resStrLen((const byte *)entry); - ah = defineArray(0, kStringArray, 0, len); - memcpy(ah->data, entry, len); - - push(readVar(0)); - break; - default: - error("o70_readINI: default type %d", type); - } - debug(1, "o70_readINI: Option %s", option); -} - -void ScummEngine_v70he::o70_writeINI() { - int type, value; - byte option[256], string[256]; - int len; - - type = pop(); - value = pop(); - - convertMessageToString(_scriptPointer, option, sizeof(option)); - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - switch (type) { - case 1: // number - ConfMan.set((char *)option, value); - debug(1, "o70_writeINI: Option %s Value %d", option, value); - break; - case 2: // string - convertMessageToString(_scriptPointer, string, sizeof(string)); - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - ConfMan.set((char *)option, (char *)string); - debug(1, "o70_writeINI: Option %s String %s", option, string); - break; - default: - error("o70_writeINI: default type %d", type); - } -} - -void ScummEngine_v70he::o70_getStringLenForWidth() { - int chr, max; - int array, len, pos, width = 0; - - max = pop(); - pos = pop(); - array = pop(); - - len = resStrLen(getStringAddress(array)); - - writeVar(0, array); - while (pos <= len) { - chr = readArray(0, 0, pos); - width += getStringCharWidth(chr); - if (width >= max) { - push(pos); - return; - } - pos++; - } - - push(len); -} - -void ScummEngine_v70he::o70_getCharIndexInString() { - int array, end, len, pos, value; - - value = pop(); - end = pop(); - pos = pop(); - array = pop(); - - if (end >= 0) { - len = resStrLen(getStringAddress(array)); - if (len < end) - end = len; - } else { - end = 0; - } - - if (pos < 0) - pos = 0; - - writeVar(0, array); - if (end > pos) { - while (end >= pos) { - if (readArray(0, 0, pos) == value) { - push(pos); - return; - } - pos++; - } - } else { - while (end <= pos) { - if (readArray(0, 0, pos) == value) { - push(pos); - return; - } - pos--; - } - } - - push(-1); -} - -void ScummEngine_v70he::o70_setFilePath() { - int len; - byte filename[100]; - - convertMessageToString(_scriptPointer, filename, sizeof(filename)); - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - debug(1,"stub o70_setFilePath(%s)", filename); -} - -void ScummEngine_v70he::o70_setSystemMessage() { - int len; - byte name[255]; - - byte subOp = fetchScriptByte(); - - convertMessageToString(_scriptPointer, name, sizeof(name)); - len = resStrLen(_scriptPointer); - _scriptPointer += len + 1; - - switch (subOp) { - case 240: - debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); - break; - case 241: // Set Version - debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); - break; - case 242: - debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); - break; - case 243: // Set Window Caption - _system->setWindowCaption((const char *)name); - break; - default: - error("o70_setSystemMessage: default case %d", subOp); - } -} - -void ScummEngine_v70he::o70_polygonOps() { - int vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y; - int id, fromId, toId; - bool flag; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 68: // HE 100 - case 69: // HE 100 - case 246: - case 248: - vert4y = pop(); - vert4x = pop(); - vert3y = pop(); - vert3x = pop(); - vert2y = pop(); - vert2x = pop(); - vert1y = pop(); - vert1x = pop(); - flag = (subOp == 69 || subOp == 248); - id = pop(); - _wiz->polygonStore(id, flag, vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y); - break; - case 28: // HE 100 - case 247: - toId = pop(); - fromId = pop(); - _wiz->polygonErase(fromId, toId); - break; - default: - error("o70_polygonOps: default case %d", subOp); - } -} - -void ScummEngine_v70he::o70_polygonHit() { - int y = pop(); - int x = pop(); - push(_wiz->polygonHit(0, x, y)); -} - -} // End of namespace Scumm diff --git a/engines/scumm/script_v80he.cpp b/engines/scumm/script_v80he.cpp deleted file mode 100644 index 02c3f403d9..0000000000 --- a/engines/scumm/script_v80he.cpp +++ /dev/null @@ -1,811 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" - -#include "common/config-file.h" -#include "common/config-manager.h" -#include "common/str.h" - -#include "scumm/actor.h" -#include "scumm/charset.h" -#include "scumm/intern_he.h" -#include "scumm/object.h" -#include "scumm/resource.h" -#include "scumm/resource_v7he.h" -#include "scumm/scumm.h" -#include "scumm/sound.h" -#include "scumm/util.h" - -namespace Scumm { - -#define OPCODE(x) _OPCODE(ScummEngine_v80he, x) - -void ScummEngine_v80he::setupOpcodes() { - static const OpcodeEntryV80he opcodes[256] = { - /* 00 */ - OPCODE(o6_pushByte), - OPCODE(o6_pushWord), - OPCODE(o72_pushDWord), - OPCODE(o6_pushWordVar), - /* 04 */ - OPCODE(o72_getScriptString), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_wordArrayRead), - /* 08 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_wordArrayIndexedRead), - /* 0C */ - OPCODE(o6_dup), - OPCODE(o6_not), - OPCODE(o6_eq), - OPCODE(o6_neq), - /* 10 */ - OPCODE(o6_gt), - OPCODE(o6_lt), - OPCODE(o6_le), - OPCODE(o6_ge), - /* 14 */ - OPCODE(o6_add), - OPCODE(o6_sub), - OPCODE(o6_mul), - OPCODE(o6_div), - /* 18 */ - OPCODE(o6_land), - OPCODE(o6_lor), - OPCODE(o6_pop), - OPCODE(o72_isAnyOf), - /* 1C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 20 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 24 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 28 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 2C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 30 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 34 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 38 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 3C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 40 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_writeWordVar), - /* 44 */ - OPCODE(o6_invalid), - OPCODE(o80_createSound), - OPCODE(o80_getFileSize), - OPCODE(o6_wordArrayWrite), - /* 48 */ - OPCODE(o80_stringToInt), - OPCODE(o80_getSoundVar), - OPCODE(o80_localizeArrayToRoom), - OPCODE(o6_wordArrayIndexedWrite), - /* 4C */ - OPCODE(o80_sourceDebug), - OPCODE(o80_readConfigFile), - OPCODE(o80_writeConfigFile), - OPCODE(o6_wordVarInc), - /* 50 */ - OPCODE(o72_resetCutscene), - OPCODE(o6_invalid), - OPCODE(o72_findObjectWithClassOf), - OPCODE(o6_wordArrayInc), - /* 54 */ - OPCODE(o72_getObjectImageX), - OPCODE(o72_getObjectImageY), - OPCODE(o72_captureWizImage), - OPCODE(o6_wordVarDec), - /* 58 */ - OPCODE(o72_getTimer), - OPCODE(o72_setTimer), - OPCODE(o72_getSoundPosition), - OPCODE(o6_wordArrayDec), - /* 5C */ - OPCODE(o6_if), - OPCODE(o6_ifNot), - OPCODE(o72_startScript), - OPCODE(o6_startScriptQuick), - /* 60 */ - OPCODE(o72_startObject), - OPCODE(o72_drawObject), - OPCODE(o72_printWizImage), - OPCODE(o72_getArrayDimSize), - /* 64 */ - OPCODE(o72_getNumFreeArrays), - OPCODE(o6_stopObjectCode), - OPCODE(o6_stopObjectCode), - OPCODE(o6_endCutscene), - /* 68 */ - OPCODE(o6_cutscene), - OPCODE(o6_invalid), - OPCODE(o6_freezeUnfreeze), - OPCODE(o80_cursorCommand), - /* 6C */ - OPCODE(o6_breakHere), - OPCODE(o6_ifClassOfIs), - OPCODE(o6_setClass), - OPCODE(o6_getState), - /* 70 */ - OPCODE(o80_setState), - OPCODE(o6_setOwner), - OPCODE(o6_getOwner), - OPCODE(o6_jump), - /* 74 */ - OPCODE(o70_startSound), - OPCODE(o6_stopSound), - OPCODE(o6_invalid), - OPCODE(o6_stopObjectScript), - /* 78 */ - OPCODE(o6_panCameraTo), - OPCODE(o6_actorFollowCamera), - OPCODE(o6_setCameraAt), - OPCODE(o6_loadRoom), - /* 7C */ - OPCODE(o6_stopScript), - OPCODE(o6_walkActorToObj), - OPCODE(o6_walkActorTo), - OPCODE(o6_putActorAtXY), - /* 80 */ - OPCODE(o6_putActorAtObject), - OPCODE(o6_faceActor), - OPCODE(o6_animateActor), - OPCODE(o6_doSentence), - /* 84 */ - OPCODE(o70_pickupObject), - OPCODE(o6_loadRoomWithEgo), - OPCODE(o6_invalid), - OPCODE(o6_getRandomNumber), - /* 88 */ - OPCODE(o6_getRandomNumberRange), - OPCODE(o6_invalid), - OPCODE(o6_getActorMoving), - OPCODE(o6_isScriptRunning), - /* 8C */ - OPCODE(o70_getActorRoom), - OPCODE(o6_getObjectX), - OPCODE(o6_getObjectY), - OPCODE(o6_getObjectOldDir), - /* 90 */ - OPCODE(o6_getActorWalkBox), - OPCODE(o6_getActorCostume), - OPCODE(o6_findInventory), - OPCODE(o6_getInventoryCount), - /* 94 */ - OPCODE(o6_invalid), - OPCODE(o6_beginOverride), - OPCODE(o6_endOverride), - OPCODE(o6_setObjectName), - /* 98 */ - OPCODE(o6_isSoundRunning), - OPCODE(o6_setBoxFlags), - OPCODE(o6_invalid), - OPCODE(o70_resourceRoutines), - /* 9C */ - OPCODE(o72_roomOps), - OPCODE(o72_actorOps), - OPCODE(o6_invalid), - OPCODE(o6_getActorFromXY), - /* A0 */ - OPCODE(o72_findObject), - OPCODE(o6_pseudoRoom), - OPCODE(o6_getActorElevation), - OPCODE(o6_getVerbEntrypoint), - /* A4 */ - OPCODE(o72_arrayOps), - OPCODE(o6_invalid), - OPCODE(o6_drawBox), - OPCODE(o6_pop), - /* A8 */ - OPCODE(o6_getActorWidth), - OPCODE(o6_wait), - OPCODE(o6_getActorScaleX), - OPCODE(o6_getActorAnimCounter1), - /* AC */ - OPCODE(o80_drawWizPolygon), - OPCODE(o6_isAnyOf), - OPCODE(o72_systemOps), - OPCODE(o6_isActorInBox), - /* B0 */ - OPCODE(o6_delay), - OPCODE(o6_delaySeconds), - OPCODE(o6_delayMinutes), - OPCODE(o6_stopSentence), - /* B4 */ - OPCODE(o6_printLine), - OPCODE(o6_printText), - OPCODE(o6_printDebug), - OPCODE(o6_printSystem), - /* B8 */ - OPCODE(o6_printActor), - OPCODE(o6_printEgo), - OPCODE(o72_talkActor), - OPCODE(o72_talkEgo), - /* BC */ - OPCODE(o72_dimArray), - OPCODE(o6_stopObjectCode), - OPCODE(o6_startObjectQuick), - OPCODE(o6_startScriptQuick2), - /* C0 */ - OPCODE(o72_dim2dimArray), - OPCODE(o72_traceStatus), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* C4 */ - OPCODE(o6_abs), - OPCODE(o6_distObjectObject), - OPCODE(o6_distObjectPt), - OPCODE(o6_distPtPt), - /* C8 */ - OPCODE(o72_kernelGetFunctions), - OPCODE(o70_kernelSetFunctions), - OPCODE(o6_delayFrames), - OPCODE(o6_pickOneOf), - /* CC */ - OPCODE(o6_pickOneOfDefault), - OPCODE(o6_stampObject), - OPCODE(o72_drawWizImage), - OPCODE(o72_debugInput), - /* D0 */ - OPCODE(o6_getDateTime), - OPCODE(o6_stopTalking), - OPCODE(o6_getAnimateVariable), - OPCODE(o6_invalid), - /* D4 */ - OPCODE(o6_shuffle), - OPCODE(o72_jumpToScript), - OPCODE(o6_band), - OPCODE(o6_bor), - /* D8 */ - OPCODE(o6_isRoomScriptRunning), - OPCODE(o60_closeFile), - OPCODE(o72_openFile), - OPCODE(o72_readFile), - /* DC */ - OPCODE(o72_writeFile), - OPCODE(o72_findAllObjects), - OPCODE(o72_deleteFile), - OPCODE(o72_rename), - /* E0 */ - OPCODE(o80_drawLine), - OPCODE(o72_getPixel), - OPCODE(o60_localizeArrayToScript), - OPCODE(o80_pickVarRandom), - /* E4 */ - OPCODE(o6_setBoxSet), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* E8 */ - OPCODE(o6_invalid), - OPCODE(o70_seekFilePos), - OPCODE(o72_redimArray), - OPCODE(o60_readFilePos), - /* EC */ - OPCODE(o70_copyString), - OPCODE(o70_getStringWidth), - OPCODE(o70_getStringLen), - OPCODE(o70_appendString), - /* F0 */ - OPCODE(o70_concatString), - OPCODE(o70_compareString), - OPCODE(o70_isResourceLoaded), - OPCODE(o72_readINI), - /* F4 */ - OPCODE(o72_writeINI), - OPCODE(o70_getStringLenForWidth), - OPCODE(o70_getCharIndexInString), - OPCODE(o6_invalid), - /* F8 */ - OPCODE(o72_getResourceSize), - OPCODE(o72_setFilePath), - OPCODE(o72_setSystemMessage), - OPCODE(o70_polygonOps), - /* FC */ - OPCODE(o70_polygonHit), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - }; - - _opcodesV80he = opcodes; -} - -void ScummEngine_v80he::executeOpcode(byte i) { - OpcodeProcV80he op = _opcodesV80he[i].proc; - (this->*op) (); -} - -const char *ScummEngine_v80he::getOpcodeDesc(byte i) { - return _opcodesV80he[i].desc; -} - -void ScummEngine_v80he::o80_createSound() { - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 27: - createSound(_heSndResId, pop()); - break; - case 217: - createSound(_heSndResId, -1); - break; - case 232: - _heSndResId = pop(); - break; - case 255: - // dummy case - break; - default: - error("o80_createSound: default case %d", subOp); - } -} - -void ScummEngine_v80he::o80_getFileSize() { - byte filename[256]; - - copyScriptString(filename, sizeof(filename)); - - Common::File f; - if (!f.open((char *)filename)) { - push(-1); - } else { - push(f.size()); - f.close(); - } -} - -void ScummEngine_v80he::o80_stringToInt() { - int id, len, val; - byte *addr; - char string[100]; - - id = pop(); - - addr = getStringAddress(id); - if (!addr) - error("o80_stringToInt: Reference to zeroed array pointer (%d)", id); - - len = resStrLen(getStringAddress(id)) + 1; - memcpy(string, addr, len); - val = atoi(string); - push(val); -} - -void ScummEngine_v80he::o80_getSoundVar() { - int var = pop(); - int snd = pop(); - push(_sound->getSoundVar(snd, var)); -} - -void ScummEngine_v80he::o80_localizeArrayToRoom() { - int slot = pop(); - localizeArray(slot, 0xFF); -} - -void ScummEngine_v80he::o80_sourceDebug() { - fetchScriptDWord(); - fetchScriptDWord(); -} - -void ScummEngine_v80he::o80_readConfigFile() { - byte option[128], section[128], filename[256]; - ArrayHeader *ah; - Common::String entry; - int len; - - copyScriptString(option, sizeof(option)); - copyScriptString(section, sizeof(section)); - copyScriptString(filename, sizeof(filename)); - convertFilePath(filename, true); - - Common::ConfigFile ConfFile; - ConfFile.loadFromFile((const char *)filename); - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 43: // HE 100 - case 6: // number - ConfFile.getKey((const char *)option, (const char *)section, entry); - - push(atoi(entry.c_str())); - break; - case 77: // HE 100 - case 7: // string - ConfFile.getKey((const char *)option, (const char *)section, entry); - - writeVar(0, 0); - len = resStrLen((const byte *)entry.c_str()); - ah = defineArray(0, kStringArray, 0, 0, 0, len); - memcpy(ah->data, entry.c_str(), len); - push(readVar(0)); - break; - default: - error("o80_readConfigFile: default type %d", subOp); - } - - debug(1, "o80_readConfigFile: Filename %s Section %s Option %s Value %s", filename, section, option, entry.c_str()); -} - -void ScummEngine_v80he::o80_writeConfigFile() { - byte filename[256], section[256], option[256], string[1024]; - int value; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 43: // HE 100 - case 6: // number - value = pop(); - sprintf((char *)string, "%d", value); - copyScriptString(option, sizeof(option)); - copyScriptString(section, sizeof(section)); - copyScriptString(filename, sizeof(filename)); - convertFilePath(filename, true); - break; - case 77: // HE 100 - case 7: // string - copyScriptString(string, sizeof(string)); - copyScriptString(option, sizeof(option)); - copyScriptString(section, sizeof(section)); - copyScriptString(filename, sizeof(filename)); - convertFilePath(filename, true); - break; - default: - error("o80_writeConfigFile: default type %d", subOp); - } - - Common::ConfigFile ConfFile; - ConfFile.loadFromFile((const char *)filename); - ConfFile.setKey((char *)option, (char *)section, (char *)string); - ConfFile.saveToFile((const char *)filename); - debug(1,"o80_writeConfigFile: Filename %s Section %s Option %s String %s", filename, section, option, string); -} - -void ScummEngine_v80he::o80_cursorCommand() { - int a, i; - int args[16]; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 0x13: - case 0x14: - a = pop(); - _wiz->loadWizCursor(a); - break; - case 0x3C: - pop(); - a = pop(); - _wiz->loadWizCursor(a); - break; - case 0x90: // SO_CURSOR_ON Turn cursor on - _cursor.state = 1; - break; - case 0x91: // SO_CURSOR_OFF Turn cursor off - _cursor.state = 0; - break; - case 0x92: // SO_USERPUT_ON - _userPut = 1; - break; - case 0x93: // SO_USERPUT_OFF - _userPut = 0; - break; - case 0x94: // SO_CURSOR_SOFT_ON Turn soft cursor on - _cursor.state++; - if (_cursor.state > 1) - error("Cursor state greater than 1 in script"); - break; - case 0x95: // SO_CURSOR_SOFT_OFF Turn soft cursor off - _cursor.state--; - break; - case 0x96: // SO_USERPUT_SOFT_ON - _userPut++; - break; - case 0x97: // SO_USERPUT_SOFT_OFF - _userPut--; - break; - case 0x9C: // SO_CHARSET_SET - initCharset(pop()); - break; - case 0x9D: // SO_CHARSET_COLOR - getStackList(args, ARRAYSIZE(args)); - for (i = 0; i < 16; i++) - _charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i]; - break; - default: - error("o80_cursorCommand: default case %x", subOp); - } - - VAR(VAR_CURSORSTATE) = _cursor.state; - VAR(VAR_USERPUT) = _userPut; -} - -void ScummEngine_v80he::o80_setState() { - int state = pop(); - int obj = pop(); - - state &= 0x7FFF; - putState(obj, state); - removeObjectFromDrawQue(obj); -} - -void ScummEngine_v80he::o80_drawWizPolygon() { - WizImage wi; - wi.x1 = wi.y1 = pop(); - wi.resNum = pop(); - wi.state = 0; - wi.flags = kWIFIsPolygon; - _wiz->displayWizImage(&wi); -} - -/** - * Draw a 'line' between two points. - * - * @param x1 the starting x coordinate - * @param y1 the starting y coordinate - * @param x the ending x coordinate - * @param y the ending y coordinate - * @param step the step size used to render the line, only ever 'step'th point is drawn - * @param type the line type -- points are rendered by drawing actors (type == 2), - * wiz images (type == 3), or pixels (any other type) - * @param id the id of an actor, wizimage or color (low bit) & flag (high bit) - */ -void ScummEngine_v80he::drawLine(int x1, int y1, int x, int y, int step, int type, int id) { - if (step < 0) { - step = -step; - } - if (step == 0) { - step = 1; - } - - const int dx = x - x1; - const int dy = y - y1; - - const int absDX = ABS(dx); - const int absDY = ABS(dy); - - const int maxDist = MAX(absDX, absDY); - - y = y1; - x = x1; - - - if (type == 2) { - Actor *a = derefActor(id, "drawLine"); - a->drawActorToBackBuf(x, y); - } else if (type == 3) { - WizImage wi; - wi.flags = 0; - wi.y1 = y; - wi.x1 = x; - wi.resNum = id; - wi.state = 0; - _wiz->displayWizImage(&wi); - } else { - drawPixel(x, y, id); - } - - int stepCount = 0; - int tmpX = 0; - int tmpY = 0; - for (int i = 0; i <= maxDist; i++) { - tmpX += absDX; - tmpY += absDY; - - int drawFlag = 0; - - if (tmpX > maxDist) { - drawFlag = 1; - tmpX -= maxDist; - - if (dx >= 0) { - x++; - } else { - x--; - } - } - if (tmpY > maxDist) { - drawFlag = dy; - tmpY -= maxDist; - - if (dy >= 0) { - y++; - } else { - y--; - } - } - - if (drawFlag == 0) - continue; - - if ((stepCount++ % step) != 0 && maxDist != i) - continue; - - if (type == 2) { - Actor *a = derefActor(id, "drawLine"); - a->drawActorToBackBuf(x, y); - } else if (type == 3) { - WizImage wi; - wi.flags = 0; - wi.y1 = y; - wi.x1 = x; - wi.resNum = id; - wi.state = 0; - _wiz->displayWizImage(&wi); - } else { - drawPixel(x, y, id); - } - } -} - -void ScummEngine_v80he::drawPixel(int x, int y, int flags) { - byte *src, *dst; - VirtScreen *vs; - - if (x < 0 || x > 639) - return; - - if (y < 0) - return; - - if ((vs = findVirtScreen(y)) == NULL) - return; - - markRectAsDirty(vs->number, x, y, x, y + 1); - - if ((flags & 0x4000) || (flags & 0x2000000)) { - src = vs->getPixels(x, y); - dst = vs->getBackPixels(x, y); - *dst = *src; - } else if ((flags & 0x2000) || (flags & 4000000)) { - src = vs->getBackPixels(x, y); - dst = vs->getPixels(x, y); - *dst = *src; - } else if (flags & 0x8000000) { - error("drawPixel: unsupported flag 0x%x", flags); - } else { - dst = vs->getPixels(x, y); - *dst = flags; - if ((flags & 0x8000) || (flags & 0x1000000)) { - dst = vs->getBackPixels(x, y); - *dst = flags; - } - } -} - -void ScummEngine_v80he::o80_drawLine() { - int id, step, x, y, x1, y1; - - step = pop(); - id = pop(); - y = pop(); - x = pop(); - y1 = pop(); - x1 = pop(); - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 55: - drawLine(x1, y1, x, y, step, 2, id); - break; - case 63: - drawLine(x1, y1, x, y, step, 3, id); - break; - case 66: - drawLine(x1, y1, x, y, step, 1, id); - break; - default: - error("o80_drawLine: default case %d", subOp); - } - -} - -void ScummEngine_v80he::o80_pickVarRandom() { - int num; - int args[100]; - int32 dim1end; - - num = getStackList(args, ARRAYSIZE(args)); - int value = fetchScriptWord(); - - if (readVar(value) == 0) { - defineArray(value, kDwordArray, 0, 0, 0, num); - if (value & 0x8000) - localizeArray(readVar(value), 0xFF); - else if (value & 0x4000) - localizeArray(readVar(value), _currentScript); - - if (num > 0) { - int16 counter = 0; - do { - writeArray(value, 0, counter + 1, args[counter]); - } while (++counter < num); - } - - shuffleArray(value, 1, num); - writeArray(value, 0, 0, 2); - push(readArray(value, 0, 1)); - return; - } - - num = readArray(value, 0, 0); - - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(value)); - dim1end = FROM_LE_32(ah->dim1end); - - if (dim1end < num) { - int32 var_2 = readArray(value, 0, num - 1); - shuffleArray(value, 1, dim1end); - num = 1; - if (readArray(value, 0, 1) == var_2 && dim1end >= 3) { - int32 tmp = readArray(value, 0, 2); - writeArray(value, 0, num, tmp); - writeArray(value, 0, 2, var_2); - } - } - - writeArray(value, 0, 0, num + 1); - push(readArray(value, 0, num)); -} - -} // End of namespace Scumm diff --git a/engines/scumm/script_v90he.cpp b/engines/scumm/script_v90he.cpp deleted file mode 100644 index 89b3463837..0000000000 --- a/engines/scumm/script_v90he.cpp +++ /dev/null @@ -1,2636 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" - -#include "scumm/actor.h" -#include "scumm/charset.h" -#include "scumm/intern_he.h" -#include "scumm/logic_he.h" -#include "scumm/object.h" -#include "scumm/resource.h" -#include "scumm/resource_v7he.h" -#include "scumm/scumm.h" -#include "scumm/sound.h" -#include "scumm/sprite_he.h" -#include "scumm/util.h" - -namespace Scumm { - -#define OPCODE(x) _OPCODE(ScummEngine_v90he, x) - -void ScummEngine_v90he::setupOpcodes() { - static const OpcodeEntryV90he opcodes[256] = { - /* 00 */ - OPCODE(o6_pushByte), - OPCODE(o6_pushWord), - OPCODE(o72_pushDWord), - OPCODE(o6_pushWordVar), - /* 04 */ - OPCODE(o72_getScriptString), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_wordArrayRead), - /* 08 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o90_dup_n), - OPCODE(o6_wordArrayIndexedRead), - /* 0C */ - OPCODE(o6_dup), - OPCODE(o6_not), - OPCODE(o6_eq), - OPCODE(o6_neq), - /* 10 */ - OPCODE(o6_gt), - OPCODE(o6_lt), - OPCODE(o6_le), - OPCODE(o6_ge), - /* 14 */ - OPCODE(o6_add), - OPCODE(o6_sub), - OPCODE(o6_mul), - OPCODE(o6_div), - /* 18 */ - OPCODE(o6_land), - OPCODE(o6_lor), - OPCODE(o6_pop), - OPCODE(o72_isAnyOf), - /* 1C */ - OPCODE(o90_wizImageOps), - OPCODE(o90_min), - OPCODE(o90_max), - OPCODE(o90_sin), - /* 20 */ - OPCODE(o90_cos), - OPCODE(o90_sqrt), - OPCODE(o90_atan2), - OPCODE(o90_getSegmentAngle), - /* 24 */ - OPCODE(o90_getDistanceBetweenPoints), - OPCODE(o90_getSpriteInfo), - OPCODE(o90_setSpriteInfo), - OPCODE(o90_getSpriteGroupInfo), - /* 28 */ - OPCODE(o90_setSpriteGroupInfo), - OPCODE(o90_getWizData), - OPCODE(o90_getActorData), - OPCODE(o90_startScriptUnk), - /* 2C */ - OPCODE(o90_jumpToScriptUnk), - OPCODE(o90_videoOps), - OPCODE(o90_getVideoData), - OPCODE(o90_floodFill), - /* 30 */ - OPCODE(o90_mod), - OPCODE(o90_shl), - OPCODE(o90_shr), - OPCODE(o90_xor), - /* 34 */ - OPCODE(o90_findAllObjectsWithClassOf), - OPCODE(o90_getPolygonOverlap), - OPCODE(o90_cond), - OPCODE(o90_dim2dim2Array), - /* 38 */ - OPCODE(o90_redim2dimArray), - OPCODE(o90_getLinesIntersectionPoint), - OPCODE(o90_sortArray), - OPCODE(o6_invalid), - /* 3C */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* 40 */ - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_writeWordVar), - /* 44 */ - OPCODE(o90_getObjectData), - OPCODE(o80_createSound), - OPCODE(o80_getFileSize), - OPCODE(o6_wordArrayWrite), - /* 48 */ - OPCODE(o80_stringToInt), - OPCODE(o80_getSoundVar), - OPCODE(o80_localizeArrayToRoom), - OPCODE(o6_wordArrayIndexedWrite), - /* 4C */ - OPCODE(o80_sourceDebug), - OPCODE(o80_readConfigFile), - OPCODE(o80_writeConfigFile), - OPCODE(o6_wordVarInc), - /* 50 */ - OPCODE(o72_resetCutscene), - OPCODE(o6_invalid), - OPCODE(o72_findObjectWithClassOf), - OPCODE(o6_wordArrayInc), - /* 54 */ - OPCODE(o72_getObjectImageX), - OPCODE(o72_getObjectImageY), - OPCODE(o72_captureWizImage), - OPCODE(o6_wordVarDec), - /* 58 */ - OPCODE(o72_getTimer), - OPCODE(o72_setTimer), - OPCODE(o72_getSoundPosition), - OPCODE(o6_wordArrayDec), - /* 5C */ - OPCODE(o6_if), - OPCODE(o6_ifNot), - OPCODE(o72_startScript), - OPCODE(o6_startScriptQuick), - /* 60 */ - OPCODE(o72_startObject), - OPCODE(o72_drawObject), - OPCODE(o72_printWizImage), - OPCODE(o72_getArrayDimSize), - /* 64 */ - OPCODE(o72_getNumFreeArrays), - OPCODE(o6_stopObjectCode), - OPCODE(o6_stopObjectCode), - OPCODE(o6_endCutscene), - /* 68 */ - OPCODE(o6_cutscene), - OPCODE(o6_invalid), - OPCODE(o6_freezeUnfreeze), - OPCODE(o80_cursorCommand), - /* 6C */ - OPCODE(o6_breakHere), - OPCODE(o6_ifClassOfIs), - OPCODE(o6_setClass), - OPCODE(o6_getState), - /* 70 */ - OPCODE(o80_setState), - OPCODE(o6_setOwner), - OPCODE(o6_getOwner), - OPCODE(o6_jump), - /* 74 */ - OPCODE(o70_startSound), - OPCODE(o6_stopSound), - OPCODE(o6_invalid), - OPCODE(o6_stopObjectScript), - /* 78 */ - OPCODE(o6_panCameraTo), - OPCODE(o6_actorFollowCamera), - OPCODE(o6_setCameraAt), - OPCODE(o6_loadRoom), - /* 7C */ - OPCODE(o6_stopScript), - OPCODE(o6_walkActorToObj), - OPCODE(o6_walkActorTo), - OPCODE(o6_putActorAtXY), - /* 80 */ - OPCODE(o6_putActorAtObject), - OPCODE(o6_faceActor), - OPCODE(o6_animateActor), - OPCODE(o6_doSentence), - /* 84 */ - OPCODE(o70_pickupObject), - OPCODE(o6_loadRoomWithEgo), - OPCODE(o6_invalid), - OPCODE(o6_getRandomNumber), - /* 88 */ - OPCODE(o6_getRandomNumberRange), - OPCODE(o6_invalid), - OPCODE(o6_getActorMoving), - OPCODE(o6_isScriptRunning), - /* 8C */ - OPCODE(o70_getActorRoom), - OPCODE(o6_getObjectX), - OPCODE(o6_getObjectY), - OPCODE(o6_getObjectOldDir), - /* 90 */ - OPCODE(o6_getActorWalkBox), - OPCODE(o6_getActorCostume), - OPCODE(o6_findInventory), - OPCODE(o6_getInventoryCount), - /* 94 */ - OPCODE(o90_getPaletteData), - OPCODE(o6_beginOverride), - OPCODE(o6_endOverride), - OPCODE(o6_setObjectName), - /* 98 */ - OPCODE(o6_isSoundRunning), - OPCODE(o6_setBoxFlags), - OPCODE(o6_invalid), - OPCODE(o70_resourceRoutines), - /* 9C */ - OPCODE(o72_roomOps), - OPCODE(o72_actorOps), - OPCODE(o90_paletteOps), - OPCODE(o6_getActorFromXY), - /* A0 */ - OPCODE(o72_findObject), - OPCODE(o6_pseudoRoom), - OPCODE(o6_getActorElevation), - OPCODE(o6_getVerbEntrypoint), - /* A4 */ - OPCODE(o72_arrayOps), - OPCODE(o90_fontUnk), - OPCODE(o6_drawBox), - OPCODE(o6_pop), - /* A8 */ - OPCODE(o6_getActorWidth), - OPCODE(o6_wait), - OPCODE(o6_getActorScaleX), - OPCODE(o90_getActorAnimProgress), - /* AC */ - OPCODE(o80_drawWizPolygon), - OPCODE(o6_isAnyOf), - OPCODE(o72_systemOps), - OPCODE(o6_isActorInBox), - /* B0 */ - OPCODE(o6_delay), - OPCODE(o6_delaySeconds), - OPCODE(o6_delayMinutes), - OPCODE(o6_stopSentence), - /* B4 */ - OPCODE(o6_printLine), - OPCODE(o6_printText), - OPCODE(o6_printDebug), - OPCODE(o6_printSystem), - /* B8 */ - OPCODE(o6_printActor), - OPCODE(o6_printEgo), - OPCODE(o72_talkActor), - OPCODE(o72_talkEgo), - /* BC */ - OPCODE(o72_dimArray), - OPCODE(o6_stopObjectCode), - OPCODE(o6_startObjectQuick), - OPCODE(o6_startScriptQuick2), - /* C0 */ - OPCODE(o72_dim2dimArray), - OPCODE(o72_traceStatus), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* C4 */ - OPCODE(o6_abs), - OPCODE(o6_distObjectObject), - OPCODE(o6_distObjectPt), - OPCODE(o6_distPtPt), - /* C8 */ - OPCODE(o90_kernelGetFunctions), - OPCODE(o90_kernelSetFunctions), - OPCODE(o6_delayFrames), - OPCODE(o6_pickOneOf), - /* CC */ - OPCODE(o6_pickOneOfDefault), - OPCODE(o6_stampObject), - OPCODE(o72_drawWizImage), - OPCODE(o72_debugInput), - /* D0 */ - OPCODE(o6_getDateTime), - OPCODE(o6_stopTalking), - OPCODE(o6_getAnimateVariable), - OPCODE(o6_invalid), - /* D4 */ - OPCODE(o6_shuffle), - OPCODE(o72_jumpToScript), - OPCODE(o6_band), - OPCODE(o6_bor), - /* D8 */ - OPCODE(o6_isRoomScriptRunning), - OPCODE(o60_closeFile), - OPCODE(o72_openFile), - OPCODE(o72_readFile), - /* DC */ - OPCODE(o72_writeFile), - OPCODE(o72_findAllObjects), - OPCODE(o72_deleteFile), - OPCODE(o72_rename), - /* E0 */ - OPCODE(o80_drawLine), - OPCODE(o72_getPixel), - OPCODE(o60_localizeArrayToScript), - OPCODE(o80_pickVarRandom), - /* E4 */ - OPCODE(o6_setBoxSet), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - /* E8 */ - OPCODE(o6_invalid), - OPCODE(o70_seekFilePos), - OPCODE(o72_redimArray), - OPCODE(o60_readFilePos), - /* EC */ - OPCODE(o70_copyString), - OPCODE(o70_getStringWidth), - OPCODE(o70_getStringLen), - OPCODE(o70_appendString), - /* F0 */ - OPCODE(o70_concatString), - OPCODE(o70_compareString), - OPCODE(o70_isResourceLoaded), - OPCODE(o72_readINI), - /* F4 */ - OPCODE(o72_writeINI), - OPCODE(o70_getStringLenForWidth), - OPCODE(o70_getCharIndexInString), - OPCODE(o6_invalid), - /* F8 */ - OPCODE(o72_getResourceSize), - OPCODE(o72_setFilePath), - OPCODE(o72_setSystemMessage), - OPCODE(o70_polygonOps), - /* FC */ - OPCODE(o70_polygonHit), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - OPCODE(o6_invalid), - }; - - _opcodesV90he = opcodes; -} - -void ScummEngine_v90he::executeOpcode(byte i) { - OpcodeProcV90he op = _opcodesV90he[i].proc; - (this->*op) (); -} - -const char *ScummEngine_v90he::getOpcodeDesc(byte i) { - return _opcodesV90he[i].desc; -} - -void ScummEngine_v90he::o90_dup_n() { - int num; - int args[16]; - - push(fetchScriptWord()); - num = getStackList(args, ARRAYSIZE(args)); - - for (int i = 0; i < 2; i++) { - for (int j = 0; j < num; j++) - push(args[j]); - } -} - -void ScummEngine_v90he::o90_min() { - int a = pop(); - int b = pop(); - - if (b < a) { - push(b); - } else { - push(a); - } -} - -void ScummEngine_v90he::o90_max() { - int a = pop(); - int b = pop(); - - if (b > a) { - push(b); - } else { - push(a); - } -} - -void ScummEngine_v90he::o90_sin() { - double a = pop() * PI / 180.; - push((int)(sin(a) * 100000)); -} - -void ScummEngine_v90he::o90_cos() { - double a = pop() * PI / 180.; - push((int)(cos(a) * 100000)); -} - -void ScummEngine_v90he::o90_sqrt() { - int i = pop(); - if (i < 2) { - push(i); - } else { - push((int)sqrt((double)(i + 1))); - } -} - -void ScummEngine_v90he::o90_atan2() { - int y = pop(); - int x = pop(); - int a = (int)(atan2((double)y, (double)x) * 180. / PI); - if (a < 0) { - a += 360; - } - push(a); -} - -void ScummEngine_v90he::o90_getSegmentAngle() { - int y1 = pop(); - int x1 = pop(); - int dy = y1 - pop(); - int dx = x1 - pop(); - int a = (int)(atan2((double)dy, (double)dx) * 180. / PI); - if (a < 0) { - a += 360; - } - push(a); -} - -void ScummEngine_v90he::o90_getActorData() { - Actor *a; - - int subOp = pop(); - int val = pop(); - int act = pop(); - - a = derefActor(act, "o90_getActorData"); - - switch (subOp) { - case 1: - push(a->isUserConditionSet(val)); - break; - case 2: - checkRange(15, 0, val, "Limb %d out of range"); - push(a->_cost.frame[val]); - break; - case 3: - push(a->getAnimSpeed()); - break; - case 4: - push(a->_shadowMode); - break; - case 5: - push(a->_layer); - break; - case 6: - push(a->_hePaletteNum); - break; - default: - error("o90_getActorData: Unknown actor property %d", subOp); - } -} - -void ScummEngine_v90he::o90_startScriptUnk() { - int args[25]; - int script, cycle; - byte flags; - - getStackList(args, ARRAYSIZE(args)); - cycle = pop(); - script = pop(); - flags = fetchScriptByte(); - runScript(script, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args, cycle); -} - -void ScummEngine_v90he::o90_jumpToScriptUnk() { - int args[25]; - int script, cycle; - byte flags; - - getStackList(args, ARRAYSIZE(args)); - cycle = pop(); - script = pop(); - flags = fetchScriptByte(); - stopObjectCode(); - runScript(script, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args, cycle); -} - -void ScummEngine_v90he::o90_videoOps() { - // Uses Smacker video - int status = fetchScriptByte(); - int subOp = status - 49; - - switch (subOp) { - case 0: - copyScriptString(_videoParams.filename, sizeof(_videoParams.filename)); - _videoParams.status = status; - break; - case 5: - _videoParams.flags |= pop(); - break; - case 8: - memset(_videoParams.filename, 0, sizeof(_videoParams.filename)); - _videoParams.unk2 = pop(); - break; - case 14: - _videoParams.wizResNum = pop(); - if (_videoParams.wizResNum) - _videoParams.flags |= 2; - break; - case 116: - _videoParams.status = status; - break; - case 206: - if (_videoParams.status == 49) { - // Start video - if (_videoParams.flags == 0) - _videoParams.flags = 4; - - if (_videoParams.flags == 2) { - // result = startVideo(_videoParams.filename, _videoParams.flags, _videoParams.wizResNum); - // VAR(119) = result; - } else { - // result = startVideo(_videoParams.filename, _videoParams.flags); - // VAR(119) = result; - } - } else if (_videoParams.status == 165) { - // Stop video - } - break; - default: - error("o90_videoOps: unhandled case %d", subOp); - } - - debug(1, "o90_videoOps stub (%d)", subOp); -} - -void ScummEngine_v90he::o90_getVideoData() { - // Uses Smacker video - byte subOp = fetchScriptByte(); - subOp -= 32; - - switch (subOp) { - case 0: // Get width - pop(); - break; - case 1: // Get height - pop(); - break; - case 4: // Get frame count - pop(); - break; - case 20: // Get current frame - pop(); - break; - case 31: // Get image number - pop(); - break; - case 107: // Get statistics - pop(); - pop(); - break; - default: - error("o90_getVideoData: unhandled case %d", subOp); - } - - push(-1); - debug(1, "o90_getVideoData stub (%d)", subOp); -} - -void ScummEngine_v90he::o90_wizImageOps() { - int a, b; - - int subOp = fetchScriptByte(); - subOp -= 46; - - switch (subOp) { - case -14: // HE99+ - _wizParams.processFlags |= kWPFUseDefImgWidth; - _wizParams.resDefImgW = pop(); - break; - case -13: // HE99+ - _wizParams.processFlags |= kWPFUseDefImgHeight; - _wizParams.resDefImgH = pop(); - break; - case 0: - // Dummy case - pop(); - break; - case 1: - _wizParams.box.bottom = pop(); - _wizParams.box.right = pop(); - _wizParams.box.top = pop(); - _wizParams.box.left = pop(); - break; - case 2: - _wizParams.processMode = 1; - break; - case 3: - _wizParams.processFlags |= kWPFUseFile; - _wizParams.processMode = 3; - copyScriptString(_wizParams.filename, sizeof(_wizParams.filename)); - break; - case 4: - _wizParams.processFlags |= kWPFUseFile; - _wizParams.processMode = 4; - copyScriptString(_wizParams.filename, sizeof(_wizParams.filename)); - _wizParams.fileWriteMode = pop(); - break; - case 5: - _wizParams.processFlags |= kWPFClipBox | 0x100; - _wizParams.processMode = 2; - _wizParams.box.bottom = pop(); - _wizParams.box.right = pop(); - _wizParams.box.top = pop(); - _wizParams.box.left = pop(); - _wizParams.compType = pop(); - break; - case 6: - _wizParams.processFlags |= kWPFNewState; - _wizParams.img.state = pop(); - break; - case 7: - _wizParams.processFlags |= kWPFRotate; - _wizParams.angle = pop(); - break; - case 8: - _wizParams.processFlags |= kWPFNewFlags; - _wizParams.img.flags |= pop(); - break; - case 10: - _wizParams.img.flags = pop(); - _wizParams.img.state = pop(); - _wizParams.img.y1 = pop(); - _wizParams.img.x1 = pop(); - _wizParams.img.resNum = pop(); - _wiz->displayWizImage(&_wizParams.img); - break; - case 11: - _wizParams.img.resNum = pop(); - _wizParams.processMode = 0; - _wizParams.processFlags = 0; - _wizParams.remapNum = 0; - _wizParams.img.flags = 0; - _wizParams.field_184 = 0; - _wizParams.field_180 = 0; - _wizParams.spriteId = 0; - _wizParams.spriteGroup = 0; - break; - case 16: // HE99+ - _wizParams.processFlags |= kWPFMaskImg; - _wizParams.sourceImage = pop(); - break; - case 19: - case 108: - _wizParams.processFlags |= kWPFSetPos; - _wizParams.img.y1 = pop(); - _wizParams.img.x1 = pop(); - break; - case 20: - case 203: // HE98+ - b = pop(); - a = pop(); - _wizParams.processFlags |= kWPFRemapPalette; - _wizParams.processMode = 6; - if (_wizParams.remapNum == 0) { - memset(_wizParams.remapIndex, 0, sizeof(_wizParams.remapIndex)); - } else { - assert(_wizParams.remapNum < ARRAYSIZE(_wizParams.remapIndex)); - _wizParams.remapIndex[_wizParams.remapNum] = a; - _wizParams.remapColor[a] = b; - ++_wizParams.remapNum; - } - break; - case 21: - _wizParams.processFlags |= kWPFClipBox; - _wizParams.box.bottom = pop(); - _wizParams.box.right = pop(); - _wizParams.box.top = pop(); - _wizParams.box.left = pop(); - break; - case 40: // HE99+ - _wizParams.processFlags |= kWPFPaletteNum; - _wizParams.img.palette = pop(); - break; - case 46: - _wizParams.processFlags |= kWPFScaled; - _wizParams.scale = pop(); - break; - case 52: - _wizParams.processFlags |= kWPFShadow; - _wizParams.img.shadow = pop(); - break; - case 85: // HE99+ - _wizParams.processFlags |= 0x1000 | 0x100 | 0x2; - _wizParams.processMode = 7; - _wizParams.field_168 = pop(); - _wizParams.field_164 = pop(); - _wizParams.compType = pop(); - break; - case 87: // HE99+ - _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; - _wizParams.processMode = 9; - _wizParams.fillColor = pop(); - _wizParams.box2.bottom = pop(); - _wizParams.box2.right = pop(); - _wizParams.box2.top = pop(); - _wizParams.box2.left = pop(); - break; - case 88: // HE99+ - _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; - _wizParams.processMode = 10; - _wizParams.fillColor = pop(); - _wizParams.box2.bottom = pop(); - _wizParams.box2.right = pop(); - _wizParams.box2.top = pop(); - _wizParams.box2.left = pop(); - break; - case 89: // HE99+ - _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; - _wizParams.processMode = 11; - _wizParams.fillColor = pop(); - _wizParams.box2.top = _wizParams.box2.bottom = pop(); - _wizParams.box2.left = _wizParams.box2.right = pop(); - break; - case 90: // HE99+ - _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; - _wizParams.processMode = 12; - _wizParams.fillColor = pop(); - _wizParams.box2.top = _wizParams.box2.bottom = pop(); - _wizParams.box2.left = _wizParams.box2.right = pop(); - break; - case 91: // HE99+ - _wizParams.processFlags |= kWPFDstResNum; - _wizParams.dstResNum = pop(); - break; - case 93: // HE99+ - _wizParams.processFlags |= 0x100000; - _wizParams.field_180 = pop(); - _wizParams.field_184 = pop(); - break; - case 95: // HE99+ - _wizParams.processMode = 13; - break; - case 96: // HE99+ - _wizParams.field_239D = pop(); - _wizParams.field_2399 = pop(); - _wizParams.field_23A5 = pop(); - _wizParams.field_23A1 = pop(); - copyScriptString(_wizParams.string2, sizeof(_wizParams.string2)); - _wizParams.processMode = 15; - break; - case 97: // HE99+ - _wizParams.processMode = 16; - _wizParams.field_23AD = pop(); - _wizParams.field_23A9 = pop(); - copyScriptString(_wizParams.string1, sizeof(_wizParams.string1)); - break; - case 143: // HE99+ - _wizParams.processMode = 17; - _wizParams.field_23CD = pop(); - _wizParams.field_23C9 = pop(); - _wizParams.field_23C5 = pop(); - _wizParams.field_23C1 = pop(); - _wizParams.field_23BD = pop(); - _wizParams.field_23B9 = pop(); - _wizParams.field_23B5 = pop(); - _wizParams.field_23B1 = pop(); - break; - case 150: // HE99+ - _wizParams.processMode = 14; - break; - case 171: // HE99+ - _wizParams.processMode = 8; - break; - case 200: - _wizParams.processFlags |= kWPFNewFlags | kWPFSetPos | 2; - _wizParams.img.flags |= kWIFIsPolygon; - _wizParams.field_164 = _wizParams.img.y1 = _wizParams.img.x1 = pop(); - break; - case 209: - if (_wizParams.img.resNum) - _wiz->processWizImage(&_wizParams); - break; - default: - error("o90_wizImageOps: unhandled case %d", subOp); - } -} - -void ScummEngine_v90he::o90_getDistanceBetweenPoints() { - int x1, y1, z1, x2, y2, z2, dx, dy, dz, d; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 23: // HE100 - case 28: - y2 = pop(); - x2 = pop(); - y1 = pop(); - x1 = pop(); - dx = x2 - x1; - dy = y2 - y1; - d = dx * dx + dy * dy; - if (d < 2) { - push(d); - } else { - push((int)sqrt((double)(d + 1))); - } - break; - case 24: // HE100 - case 29: - z2 = pop(); - y2 = pop(); - x2 = pop(); - z1 = pop(); - y1 = pop(); - x1 = pop(); - dx = x2 - x1; - dy = y2 - y1; - dz = z2 - z1; - d = dx * dx + dy * dy + dz * dz; - if (d < 2) { - push(d); - } else { - push((int)sqrt((double)(d + 1))); - } - break; - default: - error("o90_getDistanceBetweenPoints: Unknown case %d", subOp); - } -} - -void ScummEngine_v90he::o90_getSpriteInfo() { - int args[16]; - int spriteId, flags, groupId, type; - int32 x, y; - - byte subOp = fetchScriptByte(); - subOp -= 30; - - switch (subOp) { - case 0: - spriteId = pop(); - if (spriteId) { - _sprite->getSpritePosition(spriteId, x, y); - push(x); - } else { - push(0); - } - break; - case 1: - spriteId = pop(); - if (spriteId) { - _sprite->getSpritePosition(spriteId, x, y); - push(y); - } else { - push(0); - } - break; - case 2: - spriteId = pop(); - if (spriteId) { - _sprite->getSpriteImageDim(spriteId, x, y); - push(x); - } else { - push(0); - } - break; - case 3: - spriteId = pop(); - if (spriteId) { - _sprite->getSpriteImageDim(spriteId, x, y); - push(y); - } else { - push(0); - } - break; - case 4: - spriteId = pop(); - if (spriteId) { - _sprite->getSpriteDist(spriteId, x, y); - push(x); - } else { - push(0); - } - break; - case 5: - spriteId = pop(); - if (spriteId) { - _sprite->getSpriteDist(spriteId, x, y); - push(y); - } else { - push(0); - } - break; - case 6: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteImageStateCount(spriteId)); - else - push(0); - break; - case 7: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteGroup(spriteId)); - else - push(0); - break; - case 8: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteDisplayX(spriteId)); - else - push(0); - break; - case 9: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteDisplayY(spriteId)); - else - push(0); - break; - case 12: - flags = pop(); - spriteId = pop(); - if (spriteId) { - switch(flags) { - case 0: - push(_sprite->getSpriteFlagXFlipped(spriteId)); - break; - case 1: - push(_sprite->getSpriteFlagYFlipped(spriteId)); - break; - case 2: - push(_sprite->getSpriteFlagActive(spriteId)); - break; - case 3: - push(_sprite->getSpriteFlagDoubleBuffered(spriteId)); - break; - case 4: - push(_sprite->getSpriteFlagRemapPalette(spriteId)); - break; - default: - push(0); - } - } else { - push(0); - } - break; - case 13: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpritePriority(spriteId)); - else - push(0); - break; - case 15: - if (_heversion == 99) { - flags = getStackList(args, ARRAYSIZE(args)); - type = pop(); - groupId = pop(); - y = pop(); - x = pop(); - push(_sprite->findSpriteWithClassOf(x, y, groupId, type, flags, args)); - } else if (_heversion == 98) { - type = pop(); - groupId = pop(); - y = pop(); - x = pop(); - push(_sprite->findSpriteWithClassOf(x, y, groupId, type, 0, 0)); - } else { - groupId = pop(); - y = pop(); - x = pop(); - push(_sprite->findSpriteWithClassOf(x, y, groupId, 0, 0, 0)); - } - break; - case 22: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteImageState(spriteId)); - else - push(0); - break; - case 32: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteSourceImage(spriteId)); - else - push(0); - break; - case 33: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteImage(spriteId)); - else - push(0); - break; - case 38: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteFlagEraseType(spriteId)); - else - push(1); - break; - case 52: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteFlagAutoAnim(spriteId)); - else - push(0); - break; - case 56: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpritePalette(spriteId)); - else - push(0); - break; - case 62: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteScale(spriteId)); - else - push(0); - break; - case 67: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteAnimSpeed(spriteId)); - else - push(1); - break; - case 68: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteShadow(spriteId)); - else - push(0); - break; - case 94: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteFlagUpdateType(spriteId)); - else - push(0); - break; - case 95: - flags = getStackList(args, ARRAYSIZE(args)); - spriteId = pop(); - if (spriteId) { - push(_sprite->getSpriteClass(spriteId, flags, args)); - } else { - push(0); - } - break; - case 109: - flags = pop(); - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteGeneralProperty(spriteId, flags)); - else - push(0); - break; - case 110: - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteMaskImage(spriteId)); - else - push(0); - break; - case 168: - pop(); - spriteId = pop(); - if (spriteId) - push(_sprite->getSpriteUserValue(spriteId)); - else - push(0); - break; - default: - error("o90_getSpriteInfo: Unknown case %d", subOp); - } -} - -void ScummEngine_v90he::o90_setSpriteInfo() { - int args[16]; - int spriteId; - int32 tmp[2]; - int n; - - byte subOp = fetchScriptByte(); - subOp -= 34; - - switch (subOp) { - case 0: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) { - _sprite->getSpriteDist(spriteId, tmp[0], tmp[1]); - _sprite->setSpriteDist(spriteId, args[0], tmp[1]); - } - break; - case 1: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) { - _sprite->getSpriteDist(spriteId, tmp[0], tmp[1]); - _sprite->setSpriteDist(spriteId, tmp[0], args[0]); - } - break; - case 3: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteGroup(spriteId, args[0]); - break; - case 8: - args[1] = pop(); - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - switch(args[1]) { - case 0: - _sprite->setSpriteFlagXFlipped(spriteId, args[0]); - break; - case 1: - _sprite->setSpriteFlagYFlipped(spriteId, args[0]); - break; - case 2: - _sprite->setSpriteFlagActive(spriteId, args[0]); - break; - case 3: - _sprite->setSpriteFlagDoubleBuffered(spriteId, args[0]); - break; - case 4: - _sprite->setSpriteFlagRemapPalette(spriteId, args[0]); - break; - default: - break; - } - break; - case 9: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpritePriority(spriteId, args[0]); - break; - case 10: - args[1] = pop(); - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->moveSprite(spriteId, args[0], args[1]); - break; - case 18: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteImageState(spriteId, args[0]); - break; - case 19: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteAngle(spriteId, args[0]); - break; - case 23: - if (_features & GF_HE_985 || _heversion >= 99) { - _curMaxSpriteId = pop(); - _curSpriteId = pop(); - - if (_curSpriteId > _curMaxSpriteId) - SWAP(_curSpriteId, _curMaxSpriteId); - } else { - _curSpriteId = pop(); - _curMaxSpriteId = _curSpriteId; // to make all functions happy - } - break; - case 28: // HE99+ - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteSourceImage(spriteId, args[0]); - break; - case 29: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteImage(spriteId, args[0]); - break; - case 31: - args[1] = pop(); - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpritePosition(spriteId, args[0], args[1]); - break; - case 34: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteFlagEraseType(spriteId, args[0]); - break; - case 43: - args[1] = pop(); - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteDist(spriteId, args[0], args[1]); - break; - case 48: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteFlagAutoAnim(spriteId, args[0]); - break; - case 52: // HE 98+ - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpritePalette(spriteId, args[0]); - break; - case 58: // HE 99+ - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteScale(spriteId, args[0]); - break; - case 63: // HE 98+ - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteAnimSpeed(spriteId, args[0]); - break; - case 64: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteShadow(spriteId, args[0]); - break; - case 90: - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteFlagUpdateType(spriteId, args[0]); - break; - case 91: - n = getStackList(args, ARRAYSIZE(args)); - if (_curSpriteId != 0 && _curMaxSpriteId != 0 && n != 0) { - int *p = &args[n - 1]; - do { - int code = *p; - if (code == 0) { - for (int i = _curSpriteId; i <= _curMaxSpriteId; ++i) { - _sprite->setSpriteResetClass(i); - } - } else if (code & 0x80) { - for (int i = _curSpriteId; i <= _curMaxSpriteId; ++i) { - _sprite->setSpriteSetClass(i, code & 0x7F, 1); - } - } else { - for (int i = _curSpriteId; i <= _curMaxSpriteId; ++i) { - _sprite->setSpriteSetClass(i, code & 0x7F, 0); - } - } - --p; - } while (--n); - } - break; - case 105: // HE 99+ - args[1] = pop(); - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteGeneralProperty(spriteId, args[0], args[1]); - break; - case 106: // HE 99+ - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteMaskImage(spriteId, args[0]); - break; - case 124: - _sprite->resetTables(true); - break; - case 164: - args[1] = pop(); - args[0] = pop(); - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->setSpriteUserValue(spriteId, args[0], args[1]); - break; - case 183: - if (_curSpriteId > _curMaxSpriteId) - break; - spriteId = _curSpriteId; - if (!spriteId) - spriteId++; - - for (; spriteId <= _curMaxSpriteId; spriteId++) - _sprite->resetSprite(spriteId); - break; - default: - error("o90_setSpriteInfo: Unknown case %d", subOp); - } -} - -void ScummEngine_v90he::o90_getSpriteGroupInfo() { - int32 tx, ty; - int spriteGroupId, type; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 8: // HE 99+ - spriteGroupId = pop(); - if (spriteGroupId) - push(getGroupSpriteArray(spriteGroupId)); - else - push(0); - break; - case 30: - spriteGroupId = pop(); - if (spriteGroupId) { - _sprite->getGroupPosition(spriteGroupId, tx, ty); - push(tx); - } else { - push(0); - } - break; - case 31: - spriteGroupId = pop(); - if (spriteGroupId) { - _sprite->getGroupPosition(spriteGroupId, tx, ty); - push(ty); - } else { - push(0); - } - break; - case 42: // HE 99+ - type = pop(); - spriteGroupId = pop(); - if (spriteGroupId) { - switch(type) { - case 0: - push(_sprite->getGroupXMul(spriteGroupId)); - break; - case 1: - push(_sprite->getGroupXDiv(spriteGroupId)); - break; - case 2: - push(_sprite->getGroupYMul(spriteGroupId)); - break; - case 3: - push(_sprite->getGroupYDiv(spriteGroupId)); - break; - default: - push(0); - } - } else { - push(0); - } - break; - case 43: - spriteGroupId = pop(); - if (spriteGroupId) - push(_sprite->getGroupPriority(spriteGroupId)); - else - push(0); - break; - case 63: // HE 99+ - spriteGroupId = pop(); - if (spriteGroupId) - push(_sprite->getGroupDstResNum(spriteGroupId)); - else - push(0); - break; - case 139: // HE 99+ - // dummy case - pop(); - pop(); - push(0); - break; - default: - error("o90_getSpriteGroupInfo: Unknown case %d", subOp); - } -} - -void ScummEngine_v90he::o90_setSpriteGroupInfo() { - int type, value1, value2, value3, value4; - - byte subOp = fetchScriptByte(); - subOp -= 37; - - switch (subOp) { - case 0: - type = pop() - 1; - switch (type) { - case 0: - value2 = pop(); - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->moveGroupMembers(_curSpriteGroupId, value1, value2); - break; - case 1: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupMembersPriority(_curSpriteGroupId, value1); - break; - case 2: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupMembersGroup(_curSpriteGroupId, value1); - break; - case 3: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupMembersUpdateType(_curSpriteGroupId, value1); - break; - case 4: - if (!_curSpriteGroupId) - break; - - _sprite->setGroupMembersResetSprite(_curSpriteGroupId); - break; - case 5: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupMembersAnimationSpeed(_curSpriteGroupId, value1); - break; - case 6: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupMembersAutoAnimFlag(_curSpriteGroupId, value1); - break; - case 7: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupMembersShadow(_curSpriteGroupId, value1); - break; - default: - error("o90_setSpriteGroupInfo subOp 0: Unknown case %d", subOp); - } - break; - case 5: - type = pop(); - value1 = pop(); - if (!_curSpriteGroupId) - break; - - switch (type) { - case 0: - _sprite->setGroupXMul(_curSpriteGroupId, value1); - break; - case 1: - _sprite->setGroupXDiv(_curSpriteGroupId, value1); - break; - case 2: - _sprite->setGroupYMul(_curSpriteGroupId, value1); - break; - case 3: - _sprite->setGroupYDiv(_curSpriteGroupId, value1); - break; - default: - error("o90_setSpriteGroupInfo subOp 5: Unknown case %d", subOp); - } - break; - case 6: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupPriority(_curSpriteGroupId, value1); - break; - case 7: - value2 = pop(); - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->moveGroup(_curSpriteGroupId, value1, value2); - break; - case 20: - _curSpriteGroupId = pop(); - break; - case 26: - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupImage(_curSpriteGroupId, value1); - break; - case 28: - value2 = pop(); - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupPosition(_curSpriteGroupId, value1, value2); - break; - case 30: - value4 = pop(); - value3 = pop(); - value2 = pop(); - value1 = pop(); - if (!_curSpriteGroupId) - break; - - _sprite->setGroupBounds(_curSpriteGroupId, value1, value2, value3, value4); - break; - case 56: - if (!_curSpriteGroupId) - break; - - _sprite->resetGroupBounds(_curSpriteGroupId); - break; - case 180: - if (!_curSpriteGroupId) - break; - - _sprite->resetGroup(_curSpriteGroupId); - break; - default: - error("o90_setSpriteGroupInfo: Unknown case %d", subOp); - } -} - -void ScummEngine_v90he::o90_getWizData() { - byte filename[4096]; - int state, resId; - int32 w, h; - int32 x, y; - - byte subOp = fetchScriptByte(); - subOp -= 30; - - switch (subOp) { - case 0: - state = pop(); - resId = pop(); - _wiz->getWizImageSpot(resId, state, x, y); - push(x); - break; - case 1: - state = pop(); - resId = pop(); - _wiz->getWizImageSpot(resId, state, x, y); - push(y); - break; - case 2: - state = pop(); - resId = pop(); - _wiz->getWizImageDim(resId, state, w, h); - push(w); - break; - case 3: - state = pop(); - resId = pop(); - _wiz->getWizImageDim(resId, state, w, h); - push(h); - break; - case 6: - resId = pop(); - push(_wiz->getWizImageStates(resId)); - break; - case 15: - y = pop(); - x = pop(); - state = pop(); - resId = pop(); - push(_wiz->isWizPixelNonTransparent(resId, state, x, y, 0)); - break; - case 36: - y = pop(); - x = pop(); - state = pop(); - resId = pop(); - push(_wiz->getWizPixelColor(resId, state, x, y, 0)); - break; - case 100: - h = pop(); - w = pop(); - y = pop(); - x = pop(); - state = pop(); - resId = pop(); - if (x == -1 && y == -1 && w == -1 && h == -1) { - _wiz->getWizImageDim(resId, state, w, h); - x = 0; - y = 0; - } - push(computeWizHistogram(resId, state, x, y, w, h)); - break; - case 109: - pop(); - pop(); - push(0); - break; - case 111: - pop(); - copyScriptString(filename, sizeof(filename)); - pop(); - push(0); - debug(0, "o90_getWizData() case 111 unhandled"); - break; - default: - error("o90_getWizData: Unknown case %d", subOp); - } -} - -void ScummEngine_v90he::o90_floodFill() { - byte subOp = fetchScriptByte(); - subOp -= 54; - - switch (subOp) { - case 0: - pop(); - break; - case 3: - memset(&_floodFillParams, 0, sizeof(_floodFillParams)); - _floodFillParams.box.left = 0; - _floodFillParams.box.top = 0; - _floodFillParams.box.right = 639; - _floodFillParams.box.bottom = 479; - break; - case 11: - _floodFillParams.y = pop(); - _floodFillParams.x = pop(); - break; - case 12: - _floodFillParams.flags = pop(); - break; - case 13: - _floodFillParams.box.bottom = pop(); - _floodFillParams.box.right = pop(); - _floodFillParams.box.top = pop(); - _floodFillParams.box.left = pop(); - break; - case 201: - floodFill(&_floodFillParams, this); - break; - default: - error("o90_floodFill: Unknown case %d", subOp); - } -} - -void ScummEngine_v90he::o90_shl() { - int a = pop(); - push(pop() << a); -} - -void ScummEngine_v90he::o90_shr() { - int a = pop(); - push(pop() >> a); -} - -void ScummEngine_v90he::o90_xor() { - int a = pop(); - push(pop() ^ a); -} - -void ScummEngine_v90he::o90_mod() { - int a = pop(); - if (a == 0) - error("modulus by zero"); - push(pop() % a); -} - -void ScummEngine_v90he::o90_findAllObjectsWithClassOf() { - int args[16]; - int cond, num, cls, tmp; - bool b; - - num = getStackList(args, ARRAYSIZE(args)); - int room = pop(); - int numObjs = 0; - - if (room != _currentRoom) - error("o90_findAllObjectsWithClassOf: current room is not %d", room); - - writeVar(0, 0); - defineArray(0, kDwordArray, 0, 0, 0, _numLocalObjects); - for (int i = 1; i < _numLocalObjects; i++) { - cond = 1; - tmp = num; - while (--tmp >= 0) { - cls = args[tmp]; - b = getClass(_objs[i].obj_nr, cls); - if ((cls & 0x80 && !b) || (!(cls & 0x80) && b)) - cond = 0; - } - - if (cond) { - numObjs++; - writeArray(0, 0, numObjs, _objs[i].obj_nr); - } - } - - writeArray(0, 0, 0, numObjs); - - push(readVar(0)); -} - -void ScummEngine_v90he::o90_getPolygonOverlap() { - int args1[32]; - int args2[32]; - - int n1 = getStackList(args1, ARRAYSIZE(args1)); - int n2 = getStackList(args2, ARRAYSIZE(args2)); - - int subOp = pop(); - - switch (subOp) { - case 1: - { - Common::Rect r(args1[0], args1[1], args1[2] + 1, args1[3] + 1); - Common::Point p(args2[0], args2[1]); - push(r.contains(p) ? 1 : 0); - } - break; - case 2: - { - int dx = args2[0] - args1[0]; - int dy = args2[1] - args1[1]; - int dist = dx * dx + dy * dy; - if (dist >= 2) { - dist = (int)sqrt((double)(dist + 1)); - } - if (_heversion >= 98) { - push((dist <= args1[2]) ? 1 : 0); - } else { - push((dist > args1[2]) ? 1 : 0); - } - } - break; - case 3: - { - Common::Rect r1(args1[0], args1[1], args1[2] + 1, args1[3] + 1); - Common::Rect r2(args2[0], args2[1], args2[2] + 1, args2[3] + 1); - push(r2.intersects(r1) ? 1 : 0); - } - break; - case 4: - { - int dx = args2[0] - args1[0]; - int dy = args2[1] - args1[1]; - int dist = dx * dx + dy * dy; - if (dist >= 2) { - dist = (int)sqrt((double)(dist + 1)); - } - push((dist < args1[2] && dist < args2[2]) ? 1 : 0); - } - break; - case 5: - { - assert((n1 & 1) == 0); - n1 /= 2; - if (n1 == 0) { - push(0); - } else { - WizPolygon wp; - memset(&wp, 0, sizeof(wp)); - wp.numVerts = n1; - assert(n1 < ARRAYSIZE(wp.vert)); - for (int i = 0; i < n1; ++i) { - wp.vert[i].x = args1[i * 2 + 0]; - wp.vert[i].y = args1[i * 2 + 1]; - } - push(_wiz->polygonContains(wp, args2[0], args2[1]) ? 1 : 0); - } - } - break; - // HE 98+ - case 6: - { - Common::Rect r1, r2; - _sprite->getSpriteBounds(args2[0], false, r2); - _sprite->getSpriteBounds(args1[0], false, r1); - if (r2.isValidRect() == false) { - push(0); - break; - } - - if (n2 == 3) { - r2.left += args2[1]; - r2.right += args2[1]; - r2.top += args2[2]; - r2.bottom += args2[2]; - } - if (n1 == 3) { - r1.left += args1[1]; - r1.right += args1[1]; - r1.top += args1[2]; - r1.bottom += args1[2]; - } - push(r2.intersects(r1) ? 1 : 0); - } - break; - case 7: - { - Common::Rect r2; - _sprite->getSpriteBounds(args2[0], false, r2); - Common::Rect r1(args1[0], args1[1], args1[2], args1[3]); - if (r2.isValidRect() == false) { - push(0); - break; - } - - if (n2 == 3) { - r2.left += args2[1]; - r2.right += args2[1]; - r2.top += args2[2]; - r2.bottom += args2[2]; - } - push(r2.intersects(r1) ? 1 : 0); - } - break; - case 8: - case 10: // TODO: Draw sprites to buffer and compare. - { - Common::Rect r1, r2; - _sprite->getSpriteBounds(args2[0], true, r2); - _sprite->getSpriteBounds(args1[0], true, r1); - if (r2.isValidRect() == false) { - push(0); - break; - } - - if (n2 == 3) { - r2.left += args2[1]; - r2.right += args2[1]; - r2.top += args2[2]; - r2.bottom += args2[2]; - } - if (n1 == 3) { - r1.left += args1[1]; - r1.right += args1[1]; - r1.top += args1[2]; - r1.bottom += args1[2]; - } - push(r2.intersects(r1) ? 1 : 0); - } - break; - case 9: - { - Common::Rect r2; - _sprite->getSpriteBounds(args2[0], true, r2); - Common::Rect r1(args1[0], args1[1], args1[2], args1[3]); - if (r2.isValidRect() == false) { - push(0); - break; - } - - if (n2 == 3) { - r2.left += args2[1]; - r2.right += args2[1]; - r2.top += args2[2]; - r2.bottom += args2[2]; - } - push(r2.intersects(r1) ? 1 : 0); - } - break; - default: - error("o90_getPolygonOverlap: default case %d", subOp); - } -} - -void ScummEngine_v90he::o90_cond() { - int a = pop(); - int b = pop(); - int c = pop(); - - if (!c) - b = a; - push(b); -} - -void ScummEngine_v90he::o90_dim2dim2Array() { - int data, dim1start, dim1end, dim2start, dim2end; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 2: // SO_BIT_ARRAY - data = kBitArray; - break; - case 3: // SO_NIBBLE_ARRAY - data = kNibbleArray; - break; - case 4: // SO_BYTE_ARRAY - data = kByteArray; - break; - case 5: // SO_INT_ARRAY - data = kIntArray; - break; - case 6: - data = kDwordArray; - break; - case 7: // SO_STRING_ARRAY - data = kStringArray; - break; - default: - error("o90_dim2dim2Array: default case %d", subOp); - } - - if (pop() == 2) { - dim1end = pop(); - dim1start = pop(); - dim2end = pop(); - dim2start = pop(); - } else { - dim2end = pop(); - dim2start = pop(); - dim1end = pop(); - dim1start = pop(); - } - - defineArray(fetchScriptWord(), data, dim2start, dim2end, dim1start, dim1end); -} - -void ScummEngine_v90he::o90_redim2dimArray() { - int a, b, c, d; - d = pop(); - c = pop(); - b = pop(); - a = pop(); - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 4: - redimArray(fetchScriptWord(), a, b, c, d, kByteArray); - break; - case 5: - redimArray(fetchScriptWord(), a, b, c, d, kIntArray); - break; - case 6: - redimArray(fetchScriptWord(), a, b, c, d, kDwordArray); - break; - default: - error("o90_redim2dimArray: default type %d", subOp); - } -} - -void ScummEngine_v90he::o90_getLinesIntersectionPoint() { - int var_ix = fetchScriptWord(); - int var_iy = fetchScriptWord(); - int line2_y2 = pop(); - int line2_x2 = pop(); - int line2_y1 = pop(); - int line2_x1 = pop(); - int line1_y2 = pop(); - int line1_x2 = pop(); - int line1_y1 = pop(); - int line1_x1 = pop(); - - int result = 0; - int ix = 0; - int iy = 0; - - bool isLine1Point = (line1_x1 == line1_x2 && line1_y1 == line1_y2); - bool isLine2Point = (line2_x1 == line2_x2 && line2_y1 == line2_y2); - - if (isLine1Point) { - if (isLine2Point) { - if (line1_x1 == line2_x1 && line1_y1 == line2_y2) { - ix = line1_x1; - iy = line2_x1; - result = 1; - } - } else { - // 1 point and 1 line - int dx2 = line2_x2 - line2_x1; - if (dx2 != 0) { - int dy2 = line2_y2 - line2_y1; - float y = (float)dy2 / dx2 * (line1_x1 - line2_x1) + line2_y1 + .5f; - if (line1_y1 == (int)y) { - ix = line1_x1; - iy = line1_y1; - result = 1; - } - } else { - // vertical line - if (line1_x1 == line2_x1) { - if (line2_y1 > line2_y2) { - if (line1_y1 >= line2_y2 && line1_y1 <= line2_y1) { - ix = line1_x1; - iy = line1_y1; - result = 1; - } - } else { - if (line1_y1 >= line2_y1 && line1_y1 <= line2_y2) { - ix = line1_x1; - iy = line1_y1; - result = 1; - } - } - } - } - } - } else { - if (isLine2Point) { - // 1 point and 1 line - int dx1 = line1_x2 - line1_x1; - if (dx1 != 0) { - int dy1 = line1_y2 - line1_y1; - float y = (float)dy1 / dx1 * (line2_x1 - line1_x1) + line1_y1 + .5f; - if (line2_y1 == (int)y) { - ix = line2_x1; - iy = line2_y1; - result = 1; - } - } else { - // vertical line - if (line2_x1 == line1_x1) { - if (line1_y1 > line1_y2) { - if (line2_y1 >= line1_y2 && line2_y1 <= line1_y1) { - ix = line2_x1; - iy = line2_y1; - result = 1; - } - } else { - if (line2_y1 >= line1_y1 && line2_y1 <= line1_y2) { - ix = line2_x2; - iy = line2_y1; - result = 1; - } - } - } - } - } else { - // 2 lines - int dy1 = line1_y2 - line1_y1; - int dx1 = line1_x2 - line1_x1; - int dy2 = line2_y2 - line2_y1; - int dx2 = line2_x2 - line2_x1; - int det = dx1 * dy2 - dx2 * dy1; - int cross_p1 = dx1 * (line1_y1 - line2_y1) - dy1 * (line1_x1 - line2_x1); - int cross_p2 = dx2 * (line1_y1 - line2_y1) - dy2 * (line1_x1 - line2_x1); - if (det == 0) { - // parallel lines - if (cross_p2 == 0) { - ix = ABS(line2_x2 + line2_x1) / 2; - iy = ABS(line2_y2 + line2_y1) / 2; - result = 2; - } - } else { - float rcp1 = (float)cross_p1 / det; - float rcp2 = (float)cross_p2 / det; - if (rcp1 >= 0 && rcp1 <= 1 && rcp2 >= 0 && rcp2 <= 1) { - ix = (int)(dx1 * rcp2 + line1_x1 + .5f); - iy = (int)(dy1 * rcp2 + line1_y1 + .5f); - result = 1; - } - } - } - } - - writeVar(var_ix, ix); - writeVar(var_iy, iy); - push(result); -} - -void ScummEngine_v90he::getArrayDim(int array, int *dim2start, int *dim2end, int *dim1start, int *dim1end) { - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array)); - assert(ah); - if (dim2start && *dim2start == -1) { - *dim2start = ah->dim2start; - } - if (dim2end && *dim2end == -1) { - *dim2end = ah->dim2end; - } - if (dim1start && *dim1start == -1) { - *dim1start = ah->dim1start; - } - if (dim1end && *dim1end == -1) { - *dim1end = ah->dim1end; - } -} - -static int sortArrayOffset; - -static int compareByteArray(const void *a, const void *b) { - int va = *((const uint8 *)a + sortArrayOffset); - int vb = *((const uint8 *)a + sortArrayOffset); - return va - vb; -} - -static int compareByteArrayReverse(const void *a, const void *b) { - int va = *((const uint8 *)a + sortArrayOffset); - int vb = *((const uint8 *)a + sortArrayOffset); - return vb - va; -} - -static int compareIntArray(const void *a, const void *b) { - int va = (int16)READ_LE_UINT16((const uint8 *)a + sortArrayOffset * 2); - int vb = (int16)READ_LE_UINT16((const uint8 *)b + sortArrayOffset * 2); - return va - vb; -} - -static int compareIntArrayReverse(const void *a, const void *b) { - int va = (int16)READ_LE_UINT16((const uint8 *)a + sortArrayOffset * 2); - int vb = (int16)READ_LE_UINT16((const uint8 *)b + sortArrayOffset * 2); - return vb - va; -} - -static int compareDwordArray(const void *a, const void *b) { - int va = (int32)READ_LE_UINT32((const uint8 *)a + sortArrayOffset * 4); - int vb = (int32)READ_LE_UINT32((const uint8 *)b + sortArrayOffset * 4); - return va - vb; -} - -static int compareDwordArrayReverse(const void *a, const void *b) { - int va = (int32)READ_LE_UINT32((const uint8 *)a + sortArrayOffset * 4); - int vb = (int32)READ_LE_UINT32((const uint8 *)b + sortArrayOffset * 4); - return vb - va; -} - -void ScummEngine_v90he::sortArray(int array, int dim2start, int dim2end, int dim1start, int dim1end, int sortOrder) { - debug(9, "sortArray(%d, [%d,%d,%d,%d], %d)", array, dim2start, dim2end, dim1start, dim1end, sortOrder); - - assert(dim1start == dim1end); - checkArrayLimits(array, dim2start, dim2end, dim1start, dim1end); - ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array)); - assert(ah); - - const int num = dim2end - dim2start + 1; - const int pitch = FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1; - const int offset = pitch * (dim2start - FROM_LE_32(ah->dim2start)); - sortArrayOffset = dim1start - FROM_LE_32(ah->dim1start); - - switch (FROM_LE_32(ah->type)) { - case kByteArray: - case kStringArray: - if (sortOrder <= 0) { - qsort(ah->data + offset, num, pitch, compareByteArray); - } else { - qsort(ah->data + offset, num, pitch, compareByteArrayReverse); - } - break; - case kIntArray: - if (sortOrder <= 0) { - qsort(ah->data + offset * 2, num, pitch * 2, compareIntArray); - } else { - qsort(ah->data + offset * 2, num, pitch * 2, compareIntArrayReverse); - } - break; - case kDwordArray: - if (sortOrder <= 0) { - qsort(ah->data + offset * 4, num, pitch * 4, compareDwordArray); - } else { - qsort(ah->data + offset * 4, num, pitch * 4, compareDwordArrayReverse); - } - break; - default: - error("Invalid array type", FROM_LE_32(ah->type)); - } -} - -void ScummEngine_v90he::o90_sortArray() { - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 129: - case 134: // HE100 - { - int array = fetchScriptWord(); - int sortOrder = pop(); - int dim1end = pop(); - int dim1start = pop(); - int dim2end = pop(); - int dim2start = pop(); - getArrayDim(array, &dim2start, &dim2end, &dim1start, &dim1end); - sortArray(array, dim2start, dim2end, dim1start, dim1end, sortOrder); - } - break; - default: - error("o90_sortArray: Unknown case %d", subOp); - } -} - -void ScummEngine_v90he::o90_getObjectData() { - byte subOp = fetchScriptByte(); - subOp -= 32; - - switch (subOp) { - case 0: - if (_heObjectNum == -1) - push(0); - else - push(_objs[_heObjectNum].width); - break; - case 1: - if (_heObjectNum == -1) - push(0); - else - push(_objs[_heObjectNum].height); - break; - case 4: - push(getObjectImageCount(_heObject)); - break; - case 6: - if (_heObjectNum == -1) - push(0); - else - push(_objs[_heObjectNum].x_pos); - break; - case 7: - if (_heObjectNum == -1) - push(0); - else - push(_objs[_heObjectNum].y_pos); - break; - case 20: - push(getState(_heObject)); - break; - case 25: - _heObject = pop(); - _heObjectNum = getObjectIndex(_heObject); - break; - case 107: - // Dummy case - pop(); - push(0); - break; - default: - error("o90_getObjectData: Unknown case %d", subOp); - } -} - -void ScummEngine_v90he::o90_getPaletteData() { - int b, c, d, e; - int palSlot, color; - - byte subOp = fetchScriptByte(); - subOp -= 45; - - switch (subOp) { - case 0: - e = pop(); - d = pop(); - palSlot = pop(); - pop(); - c = pop(); - b = pop(); - push(getHEPaletteSimilarColor(palSlot, b, c, d, e)); - break; - case 7: - c = pop(); - b = pop(); - palSlot = pop(); - push(getHEPaletteColorComponent(palSlot, b, c)); - break; - case 21: - color = pop(); - palSlot = pop(); - push(getHEPaletteColor(palSlot, color)); - break; - case 87: - c = pop(); - b = pop(); - push(getHEPaletteColorComponent(1, b, c)); - break; - case 172: - pop(); - c = pop(); - c = MAX(0, c); - c = MIN(c, 255); - b = pop(); - b = MAX(0, b); - b = MIN(b, 255); - push(getHEPaletteSimilarColor(1, b, c, 10, 245)); - break; - default: - error("o90_getPaletteData: Unknown case %d", subOp); - } -} - -void ScummEngine_v90he::o90_paletteOps() { - int a, b, c, d, e; - - byte subOp = fetchScriptByte(); - subOp -= 57; - - switch (subOp) { - case 0: - _hePaletteNum = pop(); - break; - case 6: - b = pop(); - a = pop(); - if (_hePaletteNum != 0) { - setHEPaletteFromImage(_hePaletteNum, a, b); - } - break; - case 9: - e = pop(); - d = pop(); - c = pop(); - b = pop(); - a = pop(); - if (_hePaletteNum != 0) { - for (; a <= b; ++a) { - setHEPaletteColor(_hePaletteNum, a, c, d, e); - } - } - break; - case 13: - c = pop(); - b = pop(); - a = pop(); - if (_hePaletteNum != 0) { - for (; a <= b; ++a) { - copyHEPaletteColor(_hePaletteNum, a, c); - } - } - break; - case 19: //HE99+ - a = pop(); - if (_hePaletteNum != 0) { - setHEPaletteFromCostume(_hePaletteNum, a); - } - break; - case 29: - a = pop(); - if (_hePaletteNum != 0) { - copyHEPalette(_hePaletteNum, a); - } - break; - case 118: - b = pop(); - a = pop(); - if (_hePaletteNum != 0) { - setHEPaletteFromRoom(_hePaletteNum, a, b); - } - break; - case 160: - if (_hePaletteNum != 0) { - restoreHEPalette(_hePaletteNum); - } - break; - case 198: - _hePaletteNum = 0; - break; - default: - error("o90_paletteOps: Unknown case %d", subOp); - } -} - -void ScummEngine_v90he::o90_fontUnk() { - // Font related - byte string[80]; - int a; - - byte subOp = fetchScriptByte(); - - switch (subOp) { - case 60: // HE100 - case 42: - a = pop(); - if (a == 2) { - copyScriptString(string, sizeof(string)); - push(-1); - } else if (a == 1) { - pop(); - writeVar(0, 0); - defineArray(0, kStringArray, 0, 0, 0, 0); - writeArray(0, 0, 0, 0); - push(readVar(0)); - } - break; - case 0: // HE100 - case 57: - push(1); - break; - default: - error("o90_fontUnk: Unknown case %d", subOp); - } - - debug(1, "o90_fontUnk stub (%d)", subOp); -} - -void ScummEngine_v90he::o90_getActorAnimProgress() { - Actor *a = derefActor(pop(), "o90_getActorAnimProgress"); - push(a->getAnimProgress()); -} - -void ScummEngine_v90he::o90_kernelGetFunctions() { - int args[29]; - int num, tmp; - Actor *a; - - num = getStackList(args, ARRAYSIZE(args)); - - switch (args[0]) { - case 1001: - { - double b = args[1] * PI / 180.; - push((int)(sin(b) * 100000)); - } - break; - case 1002: - { - double b = args[1] * PI / 180.; - push((int)(cos(b) * 100000)); - } - break; - case 1969: - a = derefActor(args[1], "o90_kernelGetFunctions: 1969"); - tmp = a->_heCondMask; - tmp &= 0x7FFF0000; - push(tmp); - break; - case 2001: - push(_logicHE->dispatch(args[1], num - 2, (int32 *)&args[2])); - break; - default: - error("o90_kernelGetFunctions: default case %d", args[0]); - } -} - -void ScummEngine_v90he::o90_kernelSetFunctions() { - int args[29]; - int num, tmp; - Actor *a; - - num = getStackList(args, ARRAYSIZE(args)); - - switch (args[0]) { - case 20: - a = derefActor(args[1], "o90_kernelSetFunctions: 20"); - queueAuxBlock(a); - break; - case 21: - _skipDrawObject = 1; - break; - case 22: - _skipDrawObject = 0; - break; - case 23: - _charset->clearCharsetMask(); - _fullRedraw = true; - break; - case 24: - _skipProcessActors = 1; - redrawAllActors(); - break; - case 25: - _skipProcessActors = 0; - redrawAllActors(); - break; - case 27: - // Used in readdemo - break; - case 42: - _wiz->_rectOverrideEnabled = true; - _wiz->_rectOverride.left = args[1]; - _wiz->_rectOverride.top = args[2]; - _wiz->_rectOverride.right = args[3]; - _wiz->_rectOverride.bottom = args[4]; - break; - case 43: - _wiz->_rectOverrideEnabled = false; - break; - case 714: - debug(5, "o90_kernelSetFunctions: case 714: type %d resId %d unk1 %d", args[1], args[2], args[3]); - break; - case 1492: - // Remote start script function - break; - case 1969: - a = derefActor(args[1], "o90_kernelSetFunctions: 1969"); - tmp = a->_heCondMask; - tmp ^= args[2]; - tmp &= 0x7FFF0000; - a->_heCondMask ^= tmp; - break; - case 2001: - _logicHE->dispatch(args[1], num - 2, (int32 *)&args[2]); - break; - default: - error("o90_kernelSetFunctions: default case %d (param count %d)", args[0], num); - } -} - -} // End of namespace Scumm diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 11bfc096c4..3f9d1ea877 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -44,17 +44,17 @@ #include "scumm/imuse_digi/dimuse.h" #include "scumm/insane/insane.h" #include "scumm/intern.h" -#include "scumm/intern_he.h" -#include "scumm/logic_he.h" +#include "scumm/he/intern_he.h" +#include "scumm/he/logic_he.h" #include "scumm/player_nes.h" #include "scumm/player_v1.h" #include "scumm/player_v2.h" #include "scumm/player_v2a.h" #include "scumm/player_v3a.h" -#include "scumm/resource_v7he.h" +#include "scumm/he/resource_v7he.h" #include "scumm/scumm.h" #include "scumm/sound.h" -#include "scumm/sprite_he.h" +#include "scumm/he/sprite_he.h" #include "scumm/util.h" #ifdef PALMOS_68K diff --git a/engines/scumm/sound_he.cpp b/engines/scumm/sound_he.cpp deleted file mode 100644 index 879e34a99e..0000000000 --- a/engines/scumm/sound_he.cpp +++ /dev/null @@ -1,516 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" -#include "scumm/actor.h" -#include "scumm/imuse.h" -#include "scumm/scumm.h" -#include "scumm/sound.h" -#include "scumm/util.h" - -#include "common/config-manager.h" -#include "common/timer.h" -#include "common/util.h" - -#include "sound/adpcm.h" -#include "sound/audiocd.h" -#include "sound/flac.h" -#include "sound/mididrv.h" -#include "sound/mixer.h" -#include "sound/mp3.h" -#include "sound/voc.h" -#include "sound/vorbis.h" -#include "sound/wave.h" - -namespace Scumm { - -int Sound::findFreeSoundChannel() { - int chan, min; - - min = _vm->VAR(_vm->VAR_RESERVED_SOUND_CHANNELS); - if (min == 0) { - _vm->VAR(_vm->VAR_RESERVED_SOUND_CHANNELS) = 8; - return 1; - } - - if (min < 8) { - for (chan = min; chan < ARRAYSIZE(_heChannel); chan++) { - if (_vm->_mixer->isSoundHandleActive(_heSoundChannels[chan]) == 0) - return chan; - } - } else { - return 1; - } - - return min; -} - -int Sound::isSoundCodeUsed(int sound) { - int chan = -1; - for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) { - if (_heChannel[i].sound == sound) - chan = i; - } - - if (chan != -1) { - return _heChannel[chan].sbngBlock; - } else { - return 0; - } -} - -int Sound::getSoundPos(int sound) { - int chan = -1; - for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) { - if (_heChannel[i].sound == sound) - chan = i; - } - - if (chan != -1) { - int time = _vm->getHETimer(chan + 4) * 11025 / 1000; - return time; - } else { - return 0; - } -} - -int Sound::getSoundVar(int sound, int var) { - if (_vm->_heversion >= 90 && var == 26) { - return isSoundCodeUsed(sound); - } - - checkRange(25, 0, var, "Illegal sound variable %d"); - - int chan = -1; - for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) { - if (_heChannel[i].sound == sound) - chan = i; - } - - if (chan != -1) { - debug(5, "getSoundVar: sound %d var %d result %d", sound, var, _heChannel[chan].soundVars[var]); - return _heChannel[chan].soundVars[var]; - } else { - return 0; - } -} - -void Sound::setSoundVar(int sound, int var, int val) { - checkRange(25, 0, var, "Illegal sound variable %d"); - - int chan = -1; - for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) { - if (_heChannel[i].sound == sound) - chan = i; - } - - if (chan != -1) { - debug(5, "setSoundVar: sound %d var %d val %d", sound, var, val); - _heChannel[chan].soundVars[var] = val; - } -} - -void Sound::setOverrideFreq(int freq) { - _overrideFreq = freq; -} - -void Sound::setupHEMusicFile() { - int i, total_size; - char buf[32], buf1[128]; - Common::File musicFile; - - sprintf(buf, "%s.he4", _vm->getBaseName()); - - if (_vm->_substResFileNameIndex > 0) { - _vm->generateSubstResFileName(buf, buf1, sizeof(buf1)); - strcpy(buf, buf1); - } - if (musicFile.open(buf) == true) { - musicFile.seek(4, SEEK_SET); - total_size = musicFile.readUint32BE(); - musicFile.seek(16, SEEK_SET); - _heMusicTracks = musicFile.readUint32LE(); - debug(5, "Total music tracks %d", _heMusicTracks); - - int musicStart = (_vm->_heversion >= 80) ? 56 : 20; - musicFile.seek(musicStart, SEEK_SET); - - _heMusic = (HEMusic *)malloc((_heMusicTracks + 1) * sizeof(HEMusic)); - for (i = 0; i < _heMusicTracks; i++) { - _heMusic[i].id = musicFile.readUint32LE(); - _heMusic[i].offset = musicFile.readUint32LE(); - _heMusic[i].size = musicFile.readUint32LE(); - - if (_vm->_heversion >= 80) { - musicFile.seek(+9, SEEK_CUR); - } else { - musicFile.seek(+13, SEEK_CUR); - } - } - - musicFile.close(); - } -} - -bool Sound::getHEMusicDetails(int id, int &musicOffs, int &musicSize) { - int i; - - for (i = 0; i < _heMusicTracks; i++) { - if (_heMusic[i].id == id) { - musicOffs = _heMusic[i].offset; - musicSize = _heMusic[i].size; - return 1; - } - } - - return 0; -} - -void Sound::processSoundCode() { - byte *codePtr; - int chan, tmr, size, time; - - for (chan = 0; chan < ARRAYSIZE(_heChannel); chan++) { - if (_heChannel[chan].sound == 0) { - continue; - } - - if (_heChannel[chan].codeOffs == -1) { - continue; - } - - tmr = _vm->getHETimer(chan + 4) * 11025 / 1000; - tmr += _vm->VAR(_vm->VAR_SOUNDCODE_TMR); - if (tmr < 0) - tmr = 0; - - if (_heChannel[chan].sound > _vm->_numSounds) { - codePtr = _vm->getResourceAddress(rtSpoolBuffer, chan); - } else { - codePtr = _vm->getResourceAddress(rtSound, _heChannel[chan].sound); - } - assert(codePtr); - codePtr += _heChannel[chan].codeOffs; - - while(1) { - size = READ_LE_UINT16(codePtr); - time = READ_LE_UINT32(codePtr + 2); - - if (size == 0) { - _heChannel[chan].codeOffs = -1; - break; - } - - debug(5, "Channel %d Timer %d Time %d", chan, tmr, time); - if (time >= tmr) - break; - - processSoundOpcodes(_heChannel[chan].sound, codePtr + 6, _heChannel[chan].soundVars); - - codePtr += size; - _heChannel[chan].codeOffs += size; - } - } -} - -void Sound::processSoundOpcodes(int sound, byte *codePtr, int *soundVars) { - int arg, opcode, var, val; - - while(READ_LE_UINT16(codePtr) != 0) { - codePtr += 2; - opcode = READ_LE_UINT16(codePtr); codePtr += 2; - opcode = (opcode & 0xFFF) >> 4; - arg = opcode & 3; - opcode &= ~3; - debug(5, "processSoundOpcodes: sound %d opcode %d", sound, opcode); - switch (opcode) { - case 0: // Continue - break; - case 16: // Set talk state - val = READ_LE_UINT16(codePtr); codePtr += 2; - setSoundVar(sound, 19, val); - break; - case 32: // Set var - var = READ_LE_UINT16(codePtr); codePtr += 2; - val = READ_LE_UINT16(codePtr); codePtr += 2; - if (arg == 2) { - val = getSoundVar(sound, val); - } - setSoundVar(sound, var, val); - break; - case 48: // Add - var = READ_LE_UINT16(codePtr); codePtr += 2; - val = READ_LE_UINT16(codePtr); codePtr += 2; - if (arg == 2) { - val = getSoundVar(sound, val); - } - val = getSoundVar(sound, var) + val; - setSoundVar(sound, var, val); - break; - case 56: // Subtract - var = READ_LE_UINT16(codePtr); codePtr += 2; - val = READ_LE_UINT16(codePtr); codePtr += 2; - if (arg == 2) { - val = getSoundVar(sound, val); - } - val = getSoundVar(sound, var) - val; - setSoundVar(sound, var, val); - break; - case 64: // Multiple - var = READ_LE_UINT16(codePtr); codePtr += 2; - val = READ_LE_UINT16(codePtr); codePtr += 2; - if (arg == 2) { - val = getSoundVar(sound, val); - } - val = getSoundVar(sound, var) * val; - setSoundVar(sound, var, val); - break; - case 80: // Divide - var = READ_LE_UINT16(codePtr); codePtr += 2; - val = READ_LE_UINT16(codePtr); codePtr += 2; - if (arg == 2) { - val = getSoundVar(sound, val); - } - val = getSoundVar(sound, var) / val; - setSoundVar(sound, var, val); - break; - case 96: // Increment - var = READ_LE_UINT16(codePtr); codePtr += 2; - val = getSoundVar(sound, var) + 1; - setSoundVar(sound, var, val); - break; - case 104: // Decrement - var = READ_LE_UINT16(codePtr); codePtr += 2; - val = getSoundVar(sound, var) - 1; - setSoundVar(sound, var, val); - break; - default: - error("Illegal sound %d opcode %d", sound, opcode); - } - } -} - -void Sound::playHESound(int soundID, int heOffset, int heChannel, int heFlags) { - byte *ptr, *spoolPtr; - char *sound; - int size = -1; - int priority, rate; - byte flags = Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE; - - if (heChannel == -1) - heChannel = (_vm->VAR_RESERVED_SOUND_CHANNELS != 0xFF) ? findFreeSoundChannel() : 1; - - debug(5,"playHESound: soundID %d heOffset %d heChannel %d heFlags %d", soundID, heOffset, heChannel, heFlags); - - if (soundID >= 10000) { - // Special codes, used in pjgames - return; - } - - if (soundID > _vm->_numSounds) { - int music_offs; - char buf[32], buf1[128]; - Common::File musicFile; - - sprintf(buf, "%s.he4", _vm->getBaseName()); - - if (_vm->_substResFileNameIndex > 0) { - _vm->generateSubstResFileName(buf, buf1, sizeof(buf1)); - strcpy(buf, buf1); - } - if (musicFile.open(buf) == false) { - warning("playSound: Can't open music file %s", buf); - return; - } - if (!getHEMusicDetails(soundID, music_offs, size)) { - debug(0, "playSound: musicID %d not found", soundID); - return; - } - - musicFile.seek(music_offs, SEEK_SET); - - if (_vm->_heversion == 70) { - spoolPtr = (byte *)malloc(size); - musicFile.read(spoolPtr, size); - } else { - spoolPtr = _vm->res.createResource(rtSpoolBuffer, heChannel, size); - assert(spoolPtr); - musicFile.read(spoolPtr, size); - } - musicFile.close(); - - if (_vm->_heversion == 70) { - _vm->_mixer->stopHandle(_heSoundChannels[heChannel]); - _vm->_mixer->playRaw(&_heSoundChannels[heChannel], spoolPtr, size, 11025, flags, soundID); - return; - } - } - - if (soundID > _vm->_numSounds) { - ptr = _vm->getResourceAddress(rtSpoolBuffer, heChannel); - } else { - ptr = _vm->getResourceAddress(rtSound, soundID); - } - - if (!ptr) { - return; - } - - // TODO: Extra sound flags - if (heFlags & 1) { - flags |= Audio::Mixer::FLAG_LOOP; - } - - // Support for sound in later Backyard sports games - if (READ_UINT32(ptr) == MKID('RIFF') || READ_UINT32(ptr) == MKID('WSOU')) { - uint16 type; - int blockAlign; - - if (READ_UINT32(ptr) == MKID('WSOU')) - ptr += 8; - - size = READ_LE_UINT32(ptr + 4); - Common::MemoryReadStream stream(ptr, size); - - if (!loadWAVFromStream(stream, size, rate, flags, &type, &blockAlign)) { - error("playSound: Not a valid WAV file"); - } - - if (type == 17) { - AudioStream *voxStream = new ADPCMInputStream(&stream, size, kADPCMIma, (flags & Audio::Mixer::FLAG_STEREO) ? 2 : 1, blockAlign); - - sound = (char *)malloc(size * 4); - size = voxStream->readBuffer((int16*)sound, size * 2); - size *= 2; // 16bits. - delete voxStream; - } else { - // Allocate a sound buffer, copy the data into it, and play - sound = (char *)malloc(size); - memcpy(sound, ptr + stream.pos(), size); - } - _vm->_mixer->stopHandle(_heSoundChannels[heChannel]); - _vm->_mixer->playRaw(&_heSoundChannels[heChannel], sound, size, rate, flags, soundID); - } - // Support for sound in Humongous Entertainment games - else if (READ_UINT32(ptr) == MKID('DIGI') || READ_UINT32(ptr) == MKID('TALK')) { - byte *sndPtr = ptr; - - priority = (soundID > _vm->_numSounds) ? 255 : *(ptr + 18); - rate = READ_LE_UINT16(ptr + 22); - ptr += 8 + READ_BE_UINT32(ptr + 12); - - if (_vm->_mixer->isSoundHandleActive(_heSoundChannels[heChannel])) { - int curSnd = _heChannel[heChannel].sound; - if (curSnd == 1 && soundID != 1) - return; - if (curSnd != 0 && curSnd != 1 && soundID != 1 && _heChannel[heChannel].priority > priority) - return; - } - - int codeOffs = -1; - if (READ_UINT32(ptr) == MKID('SBNG')) { - codeOffs = ptr - sndPtr + 8; - ptr += READ_BE_UINT32(ptr + 4); - } - - assert(READ_UINT32(ptr) == MKID('SDAT')); - size = READ_BE_UINT32(ptr+4) - 8; - if (heOffset < 0 || heOffset > size) { - // Occurs when making fireworks in puttmoon - debug(0, "playSound: Invalid sound offset (offset %d, size %d) in sound %d", heOffset, size, soundID); - heOffset = 0; - } - size -= heOffset; - - if (_overrideFreq) { - // Used by the piano in Fatty Bear's Birthday Surprise - rate = _overrideFreq; - _overrideFreq = 0; - } - - // Allocate a sound buffer, copy the data into it, and play - sound = (char *)malloc(size); - memcpy(sound, ptr + heOffset + 8, size); - _vm->_mixer->stopHandle(_heSoundChannels[heChannel]); - _vm->_mixer->playRaw(&_heSoundChannels[heChannel], sound, size, rate, flags, soundID); - - _vm->setHETimer(heChannel + 4); - _heChannel[heChannel].sound = soundID; - _heChannel[heChannel].priority = priority; - _heChannel[heChannel].sbngBlock = (codeOffs != -1) ? 1 : 0; - _heChannel[heChannel].codeOffs = codeOffs; - memset(_heChannel[heChannel].soundVars, 0, sizeof(_heChannel[heChannel].soundVars)); - } - // Support for PCM music in 3DO versions of Humongous Entertainment games - else if (READ_UINT32(ptr) == MKID('MRAW')) { - priority = *(ptr + 18); - rate = READ_LE_UINT16(ptr + 22); - ptr += 8 + READ_BE_UINT32(ptr+12); - - assert(READ_UINT32(ptr) == MKID('SDAT')); - size = READ_BE_UINT32(ptr+4) - 8; - - flags = Audio::Mixer::FLAG_AUTOFREE; - - // Allocate a sound buffer, copy the data into it, and play - sound = (char *)malloc(size); - memcpy(sound, ptr + 8, size); - _vm->_mixer->stopID(_currentMusic); - _currentMusic = soundID; - _vm->_mixer->playRaw(NULL, sound, size, rate, flags, soundID); - } - else if (READ_UINT32(ptr) == MKID('MIDI')) { - if (_vm->_musicEngine) { - _vm->_musicEngine->startSound(soundID); - } - } -} - -void Sound::startHETalkSound(uint32 offset) { - byte *ptr; - int32 size; - - if (ConfMan.getBool("speech_mute")) - return; - - if (!_sfxFile->isOpen()) { - error("startHETalkSound: Speech file is not open"); - return; - } - - _sfxMode |= 2; - _vm->res.nukeResource(rtSound, 1); - - _sfxFile->seek(offset + 4, SEEK_SET); - size = _sfxFile->readUint32BE(); - _sfxFile->seek(offset, SEEK_SET); - - _vm->res.createResource(rtSound, 1, size); - ptr = _vm->getResourceAddress(rtSound, 1); - _sfxFile->read(ptr, size); - - int channel = (_vm->VAR_TALK_CHANNEL != 0xFF) ? _vm->VAR(_vm->VAR_TALK_CHANNEL) : 0; - addSoundToQueue2(1, 0, channel, 0); -} - -} // End of namespace Scumm diff --git a/engines/scumm/sprite_he.cpp b/engines/scumm/sprite_he.cpp deleted file mode 100644 index a6065eb7be..0000000000 --- a/engines/scumm/sprite_he.cpp +++ /dev/null @@ -1,1440 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" - -#include "scumm/intern_he.h" -#include "scumm/resource.h" -#include "scumm/saveload.h" -#include "scumm/scumm.h" -#include "scumm/sprite_he.h" -#include "scumm/usage_bits.h" -#include "scumm/util.h" -#include "scumm/wiz_he.h" - -namespace Scumm { - -Sprite::Sprite(ScummEngine_v90he *vm) : _vm(vm) { -} - -Sprite::~Sprite() { - free(_spriteGroups); - free(_spriteTable); - free(_activeSpritesTable); -} - -void ScummEngine_v90he::allocateArrays() { - ScummEngine::allocateArrays(); - _sprite->allocTables(_numSprites, MAX(64, _numSprites / 4), 64); -} - -void Sprite::getSpriteBounds(int spriteId, bool checkGroup, Common::Rect &bound) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - int32 spr_wiz_x, spr_wiz_y; - int angle, scale, x1, y1; - int32 w, h; - - SpriteInfo *spi = &_spriteTable[spriteId]; - - _vm->_wiz->getWizImageSpot(spi->image, spi->imageState, spr_wiz_x, spr_wiz_y); - if (checkGroup && spi->group) { - SpriteGroup *spg = &_spriteGroups[spi->group]; - - if (spg->scaling) { - x1 = spi->tx * spg->scale_x_ratio_mul / spg->scale_x_ratio_div - spr_wiz_x + spg->tx; - y1 = spi->ty * spg->scale_y_ratio_mul / spg->scale_y_ratio_div - spr_wiz_y + spg->ty; - } else { - x1 = spi->tx - spr_wiz_x + spg->tx; - y1 = spi->ty - spr_wiz_y + spg->ty; - } - } else { - x1 = spi->tx - spr_wiz_x; - y1 = spi->ty - spr_wiz_y; - } - - if (spi->image) { - angle = spi->angle; - scale = spi->scale; - _vm->_wiz->getWizImageDim(spi->image, spi->imageState, w, h); - if (spi->flags & (kSFScaled | kSFRotated)) { - Common::Point pts[4]; - _vm->_wiz->polygonTransform(spi->image, spi->imageState, x1, y1, angle, scale, pts); - _vm->_wiz->polygonCalcBoundBox(pts, 4, bound); - } else { - bound.left = x1; - bound.top = y1; - bound.right = x1 + w; - bound.bottom = y1 + h; - } - } else { - bound.left = 1234; - bound.top = 1234; - bound.right = -1234; - bound.bottom = -1234; - } -} - -// -// spriteInfoGet functions -// -int Sprite::findSpriteWithClassOf(int x_pos, int y_pos, int spriteGroupId, int type, int num, int *args) { - debug(2, "findSprite: x %d, y %d, spriteGroup %d, type %d, num %d", x_pos, y_pos, spriteGroupId, type, num); - Common::Point pos[1]; - bool cond; - int code, classId; - - for (int i = (_numSpritesToProcess - 1); i >= 0; i--) { - SpriteInfo *spi = _activeSpritesTable[i]; - if (!spi->curImage) - continue; - - if (spriteGroupId && spi->group != spriteGroupId) - continue; - - cond = true; - for (int j = 0; j < num; j++) { - code = classId = args[j]; - classId &= 0x7F; - checkRange(32, 1, classId, "class %d out of range in statement"); - if (code & 0x80) { - if (!(spi->classFlags & (1 << (classId - 1)))) - cond = 0; - } else { - if ((spi->classFlags & (1 << (classId - 1)))) - cond = 0; - } - } - if (!cond) - continue; - - if (type) { - if (spi->bbox.left > spi->bbox.right) - continue; - if (spi->bbox.top > spi->bbox.bottom) - continue; - if (spi->bbox.left > x_pos) - continue; - if (spi->bbox.top > y_pos) - continue; - if (spi->bbox.right < x_pos) - continue; - if (spi->bbox.bottom < y_pos) - continue; - return spi->id; - } else { - int image, imageState, angle, scale; - int32 w, h; - - image = spi->curImage; - if (spi->maskImage) { - int32 x1, x2, y1, y2; - - imageState = spi->curImageState % _vm->_wiz->getWizImageStates(spi->maskImage); - - pos[0].x = x_pos - spi->pos.x; - pos[0].y = y_pos - spi->pos.y; - - _vm->_wiz->getWizImageSpot(spi->curImage, imageState, x1, y1); - _vm->_wiz->getWizImageSpot(spi->maskImage, imageState, x2, y2); - - pos[0].x += (x2 - x1); - pos[0].y += (y2 - y1); - } else { - if (spi->bbox.left > spi->bbox.right) - continue; - if (spi->bbox.top > spi->bbox.bottom) - continue; - if (spi->bbox.left > x_pos) - continue; - if (spi->bbox.top > y_pos) - continue; - if (spi->bbox.right < x_pos) - continue; - if (spi->bbox.bottom < y_pos) - continue; - - pos[0].x = x_pos - spi->pos.x; - pos[0].y = y_pos - spi->pos.y; - imageState = spi->curImageState; - } - - angle = spi->curAngle; - scale = spi->curScale; - if ((spi->flags & kSFScaled) || (spi->flags & kSFRotated)) { - if (spi->flags & kSFScaled && scale) { - pos[0].x = pos[0].x * 256 / scale; - pos[0].y = pos[0].y * 256 / scale; - } - if (spi->flags & kSFRotated && angle) { - angle = (360 - angle) % 360; - _vm->_wiz->polygonRotatePoints(pos, 1, angle); - } - - _vm->_wiz->getWizImageDim(image, imageState, w, h); - pos[0].x += w / 2; - pos[0].y += h / 2; - } - - if (_vm->_wiz->isWizPixelNonTransparent(image, imageState, pos[0].x, pos[0].y, spi->curImgFlags)) - return spi->id; - } - } - - return 0; -} - -int Sprite::getSpriteClass(int spriteId, int num, int *args) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - int code, classId; - - if (num == 0) - return _spriteTable[spriteId].classFlags; - - for (int i = 0; i < num; i++) { - code = classId = args[i]; - classId &= 0x7F; - checkRange(32, 1, classId, "class %d out of range in statement"); - if (code & 0x80) { - if (!(_spriteTable[spriteId].classFlags & (1 << (classId - 1)))) - return 0; - } else { - if ((_spriteTable[spriteId].classFlags & (1 << (classId - 1)))) - return 0; - } - } - - return 1; -} - -int Sprite::getSpriteFlagDoubleBuffered(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return ((_spriteTable[spriteId].flags & kSFDoubleBuffered) != 0) ? 1 : 0; -} - -int Sprite::getSpriteFlagYFlipped(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return ((_spriteTable[spriteId].flags & kSFYFlipped) != 0) ? 1 : 0; -} - -int Sprite::getSpriteFlagXFlipped(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return ((_spriteTable[spriteId].flags & kSFXFlipped) != 0) ? 1 : 0; -} - -int Sprite::getSpriteFlagActive(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return ((_spriteTable[spriteId].flags & kSFActive) != 0) ? 1 : 0; -} - -int Sprite::getSpriteFlagRemapPalette(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return ((_spriteTable[spriteId].flags & kSFRemapPalette) != 0) ? 1 : 0; -} - -int Sprite::getSpriteFlagAutoAnim(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return ((_spriteTable[spriteId].flags & kSFAutoAnim) != 0) ? 1 : 0; -} - -int Sprite::getSpriteFlagUpdateType(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return ((_spriteTable[spriteId].flags & kSFMarkDirty) != 0) ? 1 : 0; -} - -int Sprite::getSpriteFlagEraseType(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return ((_spriteTable[spriteId].flags & kSFImageless) != 0) ? 1 : 0; -} - -int Sprite::getSpriteImage(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return _spriteTable[spriteId].image; -} - -int Sprite::getSpriteImageState(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return _spriteTable[spriteId].imageState; -} - -int Sprite::getSpriteGroup(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return _spriteTable[spriteId].group; -} - -int Sprite::getSpritePalette(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return _spriteTable[spriteId].palette; -} - -int Sprite::getSpritePriority(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return _spriteTable[spriteId].priority; -} - -int Sprite::getSpriteDisplayX(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - if (_spriteTable[spriteId].group) - return _spriteTable[spriteId].tx + _spriteGroups[_spriteTable[spriteId].group].tx; - else - return _spriteTable[spriteId].tx; -} - -int Sprite::getSpriteDisplayY(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - if (_spriteTable[spriteId].group) - return _spriteTable[spriteId].ty + _spriteGroups[_spriteTable[spriteId].group].ty; - else - return _spriteTable[spriteId].ty; -} - -int Sprite::getSpriteUserValue(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return _spriteTable[spriteId].userValue; -} - -int Sprite::getSpriteShadow(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return _spriteTable[spriteId].shadow; -} - -int Sprite::getSpriteImageStateCount(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return _spriteTable[spriteId].imageStateCount; -} - -int Sprite::getSpriteScale(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return _spriteTable[spriteId].scale; -} - -int Sprite::getSpriteAnimSpeed(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return _spriteTable[spriteId].animSpeed; -} - -int Sprite::getSpriteSourceImage(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return _spriteTable[spriteId].sourceImage; -} - -int Sprite::getSpriteMaskImage(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - return _spriteTable[spriteId].maskImage; -} - -int Sprite::getSpriteGeneralProperty(int spriteId, int type) { - debug(0, "getSpriteGeneralProperty: spriteId %d type 0x%x", spriteId, type); - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - // XXX U32 related check - - switch(type) { - case 0x7B: - return _spriteTable[spriteId].imgFlags; - case 0x7D: - return _spriteTable[spriteId].field_90; - case 0x7E: - return _spriteTable[spriteId].animProgress; - default: - error("getSpriteGeneralProperty: Invalid type %d", type); - } -} - -void Sprite::getSpriteImageDim(int spriteId, int32 &w, int32 &h) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - if (_spriteTable[spriteId].image) { - _vm->_wiz->getWizImageDim(_spriteTable[spriteId].image, _spriteTable[spriteId].imageState, w, h); - } else { - w = 0; - h = 0; - } -} - -void Sprite::getSpritePosition(int spriteId, int32 &tx, int32 &ty) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - tx = _spriteTable[spriteId].tx; - ty = _spriteTable[spriteId].ty; -} - -void Sprite::getSpriteDist(int spriteId, int32 &dx, int32 &dy) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - dx = _spriteTable[spriteId].dx; - dy = _spriteTable[spriteId].dy; -} - -// -// spriteGroupGet functions -// -int ScummEngine_v90he::getGroupSpriteArray(int spriteGroupId) { - int i, numSprites = 0; - - checkRange(_sprite->_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - for (i = (_sprite->_varNumSprites - 1); i > 0; i--) { - if (_sprite->_spriteTable[i].group == spriteGroupId) - numSprites++; - } - - if (!numSprites) - return 0; - - writeVar(0, 0); - defineArray(0, kDwordArray, 0, 0, 0, numSprites); - writeArray(0, 0, 0, numSprites); - - numSprites = 1; - for (i = (_sprite->_varNumSprites - 1); i > 0; i--) { - if (_sprite->_spriteTable[i].group == spriteGroupId) { - writeArray(0, 0, numSprites, i); - numSprites++; - } - } - - return readVar(0); -} - -int Sprite::getGroupPriority(int spriteGroupId) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - return _spriteGroups[spriteGroupId].priority; -} - -int Sprite::getGroupDstResNum(int spriteGroupId) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - return _spriteGroups[spriteGroupId].image; -} - -int Sprite::getGroupXMul(int spriteGroupId) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - return _spriteGroups[spriteGroupId].scale_x_ratio_mul; -} - -int Sprite::getGroupXDiv(int spriteGroupId) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - return _spriteGroups[spriteGroupId].scale_x_ratio_div; -} - -int Sprite::getGroupYMul(int spriteGroupId) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - return _spriteGroups[spriteGroupId].scale_y_ratio_mul; -} - -int Sprite::getGroupYDiv(int spriteGroupId) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - return _spriteGroups[spriteGroupId].scale_y_ratio_div; -} - -void Sprite::getGroupPosition(int spriteGroupId, int32 &tx, int32 &ty) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - tx = _spriteGroups[spriteGroupId].tx; - ty = _spriteGroups[spriteGroupId].ty; -} - -// -// spriteInfoSet functions -// -void Sprite::setSpritePalette(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - if (_spriteTable[spriteId].palette != value) { - _spriteTable[spriteId].palette = value; - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; - } -} - -void Sprite::setSpriteSourceImage(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - if (_spriteTable[spriteId].sourceImage != value) { - _spriteTable[spriteId].sourceImage = value; - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; - } -} - -void Sprite::setSpriteMaskImage(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - _spriteTable[spriteId].maskImage = value; -} - -void Sprite::setSpriteImageState(int spriteId, int state) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - if (_spriteTable[spriteId].image) { - int imageStateCount = _spriteTable[spriteId].imageStateCount - 1; - state = MAX(0, state); - state = MIN(state, imageStateCount); - - if (_spriteTable[spriteId].imageState != state) { - _spriteTable[spriteId].imageState = state; - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; - } - } -} - -void Sprite::setSpritePosition(int spriteId, int tx, int ty) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - if (_spriteTable[spriteId].tx != tx || _spriteTable[spriteId].ty != ty) { - _spriteTable[spriteId].tx = tx; - _spriteTable[spriteId].ty = ty; - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; - } -} - -void Sprite::setSpriteGroup(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - checkRange(_varNumSpriteGroups, 0, value, "Invalid sprite group %d"); - - _spriteTable[spriteId].group = value; - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; -} - -void Sprite::setSpriteDist(int spriteId, int value1, int value2) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - _spriteTable[spriteId].dx = value1; - _spriteTable[spriteId].dy = value2; -} - -void Sprite::setSpriteShadow(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - _spriteTable[spriteId].shadow = value; - if (_spriteTable[spriteId].image) - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; -} - -void Sprite::setSpriteUserValue(int spriteId, int value1, int value2) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - _spriteTable[spriteId].userValue = value2; -} - -void Sprite::setSpritePriority(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - _spriteTable[spriteId].priority = value; -} - -void Sprite::moveSprite(int spriteId, int value1, int value2) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - _spriteTable[spriteId].tx += value1; - _spriteTable[spriteId].ty += value2; - - if (value1 || value2) - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; -} - -void Sprite::setSpriteScale(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - _spriteTable[spriteId].flags |= kSFScaled; - - if (_spriteTable[spriteId].scale != value) { - _spriteTable[spriteId].scale = value; - - if (_spriteTable[spriteId].image) - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; - } -} - -void Sprite::setSpriteAngle(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - _spriteTable[spriteId].flags |= kSFRotated; - - if (_spriteTable[spriteId].angle != value) { - _spriteTable[spriteId].angle = value; - - if (_spriteTable[spriteId].image) - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; - } -} - -void Sprite::setSpriteFlagDoubleBuffered(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - int oldFlags = _spriteTable[spriteId].flags; - if (value) - _spriteTable[spriteId].flags |= kSFDoubleBuffered; - else - _spriteTable[spriteId].flags &= ~kSFDoubleBuffered; - - if (_spriteTable[spriteId].image && _spriteTable[spriteId].flags != oldFlags) - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; -} - -void Sprite::setSpriteFlagYFlipped(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - int oldFlags = _spriteTable[spriteId].flags; - if (value) - _spriteTable[spriteId].flags |= kSFYFlipped; - else - _spriteTable[spriteId].flags &= ~kSFYFlipped; - - if (_spriteTable[spriteId].image && _spriteTable[spriteId].flags != oldFlags) - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; -} - -void Sprite::setSpriteFlagXFlipped(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - int oldFlags = _spriteTable[spriteId].flags; - if (value) - _spriteTable[spriteId].flags |= kSFXFlipped; - else - _spriteTable[spriteId].flags &= ~kSFXFlipped; - - if (_spriteTable[spriteId].image && _spriteTable[spriteId].flags != oldFlags) - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; -} - -void Sprite::setSpriteFlagActive(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - if (value) - _spriteTable[spriteId].flags |= kSFActive; - else - _spriteTable[spriteId].flags &= ~kSFActive; -} - -void Sprite::setSpriteFlagRemapPalette(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - int oldFlags = _spriteTable[spriteId].flags; - if (value) - _spriteTable[spriteId].flags |= kSFRemapPalette; - else - _spriteTable[spriteId].flags &= ~kSFRemapPalette; - - if (_spriteTable[spriteId].image && _spriteTable[spriteId].flags != oldFlags) - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; -} - -void Sprite::setSpriteFlagAutoAnim(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - if (value) - _spriteTable[spriteId].flags |= kSFAutoAnim; - else - _spriteTable[spriteId].flags &= ~kSFAutoAnim; -} - -void Sprite::setSpriteFlagUpdateType(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - switch(value) { - case 2: - _spriteTable[spriteId].flags &= ~(kSFMarkDirty); - _spriteTable[spriteId].flags |= kSFBlitDirectly; - break; - case 1: - _spriteTable[spriteId].flags |= kSFMarkDirty | kSFBlitDirectly; - break; - case 0: - _spriteTable[spriteId].flags &= ~(kSFMarkDirty | kSFBlitDirectly); - break; - default: - error("setSpriteFlagUpdateType: Invalid value %d", value); - } -} - -void Sprite::setSpriteFlagEraseType(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - // Note that condition is inverted - if (!value) - _spriteTable[spriteId].flags |= kSFImageless; - else - _spriteTable[spriteId].flags &= ~kSFImageless; -} - -void Sprite::setSpriteAnimSpeed(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - _spriteTable[spriteId].animSpeed = value; - _spriteTable[spriteId].animProgress = value; -} - -void Sprite::setSpriteSetClass(int spriteId, int classId, int toggle) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - checkRange(32, 1, classId, "class %d out of range in statement"); - - if (toggle) { - _spriteTable[spriteId].classFlags |= (1 << (classId - 1)); - } else { - _spriteTable[spriteId].classFlags &= ~(1 << (classId - 1)); - } -} - -void Sprite::setSpriteResetClass(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - _spriteTable[spriteId].classFlags = 0; -} - -void Sprite::setSpriteField84(int spriteId, int value) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - _spriteTable[spriteId].field_84 = value; -} - -void Sprite::setSpriteGeneralProperty(int spriteId, int type, int value) { - debug(0, "setSpriteGeneralProperty: spriteId %d type 0x%x", spriteId, type); - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - int32 delay; - - // XXX U32 related check - - switch(type) { - case 0x7B: - _spriteTable[spriteId].imgFlags = value; - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; - break; - case 0x7D: - _spriteTable[spriteId].field_90 = value; - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; - break; - case 0x7E: - delay = MAX(0, value); - delay = MIN(delay, _spriteTable[spriteId].animSpeed); - - _spriteTable[spriteId].animProgress = delay; - break; - default: - error("setSpriteGeneralProperty: Invalid value %d", type); - } -} - -void Sprite::resetSprite(int spriteId) { - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - _spriteTable[spriteId].angle = 0; - _spriteTable[spriteId].scale = 0; - - setSpriteImage(spriteId, 0); - - _spriteTable[spriteId].shadow = 0; - _spriteTable[spriteId].tx = 0; - _spriteTable[spriteId].ty = 0; - - _spriteTable[spriteId].flags &= ~(kSFYFlipped | kSFXFlipped); - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; - _spriteTable[spriteId].dx = 0; - _spriteTable[spriteId].dy = 0; - _spriteTable[spriteId].userValue = 0; - _spriteTable[spriteId].group = 0; - _spriteTable[spriteId].animSpeed = 0; - _spriteTable[spriteId].animProgress = 0; - _spriteTable[spriteId].classFlags = 0; - _spriteTable[spriteId].palette = 0; - _spriteTable[spriteId].sourceImage = 0; - _spriteTable[spriteId].maskImage = 0; - _spriteTable[spriteId].priority = 0; - _spriteTable[spriteId].field_84 = 0; - _spriteTable[spriteId].imgFlags = 0; - _spriteTable[spriteId].field_90 = 0; -} - -void Sprite::setSpriteImage(int spriteId, int imageNum) { - int origResId, origResWizStates; - - checkRange(_varNumSprites, 1, spriteId, "Invalid sprite %d"); - - origResId = _spriteTable[spriteId].image; - origResWizStates = _spriteTable[spriteId].imageStateCount; - - _spriteTable[spriteId].image = imageNum; - _spriteTable[spriteId].field_74 = 0; - _spriteTable[spriteId].imageState = 0; - - if (_spriteTable[spriteId].image) { - _spriteTable[spriteId].imageStateCount = _vm->_wiz->getWizImageStates(_spriteTable[spriteId].image); - _spriteTable[spriteId].flags |= kSFActive | kSFAutoAnim | kSFMarkDirty | kSFBlitDirectly; - - if (_spriteTable[spriteId].image != origResId || _spriteTable[spriteId].imageStateCount != origResWizStates) - _spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw; - } else { - if (_spriteTable[spriteId].flags & kSFImageless) - _spriteTable[spriteId].flags = 0; - else - _spriteTable[spriteId].flags = kSFChanged | kSFBlitDirectly; - _spriteTable[spriteId].curImage = 0; - _spriteTable[spriteId].curImageState = 0; - _spriteTable[spriteId].imageStateCount = 0; - } -} - -// -// spriteGroupSet functions -// -void Sprite::redrawSpriteGroup(int spriteGroupId) { - for (int i = 0; i < _numSpritesToProcess; ++i) { - SpriteInfo *spi = _activeSpritesTable[i]; - if (spi->group == spriteGroupId) { - spi->flags |= kSFChanged | kSFNeedRedraw; - } - } -} - -void Sprite::moveGroupMembers(int spriteGroupId, int value1, int value2) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - for (int i = 1; i < _varNumSprites; i++) { - if (_spriteTable[i].group == spriteGroupId) { - _spriteTable[i].tx += value1; - _spriteTable[i].ty += value2; - - if (value1 || value2) - _spriteTable[i].flags |= kSFChanged | kSFNeedRedraw; - } - } -} - -void Sprite::setGroupMembersPriority(int spriteGroupId, int value) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - for (int i = 1; i < _varNumSprites; i++) { - if (_spriteTable[i].group == spriteGroupId) - _spriteTable[i].priority = value; - } -} - -void Sprite::setGroupMembersGroup(int spriteGroupId, int value) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - for (int i = 1; i < _varNumSprites; i++) { - if (_spriteTable[i].group == spriteGroupId) { - _spriteTable[i].group = value; - _spriteTable[i].flags |= kSFChanged | kSFNeedRedraw; - } - } -} - -void Sprite::setGroupMembersUpdateType(int spriteGroupId, int value) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - for (int i = 1; i < _varNumSprites; i++) { - if (_spriteTable[i].group == spriteGroupId) - setSpriteFlagUpdateType(i, value); - } -} - -void Sprite::setGroupMembersResetSprite(int spriteGroupId) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - for (int i = 1; i < _varNumSprites; i++) { - if (_spriteTable[i].group == spriteGroupId) - resetSprite(i); - } -} - -void Sprite::setGroupMembersAnimationSpeed(int spriteGroupId, int value) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - for (int i = 1; i < _varNumSprites; i++) { - if (_spriteTable[i].group == spriteGroupId) { - _spriteTable[i].animSpeed = value; - _spriteTable[i].animProgress = value; - } - } -} - -void Sprite::setGroupMembersAutoAnimFlag(int spriteGroupId, int value) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - for (int i = 1; i < _varNumSprites; i++) { - if (_spriteTable[i].group == spriteGroupId) { - if (value) - _spriteTable[i].flags |= kSFAutoAnim; - else - _spriteTable[i].flags &= ~kSFAutoAnim; - } - } -} - -void Sprite::setGroupMembersShadow(int spriteGroupId, int value) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - for (int i = 1; i < _varNumSprites; i++) { - if (_spriteTable[i].group == spriteGroupId) { - _spriteTable[i].shadow = value; - if (_spriteTable[i].image) - _spriteTable[i].flags |= kSFChanged | kSFNeedRedraw; - } - } -} - -void Sprite::setGroupBounds(int spriteGroupId, int x1, int y1, int x2, int y2) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - _spriteGroups[spriteGroupId].flags |= kSGFClipBox; - _spriteGroups[spriteGroupId].bbox.left = x1; - _spriteGroups[spriteGroupId].bbox.top = y1; - _spriteGroups[spriteGroupId].bbox.right = x2; - _spriteGroups[spriteGroupId].bbox.bottom = y2; - - redrawSpriteGroup(spriteGroupId); -} - -void Sprite::setGroupPriority(int spriteGroupId, int value) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - if (_spriteGroups[spriteGroupId].priority != value) { - _spriteGroups[spriteGroupId].priority = value; - redrawSpriteGroup(spriteGroupId); - } -} - -void Sprite::setGroupPosition(int spriteGroupId, int value1, int value2) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - if (_spriteGroups[spriteGroupId].tx != value1 || _spriteGroups[spriteGroupId].ty != value2) { - _spriteGroups[spriteGroupId].tx = value1; - _spriteGroups[spriteGroupId].ty = value2; - redrawSpriteGroup(spriteGroupId); - } -} - -void Sprite::moveGroup(int spriteGroupId, int value1, int value2) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - if (value1 || value2) { - _spriteGroups[spriteGroupId].tx += value1; - _spriteGroups[spriteGroupId].ty += value2; - redrawSpriteGroup(spriteGroupId); - } -} - -void Sprite::setGroupImage(int spriteGroupId, int value) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - if (_spriteGroups[spriteGroupId].image != value) { - _spriteGroups[spriteGroupId].image = value; - redrawSpriteGroup(spriteGroupId); - } -} - -void Sprite::setGroupScaling(int spriteGroupId) { - if ((_spriteGroups[spriteGroupId].scale_x_ratio_mul != _spriteGroups[spriteGroupId].scale_x_ratio_div) || (_spriteGroups[spriteGroupId].scale_y_ratio_mul != _spriteGroups[spriteGroupId].scale_y_ratio_div)) - _spriteGroups[spriteGroupId].scaling = 1; - else - _spriteGroups[spriteGroupId].scaling = 0; - -} - -void Sprite::setGroupXMul(int spriteGroupId, int value) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - if (_spriteGroups[spriteGroupId].scale_x_ratio_mul != value) { - _spriteGroups[spriteGroupId].scale_x_ratio_mul = value; - setGroupScaling(spriteGroupId); - redrawSpriteGroup(spriteGroupId); - } -} - -void Sprite::setGroupXDiv(int spriteGroupId, int value) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - if (value == 0) - error("setGroupXDiv: Divisor must not be 0"); - - if (_spriteGroups[spriteGroupId].scale_x_ratio_div != value) { - _spriteGroups[spriteGroupId].scale_x_ratio_div = value; - setGroupScaling(spriteGroupId); - redrawSpriteGroup(spriteGroupId); - } -} - -void Sprite::setGroupYMul(int spriteGroupId, int value) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - if (_spriteGroups[spriteGroupId].scale_y_ratio_mul != value) { - _spriteGroups[spriteGroupId].scale_y_ratio_mul = value; - setGroupScaling(spriteGroupId); - redrawSpriteGroup(spriteGroupId); - } -} - -void Sprite::setGroupYDiv(int spriteGroupId, int value) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - if (value == 0) - error("setGroupYDiv: Divisor must not be 0"); - - if (_spriteGroups[spriteGroupId].scale_y_ratio_div != value) { - _spriteGroups[spriteGroupId].scale_y_ratio_div = value; - setGroupScaling(spriteGroupId); - redrawSpriteGroup(spriteGroupId); - } -} - -void Sprite::resetGroupBounds(int spriteGroupId) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - - _spriteGroups[spriteGroupId].flags &= ~(kSGFClipBox); - redrawSpriteGroup(spriteGroupId); -} - -void Sprite::allocTables(int numSprites, int numGroups, int numMaxSprites) { - _varNumSpriteGroups = numGroups; - _numSpritesToProcess = 0; - _varNumSprites = numSprites; - _varMaxSprites = numMaxSprites; - _spriteGroups = (SpriteGroup *)malloc((_varNumSpriteGroups + 1) * sizeof(SpriteGroup)); - _spriteTable = (SpriteInfo *)malloc((_varNumSprites + 1) * sizeof(SpriteInfo)); - _activeSpritesTable = (SpriteInfo **)malloc((_varNumSprites + 1) * sizeof(SpriteInfo *)); -} - -void Sprite::resetGroup(int spriteGroupId) { - checkRange(_varNumSpriteGroups, 1, spriteGroupId, "Invalid sprite group %d"); - SpriteGroup *spg = &_spriteGroups[spriteGroupId]; - - spg->priority = 0; - spg->tx = spg->ty = 0; - - spg->flags &= ~kSGFClipBox; - redrawSpriteGroup(spriteGroupId); - - spg->image = 0; - spg->scaling = 0; - spg->scale_x_ratio_mul = 1; - spg->scale_x_ratio_div = 1; - spg->scale_y_ratio_mul = 1; - spg->scale_y_ratio_div = 1; -} - -void Sprite::resetTables(bool refreshScreen) { - memset(_spriteTable, 0, (_varNumSprites + 1) * sizeof(SpriteInfo)); - memset(_spriteGroups, 0, (_varNumSpriteGroups + 1) * sizeof(SpriteGroup)); - for (int curGrp = 1; curGrp < _varNumSpriteGroups; ++curGrp) - resetGroup(curGrp); - - if (refreshScreen) { - _vm->gdi.copyVirtScreenBuffers(Common::Rect(_vm->_screenWidth, _vm->_screenHeight)); - } - _numSpritesToProcess = 0; -} - -void Sprite::resetBackground() { - int xmin, xmax, ymin, ymax; - xmin = ymin = 1234; - xmax = ymax = -1234; - bool firstLoop = true; - bool refreshScreen = false; - - for (int i = 0; i < _numSpritesToProcess; ++i) { - SpriteInfo *spi = _activeSpritesTable[i]; - if (!(spi->flags & kSFImageless) && (spi->flags & kSFChanged)) { - spi->flags &= ~kSFChanged; - if (spi->bbox.left <= spi->bbox.right && spi->bbox.top <= spi->bbox.bottom) { - if (spi->flags & kSFBlitDirectly) { - _vm->gdi.copyVirtScreenBuffers(spi->bbox, USAGE_BIT_RESTORED); - } else if (firstLoop) { - xmin = spi->bbox.left; - ymin = spi->bbox.top; - xmax = spi->bbox.right; - ymax = spi->bbox.bottom; - firstLoop = false; - refreshScreen = true; - } else { - if (xmin > spi->bbox.left) { - xmin = spi->bbox.left; - } - if (ymin > spi->bbox.top) { - ymin = spi->bbox.top; - } - if (xmax < spi->bbox.right) { - xmax = spi->bbox.right; - } - if (ymax < spi->bbox.bottom) { - ymax = spi->bbox.bottom; - } - refreshScreen = true; - } - if (!(spi->flags & kSFNeedRedraw) && spi->image) - spi->flags |= kSFNeedRedraw; - } - } - } - if (refreshScreen) { - _vm->gdi.copyVirtScreenBuffers(Common::Rect(xmin, ymin, xmax, ymax), USAGE_BIT_RESTORED); - } -} - -void Sprite::setRedrawFlags(bool checkZOrder) { - VirtScreen *vs = &_vm->virtscr[kMainVirtScreen]; - for (int i = 0; i < _numSpritesToProcess; ++i) { - SpriteInfo *spi = _activeSpritesTable[i]; - if (!(spi->flags & kSFNeedRedraw)) { - if ((!checkZOrder || spi->priority >= 0) && (spi->flags & kSFMarkDirty)) { - int lp = spi->bbox.left / 8; - lp = MAX(0, lp); - lp = MIN(lp, 79); - int rp = (spi->bbox.right + 7) / 8; - rp = MAX(0, rp); - rp = MIN(rp, 79); - for (; lp <= rp; ++lp) { - if (vs->tdirty[lp] < vs->h && spi->bbox.bottom >= vs->tdirty[lp] && spi->bbox.top <= vs->bdirty[lp]) { - spi->flags |= kSFNeedRedraw; - break; - } - } - } - } - } -} - -void Sprite::updateImages() { - for (int i = 0; i < _numSpritesToProcess; ++i) { - SpriteInfo *spi = _activeSpritesTable[i]; - if (spi->dx || spi->dy) { - int tx = spi->tx; - int ty = spi->ty; - spi->tx += spi->dx; - spi->ty += spi->dy; - if (tx != spi->tx || ty != spi->ty) { - spi->flags |= kSFChanged | kSFNeedRedraw; - } - } - if (spi->flags & kSFAutoAnim) { - if (spi->animSpeed) { - --spi->animProgress; - if (spi->animProgress) - continue; - - spi->animProgress = spi->animSpeed; - } - int imageState = spi->imageState; - ++spi->imageState; - if (spi->imageState >= spi->imageStateCount) { - spi->imageState = 0; - if (imageState == 0) - continue; - } - spi->flags |= kSFChanged | kSFNeedRedraw; - } - } -} - -static int compareSprTable(const void *a, const void *b) { - const SpriteInfo *spr1 = *(const SpriteInfo *const*)a; - const SpriteInfo *spr2 = *(const SpriteInfo *const*)b; - - if (spr1->zorder > spr2->zorder) - return 1; - - if (spr1->zorder < spr2->zorder) - return -1; - - return 0; -} - -void Sprite::sortActiveSprites() { - int groupZorder; - - _numSpritesToProcess = 0; - - if (_varNumSprites <= 1) - return; - - for (int i = 1; i < _varNumSprites; i++) { - SpriteInfo *spi = &_spriteTable[i]; - - if (spi->flags & kSFActive) { - if (!(spi->flags & kSFMarkDirty)) { - spi->flags |= kSFNeedRedraw; - if (!(spi->flags & kSFImageless)) - spi->flags |= kSFChanged; - } - if (spi->group) - groupZorder = _spriteGroups[spi->group].priority; - else - groupZorder = 0; - - spi->id = i; - spi->zorder = spi->priority + groupZorder; - - _activeSpritesTable[_numSpritesToProcess++] = spi; - } - } - - if (_numSpritesToProcess < 2) - return; - - qsort(_activeSpritesTable, _numSpritesToProcess, sizeof(SpriteInfo *), compareSprTable); -} - -void Sprite::processImages(bool arg) { - int spr_flags; - int32 spr_wiz_x, spr_wiz_y; - int image, imageState; - Common::Rect *bboxPtr; - int angle, scale; - int32 w, h; - WizParameters wiz; - - for (int i = 0; i < _numSpritesToProcess; i++) { - SpriteInfo *spi = _activeSpritesTable[i]; - - if (!(spi->flags & kSFNeedRedraw)) - continue; - - spr_flags = spi->flags; - - if (arg) { - if (spi->zorder >= 0) - return; - } else { - if (spi->zorder < 0) - continue; - } - - spi->flags &= ~kSFNeedRedraw; - image = spi->image; - imageState = spi->imageState; - _vm->_wiz->getWizImageSpot(spi->image, spi->imageState, spr_wiz_x, spr_wiz_y); - - if (spi->group) { - SpriteGroup *spg = &_spriteGroups[spi->group]; - - if (spg->scaling) { - wiz.img.x1 = spi->tx * spg->scale_x_ratio_mul / spg->scale_x_ratio_div - spr_wiz_x + spg->tx; - wiz.img.y1 = spi->ty * spg->scale_y_ratio_mul / spg->scale_y_ratio_div - spr_wiz_y + spg->ty; - } else { - wiz.img.x1 = spi->tx - spr_wiz_x + spg->tx; - wiz.img.y1 = spi->ty - spr_wiz_y + spg->ty; - } - } else { - wiz.img.x1 = spi->tx - spr_wiz_x; - wiz.img.y1 = spi->ty - spr_wiz_y; - } - - wiz.spriteId = spi->id; - wiz.spriteGroup = spi->group; - wiz.field_23EA = spi->field_90; - spi->curImageState = wiz.img.state = imageState; - spi->curImage = wiz.img.resNum = image; - wiz.processFlags = kWPFNewState | kWPFSetPos; - spi->curAngle = spi->angle; - spi->curScale = spi->scale; - spi->pos.x = wiz.img.x1; - spi->pos.y = wiz.img.y1; - bboxPtr = &spi->bbox; - if (image) { - angle = spi->angle; - scale = spi->scale; - _vm->_wiz->getWizImageDim(image, imageState, w, h); - if (spi->flags & (kSFScaled | kSFRotated)) { - Common::Point pts[4]; - _vm->_wiz->polygonTransform(image, imageState, wiz.img.x1, wiz.img.y1, angle, scale, pts); - _vm->_wiz->polygonCalcBoundBox(pts, 4, spi->bbox); - } else { - bboxPtr->left = wiz.img.x1; - bboxPtr->top = wiz.img.y1; - bboxPtr->right = wiz.img.x1 + w; - bboxPtr->bottom = wiz.img.y1 + h; - } - } else { - bboxPtr->left = 1234; - bboxPtr->top = 1234; - bboxPtr->right = -1234; - bboxPtr->bottom = -1234; - } - - wiz.img.flags = kWIFMarkBufferDirty; - wiz.img.zorder = 0; - if (spr_flags & kSFXFlipped) - wiz.img.flags |= kWIFFlipX; - if (spr_flags & kSFYFlipped) - wiz.img.flags |= kWIFFlipY; - if (spr_flags & kSFDoubleBuffered) { - wiz.img.flags &= ~kWIFMarkBufferDirty; - wiz.img.flags |= kWIFBlitToFrontVideoBuffer; - } - if (spi->shadow) { - wiz.img.flags |= 0x200; - wiz.processFlags |= kWPFShadow; - wiz.img.shadow = spi->shadow; - } - if (spr_flags & kSFRemapPalette) - wiz.img.flags |= kWIFRemapPalette; - if (spi->field_84) { - wiz.processFlags |= 0x200000; - wiz.img.field_390 = spi->field_84; - wiz.img.zorder = spi->priority; - } - if (spi->sourceImage) { - wiz.processFlags |= kWPFMaskImg; - wiz.sourceImage = spi->sourceImage; - } - wiz.processFlags |= kWPFNewFlags; - wiz.img.flags |= spi->imgFlags; - - if (spr_flags & kSFRotated) { - wiz.processFlags |= kWPFRotate; - wiz.angle = spi->angle; - } - if (spr_flags & kSFScaled) { - wiz.processFlags |= kWPFScaled; - wiz.scale = spi->scale; - } - spi->curImgFlags = wiz.img.flags; - - if (spi->group && (_spriteGroups[spi->group].flags & kSGFClipBox)) { - Common::Rect &spgBbox = _spriteGroups[spi->group].bbox; - if (spgBbox.isValidRect() && spi->bbox.intersects(spgBbox)) { - spi->bbox.clip(spgBbox); - wiz.processFlags |= kWPFClipBox; - wiz.box = spi->bbox; - } else { - bboxPtr->left = 1234; - bboxPtr->top = 1234; - bboxPtr->right = -1234; - bboxPtr->bottom = -1234; - continue; - } - } - if (spi->palette) { - wiz.processFlags |= kWPFPaletteNum; - wiz.img.palette = spi->palette; - } - if (spi->image && spi->group && _spriteGroups[spi->group].image) { - wiz.processFlags |= kWPFDstResNum; - wiz.dstResNum = _spriteGroups[spi->group].image; - } - _vm->_wiz->displayWizComplexImage(&wiz); - } -} - -void Sprite::saveOrLoadSpriteData(Serializer *s) { - static const SaveLoadEntry spriteEntries[] = { - MKLINE(SpriteInfo, id, sleInt32, VER(48)), - MKLINE(SpriteInfo, zorder, sleInt32, VER(48)), - MKLINE(SpriteInfo, flags, sleInt32, VER(48)), - MKLINE(SpriteInfo, image, sleInt32, VER(48)), - MKLINE(SpriteInfo, imageState, sleInt32, VER(48)), - MKLINE(SpriteInfo, group, sleInt32, VER(48)), - MKLINE(SpriteInfo, palette, sleInt32, VER(48)), - MKLINE(SpriteInfo, priority, sleInt32, VER(48)), - MKLINE(SpriteInfo, bbox.left, sleInt32, VER(48)), - MKLINE(SpriteInfo, bbox.top, sleInt32, VER(48)), - MKLINE(SpriteInfo, bbox.right, sleInt32, VER(48)), - MKLINE(SpriteInfo, bbox.bottom, sleInt32, VER(48)), - MKLINE(SpriteInfo, dx, sleInt32, VER(48)), - MKLINE(SpriteInfo, dy, sleInt32, VER(48)), - MKLINE(SpriteInfo, pos.x, sleInt32, VER(48)), - MKLINE(SpriteInfo, pos.y, sleInt32, VER(48)), - MKLINE(SpriteInfo, tx, sleInt32, VER(48)), - MKLINE(SpriteInfo, ty, sleInt32, VER(48)), - MKLINE(SpriteInfo, userValue, sleInt32, VER(48)), - MKLINE(SpriteInfo, curImageState, sleInt32, VER(48)), - MKLINE(SpriteInfo, curImage, sleInt32, VER(48)), - MKLINE(SpriteInfo, imglistNum, sleInt32, VER(48)), - MKLINE(SpriteInfo, shadow, sleInt32, VER(48)), - MKLINE(SpriteInfo, imageStateCount, sleInt32, VER(48)), - MKLINE(SpriteInfo, angle, sleInt32, VER(48)), - MKLINE(SpriteInfo, scale, sleInt32, VER(48)), - MKLINE(SpriteInfo, animProgress, sleInt32, VER(48)), - MKLINE(SpriteInfo, curAngle, sleInt32, VER(48)), - MKLINE(SpriteInfo, curScale, sleInt32, VER(48)), - MKLINE(SpriteInfo, curImgFlags, sleInt32, VER(48)), - MKLINE(SpriteInfo, field_74, sleInt32, VER(48)), - MKLINE(SpriteInfo, animSpeed, sleInt32, VER(48)), - MKLINE(SpriteInfo, sourceImage, sleInt32, VER(48)), - MKLINE(SpriteInfo, maskImage, sleInt32, VER(48)), - MKLINE(SpriteInfo, field_84, sleInt32, VER(48)), - MKLINE(SpriteInfo, classFlags, sleInt32, VER(48)), - MKLINE(SpriteInfo, imgFlags, sleInt32, VER(48)), - MKLINE(SpriteInfo, field_90, sleInt32, VER(48)), - MKEND() - }; - - static const SaveLoadEntry spriteGroupEntries[] = { - MKLINE(SpriteGroup, bbox.left, sleInt32, VER(48)), - MKLINE(SpriteGroup, bbox.top, sleInt32, VER(48)), - MKLINE(SpriteGroup, bbox.right, sleInt32, VER(48)), - MKLINE(SpriteGroup, bbox.bottom, sleInt32, VER(48)), - MKLINE(SpriteGroup, priority, sleInt32, VER(48)), - MKLINE(SpriteGroup, flags, sleInt32, VER(48)), - MKLINE(SpriteGroup, tx, sleInt32, VER(48)), - MKLINE(SpriteGroup, ty, sleInt32, VER(48)), - MKLINE(SpriteGroup, image, sleInt32, VER(48)), - MKLINE(SpriteGroup, scaling, sleInt32, VER(48)), - MKLINE(SpriteGroup, scale_x_ratio_mul, sleInt32, VER(48)), - MKLINE(SpriteGroup, scale_x_ratio_div, sleInt32, VER(48)), - MKLINE(SpriteGroup, scale_y_ratio_mul, sleInt32, VER(48)), - MKLINE(SpriteGroup, scale_y_ratio_div, sleInt32, VER(48)), - MKEND() - }; - - if (s->getVersion() >= VER(64)) { - s->saveLoadArrayOf(_spriteTable, _varNumSprites + 1, sizeof(_spriteTable[0]), spriteEntries); - s->saveLoadArrayOf(_spriteGroups, _varNumSpriteGroups + 1, sizeof(_spriteGroups[0]), spriteGroupEntries); - } else { - s->saveLoadArrayOf(_activeSpritesTable, _varNumSprites, sizeof(_activeSpritesTable[0]), spriteEntries); - s->saveLoadArrayOf(_spriteTable, _varNumSprites, sizeof(_spriteTable[0]), spriteEntries); - s->saveLoadArrayOf(_spriteGroups, _varNumSpriteGroups, sizeof(_spriteGroups[0]), spriteGroupEntries); - } - - // Reset active sprite table - if (s->isLoading()) - _numSpritesToProcess = 0; - -} - -} // End of namespace Scumm diff --git a/engines/scumm/sprite_he.h b/engines/scumm/sprite_he.h deleted file mode 100644 index 5396c1fed4..0000000000 --- a/engines/scumm/sprite_he.h +++ /dev/null @@ -1,222 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#if !defined(SPRITE_HE_H) && !defined(DISABLE_HE) -#define SPRITE_HE_H - -namespace Scumm { - -enum SpriteFlags { - kSFChanged = 0x1, - kSFNeedRedraw = 0x2, - kSFScaled = 0x10, - kSFRotated = 0x20, - kSFDoubleBuffered = 0x1000, - kSFYFlipped = 0x2000, - kSFXFlipped = 0x4000, - kSFActive = 0x8000, - kSFRemapPalette = 0x80000, - kSFAutoAnim = 0x200000, - kSFMarkDirty = 0x400000, - kSFBlitDirectly = 0x2000000, - kSFImageless = 0x40000000 -}; - -enum SpriteGroupFlags { - kSGFClipBox = (1 << 0) -}; - -struct SpriteInfo { - int32 id; - int32 zorder; - int32 flags; - int32 image; - int32 imageState; - int32 group; - int32 palette; - int32 priority; - Common::Rect bbox; - int32 dx; - int32 dy; - Common::Point pos; - int32 tx; - int32 ty; - int32 userValue; - int32 curImageState; - int32 curImage; - int32 imglistNum; - int32 shadow; - int32 imageStateCount; - int32 angle; - int32 scale; - int32 animProgress; - int32 curAngle; - int32 curScale; - int32 curImgFlags; - int32 field_74; - int32 animSpeed; - int32 sourceImage; - int32 maskImage; - int32 field_84; - int32 classFlags; - int32 imgFlags; - int32 field_90; -}; - -struct SpriteGroup { - Common::Rect bbox; - int32 priority; - int32 flags; - int32 tx; - int32 ty; - int32 image; - int32 scaling; - int32 scale_x_ratio_mul; - int32 scale_x_ratio_div; - int32 scale_y_ratio_mul; - int32 scale_y_ratio_div; -}; - -class ScummEngine_v90he; - -class Sprite { -public: - Sprite(ScummEngine_v90he *vm); - virtual ~Sprite(); - - SpriteInfo *_spriteTable; - SpriteGroup *_spriteGroups; - SpriteInfo **_activeSpritesTable; - - int32 _numSpritesToProcess; - int32 _varNumSpriteGroups; - int32 _varNumSprites; - int32 _varMaxSprites; - - void saveOrLoadSpriteData(Serializer *s); - void resetBackground(); - void setRedrawFlags(bool checkZOrder); - void sortActiveSprites(); - void processImages(bool arg); - void updateImages(); - - int findSpriteWithClassOf(int x, int y, int spriteGroupId, int d, int num, int *args); - int getSpriteClass(int spriteId, int num, int *args); - int getSpriteFlagDoubleBuffered(int spriteId); - int getSpriteFlagYFlipped(int spriteId); - int getSpriteFlagXFlipped(int spriteId); - int getSpriteFlagActive(int spriteId); - int getSpriteFlagRemapPalette(int spriteId); - int getSpriteFlagAutoAnim(int spriteId); - int getSpriteFlagUpdateType(int spriteId); - int getSpriteFlagEraseType(int spriteId); - int getSpriteImage(int spriteId); - int getSpriteImageState(int spriteId); - int getSpriteGroup(int spriteId); - int getSpritePalette(int spriteId); - int getSpritePriority(int spriteId); - int getSpriteDisplayX(int spriteId); - int getSpriteDisplayY(int spriteId); - int getSpriteUserValue(int spriteId); - int getSpriteShadow(int spriteId); - int getSpriteImageStateCount(int spriteId); - int getSpriteScale(int spriteId); - int getSpriteAnimSpeed(int spriteId); - int getSpriteSourceImage(int spriteId); - int getSpriteMaskImage(int spriteId); - int getSpriteGeneralProperty(int spriteId, int type); - void getSpriteBounds(int spriteId, bool checkGroup, Common::Rect &bound); - void getSpriteImageDim(int spriteId, int32 &w, int32 &h); - void getSpritePosition(int spriteId, int32 &tx, int32 &ty); - void getSpriteDist(int spriteId, int32 &dx, int32 &dy); - - int getGroupPriority(int spriteGroupId); - int getGroupDstResNum(int spriteGroupId); - int getGroupXMul(int spriteGroupId); - int getGroupXDiv(int spriteGroupId); - int getGroupYMul(int spriteGroupId); - int getGroupYDiv(int spriteGroupId); - void getGroupPosition(int spriteGroupId, int32 &tx, int32 &ty); - - void setSpritePalette(int spriteId, int value); - void setSpriteSourceImage(int spriteId, int value); - void setSpriteMaskImage(int spriteId, int value); - void resetSprite(int spriteId); - void setSpriteImageState(int spriteId, int value); - void setSpritePosition(int spriteId, int value1, int value2); - void setSpriteGroup(int spriteId, int value); - void setSpriteDist(int spriteId, int value1, int value2); - void setSpriteShadow(int spriteId, int value); - void setSpriteUserValue(int spriteId, int value1, int value2); - void setSpritePriority(int spriteId, int value); - void moveSprite(int spriteId, int value1, int value2); - void setSpriteScale(int spriteId, int value); - void setSpriteAngle(int spriteId, int value); - void setSpriteFlagDoubleBuffered(int spriteId, int value); - void setSpriteFlagYFlipped(int spriteId, int value); - void setSpriteFlagXFlipped(int spriteId, int value); - void setSpriteFlagActive(int spriteId, int value); - void setSpriteFlagRemapPalette(int spriteId, int value); - void setSpriteFlagAutoAnim(int spriteId, int value); - void setSpriteFlagUpdateType(int spriteId, int value); - void setSpriteFlagEraseType(int spriteId, int value); - void setSpriteAnimSpeed(int spriteId, int value); - void setSpriteSetClass(int spriteId, int classId, int toggle); - void setSpriteResetClass(int spriteId); - void setSpriteField84(int spriteId, int value); - void setSpriteGeneralProperty(int spriteId, int type, int value); - - void moveGroupMembers(int spriteGroupId, int value1, int value2); - void redrawSpriteGroup(int spriteGroupId); - void setGroupMembersPriority(int spriteGroupId, int value); - void setGroupMembersGroup(int spriteGroupId, int value); - void setGroupMembersUpdateType(int spriteGroupId, int value); - void setGroupMembersResetSprite(int spriteGroupId); - void setGroupMembersAnimationSpeed(int spriteGroupId, int value); - void setGroupMembersAutoAnimFlag(int spriteGroupId, int value); - void setGroupMembersShadow(int spriteGroupId, int value); - - void moveGroup(int spriteGroupId, int value1, int value2); - void setGroupBounds(int spriteGroupId, int x1, int y1, int x2, int y2); - void setGroupPriority(int spriteGroupId, int value); - void setGroupPosition(int spriteGroupId, int value1, int value2); - void setGroupImage(int spriteGroupId, int value); - void setGroupScaling(int spriteGroupId); - void setGroupXMul(int spriteGroupId, int value); - void setGroupXDiv(int spriteGroupId, int value); - void setGroupYMul(int spriteGroupId, int value); - void setGroupYDiv(int spriteGroupId, int value); - void resetGroupBounds(int spriteGroupId); - - void allocTables(int numSprites, int numGroups, int numMaxSprites); - void resetGroup(int spriteGroupId); - void resetTables(bool refreshScreen); - void setSpriteImage(int spriteId, int imageNum); -private: - ScummEngine_v90he *_vm; -}; - -} // End of namespace Scumm - -#endif - diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp index c32413542d..be530f8c81 100644 --- a/engines/scumm/string.cpp +++ b/engines/scumm/string.cpp @@ -32,7 +32,7 @@ #include "scumm/imuse_digi/dimuse.h" #include "scumm/intern.h" #ifndef DISABLE_HE -#include "scumm/intern_he.h" +#include "scumm/he/intern_he.h" #endif #include "scumm/verbs.h" #include "scumm/sound.h" diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp index 1cdc446637..d1622072ca 100644 --- a/engines/scumm/vars.cpp +++ b/engines/scumm/vars.cpp @@ -26,9 +26,9 @@ #include "scumm/scumm.h" #include "scumm/intern.h" #ifndef DISABLE_HE -#include "scumm/intern_he.h" +#include "scumm/he/intern_he.h" #endif -#include "scumm/logic_he.h" +#include "scumm/he/logic_he.h" #include "sound/mididrv.h" namespace Scumm { diff --git a/engines/scumm/wiz_he.cpp b/engines/scumm/wiz_he.cpp deleted file mode 100644 index 9b0f9c3f15..0000000000 --- a/engines/scumm/wiz_he.cpp +++ /dev/null @@ -1,2088 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" - -#include "scumm/intern_he.h" -#include "scumm/resource.h" -#include "scumm/scumm.h" -#include "scumm/wiz_he.h" - -namespace Scumm { - -Wiz::Wiz(ScummEngine_v70he *vm) : _vm(vm) { - _imagesNum = 0; - memset(&_images, 0, sizeof(_images)); - memset(&_polygons, 0, sizeof(_polygons)); - _rectOverrideEnabled = false; -} - -void Wiz::clearWizBuffer() { - _imagesNum = 0; -} - -void Wiz::polygonClear() { - for (int i = 0; i < ARRAYSIZE(_polygons); i++) { - if (_polygons[i].flag == 1) - memset(&_polygons[i], 0, sizeof(WizPolygon)); - } -} - -void Wiz::polygonLoad(const uint8 *polData) { - int slots = READ_LE_UINT32(polData); - polData += 4; - - bool flag = 1; - int id, points, vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y; - while (slots--) { - id = READ_LE_UINT32(polData); - points = READ_LE_UINT32(polData + 4); - if (points != 4) - error("Illegal polygon with %d points", points); - vert1x = READ_LE_UINT32(polData + 8); - vert1y = READ_LE_UINT32(polData + 12); - vert2x = READ_LE_UINT32(polData + 16); - vert2y = READ_LE_UINT32(polData + 20); - vert3x = READ_LE_UINT32(polData + 24); - vert3y = READ_LE_UINT32(polData + 28); - vert4x = READ_LE_UINT32(polData + 32); - vert4y = READ_LE_UINT32(polData + 36); - - polData += 40; - polygonStore(id, flag, vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y); - } -} - -void Wiz::polygonStore(int id, bool flag, int vert1x, int vert1y, int vert2x, int vert2y, int vert3x, int vert3y, int vert4x, int vert4y) { - WizPolygon *wp = NULL; - for (int i = 0; i < ARRAYSIZE(_polygons); ++i) { - if (_polygons[i].id == 0) { - wp = &_polygons[i]; - break; - } - } - if (!wp) { - error("Wiz::polygonStore: out of polygon slot, max = %d", ARRAYSIZE(_polygons)); - } - - wp->vert[0].x = vert1x; - wp->vert[0].y = vert1y; - wp->vert[1].x = vert2x; - wp->vert[1].y = vert2y; - wp->vert[2].x = vert3x; - wp->vert[2].y = vert3y; - wp->vert[3].x = vert4x; - wp->vert[3].y = vert4y; - wp->vert[4].x = vert1x; - wp->vert[4].y = vert1y; - wp->id = id; - wp->numVerts = 5; - wp->flag = flag; - - polygonCalcBoundBox(wp->vert, wp->numVerts, wp->bound); -} - -void Wiz::polygonRotatePoints(Common::Point *pts, int num, int angle) { - double alpha = angle * PI / 180.; - double cos_alpha = cos(alpha); - double sin_alpha = sin(alpha); - - for (int i = 0; i < num; ++i) { - int16 x = pts[i].x; - int16 y = pts[i].y; - pts[i].x = (int16)(x * cos_alpha - y * sin_alpha); - pts[i].y = (int16)(y * cos_alpha + x * sin_alpha); - } -} - -void Wiz::polygonTransform(int resNum, int state, int po_x, int po_y, int angle, int scale, Common::Point *pts) { - int32 w, h; - - getWizImageDim(resNum, state, w, h); - - // set the transformation origin to the center of the image - if (_vm->_heversion >= 99) { - pts[0].x = pts[3].x = -(w / 2); - pts[1].x = pts[2].x = w / 2 - 1; - pts[0].y = pts[1].y = -(h / 2); - pts[2].y = pts[3].y = h / 2 - 1; - } else { - pts[1].x = pts[2].x = w / 2 - 1; - pts[0].x = pts[0].y = pts[1].y = pts[3].x = -(w / 2); - pts[2].y = pts[3].y = h / 2 - 1; - } - - // scale - if (scale != 0 && scale != 256) { - for (int i = 0; i < 4; ++i) { - pts[i].x = pts[i].x * scale / 256; - pts[i].y = pts[i].y * scale / 256; - } - } - - // rotate - if (angle != 0) - polygonRotatePoints(pts, 4, angle); - - // translate - for (int i = 0; i < 4; ++i) { - pts[i].x += po_x; - pts[i].y += po_y; - } -} - -void Wiz::polygonCalcBoundBox(Common::Point *vert, int numVerts, Common::Rect &bound) { - bound.left = 10000; - bound.top = 10000; - bound.right = -10000; - bound.bottom = -10000; - - // compute bounding box - for (int j = 0; j < numVerts; j++) { - Common::Rect r(vert[j].x, vert[j].y, vert[j].x + 1, vert[j].y + 1); - bound.extend(r); - } -} - -void Wiz::polygonErase(int fromId, int toId) { - for (int i = 0; i < ARRAYSIZE(_polygons); i++) { - if (_polygons[i].id >= fromId && _polygons[i].id <= toId) - memset(&_polygons[i], 0, sizeof(WizPolygon)); - } -} - -int Wiz::polygonHit(int id, int x, int y) { - for (int i = 0; i < ARRAYSIZE(_polygons); i++) { - if ((id == 0 || _polygons[i].id == id) && _polygons[i].bound.contains(x, y)) { - if (polygonContains(_polygons[i], x, y)) { - return _polygons[i].id; - } - } - } - return 0; -} - -bool Wiz::polygonDefined(int id) { - for (int i = 0; i < ARRAYSIZE(_polygons); i++) - if (_polygons[i].id == id) - return true; - return false; -} - -bool Wiz::polygonContains(const WizPolygon &pol, int x, int y) { - int pi = pol.numVerts - 1; - bool diry = (y < pol.vert[pi].y); - bool curdir; - bool r = false; - - for (int i = 0; i < pol.numVerts; i++) { - curdir = (y < pol.vert[i].y); - - if (curdir != diry) { - if (((pol.vert[pi].y - pol.vert[i].y) * (pol.vert[i].x - x) < - (pol.vert[pi].x - pol.vert[i].x) * (pol.vert[i].y - y)) == diry) - r = !r; - } - - pi = i; - diry = curdir; - } - - // HE80+ - int a, b; - pi = pol.numVerts - 1; - if (r == 0) { - for (int i = 0; i < pol.numVerts; i++) { - if (pol.vert[i].y == y && pol.vert[i].y == pol.vert[pi].y) { - - a = pol.vert[i].x; - b = pol.vert[pi].x; - - if (pol.vert[i].x >= pol.vert[pi].x) - a = pol.vert[pi].x; - - if (pol.vert[i].x > pol.vert[pi].x) - b = pol.vert[i].x; - - if (x >= a && x <= b) - return 1; - - } else if (pol.vert[i].x == x && pol.vert[i].x == pol.vert[pi].x) { - - a = pol.vert[i].y; - b = pol.vert[i].y; - - if (pol.vert[i].y >= pol.vert[pi].y) - a = pol.vert[pi].y; - - if (pol.vert[i].y <= pol.vert[pi].y) - b = pol.vert[pi].y; - - if (y >= a && y <= b) - return 1; - } - pi = i; - } - } - - return r; -} - -void Wiz::copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch) { - Common::Rect dstRect(srcx, srcy, srcx + srcw, srcy + srch); - dstRect.clip(dstw, dsth); - - int rw = dstRect.width(); - int rh = dstRect.height(); - if (rh <= 0 || rw <= 0) - return; - - uint8 *dst1Ptr = dst1 + dstRect.left + dstRect.top * dstw; - uint8 *dst2Ptr = dst2 + dstRect.left + dstRect.top * dstw; - const uint8 *dataPtr = src; - - while (rh--) { - uint16 off = READ_LE_UINT16(dataPtr); dataPtr += 2; - const uint8 *dataPtrNext = off + dataPtr; - uint8 *dst1PtrNext = dst1Ptr + dstw; - uint8 *dst2PtrNext = dst2Ptr + dstw; - if (off != 0) { - int w = rw; - while (w > 0) { - uint8 code = *dataPtr++; - if (code & 1) { - code >>= 1; - dst1Ptr += code; - dst2Ptr += code; - w -= code; - } else if (code & 2) { - code = (code >> 2) + 1; - w -= code; - if (w >= 0) { - memset(dst1Ptr, *dataPtr++, code); - dst1Ptr += code; - dst2Ptr += code; - } else { - code += w; - memset(dst1Ptr, *dataPtr, code); - } - } else { - code = (code >> 2) + 1; - w -= code; - if (w >= 0) { - memcpy(dst1Ptr, dst2Ptr, code); - dst1Ptr += code; - dst2Ptr += code; - } else { - code += w; - memcpy(dst1Ptr, dst2Ptr, code); - } - } - } - } - dataPtr = dataPtrNext; - dst1Ptr = dst1PtrNext; - dst2Ptr = dst2PtrNext; - } -} - -static bool calcClipRects(int dst_w, int dst_h, int src_x, int src_y, int src_w, int src_h, const Common::Rect *rect, Common::Rect &srcRect, Common::Rect &dstRect) { - srcRect = Common::Rect(src_w, src_h); - dstRect = Common::Rect(src_x, src_y, src_x + src_w, src_y + src_h); - Common::Rect r3; - int diff; - - if (rect) { - r3 = *rect; - Common::Rect r4(dst_w, dst_h); - if (r3.intersects(r4)) { - r3.clip(r4); - } else { - return false; - } - } else { - r3 = Common::Rect(dst_w, dst_h); - } - diff = dstRect.left - r3.left; - if (diff < 0) { - srcRect.left -= diff; - dstRect.left -= diff; - } - diff = dstRect.right - r3.right; - if (diff > 0) { - srcRect.right -= diff; - dstRect.right -= diff; - } - diff = dstRect.top - r3.top; - if (diff < 0) { - srcRect.top -= diff; - dstRect.top -= diff; - } - diff = dstRect.bottom - r3.bottom; - if (diff > 0) { - srcRect.bottom -= diff; - dstRect.bottom -= diff; - } - - return srcRect.isValidRect() && dstRect.isValidRect(); -} - -void Wiz::copyWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, const uint8 *xmapPtr) { - Common::Rect r1, r2; - if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { - dst += r2.left + r2.top * dstw; - decompressWizImage(dst, dstw, r2, src, r1, flags, palPtr, xmapPtr); - } -} - -void Wiz::copyRaw16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor) { - // RAW 16 bits in 555 format - - // HACK: Skip every second bit for now - Common::Rect r1, r2; - if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { - if (flags & kWIFFlipX) { - int l = r1.left; - int r = r1.right; - r1.left = srcw - r; - r1.right = srcw - l; - } - if (flags & kWIFFlipY) { - int t = r1.top; - int b = r1.bottom; - r1.top = srch - b; - r1.bottom = srch - t; - } - byte imagePal[256]; - if (!palPtr) { - for (int i = 0; i < 256; i++) { - imagePal[i] = i; - } - palPtr = imagePal; - } - - int h = r1.height(); - int w = r1.width(); - src += r1.left + r1.top * srcw * 2; - dst += r2.left + r2.top * dstw; - - while (h--) { - const uint8 *p = src; - for (int i = 0; i < w; ++i) { - uint8 col = *p; - if (transColor == -1 || transColor != col) { - dst[i] = palPtr[col]; - } - p += 2; - } - src += srcw * 2; - dst += dstw; - } - - } -} - -void Wiz::copyRawWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor) { - Common::Rect r1, r2; - if (calcClipRects(dstw, dsth, srcx, srcy, srcw, srch, rect, r1, r2)) { - if (flags & kWIFFlipX) { - int l = r1.left; - int r = r1.right; - r1.left = srcw - r; - r1.right = srcw - l; - } - if (flags & kWIFFlipY) { - int t = r1.top; - int b = r1.bottom; - r1.top = srch - b; - r1.bottom = srch - t; - } - byte imagePal[256]; - if (!palPtr) { - for (int i = 0; i < 256; i++) { - imagePal[i] = i; - } - palPtr = imagePal; - } - int h = r1.height(); - int w = r1.width(); - src += r1.left + r1.top * srcw; - dst += r2.left + r2.top * dstw; - while (h--) { - const uint8 *p = src; - for (int i = 0; i < w; ++i) { - uint8 col = *p++; - if (transColor == -1 || transColor != col) { - dst[i] = palPtr[col]; - } - } - src += srcw; - dst += dstw; - } - } -} - -void Wiz::decompressWizImage(uint8 *dst, int dstPitch, const Common::Rect &dstRect, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr, const uint8 *xmapPtr) { - if (flags & kWIFFlipX) { - debug(1, "decompressWizImage: Unhandled flag kWIFFlipX"); - } - if (flags & kWIFFlipY) { - debug(1, "decompressWizImage: Unhandled flag kWIFFlipY"); - } - - const uint8 *dataPtr, *dataPtrNext; - uint8 *dstPtr, *dstPtrNext; - uint32 code; - uint8 databit; - int h, w, xoff; - uint16 off; - - byte imagePal[256]; - if (!palPtr) { - for (int i = 0; i < 256; i++) { - imagePal[i] = i; - } - palPtr = imagePal; - } - - dstPtr = dst; - dataPtr = src; - - // Skip over the first 'srcRect->top' lines in the data - h = srcRect.top; - while (h--) { - dataPtr += READ_LE_UINT16(dataPtr) + 2; - } - h = srcRect.height(); - w = srcRect.width(); - if (h <= 0 || w <= 0) - return; - - while (h--) { - xoff = srcRect.left; - off = READ_LE_UINT16(dataPtr); - w = srcRect.right - srcRect.left; - dstPtrNext = dstPitch + dstPtr; - dataPtrNext = off + 2 + dataPtr; - dataPtr += 2; - if (off == 0) - goto dec_next; - - // Skip over the leftmost 'srcRect->left' pixels. - // TODO: This code could be merged (at a loss of efficency) with the - // loop below which does the actual drawing. - while (xoff > 0) { - code = *dataPtr++; - databit = code & 1; - code >>= 1; - if (databit) { - xoff -= code; - if (xoff < 0) { - code = -xoff; - goto dec_sub1; - } - } else { - databit = code & 1; - code = (code >> 1) + 1; - if (databit) { - ++dataPtr; - xoff -= code; - if (xoff < 0) { - code = -xoff; - --dataPtr; - goto dec_sub2; - } - } else { - dataPtr += code; - xoff -= code; - if (xoff < 0) { - dataPtr += xoff; - code = -xoff; - goto dec_sub3; - } - } - } - } - - while (w > 0) { - code = *dataPtr++; - databit = code & 1; - code >>= 1; - if (databit) { -dec_sub1: dstPtr += code; - w -= code; - } else { - databit = code & 1; - code = (code >> 1) + 1; - if (databit) { -dec_sub2: w -= code; - if (w < 0) { - code += w; - } - while (code--) { - if (xmapPtr) { - *dstPtr = xmapPtr[palPtr[*dataPtr] * 256 + *dstPtr]; - dstPtr++; - } else { - *dstPtr++ = palPtr[*dataPtr]; - } - } - dataPtr++; - } else { -dec_sub3: w -= code; - if (w < 0) { - code += w; - } - while (code--) { - if (xmapPtr) { - *dstPtr = xmapPtr[palPtr[*dataPtr++] * 256 + *dstPtr]; - dstPtr++; - } else { - *dstPtr++ = palPtr[*dataPtr++]; - } - } - } - } - } -dec_next: - dataPtr = dataPtrNext; - dstPtr = dstPtrNext; - } -} - -int Wiz::isWizPixelNonTransparent(const uint8 *data, int x, int y, int w, int h) { - if (x < 0 || x >= w || y < 0 || y >= h) { - return 0; - } - while (y != 0) { - data += READ_LE_UINT16(data) + 2; - --y; - } - uint16 off = READ_LE_UINT16(data); data += 2; - if (off == 0) { - return 0; - } - while (x > 0) { - uint8 code = *data++; - if (code & 1) { - code >>= 1; - if (code > x) { - return 0; - } - x -= code; - } else if (code & 2) { - code = (code >> 2) + 1; - if (code > x) { - return 1; - } - x -= code; - ++data; - } else { - code = (code >> 2) + 1; - if (code > x) { - return 1; - } - x -= code; - data += code; - } - } - return (~data[0]) & 1; -} - -uint8 Wiz::getWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color) { - if (x < 0 || x >= w || y < 0 || y >= h) { - return color; - } - while (y != 0) { - data += READ_LE_UINT16(data) + 2; - --y; - } - uint16 off = READ_LE_UINT16(data); data += 2; - if (off == 0) { - return color; - } - while (x > 0) { - uint8 code = *data++; - if (code & 1) { - code >>= 1; - if (code > x) { - return color; - } - x -= code; - } else if (code & 2) { - code = (code >> 2) + 1; - if (code > x) { - return data[0]; - } - x -= code; - ++data; - } else { - code = (code >> 2) + 1; - if (code > x) { - return data[x]; - } - x -= code; - data += code; - } - } - return (data[0] & 1) ? color : data[1]; -} - -uint8 Wiz::getRawWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color) { - if (x < 0 || x >= w || y < 0 || y >= h) { - return color; - } - return data[y * w + x]; -} - -void Wiz::computeWizHistogram(uint32 *histogram, const uint8 *data, const Common::Rect &rCapt) { - int y = rCapt.top; - while (y != 0) { - data += READ_LE_UINT16(data) + 2; - --y; - } - int ih = rCapt.height(); - while (ih--) { - uint16 off = READ_LE_UINT16(data); data += 2; - if (off != 0) { - const uint8 *p = data; - int x1 = rCapt.left; - int x2 = rCapt.right; - uint8 code; - while (x1 > 0) { - code = *p++; - if (code & 1) { - code >>= 1; - if (code > x1) { - code -= x1; - x2 -= code; - break; - } - x1 -= code; - } else if (code & 2) { - code = (code >> 2) + 1; - if (code > x1) { - code -= x1; - goto dec_sub2; - } - x1 -= code; - ++p; - } else { - code = (code >> 2) + 1; - if (code > x1) { - code -= x1; - p += x1; - goto dec_sub3; - } - x1 -= code; - p += code; - } - } - while (x2 > 0) { - code = *p++; - if (code & 1) { - code >>= 1; - x2 -= code; - } else if (code & 2) { - code = (code >> 2) + 1; -dec_sub2: x2 -= code; - if (x2 < 0) { - code += x2; - } - histogram[*p++] += code; - } else { - code = (code >> 2) + 1; -dec_sub3: x2 -= code; - if (x2 < 0) { - code += x2; - } - int n = code; - while (n--) { - ++histogram[*p++]; - } - } - } - data += off; - } - } -} - -void Wiz::computeRawWizHistogram(uint32 *histogram, const uint8 *data, int srcPitch, const Common::Rect &rCapt) { - data += rCapt.top * srcPitch + rCapt.left; - int iw = rCapt.width(); - int ih = rCapt.height(); - while (ih--) { - for (int i = 0; i < iw; ++i) { - ++histogram[data[i]]; - } - data += srcPitch; - } -} - -static int wizPackType1(uint8 *dst, const uint8 *src, int srcPitch, const Common::Rect& rCapt, uint8 transColor) { - debug(9, "wizPackType1(%d, [%d,%d,%d,%d])", transColor, rCapt.left, rCapt.top, rCapt.right, rCapt.bottom); - src += rCapt.top * srcPitch + rCapt.left; - int w = rCapt.width(); - int h = rCapt.height(); - int dataSize = 0; - while (h--) { - uint8 *dstLine = dst; - if (dst) { - dst += 2; - } - uint8 diffBuffer[0x40]; - int runCountSame = 0; - int runCountDiff = 0; - uint8 prevColor = src[0]; - for (int i = 1; i < w; ) { - uint8 color = src[i++]; - if (i == 2) { - if (prevColor == color) { - runCountSame = 1; - } else { - diffBuffer[0] = prevColor; - runCountDiff = 1; - } - } - if (prevColor == color) { - if (runCountDiff != 0) { - runCountSame = 1; - if (runCountDiff > 1) { - --runCountDiff; - if (dst) { - *dst++ = ((runCountDiff - 1) << 2) | 0; - memcpy(dst, diffBuffer, runCountDiff); - dst += runCountDiff; - } - dataSize += runCountDiff + 1; - } - runCountDiff = 0; - } - ++runCountSame; - if (prevColor == transColor) { - if (runCountSame == 0x7F) { - if (dst) { - *dst++ = (runCountSame << 1) | 1; - } - ++dataSize; - runCountSame = 0; - } - } else { - if (runCountSame == 0x40) { - if (dst) { - *dst++ = ((runCountSame - 1) << 2) | 2; - *dst++ = prevColor; - } - dataSize += 2; - runCountSame = 0; - } - } - } else { - if (runCountSame != 0) { - if (prevColor == transColor) { - if (dst) { - *dst++ = (runCountSame << 1) | 1; - } - ++dataSize; - } else { - if (dst) { - *dst++ = ((runCountSame - 1) << 2) | 2; - *dst++ = prevColor; - } - dataSize += 2; - } - runCountSame = 0; - } - assert(runCountDiff < ARRAYSIZE(diffBuffer)); - diffBuffer[runCountDiff++] = color; - if (runCountDiff == 0x40) { - if (dst) { - *dst++ = ((runCountDiff - 1) << 2) | 0; - memcpy(dst, diffBuffer, runCountDiff); - dst += runCountDiff + 1; - } - dataSize += runCountDiff + 1; - runCountDiff = 0; - } - } - prevColor = color; - } - if (runCountSame != 0) { - if (prevColor == transColor) { - if (dst) { - *dst++ = (runCountSame << 1) | 1; - } - ++dataSize; - } else { - if (dst) { - *dst++ = ((runCountSame - 1) << 2) | 2; - *dst++ = prevColor; - } - dataSize += 2; - } - } - if (runCountDiff != 0) { - if (dst) { - *dst++ = ((runCountDiff - 1) << 2) | 0; - memcpy(dst, diffBuffer, runCountDiff); - dst += runCountDiff; - } - dataSize += runCountDiff + 1; - } - if (dst) { - WRITE_LE_UINT16(dstLine, dst - dstLine - 2); - } - dataSize += 2; - src += srcPitch; - } - return dataSize; -} - -static int wizPackType0(uint8 *dst, const uint8 *src, int srcPitch, const Common::Rect& rCapt) { - debug(9, "wizPackType0([%d,%d,%d,%d])", rCapt.left, rCapt.top, rCapt.right, rCapt.bottom); - int w = rCapt.width(); - int h = rCapt.height(); - int size = w * h; - if (dst) { - src += rCapt.top * srcPitch + rCapt.left; - while (h--) { - memcpy(dst, src, w); - dst += w; - src += srcPitch; - } - } - return size; -} - -void Wiz::captureWizImage(int resNum, const Common::Rect& r, bool backBuffer, int compType) { - debug(5, "ScummEngine_v72he::captureWizImage(%d, %d, [%d,%d,%d,%d])", resNum, compType, r.left, r.top, r.right, r.bottom); - uint8 *src = NULL; - VirtScreen *pvs = &_vm->virtscr[kMainVirtScreen]; - if (backBuffer) { - src = pvs->getBackPixels(0, 0); - } else { - src = pvs->getPixels(0, 0); - } - Common::Rect rCapt(pvs->w, pvs->h); - if (rCapt.intersects(r)) { - rCapt.clip(r); - const uint8 *palPtr; - if (_vm->_heversion >= 99) { - palPtr = _vm->_hePalettes + 1024; - } else { - palPtr = _vm->_currentPalette; - } - - int w = rCapt.width(); - int h = rCapt.height(); - int transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : 5; - - // compute compressed size - int dataSize = 0; - int headerSize = palPtr ? 1080 : 36; - switch (compType) { - case 0: - dataSize = wizPackType0(0, src, pvs->pitch, rCapt); - break; - case 1: - dataSize = wizPackType1(0, src, pvs->pitch, rCapt, transColor); - break; - default: - error("unhandled compression type %d", compType); - break; - } - - // alignment - dataSize = (dataSize + 1) & ~1; - int wizSize = headerSize + dataSize; - // write header - uint8 *wizImg = _vm->res.createResource(rtImage, resNum, dataSize + headerSize); - WRITE_BE_UINT32(wizImg + 0x00, 'AWIZ'); - WRITE_BE_UINT32(wizImg + 0x04, wizSize); - WRITE_BE_UINT32(wizImg + 0x08, 'WIZH'); - WRITE_BE_UINT32(wizImg + 0x0C, 0x14); - WRITE_LE_UINT32(wizImg + 0x10, compType); - WRITE_LE_UINT32(wizImg + 0x14, w); - WRITE_LE_UINT32(wizImg + 0x18, h); - int curSize = 0x1C; - if (palPtr) { - WRITE_BE_UINT32(wizImg + 0x1C, 'RGBS'); - WRITE_BE_UINT32(wizImg + 0x20, 0x308); - memcpy(wizImg + 0x24, palPtr, 0x300); - WRITE_BE_UINT32(wizImg + 0x324, 'RMAP'); - WRITE_BE_UINT32(wizImg + 0x328, 0x10C); - WRITE_BE_UINT32(wizImg + 0x32C, 0); - curSize = 0x330; - for (int i = 0; i < 256; ++i) { - wizImg[curSize] = i; - ++curSize; - } - } - WRITE_BE_UINT32(wizImg + curSize + 0x0, 'WIZD'); - WRITE_BE_UINT32(wizImg + curSize + 0x4, dataSize + 8); - curSize += 8; - - // write compressed data - switch (compType) { - case 0: - wizPackType0(wizImg + headerSize, src, pvs->pitch, rCapt); - break; - case 1: - wizPackType1(wizImg + headerSize, src, pvs->pitch, rCapt, transColor); - break; - default: - break; - } - } - _vm->res.setModified(rtImage, resNum); -} - -void Wiz::displayWizImage(WizImage *pwi) { - if (_vm->_fullRedraw) { - assert(_imagesNum < ARRAYSIZE(_images)); - WizImage *wi = &_images[_imagesNum]; - wi->resNum = pwi->resNum; - wi->x1 = pwi->x1; - wi->y1 = pwi->y1; - wi->zorder = 0; - wi->state = pwi->state; - wi->flags = pwi->flags; - wi->shadow = 0; - wi->field_390 = 0; - wi->palette = 0; - ++_imagesNum; - } else if (pwi->flags & kWIFIsPolygon) { - drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags, 0, 0, 0); - } else { - const Common::Rect *r = NULL; - drawWizImage(pwi->resNum, pwi->state, pwi->x1, pwi->y1, 0, 0, 0, r, pwi->flags, 0, 0); - } -} - -uint8 *Wiz::drawWizImage(int resNum, int state, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, int palette) { - debug(2, "drawWizImage(resNum %d, x1 %d y1 %d flags 0x%X zorder %d shadow %d field_390 %d dstResNum %d palette %d)", resNum, x1, y1, flags, zorder, shadow, field_390, dstResNum, palette); - uint8 *dataPtr; - uint8 *dst = NULL; - - const uint8 *palPtr = NULL; - if (_vm->_heversion >= 99) { - if (palette) { - palPtr = _vm->_hePalettes + palette * 1024 + 768; - } else { - palPtr = _vm->_hePalettes + 1792; - } - } - - const uint8 *xmapPtr = NULL; - if (shadow) { - dataPtr = _vm->getResourceAddress(rtImage, shadow); - assert(dataPtr); - xmapPtr = _vm->findResourceData(MKID('XMAP'), dataPtr); - assert(xmapPtr); - } - - dataPtr = _vm->getResourceAddress(rtImage, resNum); - assert(dataPtr); - - uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); - assert(wizh); - uint32 comp = READ_LE_UINT32(wizh + 0x0); - uint32 width = READ_LE_UINT32(wizh + 0x4); - uint32 height = READ_LE_UINT32(wizh + 0x8); - debug(2, "wiz_header.comp = %d wiz_header.w = %d wiz_header.h = %d", comp, width, height); - - uint8 *wizd = _vm->findWrappedBlock(MKID('WIZD'), dataPtr, state, 0); - assert(wizd); - - if (flags & kWIFHasPalette) { - uint8 *pal = _vm->findWrappedBlock(MKID('RGBS'), dataPtr, state, 0); - assert(pal); - _vm->setPaletteFromPtr(pal, 256); - } - - uint8 *rmap = NULL; - if (flags & kWIFRemapPalette) { - rmap = _vm->findWrappedBlock(MKID('RMAP'), dataPtr, state, 0); - assert(rmap); - if (_vm->_heversion <= 80 || READ_BE_UINT32(rmap) != 0x01234567) { - uint8 *rgbs = _vm->findWrappedBlock(MKID('RGBS'), dataPtr, state, 0); - assert(rgbs); - _vm->remapHEPalette(rgbs, rmap + 4); - } - } - - if (flags & kWIFPrint) { - error("WizImage printing is unimplemented"); - } - - int32 cw, ch; - if (flags & kWIFBlitToMemBuffer) { - dst = (uint8 *)malloc(width * height); - int transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? (_vm->VAR(_vm->VAR_WIZ_TCOLOR)) : 5; - memset(dst, transColor, width * height); - cw = width; - ch = height; - } else { - if (dstResNum) { - uint8 *dstPtr = _vm->getResourceAddress(rtImage, dstResNum); - assert(dstPtr); - dst = _vm->findWrappedBlock(MKID('WIZD'), dstPtr, 0, 0); - assert(dst); - getWizImageDim(dstResNum, 0, cw, ch); - } else { - VirtScreen *pvs = &_vm->virtscr[kMainVirtScreen]; - if (flags & kWIFMarkBufferDirty) { - dst = pvs->getPixels(0, pvs->topline); - } else { - dst = pvs->getBackPixels(0, pvs->topline); - } - cw = pvs->w; - ch = pvs->h; - } - } - - Common::Rect rScreen(cw, ch); - if (clipBox) { - Common::Rect clip(clipBox->left, clipBox->top, clipBox->right, clipBox->bottom); - if (rScreen.intersects(clip)) { - rScreen.clip(clip); - } else { - return 0; - } - } else if (_rectOverrideEnabled) { - if (rScreen.intersects(_rectOverride)) { - rScreen.clip(_rectOverride); - } else { - return 0; - } - } - - if (flags & kWIFRemapPalette) { - palPtr = rmap + 4; - } - - int transColor = -1; - if (_vm->VAR_WIZ_TCOLOR != 0xFF) { - uint8 *trns = _vm->findWrappedBlock(MKID('TRNS'), dataPtr, state, 0); - transColor = (trns == NULL) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : -1; - } - - switch (comp) { - case 0: - copyRawWizImage(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, transColor); - break; - case 1: - // TODO Adding masking for flags 0x80 and 0x100 - if (flags & 0x80) - // Used in maze - debug(0, "drawWizImage: Unhandled flag 0x80"); - if (flags & 0x100) { - // Used in readdemo - debug(0, "drawWizImage: Unhandled flag 0x100"); - } - copyWizImage(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, xmapPtr); - break; - case 2: - copyRaw16BitWizImage(dst, wizd, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, transColor); - break; - default: - error("drawWizImage: Unhandled wiz compression type %d", comp); - } - - if (!(flags & kWIFBlitToMemBuffer) && dstResNum == 0) { - Common::Rect rImage(x1, y1, x1 + width, y1 + height); - if (rImage.intersects(rScreen)) { - rImage.clip(rScreen); - if (!(flags & kWIFBlitToFrontVideoBuffer) && (flags & (kWIFBlitToFrontVideoBuffer | kWIFMarkBufferDirty))) { - ++rImage.bottom; - _vm->markRectAsDirty(kMainVirtScreen, rImage); - } else { - _vm->gdi.copyVirtScreenBuffers(rImage); - } - } - } - - return dst; -} - -struct PolygonDrawData { - struct PolygonArea { - int32 xmin; - int32 xmax; - int32 x1; - int32 y1; - int32 x2; - int32 y2; - }; - struct ResultArea { - int32 dst_offs; - int32 x_step; - int32 y_step; - int32 x_s; - int32 y_s; - int32 w; - }; - Common::Point mat[4]; - PolygonArea *pa; - ResultArea *ra; - int rAreasNum; - int pAreasNum; - - PolygonDrawData(int n) { - memset(mat, 0, sizeof(mat)); - pa = new PolygonArea[n]; - for (int i = 0; i < n; ++i) { - pa[i].xmin = 0x7FFFFFFF; - pa[i].xmax = 0x80000000; - } - ra = new ResultArea[n]; - rAreasNum = 0; - pAreasNum = n; - } - - ~PolygonDrawData() { - delete[] pa; - delete[] ra; - } - - void transform(const Common::Point *tp1, const Common::Point *tp2, const Common::Point *sp1, const Common::Point *sp2) { - int32 tx_acc = tp1->x << 16; - int32 sx_acc = sp1->x << 16; - int32 sy_acc = sp1->y << 16; - uint16 dy = ABS(tp2->y - tp1->y) + 1; - int32 tx_step = ((tp2->x - tp1->x) << 16) / dy; - int32 sx_step = ((sp2->x - sp1->x) << 16) / dy; - int32 sy_step = ((sp2->y - sp1->y) << 16) / dy; - - int y = tp1->y - mat[0].y; - while (dy--) { - assert(y >= 0 && y < pAreasNum); - PolygonArea *ppa = &pa[y]; - int32 ttx = tx_acc >> 16; - int32 tsx = sx_acc >> 16; - int32 tsy = sy_acc >> 16; - - if (ppa->xmin > ttx) { - ppa->xmin = ttx; - ppa->x1 = tsx; - ppa->y1 = tsy; - } - if (ppa->xmax < ttx) { - ppa->xmax = ttx; - ppa->x2 = tsx; - ppa->y2 = tsy; - } - - tx_acc += tx_step; - sx_acc += sx_step; - sy_acc += sy_step; - - if (tp2->y <= tp1->y) { - --y; - } else { - ++y; - } - } - } -}; - -void Wiz::drawWizComplexPolygon(int resNum, int state, int po_x, int po_y, int shadow, int angle, int scale, const Common::Rect *r, int flags, int dstResNum, int palette) { - Common::Point pts[4]; - - polygonTransform(resNum, state, po_x, po_y, angle, scale, pts); - drawWizPolygonTransform(resNum, state, pts, flags, shadow, dstResNum, palette); -} - -void Wiz::drawWizPolygon(int resNum, int state, int id, int flags, int shadow, int dstResNum, int palette) { - int i; - WizPolygon *wp = NULL; - for (i = 0; i < ARRAYSIZE(_polygons); ++i) { - if (_polygons[i].id == id) { - wp = &_polygons[i]; - break; - } - } - if (!wp) { - error("Polygon %d is not defined", id); - } - if (wp->numVerts != 5) { - error("Invalid point count %d for Polygon %d", wp->numVerts, id); - } - - drawWizPolygonTransform(resNum, state, wp->vert, flags, shadow, dstResNum, palette); -} - -void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int flags, int shadow, int dstResNum, int palette) { - debug(2, "drawWizPolygonTransform(resNum %d, flags 0x%X, shadow %d dstResNum %d palette %d)", resNum, flags, shadow, dstResNum, palette); - int i; - - if (flags & 0x800000) { - warning("0x800000 flags not supported"); - return; - } - - const Common::Rect *r = NULL; - uint8 *srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, shadow, 0, r, kWIFBlitToMemBuffer, 0, palette); - if (srcWizBuf) { - uint8 *dst; - int32 dstw, dsth, dstpitch, wizW, wizH; - VirtScreen *pvs = &_vm->virtscr[kMainVirtScreen]; - int transColor = (_vm->VAR_WIZ_TCOLOR != 0xFF) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : 5; - - if (dstResNum) { - uint8 *dstPtr = _vm->getResourceAddress(rtImage, dstResNum); - assert(dstPtr); - dst = _vm->findWrappedBlock(MKID('WIZD'), dstPtr, 0, 0); - assert(dst); - getWizImageDim(dstResNum, 0, dstw, dsth); - dstpitch = dstw; - } else { - if (flags & kWIFMarkBufferDirty) { - dst = pvs->getPixels(0, 0); - } else { - dst = pvs->getBackPixels(0, 0); - } - dstw = pvs->w; - dsth = pvs->h; - dstpitch = pvs->pitch; - } - - getWizImageDim(resNum, state, wizW, wizH); - - Common::Point bbox[4]; - bbox[0].x = 0; - bbox[0].y = 0; - bbox[1].x = wizW - 1; - bbox[1].y = 0; - bbox[2].x = wizW - 1; - bbox[2].y = wizH - 1; - bbox[3].x = 0; - bbox[3].y = wizH - 1; - - int16 xmin_p, xmax_p, ymin_p, ymax_p; - xmin_p = ymin_p = (int16)0x7FFF; - xmax_p = ymax_p = (int16)0x8000; - - for (i = 0; i < 4; ++i) { - xmin_p = MIN(wp[i].x, xmin_p); - xmax_p = MAX(wp[i].x, xmax_p); - ymin_p = MIN(wp[i].y, ymin_p); - ymax_p = MAX(wp[i].y, ymax_p); - } - - int16 xmin_b, xmax_b, ymin_b, ymax_b; - xmin_b = ymin_b = (int16)0x7FFF; - xmax_b = ymax_b = (int16)0x8000; - - for (i = 0; i < 4; ++i) { - xmin_b = MIN(bbox[i].x, xmin_b); - xmax_b = MAX(bbox[i].x, xmax_b); - ymin_b = MIN(bbox[i].y, ymin_b); - ymax_b = MAX(bbox[i].y, ymax_b); - } - - PolygonDrawData pdd(ymax_p - ymin_p + 1); - pdd.mat[0].x = xmin_p; - pdd.mat[0].y = ymin_p; - pdd.mat[1].x = xmax_p; - pdd.mat[1].y = ymax_p; - pdd.mat[2].x = xmin_b; - pdd.mat[2].y = ymin_b; - pdd.mat[3].x = xmax_b; - pdd.mat[3].y = ymax_b; - - // precompute the transformation which remaps 'bbox' pixels to 'wp' - for (i = 0; i < 3; ++i) { - pdd.transform(&wp[i], &wp[i + 1], &bbox[i], &bbox[i + 1]); - } - pdd.transform(&wp[3], &wp[0], &bbox[3], &bbox[0]); - - pdd.rAreasNum = 0; - PolygonDrawData::ResultArea *pra = &pdd.ra[0]; - int32 yoff = pdd.mat[0].y * dstpitch; - int16 y_start = pdd.mat[0].y; - for (i = 0; i < pdd.pAreasNum; ++i) { - PolygonDrawData::PolygonArea *ppa = &pdd.pa[i]; - if (y_start >= 0 && y_start < dsth) { - int16 x1 = ppa->xmin; - if (x1 < 0) { - x1 = 0; - } - int16 x2 = ppa->xmax; - if (x2 >= dstw) { - x2 = dstw - 1; - } - int16 w = x2 - x1 + 1; - if (w > 0) { - int16 width = ppa->xmax - ppa->xmin + 1; - pra->x_step = ((ppa->x2 - ppa->x1) << 16) / width; - pra->y_step = ((ppa->y2 - ppa->y1) << 16) / width; - pra->dst_offs = yoff + x1; - pra->w = w; - pra->x_s = ppa->x1 << 16; - pra->y_s = ppa->y1 << 16; - int16 tmp = x1 - ppa->xmin; - if (tmp != 0) { - pra->x_s += pra->x_step * tmp; - pra->y_s += pra->y_step * tmp; - } - ++pra; - ++pdd.rAreasNum; - } - } - ++ppa; - yoff += dstpitch; - ++y_start; - } - - pra = &pdd.ra[0]; - for (i = 0; i < pdd.rAreasNum; ++i, ++pra) { - uint8 *dstPtr = dst + pra->dst_offs; - int32 w = pra->w; - int32 x_acc = pra->x_s; - int32 y_acc = pra->y_s; - while (--w) { - int32 src_offs = (y_acc >> 16) * wizW + (x_acc >> 16); - assert(src_offs < wizW * wizH); - x_acc += pra->x_step; - y_acc += pra->y_step; - if (transColor == -1 || transColor != srcWizBuf[src_offs]) { - *dstPtr = srcWizBuf[src_offs]; - } - dstPtr++; - } - } - - Common::Rect bound(xmin_p, ymin_p, xmax_p + 1, ymax_p + 1); - if (flags & kWIFMarkBufferDirty) { - _vm->markRectAsDirty(kMainVirtScreen, bound); - } else { - _vm->gdi.copyVirtScreenBuffers(bound); - } - - free(srcWizBuf); - } -} - -void Wiz::flushWizBuffer() { - for (int i = 0; i < _imagesNum; ++i) { - WizImage *pwi = &_images[i]; - if (pwi->flags & kWIFIsPolygon) { - drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags, pwi->shadow, 0, pwi->palette); - } else { - const Common::Rect *r = NULL; - drawWizImage(pwi->resNum, pwi->state, pwi->x1, pwi->y1, pwi->zorder, pwi->shadow, pwi->field_390, r, pwi->flags, 0, pwi->palette); - } - } - _imagesNum = 0; -} - -void Wiz::loadWizCursor(int resId) { - int32 x, y; - getWizImageSpot(resId, 0, x, y); - if (x < 0) { - x = 0; - } else if (x > 32) { - x = 32; - } - if (y < 0) { - y = 0; - } else if (y > 32) { - y = 32; - } - - const Common::Rect *r = NULL; - uint8 *cursor = drawWizImage(resId, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, 0); - int32 cw, ch; - getWizImageDim(resId, 0, cw, ch); - _vm->setCursorFromBuffer(cursor, cw, ch, cw); - _vm->setCursorHotspot(x, y); - free(cursor); -} - -void Wiz::displayWizComplexImage(const WizParameters *params) { - int sourceImage = 0; - if (params->processFlags & kWPFMaskImg) { - sourceImage = params->sourceImage; - debug(0, "displayWizComplexImage() unhandled flag 0x80000"); - } - int palette = 0; - if (params->processFlags & kWPFPaletteNum) { - palette = params->img.palette; - } - int scale = 256; - if (params->processFlags & kWPFScaled) { - scale = params->scale; - } - int rotationAngle = 0; - if (params->processFlags & kWPFRotate) { - rotationAngle = params->angle; - } - int state = 0; - if (params->processFlags & kWPFNewState) { - state = params->img.state; - } - int flags = 0; - if (params->processFlags & kWPFNewFlags) { - flags = params->img.flags; - } - int po_x = 0; - int po_y = 0; - if (params->processFlags & kWPFSetPos) { - po_x = params->img.x1; - po_y = params->img.y1; - } - int shadow = 0; - if (params->processFlags & kWPFShadow) { - shadow = params->img.shadow; - } - int field_390 = 0; - if (params->processFlags & 0x200000) { - field_390 = params->img.field_390; - debug(0, "displayWizComplexImage() unhandled flag 0x200000"); - } - const Common::Rect *r = NULL; - if (params->processFlags & kWPFClipBox) { - r = ¶ms->box; - } - int dstResNum = 0; - if (params->processFlags & kWPFDstResNum) { - dstResNum = params->dstResNum; - } - if (params->processFlags & kWPFRemapPalette) { - remapWizImagePal(params); - flags |= kWIFRemapPalette; - } - - if (_vm->_fullRedraw && dstResNum == 0) { - if (sourceImage != 0 || (params->processFlags & (kWPFScaled | kWPFRotate))) - error("Can't do this command in the enter script."); - - assert(_imagesNum < ARRAYSIZE(_images)); - WizImage *pwi = &_images[_imagesNum]; - pwi->resNum = params->img.resNum; - pwi->x1 = po_x; - pwi->y1 = po_y; - pwi->zorder = params->img.zorder; - pwi->state = state; - pwi->flags = flags; - pwi->shadow = shadow; - pwi->field_390 = field_390; - pwi->palette = palette; - ++_imagesNum; - } else { - if (sourceImage != 0) { - // TODO - } else if (params->processFlags & (kWPFScaled | kWPFRotate)) { - drawWizComplexPolygon(params->img.resNum, state, po_x, po_y, shadow, rotationAngle, scale, r, flags, dstResNum, palette); - } else { - if (flags & kWIFIsPolygon) { - drawWizPolygon(params->img.resNum, state, po_x, flags, shadow, dstResNum, palette); // XXX , VAR(VAR_WIZ_TCOLOR)); - } else { - drawWizImage(params->img.resNum, state, po_x, po_y, params->img.zorder, shadow, field_390, r, flags, dstResNum, palette); - } - } - } -} - -void Wiz::createWizEmptyImage(const WizParameters *params) { - int img_w = 640; - if (params->processFlags & kWPFUseDefImgWidth) { - img_w = params->resDefImgW; - } - int img_h = 480; - if (params->processFlags & kWPFUseDefImgHeight) { - img_h = params->resDefImgH; - } - int img_x = 0; - int img_y = 0; - if (params->processFlags & 1) { - img_x = params->img.x1; - img_y = params->img.y1; - } - const uint16 flags = 0xB; - int res_size = 0x1C; - if (flags & 1) { - res_size += 0x308; - } - if (flags & 2) { - res_size += 0x10; - } - if (flags & 8) { - res_size += 0x10C; - } - res_size += 8 + img_w * img_h; - - const uint8 *palPtr; - if (_vm->_heversion >= 99) { - palPtr = _vm->_hePalettes + 1024; - } else { - palPtr = _vm->_currentPalette; - } - uint8 *res_data = _vm->res.createResource(rtImage, params->img.resNum, res_size); - if (!res_data) { - _vm->VAR(119) = -1; - } else { - _vm->VAR(119) = 0; - WRITE_BE_UINT32(res_data, 'AWIZ'); res_data += 4; - WRITE_BE_UINT32(res_data, res_size); res_data += 4; - WRITE_BE_UINT32(res_data, 'WIZH'); res_data += 4; - WRITE_BE_UINT32(res_data, 0x14); res_data += 4; - WRITE_LE_UINT32(res_data, 0); res_data += 4; - WRITE_LE_UINT32(res_data, img_w); res_data += 4; - WRITE_LE_UINT32(res_data, img_h); res_data += 4; - if (flags & 1) { - WRITE_BE_UINT32(res_data, 'RGBS'); res_data += 4; - WRITE_BE_UINT32(res_data, 0x308); res_data += 4; - memcpy(res_data, palPtr, 0x300); res_data += 0x300; - } - if (flags & 2) { - WRITE_BE_UINT32(res_data, 'SPOT'); res_data += 4; - WRITE_BE_UINT32(res_data, 0x10); res_data += 4; - WRITE_BE_UINT32(res_data, img_x); res_data += 4; - WRITE_BE_UINT32(res_data, img_y); res_data += 4; - } - if (flags & 8) { - WRITE_BE_UINT32(res_data, 'RMAP'); res_data += 4; - WRITE_BE_UINT32(res_data, 0x10C); res_data += 4; - WRITE_BE_UINT32(res_data, 0); res_data += 4; - for (int i = 0; i < 256; ++i) { - *res_data++ = i; - } - } - WRITE_BE_UINT32(res_data, 'WIZD'); res_data += 4; - WRITE_BE_UINT32(res_data, 8 + img_w * img_h); res_data += 4; - } - _vm->res.setModified(rtImage, params->img.resNum); -} - -void Wiz::fillWizRect(const WizParameters *params) { - int state = 0; - if (params->processFlags & kWPFNewState) { - state = params->img.state; - } - uint8 *dataPtr = _vm->getResourceAddress(rtImage, params->img.resNum); - if (dataPtr) { - uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); - assert(wizh); - int c = READ_LE_UINT32(wizh + 0x0); - int w = READ_LE_UINT32(wizh + 0x4); - int h = READ_LE_UINT32(wizh + 0x8); - assert(c == 0); - Common::Rect areaRect, imageRect(w, h); - if (params->processFlags & kWPFClipBox) { - if (!imageRect.intersects(params->box)) { - return; - } - imageRect.clip(params->box); - } - if (params->processFlags & kWPFClipBox2) { - areaRect = params->box2; - } else { - areaRect = imageRect; - } - uint8 color = _vm->VAR(93); - if (params->processFlags & kWPFFillColor) { - color = params->fillColor; - } - if (areaRect.intersects(imageRect)) { - areaRect.clip(imageRect); - uint8 *wizd = _vm->findWrappedBlock(MKID('WIZD'), dataPtr, state, 0); - assert(wizd); - int dx = areaRect.width(); - int dy = areaRect.height(); - wizd += areaRect.top * w + areaRect.left; - while (dy--) { - memset(wizd, color, dx); - wizd += w; - } - } - } - _vm->res.setModified(rtImage, params->img.resNum); -} - -void Wiz::fillWizLine(const WizParameters *params) { - if (params->processFlags & kWPFClipBox2) { - int state = 0; - if (params->processFlags & kWPFNewState) { - state = params->img.state; - } - uint8 *dataPtr = _vm->getResourceAddress(rtImage, params->img.resNum); - if (dataPtr) { - uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); - assert(wizh); - int c = READ_LE_UINT32(wizh + 0x0); - int w = READ_LE_UINT32(wizh + 0x4); - int h = READ_LE_UINT32(wizh + 0x8); - assert(c == 0); - Common::Rect imageRect(w, h); - if (params->processFlags & kWPFClipBox) { - if (!imageRect.intersects(params->box)) { - return; - } - imageRect.clip(params->box); - } - uint8 color = _vm->VAR(93); - if (params->processFlags & kWPFFillColor) { - color = params->fillColor; - } - uint8 *wizd = _vm->findWrappedBlock(MKID('WIZD'), dataPtr, state, 0); - assert(wizd); - int x1 = params->box2.left; - int y1 = params->box2.top; - int x2 = params->box2.right; - int y2 = params->box2.bottom; - - int dx = x2 - x1; - int incx = 0; - if (dx > 0) { - incx = 1; - } else if (dx < 0) { - incx = -1; - } - int dy = y2 - y1; - int incy = 0; - if (dy > 0) { - incy = 1; - } else if (dy < 0) { - incy = -1; - } - - dx = ABS(x2 - x1); - dy = ABS(y2 - y1); - - if (imageRect.contains(x1, y1)) { - *(wizd + y1 * w + x1) = color; - } - - if (dx >= dy) { - int step1_y = (dy - dx) * 2; - int step2_y = dy * 2; - int accum_y = dy * 2 - dx; - while (x1 != x2) { - if (accum_y <= 0) { - accum_y += step2_y; - } else { - accum_y += step1_y; - y1 += incy; - } - x1 += incx; - if (imageRect.contains(x1, y1)) { - *(wizd + y1 * w + x1) = color; - } - } - } else { - int step1_x = (dx - dy) * 2; - int step2_x = dx * 2; - int accum_x = dx * 2 - dy; - while (y1 != y2) { - if (accum_x <= 0) { - accum_x += step2_x; - } else { - accum_x += step1_x; - x1 += incx; - } - y1 += incy; - if (imageRect.contains(x1, y1)) { - *(wizd + y1 * w + x1) = color; - } - } - } - } - } - _vm->res.setModified(rtImage, params->img.resNum); -} - -void Wiz::fillWizPixel(const WizParameters *params) { - if (params->processFlags & kWPFClipBox2) { - int px = params->box2.left; - int py = params->box2.top; - uint8 *dataPtr = _vm->getResourceAddress(rtImage, params->img.resNum); - if (dataPtr) { - int state = 0; - if (params->processFlags & kWPFNewState) { - state = params->img.state; - } - uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); - assert(wizh); - int c = READ_LE_UINT32(wizh + 0x0); - int w = READ_LE_UINT32(wizh + 0x4); - int h = READ_LE_UINT32(wizh + 0x8); - assert(c == 0); - Common::Rect imageRect(w, h); - if (params->processFlags & kWPFClipBox) { - if (!imageRect.intersects(params->box)) { - return; - } - imageRect.clip(params->box); - } - uint8 color = _vm->VAR(93); - if (params->processFlags & kWPFFillColor) { - color = params->fillColor; - } - if (imageRect.contains(px, py)) { - uint8 *wizd = _vm->findWrappedBlock(MKID('WIZD'), dataPtr, state, 0); - assert(wizd); - *(wizd + py * w + px) = color; - } - } - } - _vm->res.setModified(rtImage, params->img.resNum); -} - -void Wiz::remapWizImagePal(const WizParameters *params) { - int st = (params->processFlags & kWPFNewState) ? params->img.state : 0; - int num = params->remapNum; - const uint8 *index = params->remapIndex; - uint8 *iwiz = _vm->getResourceAddress(rtImage, params->img.resNum); - assert(iwiz); - uint8 *rmap = _vm->findWrappedBlock(MKID('RMAP'), iwiz, st, 0) ; - assert(rmap); - WRITE_BE_UINT32(rmap, 0x01234567); - while (num--) { - uint8 idx = *index++; - rmap[4 + idx] = params->remapColor[idx]; - } - _vm->res.setModified(rtImage, params->img.resNum); -} - -void Wiz::processWizImage(const WizParameters *params) { - char buf[512]; - unsigned int i; - - debug(2, "processWizImage: processMode %d", params->processMode); - switch (params->processMode) { - case 0: - // Used in racedemo - break; - case 1: - displayWizComplexImage(params); - break; - case 2: - captureWizImage(params->img.resNum, params->box, (params->img.flags & kWIFBlitToFrontVideoBuffer) != 0, params->compType); - break; - case 3: - if (params->processFlags & kWPFUseFile) { - Common::File f; - - // Convert Windows path separators to something more portable - strncpy(buf, (const char *)params->filename, 512); - for (i = 0; i < strlen(buf); i++) { - if (buf[i] == '\\') - buf[i] = '/'; - } - - if (f.open((const char *)buf, Common::File::kFileReadMode)) { - uint32 id = f.readUint32LE(); - if (id == TO_LE_32(MKID('AWIZ')) || id == TO_LE_32(MKID('MULT'))) { - uint32 size = f.readUint32BE(); - f.seek(0, SEEK_SET); - byte *p = _vm->res.createResource(rtImage, params->img.resNum, size); - if (f.read(p, size) != size) { - _vm->res.nukeResource(rtImage, params->img.resNum); - error("i/o error when reading '%s'", buf); - _vm->VAR(_vm->VAR_GAME_LOADED) = -2; - _vm->VAR(119) = -2; - } else { - _vm->res.setModified(rtImage, params->img.resNum); - _vm->VAR(_vm->VAR_GAME_LOADED) = 0; - _vm->VAR(119) = 0; - } - } else { - _vm->VAR(_vm->VAR_GAME_LOADED) = -1; - _vm->VAR(119) = -1; - } - f.close(); - } else { - _vm->VAR(_vm->VAR_GAME_LOADED) = -3; - _vm->VAR(119) = -3; - debug(0, "Unable to open for read '%s'", buf); - } - } - break; - case 4: - if (params->processFlags & kWPFUseFile) { - Common::File f; - - switch(params->fileWriteMode) { - case 2: - _vm->VAR(119) = -1; - break; - case 1: - // TODO Write image to file - break; - case 0: - // Convert Windows path separators to something more portable - strncpy(buf, (const char *)params->filename, 512); - for (i = 0; i < strlen(buf); i++) { - if (buf[i] == '\\') - buf[i] = '/'; - } - - if (!f.open((const char *)buf, Common::File::kFileWriteMode)) { - debug(0, "Unable to open for write '%s'", buf); - _vm->VAR(119) = -3; - } else { - byte *p = _vm->getResourceAddress(rtImage, params->img.resNum); - uint32 size = READ_BE_UINT32(p + 4); - if (f.write(p, size) != size) { - error("i/o error when writing '%s'", params->filename); - _vm->VAR(119) = -2; - } else { - _vm->VAR(119) = 0; - } - f.close(); - } - break; - default: - error("processWizImage: processMode 4 unhandled fileWriteMode %d", params->fileWriteMode); - } - } - break; - case 6: - if (params->processFlags & kWPFRemapPalette) { - remapWizImagePal(params); - } - break; - // HE 99+ - case 7: - // Used in PuttsFunShop/SamsFunShop/soccer2004 - // TODO: Capture polygon - _vm->res.setModified(rtImage, params->img.resNum); - break; - case 8: - createWizEmptyImage(params); - break; - case 9: - fillWizRect(params); - break; - case 10: - fillWizLine(params); - break; - case 11: - fillWizPixel(params); - break; - case 12: - fillWizFlood(params); - break; - case 13: - // Used for text in FreddisFunShop/PuttsFunShop/SamsFunShop - // TODO: Start Font - break; - case 14: - // Used for text in FreddisFunShop/PuttsFunShop/SamsFunShop - // TODO: End Font - break; - case 15: - // Used for text in FreddisFunShop/PuttsFunShop/SamsFunShop - // TODO: Create Font - break; - case 16: - // TODO: Render Font String - error("Render Font String"); - break; - case 17: - // Used in to draw circles in FreddisFunShop/PuttsFunShop/SamsFunShop - // TODO: Ellipse - _vm->res.setModified(rtImage, params->img.resNum); - break; - default: - error("Unhandled processWizImage mode %d", params->processMode); - } -} - -void Wiz::getWizImageDim(int resNum, int state, int32 &w, int32 &h) { - uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum); - assert(dataPtr); - uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); - assert(wizh); - w = READ_LE_UINT32(wizh + 0x4); - h = READ_LE_UINT32(wizh + 0x8); -} - -void Wiz::getWizImageSpot(int resId, int state, int32 &x, int32 &y) { - uint8 *dataPtr = _vm->getResourceAddress(rtImage, resId); - assert(dataPtr); - uint8 *spotPtr = _vm->findWrappedBlock(MKID('SPOT'), dataPtr, state, 0); - if (spotPtr) { - x = READ_LE_UINT32(spotPtr + 0); - y = READ_LE_UINT32(spotPtr + 4); - } else { - x = 0; - y = 0; - } -} - -int Wiz::getWizImageData(int resNum, int state, int type) { - uint8 *dataPtr, *wizh; - - dataPtr = _vm->getResourceAddress(rtImage, resNum); - assert(dataPtr); - - switch (type) { - case 0: - wizh = _vm->findWrappedBlock(MKID('WIZH'), dataPtr, state, 0); - assert(wizh); - return READ_LE_UINT32(wizh + 0x0); - case 1: - return (_vm->findWrappedBlock(MKID('RGBS'), dataPtr, state, 0) != NULL) ? 1 : 0; - case 2: - return (_vm->findWrappedBlock(MKID('RMAP'), dataPtr, state, 0) != NULL) ? 1 : 0; - case 3: - return (_vm->findWrappedBlock(MKID('TRNS'), dataPtr, state, 0) != NULL) ? 1 : 0; - case 4: - return (_vm->findWrappedBlock(MKID('XMAP'), dataPtr, state, 0) != NULL) ? 1 : 0; - default: - error("getWizImageData: Unknown type %d", type); - } -} - -int Wiz::getWizImageStates(int resNum) { - const uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum); - assert(dataPtr); - if (READ_UINT32(dataPtr) == MKID('MULT')) { - const byte *offs, *wrap; - - wrap = _vm->findResource(MKID('WRAP'), dataPtr); - if (wrap == NULL) - return 1; - - offs = _vm->findResourceData(MKID('OFFS'), wrap); - if (offs == NULL) - return 1; - - return _vm->getResourceDataSize(offs) / 4; - } else { - return 1; - } -} - -int Wiz::isWizPixelNonTransparent(int resNum, int state, int x, int y, int flags) { - int ret = 0; - uint8 *data = _vm->getResourceAddress(rtImage, resNum); - assert(data); - uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), data, state, 0); - assert(wizh); - int c = READ_LE_UINT32(wizh + 0x0); - int w = READ_LE_UINT32(wizh + 0x4); - int h = READ_LE_UINT32(wizh + 0x8); - uint8 *wizd = _vm->findWrappedBlock(MKID('WIZD'), data, state, 0); - assert(wizd); - if (x >= 0 && x < w && y >= 0 && y < h) { - if (flags & kWIFFlipX) { - x = w - x - 1; - } - if (flags & kWIFFlipY) { - y = h - y - 1; - } - switch (c) { - case 0: - if (_vm->_heversion >= 99) { - ret = getRawWizPixelColor(wizd, x, y, w, h, _vm->VAR(_vm->VAR_WIZ_TCOLOR)) != _vm->VAR(_vm->VAR_WIZ_TCOLOR) ? 1 : 0; - } else { - ret = 0; - } - break; - case 1: - ret = isWizPixelNonTransparent(wizd, x, y, w, h); - break; - case 2: - // Used baseball2003 - debug(0, "isWizPixelNonTransparent: Unhandled wiz compression type %d", c); - break; - default: - error("isWizPixelNonTransparent: Unhandled wiz compression type %d", c); - break; - } - } - return ret; -} - -uint8 Wiz::getWizPixelColor(int resNum, int state, int x, int y, int flags) { - uint8 color; - uint8 *data = _vm->getResourceAddress(rtImage, resNum); - assert(data); - uint8 *wizh = _vm->findWrappedBlock(MKID('WIZH'), data, state, 0); - assert(wizh); - int c = READ_LE_UINT32(wizh + 0x0); - int w = READ_LE_UINT32(wizh + 0x4); - int h = READ_LE_UINT32(wizh + 0x8); - uint8 *wizd = _vm->findWrappedBlock(MKID('WIZD'), data, state, 0); - assert(wizd); - switch (c) { - case 0: - if (_vm->_heversion >= 99) { - color = getRawWizPixelColor(wizd, x, y, w, h, _vm->VAR(_vm->VAR_WIZ_TCOLOR)); - } else { - color = _vm->VAR(_vm->VAR_WIZ_TCOLOR); - } - break; - case 1: - color = getWizPixelColor(wizd, x, y, w, h, _vm->VAR(_vm->VAR_WIZ_TCOLOR)); - break; - default: - error("getWizPixelColor: Unhandled wiz compression type %d", c); - break; - } - return color; -} - -int ScummEngine_v90he::computeWizHistogram(int resNum, int state, int x, int y, int w, int h) { - writeVar(0, 0); - defineArray(0, kDwordArray, 0, 0, 0, 255); - if (readVar(0) != 0) { - Common::Rect rCapt(x, y, w + 1, h + 1); - uint8 *data = getResourceAddress(rtImage, resNum); - assert(data); - uint8 *wizh = findWrappedBlock(MKID('WIZH'), data, state, 0); - assert(wizh); - int c = READ_LE_UINT32(wizh + 0x0); - w = READ_LE_UINT32(wizh + 0x4); - h = READ_LE_UINT32(wizh + 0x8); - Common::Rect rWiz(w, h); - uint8 *wizd = findWrappedBlock(MKID('WIZD'), data, state, 0); - assert(wizd); - if (rCapt.intersects(rWiz)) { - rCapt.clip(rWiz); - uint32 histogram[256]; - memset(histogram, 0, sizeof(histogram)); - switch (c) { - case 0: - _wiz->computeRawWizHistogram(histogram, wizd, w, rCapt); - break; - case 1: - _wiz->computeWizHistogram(histogram, wizd, rCapt); - break; - default: - error("computeWizHistogram: Unhandled wiz compression type %d", c); - break; - } - for (int i = 0; i < 256; ++i) { - writeArray(0, 0, i, histogram[i]); - } - } - } - return readVar(0); -} - -} // End of namespace Scumm diff --git a/engines/scumm/wiz_he.h b/engines/scumm/wiz_he.h deleted file mode 100644 index 86d3e97721..0000000000 --- a/engines/scumm/wiz_he.h +++ /dev/null @@ -1,211 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#if !defined(WIZ_HE_H) && !defined(DISABLE_HE) -#define WIZ_HE_H - -#include "common/rect.h" - -namespace Scumm { - -struct WizPolygon { - Common::Point vert[5]; - Common::Rect bound; - int id; - int numVerts; - bool flag; -}; - -struct WizImage { - int resNum; - int x1; - int y1; - int zorder; - int state; - int flags; - int shadow; - int field_390; - int palette; -}; - -struct WizParameters { - int field_0; - byte filename[260]; - Common::Rect box; - int processFlags; - int processMode; - int field_11C; - int field_120; - int field_124; - int field_128; - int field_12C; - int field_130; - int field_134; - int field_138; - int compType; - int fileWriteMode; - int angle; - int scale; - int field_164; - int field_168; - int resDefImgW; - int resDefImgH; - int sourceImage; - int field_180; - int field_184; - uint8 remapColor[256]; - uint8 remapIndex[256]; - int remapNum; - int dstResNum; - byte fillColor; - byte string1[4096]; - byte string2[4096]; - int field_2399; - int field_239D; - int field_23A1; - int field_23A5; - int field_23A9; - int field_23AD; - int field_23B1; - int field_23B5; - int field_23B9; - int field_23BD; - int field_23C1; - int field_23C5; - int field_23C9; - int field_23CD; - Common::Rect box2; - int field_23DE; - int spriteId; - int spriteGroup; - int field_23EA; - WizImage img; -}; - -enum WizImageFlags { - kWIFHasPalette = 0x1, - kWIFRemapPalette = 0x2, - kWIFPrint = 0x4, - kWIFBlitToFrontVideoBuffer = 0x8, - kWIFMarkBufferDirty = 0x10, - kWIFBlitToMemBuffer = 0x20, - kWIFIsPolygon = 0x40, - kWIFFlipX = 0x400, - kWIFFlipY = 0x800 -}; - -enum WizProcessFlags { - kWPFSetPos = 0x1, - kWPFShadow = 0x4, - kWPFScaled = 0x8, - kWPFRotate = 0x10, - kWPFNewFlags = 0x20, - kWPFRemapPalette = 0x40, - kWPFClipBox = 0x200, - kWPFNewState = 0x400, - kWPFUseFile = 0x800, - kWPFUseDefImgWidth = 0x2000, - kWPFUseDefImgHeight = 0x4000, - kWPFPaletteNum = 0x8000, - kWPFDstResNum = 0x10000, - kWPFFillColor = 0x20000, - kWPFClipBox2 = 0x40000, - kWPFMaskImg = 0x80000 -}; - -class ScummEngine_v70he; - -class Wiz { -public: - enum { - NUM_POLYGONS = 200, - NUM_IMAGES = 255 - }; - - WizImage _images[NUM_IMAGES]; - uint16 _imagesNum; - WizPolygon _polygons[NUM_POLYGONS]; - - Wiz(ScummEngine_v70he *vm); - - void clearWizBuffer(); - Common::Rect _rectOverride; - bool _rectOverrideEnabled; - - void polygonClear(); - void polygonLoad(const uint8 *polData); - void polygonStore(int id, bool flag, int vert1x, int vert1y, int vert2x, int vert2y, int vert3x, int vert3y, int vert4x, int vert4y); - void polygonCalcBoundBox(Common::Point *vert, int numVerts, Common::Rect & bound); - void polygonErase(int fromId, int toId); - int polygonHit(int id, int x, int y); - bool polygonDefined(int id); - bool polygonContains(const WizPolygon &pol, int x, int y); - void polygonRotatePoints(Common::Point *pts, int num, int alpha); - void polygonTransform(int resNum, int state, int po_x, int po_y, int angle, int zoom, Common::Point *vert); - - void createWizEmptyImage(const WizParameters *params); - void fillWizRect(const WizParameters *params); - void fillWizLine(const WizParameters *params); - void fillWizPixel(const WizParameters *params); - void fillWizFlood(const WizParameters *params); - void remapWizImagePal(const WizParameters *params); - - void getWizImageDim(int resNum, int state, int32 &w, int32 &h); - int getWizImageStates(int resnum); - int isWizPixelNonTransparent(int resnum, int state, int x, int y, int flags); - uint8 getWizPixelColor(int resnum, int state, int x, int y, int flags); - int getWizImageData(int resNum, int state, int type); - - void flushWizBuffer(); - - void getWizImageSpot(int resId, int state, int32 &x, int32 &y); - void loadWizCursor(int resId); - - void captureWizImage(int resNum, const Common::Rect& r, bool frontBuffer, int compType); - void displayWizComplexImage(const WizParameters *params); - void displayWizImage(WizImage *pwi); - void processWizImage(const WizParameters *params); - - uint8 *drawWizImage(int resNum, int state, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, int palette); - void drawWizPolygon(int resNum, int state, int id, int flags, int shadow, int dstResNum, int palette); - void drawWizComplexPolygon(int resNum, int state, int po_x, int po_y, int shadow, int angle, int zoom, const Common::Rect *r, int flags, int dstResNum, int palette); - void drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int flags, int shadow, int dstResNum, int palette); - - static void copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch); - static void copyWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags = 0, const uint8 *palPtr = NULL, const uint8 *xmapPtr = NULL); - static void copyRawWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor); - static void copyRaw16BitWizImage(uint8 *dst, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor); - static void decompressWizImage(uint8 *dst, int dstPitch, const Common::Rect &dstRect, const uint8 *src, const Common::Rect &srcRect, int flags, const uint8 *palPtr = NULL, const uint8 *xmapPtr = NULL); - int isWizPixelNonTransparent(const uint8 *data, int x, int y, int w, int h); - uint8 getWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color); - uint8 getRawWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 color); - void computeWizHistogram(uint32 *histogram, const uint8 *data, const Common::Rect& rCapt); - void computeRawWizHistogram(uint32 *histogram, const uint8 *data, int srcPitch, const Common::Rect& rCapt); - -private: - ScummEngine_v70he *_vm; -}; - -} // End of namespace Scumm - -#endif -- cgit v1.2.3