aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra/engine/sprites.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/kyra/engine/sprites.cpp')
-rw-r--r--engines/kyra/engine/sprites.cpp575
1 files changed, 575 insertions, 0 deletions
diff --git a/engines/kyra/engine/sprites.cpp b/engines/kyra/engine/sprites.cpp
new file mode 100644
index 0000000000..197d8eab4e
--- /dev/null
+++ b/engines/kyra/engine/sprites.cpp
@@ -0,0 +1,575 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/engine/sprites.h"
+#include "kyra/resource/resource.h"
+#include "kyra/graphics/animator_lok.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+Sprites::Sprites(KyraEngine_LoK *vm, OSystem *system) : _rnd("kyraSprites") {
+ _vm = vm;
+ _res = vm->resource();
+ _screen = vm->screen();
+ _system = system;
+ _dat = 0;
+ memset(_anims, 0, sizeof(_anims));
+ memset(_sceneShapes, 0, sizeof(_sceneShapes));
+ _spriteDefStart = 0;
+ memset(_drawLayerTable, 0, sizeof(_drawLayerTable));
+ _sceneAnimatorBeaconFlag = 0;
+}
+
+Sprites::~Sprites() {
+ delete[] _dat;
+ freeSceneShapes();
+ for (int i = 0; i < MAX_NUM_ANIMS; i++) {
+ if (_anims[i].background)
+ delete[] _anims[i].background;
+ }
+}
+
+void Sprites::setupSceneAnims() {
+ uint8 *data;
+
+ for (int i = 0; i < MAX_NUM_ANIMS; i++) {
+ delete[] _anims[i].background;
+ _anims[i].background = 0;
+
+ if (_anims[i].script != 0) {
+ data = _anims[i].script;
+
+ assert(READ_LE_UINT16(data) == 0xFF86);
+ data += 4;
+
+ _anims[i].disable = READ_LE_UINT16(data) != 0;
+ data += 4;
+ _anims[i].unk2 = READ_LE_UINT16(data);
+ data += 4;
+
+ if ((_vm->_northExitHeight & 0xFF) > READ_LE_UINT16(data))
+ _anims[i].drawY = _vm->_northExitHeight & 0xFF;
+ else
+ _anims[i].drawY = READ_LE_UINT16(data);
+ data += 4;
+
+ //sceneUnk2[i] = READ_LE_UINT16(data);
+ data += 4;
+
+ _anims[i].x = READ_LE_UINT16(data);
+ data += 4;
+ _anims[i].y = READ_LE_UINT16(data);
+ data += 4;
+ _anims[i].width = *(data);
+ data += 4;
+ _anims[i].height = *(data);
+ data += 4;
+ _anims[i].sprite = READ_LE_UINT16(data);
+ data += 4;
+ _anims[i].flipX = READ_LE_UINT16(data) != 0;
+ data += 4;
+ _anims[i].width2 = *(data);
+ data += 4;
+ _anims[i].height2 = *(data);
+ data += 4;
+ _anims[i].unk1 = READ_LE_UINT16(data) != 0;
+ data += 4;
+ _anims[i].play = READ_LE_UINT16(data) != 0;
+ data += 2;
+
+ _anims[i].script = data;
+ _anims[i].curPos = data;
+
+ int bkgdWidth = _anims[i].width;
+ int bkgdHeight = _anims[i].height;
+
+ if (_anims[i].width2 > 0)
+ bkgdWidth += (_anims[i].width2 >> 3) + 1;
+
+ if (_anims[i].height2 > 0)
+ bkgdHeight += _anims[i].height2;
+
+ _anims[i].background = new uint8[_screen->getRectSize(bkgdWidth + 1, bkgdHeight)];
+ assert(_anims[i].background);
+ memset(_anims[i].background, 0, _screen->getRectSize(bkgdWidth + 1, bkgdHeight));
+ }
+ }
+}
+
+void Sprites::updateSceneAnims() {
+ uint32 currTime = _system->getMillis();
+ bool update;
+ uint8 *data;
+ uint16 rndNr;
+ uint16 anim;
+ uint16 sound;
+
+ for (int i = 0; i < MAX_NUM_ANIMS; i++) {
+ if (_anims[i].script == 0 || !_anims[i].play || (_anims[i].nextRun != 0 && _anims[i].nextRun > currTime))
+ continue;
+
+ data = _anims[i].curPos;
+ update = true;
+ debugC(6, kDebugLevelSprites, "anim: %d 0x%.04X", i, READ_LE_UINT16(data));
+ assert((data - _anims[i].script) < _anims[i].length);
+ switch (READ_LE_UINT16(data)) {
+ case 0xFF88:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Set sprite image.");
+ debugC(6, kDebugLevelSprites, "Sprite index %i", READ_LE_UINT16(data));
+ _anims[i].sprite = READ_LE_UINT16(data);
+ data += 2;
+ //debugC(6, kDebugLevelSprites, "Unused %i", READ_LE_UINT16(data));
+ data += 2;
+ debugC(6, kDebugLevelSprites, "X %i", READ_LE_UINT16(data));
+ _anims[i].x = READ_LE_UINT16(data);
+ data += 2;
+ debugC(6, kDebugLevelSprites, "Y %i", READ_LE_UINT16(data));
+ _anims[i].y = READ_LE_UINT16(data);
+ data += 2;
+ _anims[i].flipX = false;
+ _anims[i].lastRefresh = _system->getMillis();
+ refreshSceneAnimObject(i, _anims[i].sprite, _anims[i].x, _anims[i].y, _anims[i].flipX, _anims[i].unk1 != 0);
+ break;
+ case 0xFF8D:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Set sprite image, flipped.");
+ debugC(6, kDebugLevelSprites, "Sprite index %i", READ_LE_UINT16(data));
+ _anims[i].sprite = READ_LE_UINT16(data);
+ data += 2;
+ data += 2;
+ debugC(6, kDebugLevelSprites, "X %i", READ_LE_UINT16(data));
+ _anims[i].x = READ_LE_UINT16(data);
+ data += 2;
+ debugC(6, kDebugLevelSprites, "Y %i", READ_LE_UINT16(data));
+ _anims[i].y = READ_LE_UINT16(data);
+ data += 2;
+ _anims[i].flipX = true;
+ _anims[i].lastRefresh = _system->getMillis();
+ refreshSceneAnimObject(i, _anims[i].sprite, _anims[i].x, _anims[i].y, _anims[i].flipX, _anims[i].unk1 != 0);
+ break;
+ case 0xFF8A:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Set time to wait");
+ debugC(6, kDebugLevelSprites, "Time %i", READ_LE_UINT16(data));
+ _anims[i].nextRun = _system->getMillis() + READ_LE_UINT16(data) * _vm->tickLength();
+ _anims[i].nextRun -= _system->getMillis() - _anims[i].lastRefresh;
+ data += 2;
+ break;
+ case 0xFFB3:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Set time to wait to random value");
+ rndNr = READ_LE_UINT16(data) + _rnd.getRandomNumber( READ_LE_UINT16(data) + 2);
+ debugC(6, kDebugLevelSprites, "Minimum time %i", READ_LE_UINT16(data));
+ data += 2;
+ debugC(6, kDebugLevelSprites, "Maximum time %i", READ_LE_UINT16(data));
+ data += 2;
+ _anims[i].nextRun = _system->getMillis() + rndNr * _vm->tickLength();
+ _anims[i].nextRun -= _system->getMillis() - _anims[i].lastRefresh;
+ break;
+ case 0xFF8C:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Wait until wait time has elapsed");
+ update = (_anims[i].nextRun < currTime);
+ //assert( _anims[i].nextRun > _system->getMillis());
+ break;
+ case 0xFF99:
+ data += 2;
+ debugC(1, kDebugLevelSprites, "func: Set value of unknown animation property to 1");
+ _anims[i].unk1 = 1;
+ break;
+ case 0xFF9A:
+ data += 2;
+ debugC(1, kDebugLevelSprites, "func: Set value of unknown animation property to 0");
+ _anims[i].unk1 = 0;
+ break;
+ case 0xFF97:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Set default X coordinate of sprite");
+ debugC(6, kDebugLevelSprites, "X %i", READ_LE_UINT16(data));
+ _anims[i].x = READ_LE_UINT16(data);
+ data += 2;
+ break;
+ case 0xFF98:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Set default Y coordinate of sprite");
+ debugC(6, kDebugLevelSprites, "Y %i", READ_LE_UINT16(data));
+ _anims[i].y = READ_LE_UINT16(data);
+ data += 2;
+ break;
+ case 0xFF8B:
+ debugC(6, kDebugLevelSprites, "func: Jump to start of script section");
+ _anims[i].curPos = _anims[i].script;
+ _anims[i].nextRun = _system->getMillis();
+ update = false;
+ break;
+ case 0xFF8E:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Begin for () loop");
+ debugC(6, kDebugLevelSprites, "Iterations: %i", READ_LE_UINT16(data));
+ _anims[i].loopsLeft = READ_LE_UINT16(data);
+ data += 2;
+ _anims[i].loopStart = data;
+ break;
+ case 0xFF8F:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: End for () loop");
+ if (_anims[i].loopsLeft > 0) {
+ _anims[i].loopsLeft--;
+ data = _anims[i].loopStart;
+ }
+ break;
+ case 0xFF90:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Set sprite image using default X and Y");
+ debugC(6, kDebugLevelSprites, "Sprite index %i", READ_LE_UINT16(data));
+ _anims[i].sprite = READ_LE_UINT16(data);
+ _anims[i].flipX = false;
+ data += 2;
+ _anims[i].lastRefresh = _system->getMillis();
+ refreshSceneAnimObject(i, _anims[i].sprite, _anims[i].x, _anims[i].y, _anims[i].flipX, _anims[i].unk1 != 0);
+ break;
+ case 0xFF91:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Set sprite image using default X and Y, flipped.");
+ debugC(6, kDebugLevelSprites, "Sprite index %i", READ_LE_UINT16(data));
+ _anims[i].sprite = READ_LE_UINT16(data);
+ _anims[i].flipX = true;
+ data += 2;
+ _anims[i].lastRefresh = _system->getMillis();
+ refreshSceneAnimObject(i, _anims[i].sprite, _anims[i].x, _anims[i].y, _anims[i].flipX, _anims[i].unk1 != 0);
+ break;
+ case 0xFF92:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Increase value of default X-coordinate");
+ debugC(6, kDebugLevelSprites, "Increment %i", READ_LE_UINT16(data));
+ _anims[i].x += READ_LE_UINT16(data);
+ data += 2;
+ break;
+ case 0xFF93:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Increase value of default Y-coordinate");
+ debugC(6, kDebugLevelSprites, "Increment %i", READ_LE_UINT16(data));
+ _anims[i].y += READ_LE_UINT16(data);
+ data += 2;
+ break;
+ case 0xFF94:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Decrease value of default X-coordinate");
+ debugC(6, kDebugLevelSprites, "Decrement %i", READ_LE_UINT16(data));
+ _anims[i].x -= READ_LE_UINT16(data);
+ data += 2;
+ break;
+ case 0xFF95:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Decrease value of default Y-coordinate");
+ debugC(6, kDebugLevelSprites, "Decrement %i", READ_LE_UINT16(data));
+ _anims[i].y -= READ_LE_UINT16(data);
+ data += 2;
+ break;
+ case 0xFF96:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Stop animation");
+ debugC(6, kDebugLevelSprites, "Animation index %i", READ_LE_UINT16(data));
+ anim = READ_LE_UINT16(data);
+ data += 2;
+ _anims[anim].play = false;
+ _anims[anim].sprite = -1;
+ break;
+/* case 0xFF97:
+ data += 2;
+ debugC(1, kDebugLevelSprites, "func: Set value of animation property 34h to 0");
+ break;*/
+ case 0xFFAD:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Set Brandon's X coordinate");
+ debugC(6, kDebugLevelSprites, "X %i", READ_LE_UINT16(data));
+ _vm->currentCharacter()->x1 = READ_LE_UINT16(data);
+ data += 2;
+ break;
+ case 0xFFAE:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Set Brandon's Y coordinate");
+ debugC(6, kDebugLevelSprites, "Y %i", READ_LE_UINT16(data));
+ _vm->currentCharacter()->y1 = READ_LE_UINT16(data);
+ data += 2;
+ break;
+ case 0xFFAF:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Set Brandon's sprite");
+ debugC(6, kDebugLevelSprites, "Sprite %i", READ_LE_UINT16(data));
+ _vm->currentCharacter()->currentAnimFrame = READ_LE_UINT16(data);
+ data += 2;
+ break;
+ case 0xFFAA:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Reset Brandon's sprite");
+ _vm->animator()->actors()->sceneAnimPtr = 0;
+ _vm->animator()->actors()->bkgdChangeFlag = 1;
+ _vm->animator()->actors()->refreshFlag = 1;
+ _vm->animator()->restoreAllObjectBackgrounds();
+ _vm->animator()->flagAllObjectsForRefresh();
+ _vm->animator()->updateAllObjectShapes();
+ break;
+ case 0xFFAB:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Update Brandon's sprite");
+ _vm->animator()->animRefreshNPC(0);
+ _vm->animator()->flagAllObjectsForRefresh();
+ _vm->animator()->updateAllObjectShapes();
+ break;
+ case 0xFFB0:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Play sound");
+ debugC(6, kDebugLevelSprites, "Sound index %i", READ_LE_UINT16(data));
+ _vm->snd_playSoundEffect(READ_LE_UINT16(data));
+ data += 2;
+ break;
+ case 0xFFB1:
+ data += 2;
+ _sceneAnimatorBeaconFlag = 1;
+ break;
+ case 0xFFB2:
+ data += 2;
+ _sceneAnimatorBeaconFlag = 0;
+ break;
+ case 0xFFB4:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Play (at random) a certain sound at a certain percentage of time");
+ debugC(6, kDebugLevelSprites, "Sound index %i", READ_LE_UINT16(data));
+ sound = READ_LE_UINT16(data);
+ data += 2;
+ debugC(6, kDebugLevelSprites, "Percentage %i", READ_LE_UINT16(data));
+ rndNr = _rnd.getRandomNumber(100);
+ if (rndNr <= READ_LE_UINT16(data))
+ _vm->snd_playSoundEffect(sound);
+ data += 2;
+ break;
+ case 0xFFA7:
+ data += 2;
+ debugC(6, kDebugLevelSprites, "func: Play animation");
+ debugC(6, kDebugLevelSprites, "Animation index %i", READ_LE_UINT16(data));
+ _anims[READ_LE_UINT16(data)].play = 1;
+ data += 2;
+ break;
+ default:
+ warning("Unsupported anim command %X in script %i", READ_LE_UINT16(data), i);
+ data += 2;
+ }
+
+ if (update)
+ _anims[i].curPos = data;
+ if (READ_LE_UINT16(data) == 0xFF87)
+ _anims[i].play = false;
+ }
+}
+
+void Sprites::loadDat(const char *filename, SceneExits &exits) {
+ uint32 fileSize;
+
+ delete[] _dat;
+ _spriteDefStart = 0;
+
+ _res->exists(filename, true);
+ _dat = _res->fileData(filename, &fileSize);
+
+ for (uint i = 0; i < MAX_NUM_ANIMS; ++i)
+ delete[] _anims[i].background;
+
+ memset(_anims, 0, sizeof(_anims));
+ uint8 nextAnim = 0;
+
+ assert(fileSize > 0x6D);
+
+ memcpy(_drawLayerTable, (_dat + 0x0D), 8);
+ _vm->_northExitHeight = READ_LE_UINT16(_dat + 0x15);
+ if (_vm->_northExitHeight & 1)
+ _vm->_northExitHeight += 1;
+
+ // XXX
+ _vm->_paletteChanged = 1;
+
+ if (_vm->gameFlags().platform == Common::kPlatformAmiga) {
+ if (_vm->queryGameFlag(0xA0))
+ _screen->copyPalette(3, 4);
+ else
+ _screen->copyPalette(3, 0);
+ } else {
+ if (_vm->queryGameFlag(0xA0))
+ _screen->copyPalette(1, 3);
+ else
+ _screen->copyPalette(1, 0);
+
+ _screen->getPalette(1).copy(_dat + 0x17, 0, 20, 228);
+ }
+ uint8 *data = _dat + 0x6B;
+
+ uint16 length = READ_LE_UINT16(data);
+ data += 2;
+
+ if (length > 2) {
+ assert( length < fileSize);
+ uint8 *animstart;
+ uint8 *start = data;
+
+ while (1) {
+ if (((uint16)(data - _dat) >= fileSize) || (data - start) >= length)
+ break;
+
+ if (READ_LE_UINT16(data) == 0xFF83) {
+ //debugC(1, kDebugLevelSprites, "Body section end.");
+ data += 2;
+ break;
+ }
+
+ switch (READ_LE_UINT16(data)) {
+ case 0xFF81:
+ data += 2;
+ //debugC(1, kDebugLevelSprites, "Body section start");
+ break;
+ case 0xFF82:
+ data += 2;
+ //debugC(1, kDebugLevelSprites, "Unknown 0xFF82 section");
+ break;
+ case 0xFF84:
+ data += 2;
+ _spriteDefStart = data;
+ while (READ_LE_UINT16(data) != 0xFF85)
+ data += 2;
+ data += 2;
+ break;
+ case 0xFF86:
+ assert(nextAnim < MAX_NUM_ANIMS);
+ _anims[nextAnim].script = data;
+ _anims[nextAnim].curPos = data;
+ _anims[nextAnim].sprite = -1;
+ _anims[nextAnim].play = true;
+ animstart = data;
+ data += 2;
+ while (READ_LE_UINT16(data) != 0xFF87) {
+ assert((uint16)(data - _dat) < fileSize);
+ data += 2;
+ }
+ _anims[nextAnim].length = data - animstart;
+ //debugC(1, kDebugLevelSprites, "Found an anim script of length %i", _anims[nextAnim].length);
+ nextAnim++;
+ data += 2;
+ break;
+ default:
+ warning("Unknown code in DAT file '%s' offset %d: %x", filename, int(data - _dat), READ_LE_UINT16(data));
+ data += 2;
+ }
+ }
+ } else {
+ data += 2;
+ }
+
+ assert(fileSize - (data - _dat) == 0xC);
+
+ exits.northXPos = READ_LE_UINT16(data) & 0xFFFC; data += 2;
+ exits.northYPos = *data++ & 0xFFFE;
+ exits.eastXPos = READ_LE_UINT16(data) & 0xFFFC; data += 2;
+ exits.eastYPos = *data++ & 0xFFFE;
+ exits.southXPos = READ_LE_UINT16(data) & 0xFFFC; data += 2;
+ exits.southYPos = *data++ & 0xFFFE;
+ exits.westXPos = READ_LE_UINT16(data) & 0xFFFC; data += 2;
+ exits.westYPos = *data++ & 0xFFFE;
+}
+
+void Sprites::freeSceneShapes() {
+ for (int i = 0; i < ARRAYSIZE(_sceneShapes); i++) {
+ delete[] _sceneShapes[i];
+ _sceneShapes[i] = 0;
+ }
+}
+
+void Sprites::loadSceneShapes() {
+ uint8 *data = _spriteDefStart;
+ int spriteNum, x, y, width, height;
+
+ freeSceneShapes();
+ memset( _sceneShapes, 0, sizeof(_sceneShapes));
+
+ if (_spriteDefStart == 0)
+ return;
+
+ int bakPage = _screen->_curPage;
+ _screen->_curPage = 3;
+
+ while (READ_LE_UINT16(data) != 0xFF85) {
+ spriteNum = READ_LE_UINT16(data);
+ assert(spriteNum < ARRAYSIZE(_sceneShapes));
+ data += 2;
+ x = READ_LE_UINT16(data) * 8;
+ data += 2;
+ y = READ_LE_UINT16(data);
+ data += 2;
+ width = READ_LE_UINT16(data) * 8;
+ data += 2;
+ height = READ_LE_UINT16(data);
+ data += 2;
+ _sceneShapes[spriteNum] = _screen->encodeShape(x, y, width, height, 2);
+ }
+ _screen->_curPage = bakPage;
+}
+
+void Sprites::refreshSceneAnimObject(uint8 animNum, uint8 shapeNum, uint16 x, uint16 y, bool flipX, bool unkFlag) {
+ Animator_LoK::AnimObject &anim = _vm->animator()->sprites()[animNum];
+ anim.refreshFlag = 1;
+ anim.bkgdChangeFlag = 1;
+
+ if (unkFlag)
+ anim.flags |= 0x0200;
+ else
+ anim.flags &= 0xFD00;
+
+ if (flipX)
+ anim.flags |= 1;
+ else
+ anim.flags &= 0xFE;
+
+ anim.sceneAnimPtr = _sceneShapes[shapeNum];
+ anim.animFrameNumber = -1;
+ anim.x1 = x;
+ anim.y1 = y;
+}
+
+int Sprites::getDrawLayer(int y) {
+ uint8 returnValue = 0;
+ for (int i = 0; i < ARRAYSIZE(_drawLayerTable); ++i) {
+ uint8 temp = _drawLayerTable[i];
+ if (temp) {
+ if (temp <= y)
+ returnValue = i;
+ }
+ }
+
+ if (returnValue <= 0)
+ returnValue = 1;
+ else if (returnValue >= 7)
+ returnValue = 6;
+
+ return returnValue;
+}
+} // End of namespace Kyra